diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 0fe48a8ffdf..dd54aea2e92 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -249,6 +249,7 @@ CREATE TABLE `player` ( `volume` smallint(4) DEFAULT '100', `nanoui_fancy` smallint(4) DEFAULT '1', `show_ghostitem_attack` smallint(4) DEFAULT '1', + `lastchangelog` varchar(32) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index cc73257ebe2..453554f5c69 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -249,6 +249,7 @@ CREATE TABLE `SS13_player` ( `volume` smallint(4) DEFAULT '100', `nanoui_fancy` smallint(4) DEFAULT '1', `show_ghostitem_attack` smallint(4) DEFAULT '1', + `lastchangelog` varchar(32) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; diff --git a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm index b50efa38848..bb50f35b41d 100644 --- a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm +++ b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm @@ -455,7 +455,7 @@ "aiM" = (/obj/effect/spawner/window/reinforced{useFull = 1; tag = "fullReinWin"},/obj/structure/cable/yellow,/turf/simulated/floor/plating,/area/security/prison) "aiN" = (/obj/machinery/flasher/portable,/obj/machinery/flasher/portable,/obj/structure/reagent_dispensers/peppertank{pixel_x = 0; pixel_y = 29},/turf/simulated/floor/plasteel{tag = "icon-vault (WEST)"; icon_state = "vault"; dir = 8},/area/security/warden) "aiO" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/security/warden) -"aiP" = (/obj/structure/rack,/obj/item/weapon/gun/energy/advtaser{pixel_x = -3; pixel_y = 3},/obj/item/weapon/gun/energy/advtaser,/obj/item/weapon/gun/energy/advtaser{pixel_x = 3; pixel_y = -3},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{tag = "icon-vault (NORTH)"; icon_state = "vault"; dir = 1},/area/security/warden) +"aiP" = (/obj/structure/rack,/obj/item/weapon/gun/energy/gun/advtaser{pixel_x = -3; pixel_y = 3},/obj/item/weapon/gun/energy/gun/advtaser,/obj/item/weapon/gun/energy/gun/advtaser{pixel_x = 3; pixel_y = -3},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{tag = "icon-vault (NORTH)"; icon_state = "vault"; dir = 1},/area/security/warden) "aiQ" = (/obj/machinery/syndicatebomb/training,/turf/simulated/floor/plasteel{tag = "icon-vault (WEST)"; icon_state = "vault"; dir = 8},/area/security/warden) "aiR" = (/obj/structure/rack,/obj/item/weapon/gun/energy/laser{pixel_x = -3; pixel_y = 3},/obj/item/weapon/gun/energy/laser,/obj/item/weapon/gun/energy/laser{pixel_x = 3; pixel_y = -3},/turf/simulated/floor/plasteel{tag = "icon-vault (EAST)"; icon_state = "vault"; dir = 4},/area/security/warden) "aiS" = (/turf/simulated/floor/plasteel{icon_state = "dark"},/area/security/warden) @@ -583,7 +583,7 @@ "alk" = (/obj/machinery/alarm{pixel_y = 24},/obj/machinery/atmospherics/unary/vent_pump{dir = 8; on = 1},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness{name = "\improper Recreation Area"}) "all" = (/obj/structure/shuttle/engine/propulsion{tag = "icon-propulsion_l"; icon_state = "propulsion_l"},/turf/space,/area/shuttle/vox) "alm" = (/obj/structure/rack,/obj/item/clothing/accessory/storage/black_vest,/obj/item/clothing/suit/space/vox/pressure,/obj/item/clothing/head/helmet/space/vox/pressure,/obj/item/clothing/mask/breath,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox) -"aln" = (/obj/structure/rack,/obj/item/weapon/gun/launcher/spikethrower,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox) +"aln" = (/obj/structure/rack,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox) "alo" = (/obj/machinery/door/poddoor{id_tag = "trash"; name = "disposal bay door"},/turf/simulated/floor/plating,/area/maintenance/disposal) "alp" = (/obj/machinery/mass_driver{dir = 8; id_tag = "trash"},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plating{icon_state = "warnplate"; dir = 1},/area/maintenance/disposal) "alq" = (/obj/machinery/conveyor_switch/oneway{convdir = -1; id = "garbage"; name = "disposal coveyor"},/turf/simulated/floor/plating,/area/maintenance/disposal) @@ -1679,7 +1679,7 @@ "aGo" = (/obj/machinery/light,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 6},/area/security/nuke_storage) "aGp" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/cable/yellow{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/plasteel{icon_state = "vault"},/area/security/nuke_storage) "aGq" = (/obj/machinery/camera/motion{c_tag = "Vault"; dir = 1; network = list("MiniSat")},/obj/machinery/light,/obj/structure/cable/yellow{d1 = 1; d2 = 8; icon_state = "1-8"},/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 10},/area/security/nuke_storage) -"aGr" = (/obj/structure/safe,/obj/item/weapon/storage/secure/briefcase{contents = newlist(/obj/item/clothing/suit/armor/vest,/obj/item/weapon/gun/projectile/automatic/pistol,/obj/item/weapon/suppressor,/obj/item/clothing/mask/balaclava,/obj/item/bodybag,/obj/item/weapon/soap/nanotrasen)},/obj/item/weapon/storage/backpack/duffel{contents = newlist(/obj/item/clothing/under/lawyer,/obj/item/clothing/accessory/waistcoat,/obj/item/clothing/shoes/laceup,/obj/item/clothing/gloves/color/black,/obj/item/clothing/glasses/sunglasses,/obj/item/clothing/head/fedora); desc = "A large dufflebag for holding extra things. There is a NanoTrasen logo on the back."; icon_state = "duffle-syndieammo"; item_state = "duffle-syndieammo"},/obj/item/weapon/card/id/silver{access = list(12); assignment = "Reaper"; name = "Thirteen's ID Card (Reaper)"; registered_name = "Thirteen"},/obj/item/weapon/lazarus_injector,/obj/item/weapon/gun/energy/advtaser,/obj/item/weapon/gun/projectile/revolver/russian,/obj/item/ammo_box/a357,/obj/item/clothing/accessory/stethoscope,/obj/item/weapon/book{desc = "An undeniably handy book."; icon_state = "bookknock"; name = "A Simpleton's Guide to Safe-cracking with Stethoscopes"},/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 4},/area/security/nuke_storage) +"aGr" = (/obj/structure/safe,/obj/item/weapon/storage/secure/briefcase{contents = newlist(/obj/item/clothing/suit/armor/vest,/obj/item/weapon/gun/projectile/automatic/pistol,/obj/item/weapon/suppressor,/obj/item/clothing/mask/balaclava,/obj/item/bodybag,/obj/item/weapon/soap/nanotrasen)},/obj/item/weapon/storage/backpack/duffel{contents = newlist(/obj/item/clothing/under/lawyer,/obj/item/clothing/accessory/waistcoat,/obj/item/clothing/shoes/laceup,/obj/item/clothing/gloves/color/black,/obj/item/clothing/glasses/sunglasses,/obj/item/clothing/head/fedora); desc = "A large dufflebag for holding extra things. There is a NanoTrasen logo on the back."; icon_state = "duffle-syndieammo"; item_state = "duffle-syndieammo"},/obj/item/weapon/card/id/silver{access = list(12); assignment = "Reaper"; name = "Thirteen's ID Card (Reaper)"; registered_name = "Thirteen"},/obj/item/weapon/lazarus_injector,/obj/item/weapon/gun/energy/gun/advtaser,/obj/item/weapon/gun/projectile/revolver/russian,/obj/item/ammo_box/a357,/obj/item/clothing/accessory/stethoscope,/obj/item/weapon/book{desc = "An undeniably handy book."; icon_state = "bookknock"; name = "A Simpleton's Guide to Safe-cracking with Stethoscopes"},/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 4},/area/security/nuke_storage) "aGs" = (/obj/structure/shuttle/engine/heater,/obj/structure/window/reinforced{dir = 1; layer = 2.9},/turf/simulated/shuttle/plating,/area/shuttle/siberia) "aGt" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass_security{name = "Labor Camp Shuttle Airlock"; req_access_txt = "0"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/hallway/primary/fore) "aGu" = (/obj/effect/spawner/window/reinforced{useFull = 1; tag = "fullReinWin"},/obj/structure/cable/yellow{d2 = 4; icon_state = "0-4"},/obj/machinery/door/poddoor/preopen{id_tag = "Secure Gate"; name = "brig shutters"},/turf/simulated/floor/plating,/area/security/brig) diff --git a/_maps/map_files/RandomZLevels/beach.dmm b/_maps/map_files/RandomZLevels/beach.dmm index 0a5cd703fc0..04512b660bf 100644 --- a/_maps/map_files/RandomZLevels/beach.dmm +++ b/_maps/map_files/RandomZLevels/beach.dmm @@ -19,7 +19,7 @@ "as" = (/obj/structure/boulder,/turf/unsimulated/beach/water/deep/sand_floor,/area/awaymission/undersea) "at" = (/obj/item/flag/cult,/turf/unsimulated/beach/water/deep/wood_floor,/area/awaymission/undersea) "au" = (/obj/structure/mineral_door/sandstone,/obj/structure/barricade/wooden,/turf/unsimulated/beach/water/deep/wood_floor,/area/awaymission/undersea) -"av" = (/obj/item/weapon/crossbowframe,/turf/unsimulated/beach/water/deep/sand_floor,/area/awaymission/undersea) +"av" = (/turf/unsimulated/beach/water/deep/sand_floor,/area/awaymission/undersea) "aw" = (/obj/item/toy/eight_ball/conch,/turf/unsimulated/beach/water/deep/wood_floor,/area/awaymission/undersea) "ax" = (/obj/structure/reagent_dispensers/beerkeg,/turf/unsimulated/beach/water/deep/wood_floor,/area/awaymission/undersea) "ay" = (/obj/structure/closet/cabinet,/turf/unsimulated/beach/water/deep/wood_floor,/area/awaymission/undersea) diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index 47df198e5b8..7e221cf1131 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -225,7 +225,7 @@ "aeq" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall/r_wall,/area/security/interrogationobs) "aer" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/camera{c_tag = "Brig Prison Hallway"; dir = 4; network = list("Prison","SS13")},/turf/simulated/floor/plasteel{icon_state = "red"; dir = 8},/area/security/permabrig) "aes" = (/obj/structure/lattice,/obj/machinery/camera{c_tag = "Brig Secure Armory Exterior South"; dir = 8; network = list("SS13")},/turf/space,/area/security/permabrig) -"aet" = (/obj/structure/rack,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/item/weapon/gun/energy/advtaser{pixel_x = -3; pixel_y = 3},/obj/item/weapon/gun/energy/advtaser{pixel_x = 0; pixel_y = 0},/obj/item/weapon/gun/energy/advtaser{pixel_x = 3; pixel_y = -3},/turf/simulated/floor/plasteel{dir = 8; icon_state = "vault"; tag = "icon-vault (WEST)"},/area/security/securearmoury) +"aet" = (/obj/structure/rack,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/obj/item/weapon/gun/energy/gun/advtaser{pixel_x = -3; pixel_y = 3},/obj/item/weapon/gun/energy/gun/advtaser{pixel_x = 0; pixel_y = 0},/obj/item/weapon/gun/energy/gun/advtaser{pixel_x = 3; pixel_y = -3},/turf/simulated/floor/plasteel{dir = 8; icon_state = "vault"; tag = "icon-vault (WEST)"},/area/security/securearmoury) "aeu" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/effect/decal/warning_stripes/southeast,/obj/vehicle/secway,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/security/securearmoury) "aev" = (/obj/structure/rack,/obj/structure/window/reinforced,/obj/structure/window/reinforced{dir = 4},/obj/item/weapon/shield/riot,/obj/item/weapon/shield/riot,/obj/item/weapon/shield/riot,/turf/simulated/floor/plasteel{dir = 8; icon_state = "vault"; tag = "icon-vault (WEST)"},/area/security/securearmoury) "aew" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/carpet,/area/security/hos) @@ -464,7 +464,7 @@ "aiV" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel,/area/security/armoury) "aiW" = (/obj/structure/rack,/obj/item/weapon/storage/box/seccarts{pixel_x = 3; pixel_y = 2},/obj/item/weapon/storage/box/handcuffs,/obj/item/weapon/storage/box/flashbangs{pixel_x = -2; pixel_y = -2},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/storage/box/handcuffs,/obj/effect/decal/warning_stripes/red/hollow,/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/security/armoury) "aiX" = (/obj/structure/rack,/obj/item/clothing/mask/gas{pixel_x = 3; pixel_y = 3},/obj/item/clothing/mask/gas{pixel_x = 3; pixel_y = 3},/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas,/obj/item/clothing/mask/gas{pixel_x = -3; pixel_y = -3},/obj/item/clothing/mask/gas{pixel_x = -3; pixel_y = -3},/obj/effect/decal/warning_stripes/red/hollow,/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/security/armoury) -"aiY" = (/obj/structure/table,/obj/effect/decal/warning_stripes/red/hollow,/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/security/armoury) +"aiY" = (/obj/structure/table,/obj/effect/decal/warning_stripes/red/hollow,/obj/item/weapon/storage/toolbox/mechanical,/obj/item/device/lock_buster,/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/security/armoury) "aiZ" = (/obj/machinery/recharger/wallcharger{pixel_x = -25; pixel_y = 0},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 6},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/obj/machinery/light{dir = 8},/turf/simulated/floor/plasteel{icon_state = "red"; dir = 8},/area/security/main) "aja" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/cable{d1 = 1; d2 = 8; icon_state = "1-8"; tag = ""},/turf/simulated/floor/plasteel,/area/security/main) "ajb" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 5},/turf/simulated/floor/plasteel,/area/security/main) @@ -1283,7 +1283,7 @@ "ayI" = (/turf/simulated/floor/plating{icon_state = "panelscorched"},/area/maintenance/fsmaint2) "ayJ" = (/turf/simulated/wall/rust,/area/maintenance/fsmaint2) "ayK" = (/obj/structure/rack,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/fsmaint2) -"ayL" = (/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/plating,/area/maintenance/auxsolarport) +"ayL" = (/obj/structure/stool,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "ayM" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/auxsolarport) "ayN" = (/obj/machinery/power/terminal,/obj/machinery/light/small{dir = 4},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/maintenance/auxsolarport) "ayO" = (/obj/structure/stool/bed,/obj/effect/landmark{name = "xeno_spawn"; pixel_x = -1},/turf/simulated/floor/plating,/area/maintenance/fpmaint2) @@ -1316,7 +1316,7 @@ "azp" = (/obj/structure/stool/bed/chair/wood/wings{tag = "icon-wooden_chair_wings (NORTH)"; icon_state = "wooden_chair_wings"; dir = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) "azq" = (/obj/structure/stool/bed/chair/wood/wings{tag = "icon-wooden_chair_wings (NORTH)"; icon_state = "wooden_chair_wings"; dir = 1},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/wood,/area/crew_quarters/mrchangs) "azr" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{dir = 2; icon_state = "barber"},/area/civilian/barber) -"azs" = (/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/plating,/area/maintenance/auxsolarstarboard) +"azs" = (/obj/structure/stool,/turf/simulated/floor/plating,/area/maintenance/auxsolarport) "azt" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/auxsolarstarboard) "azu" = (/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/power/terminal,/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/maintenance/auxsolarstarboard) "azv" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/maintenance/fsmaint2) @@ -1638,7 +1638,7 @@ "aFz" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 4; initialize_directions = 11; level = 1},/turf/simulated/wall,/area/crew_quarters/sleep) "aFA" = (/obj/machinery/light{dir = 8},/obj/item/device/radio/intercom{frequency = 1459; name = "station intercom (General)"; pixel_x = -28},/obj/effect/landmark{name = "JoinLateCryo"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/crew_quarters/sleep) "aFB" = (/obj/machinery/light{dir = 8},/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutral"},/area/crew_quarters/fitness) -"aFC" = (/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) +"aFC" = (/obj/structure/stool,/turf/simulated/floor/plating,/area/maintenance/auxsolarstarboard) "aFD" = (/obj/structure/window/reinforced{dir = 8},/obj/effect/landmark/start{name = "Civilian"},/obj/machinery/door/window/westright{dir = 1; name = "Boxing Ring"},/turf/simulated/floor/wood,/area/crew_quarters/fitness) "aFE" = (/obj/structure/window/reinforced{dir = 1},/turf/simulated/floor/wood,/area/crew_quarters/fitness) "aFF" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/wood,/area/crew_quarters/fitness) @@ -1759,7 +1759,7 @@ "aHQ" = (/obj/structure/table/woodentable,/obj/machinery/media/receiver/boombox,/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aHR" = (/obj/structure/table/woodentable,/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aHS" = (/obj/structure/table/woodentable,/obj/item/toy/cards/deck,/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) -"aHT" = (/obj/structure/disposalpipe/segment,/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) +"aHT" = (/obj/structure/stool,/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aHU" = (/obj/structure/table,/obj/item/weapon/paper/holodeck,/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aHV" = (/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/fsmaint2) "aHW" = (/obj/effect/decal/cleanable/cobweb2,/obj/structure/closet/crate,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/fsmaint2) @@ -1877,8 +1877,8 @@ "aKe" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/wall,/area/crew_quarters/sleep) "aKf" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutral"},/area/crew_quarters/fitness) "aKg" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) -"aKh" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) -"aKi" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) +"aKh" = (/obj/structure/disposalpipe/segment,/obj/structure/stool,/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) +"aKi" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/stool,/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aKj" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_y = 0; tag = ""},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aKk" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; tag = ""},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aKl" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) @@ -2104,9 +2104,9 @@ "aOx" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/maintenance/fsmaint2) "aOy" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 10},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/maintenance/fsmaint2) "aOz" = (/obj/machinery/mass_driver{dir = 4; id_tag = "chapelgun"},/obj/machinery/door/window{dir = 8; name = "Mass Driver"; req_access_txt = "22"},/turf/simulated/floor/plating{tag = "icon-warnplate (WEST)"; icon_state = "warnplate"; dir = 8},/area/maintenance/fsmaint2) -"aOA" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'EXTERNAL AIRLOCK'"; icon_state = "space"; layer = 4; name = "EXTERNAL AIRLOCK"; pixel_x = 0; pixel_y = 32},/turf/simulated/floor/plating{tag = "icon-warnplate (EAST)"; icon_state = "warnplate"; dir = 4},/area/maintenance/fsmaint2) +"aOA" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'EXTERNAL AIRLOCK'"; icon_state = "space"; layer = 4; name = "EXTERNAL AIRLOCK"; pixel_x = 0; pixel_y = 32},/obj/machinery/atmospherics/unary/vent_pump,/turf/simulated/floor/plating{tag = "icon-warnplate (EAST)"; icon_state = "warnplate"; dir = 4},/area/maintenance/fsmaint2) "aOB" = (/obj/machinery/door/poddoor{id_tag = "chapelgun"; name = "Chapel Launcher Door"; protected = 0},/turf/simulated/floor/plating,/area/maintenance/fsmaint2) -"aOC" = (/turf/space,/area/chapel/main) +"aOC" = (/obj/machinery/atmospherics/pipe/manifold/hidden/supply{dir = 8; initialize_directions = 11; level = 1},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "aOD" = (/turf/simulated/shuttle/wall{icon_state = "swall11"; dir = 2},/area/shuttle/arrival/station) "aOE" = (/obj/effect/landmark{name = "HONKsquad"},/obj/structure/closet/walllocker/emerglocker/north,/turf/simulated/shuttle/floor,/area/shuttle/arrival/station) "aOF" = (/turf/simulated/shuttle/floor,/area/shuttle/arrival/station) @@ -2181,7 +2181,7 @@ "aPW" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall,/area/chapel/office) "aPX" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{level = 1},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall,/area/chapel/office) "aPY" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 1; initialize_directions = 11; level = 1},/turf/simulated/wall,/area/chapel/office) -"aPZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/driver_button{id_tag = "chapelgun"; name = "Chapel Mass Driver"; pixel_x = 25},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) +"aPZ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/driver_button{id_tag = "chapelgun"; name = "Chapel Mass Driver"; pixel_x = 25},/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "aQa" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/wall,/area/maintenance/fsmaint2) "aQb" = (/turf/simulated/wall,/area/chapel/main) "aQc" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/chapel/main) @@ -2304,7 +2304,7 @@ "aSp" = (/obj/structure/table,/obj/item/weapon/storage/toolbox/electrical,/turf/simulated/floor/plasteel,/area/storage/primary) "aSq" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/floor/plasteel,/area/storage/primary) "aSr" = (/obj/machinery/atmospherics/unary/vent_pump/on{dir = 8},/turf/simulated/floor/plasteel,/area/storage/primary) -"aSs" = (/obj/structure/stool{pixel_y = 8},/obj/effect/landmark/start{name = "Civilian"},/turf/simulated/floor/plasteel,/area/storage/primary) +"aSs" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/structure/stool,/turf/simulated/floor/plasteel,/area/crew_quarters/fitness) "aSt" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 4; on = 1},/turf/simulated/floor/plasteel,/area/storage/primary) "aSu" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/turf/simulated/floor/plasteel,/area/storage/primary) "aSv" = (/obj/structure/table,/obj/item/weapon/weldingtool,/obj/item/weapon/crowbar,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/obj/item/stack/packageWrap,/turf/simulated/floor/plasteel,/area/storage/primary) @@ -2366,7 +2366,7 @@ "aTz" = (/obj/structure/disposalpipe/segment{dir = 8; icon_state = "pipe-c"},/turf/simulated/floor/wood,/area/library) "aTA" = (/obj/structure/crematorium,/obj/effect/landmark{name = "revenantspawn"},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/office) "aTB" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/firealarm{dir = 4; pixel_x = 24},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/office) -"aTC" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) +"aTC" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 9; pixel_y = 0},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "aTD" = (/obj/effect/landmark/start{name = "Chaplain"},/obj/structure/stool/bed/chair,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) "aTE" = (/obj/structure/table/woodentable,/obj/item/weapon/paper_bin{pixel_x = -2; pixel_y = 5},/obj/item/weapon/storage/fancy/crayons,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) "aTF" = (/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) @@ -2488,7 +2488,7 @@ "aVR" = (/obj/effect/spawner/window/reinforced,/obj/machinery/door/firedoor{dir = 2},/obj/structure/cable{d2 = 4; icon_state = "0-4"},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable,/turf/simulated/floor/plating,/area/hallway/primary/port) "aVS" = (/obj/machinery/door/firedoor,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{icon_state = "vault"; dir = 5},/area/hallway/primary/port) "aVT" = (/obj/effect/spawner/window/reinforced,/obj/machinery/door/firedoor{dir = 2},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plating,/area/hallway/primary/port) -"aVU" = (/turf/simulated/wall/r_wall,/area/hallway/primary/port) +"aVU" = (/obj/effect/spawner/window/reinforced,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "aVV" = (/obj/structure/disposalpipe/segment,/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plating,/area/maintenance/fpmaint) "aVW" = (/obj/machinery/door/firedoor{dir = 4; name = "Firelock East"},/obj/machinery/door/airlock/command{name = "Gateway Access"; req_access_txt = "62"},/turf/simulated/floor/plasteel,/area/gateway) "aVX" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/firedoor{dir = 4; name = "Firelock East"},/obj/machinery/door/poddoor/shutters{dir = 2; id_tag = "stationawaygate"; name = "Gateway Access Shutters"},/turf/simulated/floor/plasteel,/area/gateway) @@ -2505,7 +2505,7 @@ "aWi" = (/obj/structure/grille,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/structure/window/reinforced{dir = 8},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/hallway/primary/central/ne) "aWj" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/hallway/primary/central/ne) "aWk" = (/obj/structure/grille,/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced,/turf/simulated/floor/plating,/area/hallway/primary/central/ne) -"aWl" = (/obj/machinery/vending/snack,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/hallway/primary/central) +"aWl" = (/obj/structure/table,/obj/item/device/radio/beacon/syndicate/bomb{pixel_y = 5},/obj/item/device/radio/beacon/syndicate/bomb,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "aWm" = (/turf/simulated/floor/plasteel{icon_state = "neutral"; dir = 4},/area/hallway/primary/central/ne) "aWn" = (/obj/machinery/light{dir = 1},/obj/machinery/vending/boozeomat,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/crew_quarters/bar) "aWo" = (/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/crew_quarters/bar) @@ -2697,7 +2697,7 @@ "aZS" = (/obj/machinery/navbeacon{codes_txt = "patrol;next_patrol=EVA2"; location = "Dorm"},/turf/simulated/floor/plasteel,/area/hallway/primary/central/ne) "aZT" = (/obj/machinery/camera{c_tag = "Bar East"; network = list("SS13")},/obj/machinery/newscaster{pixel_y = 32},/obj/structure/flora/kirbyplants,/turf/simulated/floor/wood,/area/crew_quarters/bar) "aZU" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/crew_quarters/bar) -"aZV" = (/obj/structure/stool{pixel_y = 8},/obj/effect/landmark/start{name = "Bartender"},/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/crew_quarters/bar) +"aZV" = (/obj/structure/stool,/obj/effect/landmark/start{name = "Civilian"},/turf/simulated/floor/plasteel,/area/storage/primary) "aZW" = (/obj/machinery/door/window{dir = 4; name = "Bar Door"; req_access_txt = "25"},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/crew_quarters/bar) "aZX" = (/turf/simulated/floor/carpet,/area/crew_quarters/bar) "aZY" = (/obj/machinery/computer/security/telescreen/entertainment{pixel_x = 32},/obj/structure/table/woodentable,/obj/item/ashtray/bronze{pixel_x = -1; pixel_y = 1},/turf/simulated/floor/carpet,/area/crew_quarters/bar) @@ -2801,7 +2801,7 @@ "bbS" = (/obj/structure/bookcase{name = "Forbidden Knowledge"},/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/library) "bbT" = (/obj/structure/table/woodentable,/obj/item/device/taperecorder{pixel_y = 0},/obj/item/device/camera{desc = "A one use - polaroid camera. 30 photos left."; name = "Camera"; pictures_left = 30; pixel_x = 0; pixel_y = 0},/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/library) "bbU" = (/obj/structure/table/woodentable,/obj/item/weapon/paper_bin{pixel_x = -3; pixel_y = 7},/obj/item/weapon/pen/invisible,/obj/machinery/camera{c_tag = "Library Study"; dir = 8; network = list("SS13")},/obj/item/stack/tape_roll,/obj/item/weapon/pen/multi,/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/library) -"bbV" = (/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) +"bbV" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "bbW" = (/turf/simulated/floor/plasteel{dir = 1; icon_state = "chapel"},/area/chapel/main) "bbX" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/turf/simulated/floor/plasteel{dir = 4; icon_state = "chapel"},/area/chapel/main) "bbY" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{dir = 1; icon_state = "chapel"},/area/chapel/main) @@ -2844,10 +2844,10 @@ "bcJ" = (/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "bridge blast"; name = "Bridge Blast Doors"; opacity = 0},/obj/effect/spawner/window/reinforced,/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/structure/cable{icon_state = "0-4"; d2 = 4},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/plating,/area/bridge) "bcK" = (/obj/effect/spawner/window/reinforced,/turf/simulated/floor/plating,/area/hallway/primary/central/ne) "bcL" = (/turf/simulated/floor/plasteel{tag = "icon-stage_stairs"; icon_state = "stage_stairs"},/area/hallway/primary/central/ne) -"bcM" = (/obj/machinery/computer/security/telescreen/entertainment{pixel_x = -32},/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/wood,/area/crew_quarters/bar) -"bcN" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/wood,/area/crew_quarters/bar) -"bcO" = (/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/wood,/area/crew_quarters/bar) -"bcP" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/wood,/area/crew_quarters/bar) +"bcM" = (/obj/structure/stool,/obj/effect/landmark/start{name = "Bartender"},/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/crew_quarters/bar) +"bcN" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/structure/stool,/turf/simulated/floor/wood,/area/crew_quarters/bar) +"bcO" = (/obj/machinery/computer/security/telescreen/entertainment{pixel_x = -32},/obj/structure/stool,/turf/simulated/floor/wood,/area/crew_quarters/bar) +"bcP" = (/obj/structure/stool,/turf/simulated/floor/wood,/area/crew_quarters/bar) "bcQ" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/wood,/area/crew_quarters/bar) "bcR" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 10},/obj/structure/disposalpipe/segment,/turf/simulated/floor/wood,/area/crew_quarters/bar) "bcS" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/unary/vent_scrubber{dir = 4; on = 1},/obj/structure/table,/obj/item/weapon/kitchen/knife,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/kitchen) @@ -3007,7 +3007,7 @@ "bfQ" = (/turf/simulated/floor/plasteel{dir = 1; icon_state = "yellowcorner"},/area/bridge) "bfR" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/floor/plasteel,/area/bridge) "bfS" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel{dir = 4; icon_state = "yellowcorner"},/area/bridge) -"bfT" = (/obj/structure/table/reinforced,/obj/item/device/aicard,/obj/item/device/multitool,/turf/simulated/floor/plasteel{icon_state = "blue"; dir = 8},/area/bridge) +"bfT" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/obj/structure/bookcase,/obj/item/weapon/book/manual/sop_engineering,/obj/item/weapon/book/manual/sop_medical,/obj/item/weapon/book/manual/sop_science,/obj/item/weapon/book/manual/sop_security,/obj/item/weapon/book/manual/sop_service,/obj/item/weapon/book/manual/sop_supply,/obj/item/weapon/book/manual/sop_general,/obj/item/weapon/book/manual/sop_legal,/obj/item/weapon/book/manual/sop_command,/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/lawoffice) "bfU" = (/obj/structure/stool/bed/chair{dir = 1},/obj/machinery/door_control{id = "bridge blast"; name = "Bridge Blast Door Control"; pixel_x = 28; pixel_y = -2; req_access_txt = "19"},/obj/machinery/keycard_auth{pixel_x = 29; pixel_y = 8},/turf/simulated/floor/plasteel,/area/bridge) "bfV" = (/obj/structure/table/reinforced,/turf/simulated/floor/plasteel{icon_state = "blue"; dir = 4},/area/bridge) "bfW" = (/turf/simulated/floor/plasteel{dir = 1; icon_state = "greencorner"},/area/bridge) @@ -3057,7 +3057,7 @@ "bgO" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/wall,/area/security/vacantoffice) "bgP" = (/obj/effect/decal/cleanable/generic,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/maintenance/port) "bgQ" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/obj/structure/closet/wardrobe/white,/turf/simulated/floor/plasteel,/area/crew_quarters/locker) -"bgR" = (/obj/structure/stool{pixel_y = 8},/turf/simulated/floor/plasteel,/area/crew_quarters/locker) +"bgR" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 5},/obj/structure/stool,/turf/simulated/floor/wood,/area/crew_quarters/bar) "bgS" = (/obj/structure/table,/obj/item/weapon/storage/toolbox/mechanical{pixel_x = -2; pixel_y = -1},/turf/simulated/floor/plasteel,/area/crew_quarters/locker) "bgT" = (/obj/structure/table,/turf/simulated/floor/plasteel,/area/crew_quarters/locker) "bgU" = (/obj/structure/table,/obj/item/weapon/storage/toolbox/mechanical{pixel_x = -2; pixel_y = -1},/obj/structure/disposalpipe/segment,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel,/area/crew_quarters/locker) @@ -3656,7 +3656,7 @@ "bsp" = (/obj/machinery/camera{c_tag = "Cargo Delivery Office"; dir = 4; network = list("SS13")},/obj/machinery/firealarm{dir = 8; pixel_x = -24},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/telepad_cargo,/turf/simulated/floor/plasteel{dir = 8; icon_state = "brown"},/area/quartermaster/office) "bsq" = (/obj/structure/filingcabinet/filingcabinet,/turf/simulated/floor/plasteel{icon_state = "arrival"; dir = 4},/area/quartermaster/office) "bsr" = (/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22},/turf/simulated/floor/plasteel{dir = 8; icon_state = "browncorner"},/area/hallway/primary/central/west) -"bss" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/obj/structure/bookcase,/obj/item/weapon/book/manual/sop_engineering,/obj/item/weapon/book/manual/sop_medical,/obj/item/weapon/book/manual/sop_science,/obj/item/weapon/book/manual/sop_security,/obj/item/weapon/book/manual/sop_service,/obj/item/weapon/book/manual/sop_supply,/obj/item/weapon/book/manual/sop_general,/obj/item/weapon/book/manual/sop_legal,/turf/simulated/floor/plasteel{tag = "icon-cult"; icon_state = "cult"; dir = 2},/area/lawoffice) +"bss" = (/obj/structure/table/reinforced,/obj/item/weapon/book/manual/sop_command,/obj/item/device/aicard,/obj/item/device/multitool,/turf/simulated/floor/plasteel{icon_state = "blue"; dir = 8},/area/bridge) "bst" = (/obj/item/weapon/paper_bin{pixel_x = -3; pixel_y = 7},/obj/item/weapon/pen,/obj/structure/table/woodentable,/turf/simulated/floor/carpet,/area/bridge/meeting_room) "bsu" = (/obj/item/weapon/folder/blue,/obj/structure/table/woodentable,/turf/simulated/floor/carpet,/area/bridge/meeting_room) "bsv" = (/obj/machinery/vending/coffee,/turf/simulated/floor/wood,/area/bridge/meeting_room) @@ -3935,7 +3935,7 @@ "bxI" = (/obj/structure/stool/bed/chair/office/light{dir = 1},/obj/effect/landmark/start{name = "Roboticist"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/assembly/robotics) "bxJ" = (/turf/simulated/floor/plasteel{icon_state = "white"},/area/assembly/robotics) "bxK" = (/obj/machinery/camera{c_tag = "Research Robotics Lab"; dir = 2; network = list("Research","SS13")},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whiteredcorner"},/area/assembly/robotics) -"bxL" = (/obj/machinery/computer/guestpass,/obj/structure/table,/obj/machinery/door_control{id = "robotics"; name = "Robotics Lab Shutters Control"; pixel_x = -24; pixel_y = 24; req_access_txt = "29"},/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitered"},/area/assembly/robotics) +"bxL" = (/obj/structure/table,/obj/machinery/door_control{id = "robotics"; name = "Robotics Lab Shutters Control"; pixel_x = -24; pixel_y = 24; req_access_txt = "29"},/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitered"},/area/assembly/robotics) "bxM" = (/obj/structure/stool,/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitered"},/area/assembly/robotics) "bxN" = (/obj/structure/filingcabinet/chestdrawer,/turf/simulated/floor/plasteel{dir = 1; icon_state = "whitered"},/area/assembly/robotics) "bxO" = (/turf/simulated/wall,/area/medical/research{name = "Research Division"}) @@ -4580,7 +4580,7 @@ "bKd" = (/obj/machinery/light/small{dir = 1},/obj/machinery/camera{c_tag = "Research Shuttle Maintenance"; dir = 2; network = list("Research","SS13")},/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitepurplecorner"},/area/medical/research{name = "Research Division"}) "bKe" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/door/firedoor,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Biohazard"; name = "Biohazard Shutter"; opacity = 0},/obj/machinery/door/airlock/glass_research{name = "Research Shuttle Dock"; req_access_txt = "65"},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitepurplecorner"},/area/medical/research_shuttle_dock) "bKf" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/turf/simulated/floor/plasteel{dir = 4; icon_state = "whitebluecorner"},/area/medical/research_shuttle_dock) -"bKg" = (/obj/effect/spawner/window/reinforced,/obj/machinery/door/firedoor{dir = 2},/turf/simulated/shuttle/plating,/area/medical/research_shuttle_dock) +"bKg" = (/obj/machinery/vending/snack,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/hallway/primary/central/ne) "bKh" = (/obj/machinery/power/apc{dir = 1; name = "Genetics Maintenance APC"; pixel_y = 24},/obj/structure/cable{icon_state = "0-2"; d2 = 2},/turf/simulated/floor/plating,/area/maintenance/genetics) "bKi" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/turf/simulated/floor/plating,/area/maintenance/genetics) "bKj" = (/obj/machinery/light/small{dir = 1},/obj/structure/disposalpipe/sortjunction{dir = 2; icon_state = "pipe-j2s"; sortType = 14},/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/genetics) @@ -4670,7 +4670,7 @@ "bLP" = (/obj/structure/stool/bed/chair/office/dark{dir = 4},/obj/effect/landmark/start{name = "Head of Personnel"},/turf/simulated/floor/plasteel,/area/crew_quarters/heads) "bLQ" = (/obj/structure/table,/obj/machinery/firealarm{dir = 8; pixel_x = -24},/obj/item/weapon/folder/yellow,/obj/item/device/eftpos,/obj/item/weapon/book/manual/sop_supply,/turf/simulated/floor/plasteel,/area/quartermaster/office) "bLR" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/floor/plasteel,/area/crew_quarters/heads) -"bLS" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel,/area/crew_quarters/heads) +"bLS" = (/obj/machinery/computer/guestpass,/obj/structure/table,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/lab) "bLT" = (/obj/machinery/computer/message_monitor,/obj/machinery/light/small{dir = 8},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/server) "bLU" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/supply{req_access_txt = "0"},/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/server) "bLV" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/server) @@ -4821,7 +4821,7 @@ "bOK" = (/obj/machinery/light{dir = 1},/turf/simulated/floor/plasteel{icon_state = "white"},/area/crew_quarters/hor) "bOL" = (/obj/machinery/ai_status_display{pixel_y = 32},/turf/simulated/floor/plasteel{dir = 4; icon_state = "warnwhite"; tag = "icon-warnwhite (NORTH)"},/area/crew_quarters/hor) "bOM" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plating,/area/maintenance/asmaint2) -"bON" = (/obj/effect/spawner/window/reinforced,/turf/simulated/shuttle/plating,/area/maintenance/asmaint2) +"bON" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable,/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "representative"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area/ntrep) "bOO" = (/turf/simulated/floor/plasteel{dir = 10; icon_state = "warning"},/area/medical/research_shuttle_dock) "bOP" = (/obj/machinery/power/apc{dir = 2; name = "Research Shuttle Dock APC"; pixel_y = -24},/obj/structure/cable,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/research_shuttle_dock) "bOQ" = (/turf/simulated/floor/plasteel{dir = 2; icon_state = "cmo"},/area/medical/research_shuttle_dock) @@ -4839,7 +4839,7 @@ "bPc" = (/turf/simulated/wall,/area/hallway/primary/central/sw) "bPd" = (/obj/machinery/door/airlock/command{name = "Head of Personnel"; req_access = null; req_access_txt = "57"},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plasteel,/area/crew_quarters/heads) "bPe" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/wall/r_wall,/area/server) -"bPf" = (/obj/machinery/door/airlock/external{aiControlDisabled = 1; hackProof = 1; id_tag = "emergency_home"; name = "Escape Airlock"},/turf/simulated/floor/plating,/area/hallway/secondary/exit) +"bPf" = (/obj/machinery/door/airlock/external{aiControlDisabled = 0; hackProof = 1; id_tag = "emergency_home"; name = "Escape Airlock"},/turf/simulated/floor/plating,/area/hallway/secondary/exit) "bPg" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/wall,/area/engine/gravitygenerator) "bPh" = (/obj/machinery/door/firedoor{dir = 8; name = "Firelock West"},/obj/machinery/door/airlock/engineering{name = "Gravity Generator"; req_access_txt = "0"; req_one_access_txt = "10;30"},/turf/simulated/floor/plasteel{tag = "icon-vault"; icon_state = "vault"},/area/engine/gravitygenerator) "bPi" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/status_display{density = 0; layer = 4; pixel_x = -32; pixel_y = 0},/turf/simulated/floor/plasteel,/area/hallway/primary/central/se) @@ -5115,7 +5115,7 @@ "bUs" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/floor/plasteel{dir = 9; icon_state = "whitehall"},/area/medical/research{name = "Research Division"}) "bUt" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/turf/simulated/wall/r_wall,/area/crew_quarters/hor) "bUu" = (/obj/machinery/power/apc{dir = 8; name = "RD Office APC"; pixel_x = -25},/obj/structure/cable,/obj/machinery/light_switch{pixel_y = -23},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/structure/disposalpipe/segment{dir = 1; icon_state = "pipe-c"},/obj/structure/flora/kirbyplants,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/hor) -"bUv" = (/obj/machinery/hologram/holopad,/obj/machinery/keycard_auth{pixel_x = 0; pixel_y = -24},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light,/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/photocopier/faxmachine{department = "Research Director's Office"},/obj/structure/table/glass,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/hor) +"bUv" = (/obj/machinery/keycard_auth{pixel_x = 0; pixel_y = -24},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/light,/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/photocopier/faxmachine{department = "Research Director's Office"},/obj/structure/table/glass,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/hor) "bUw" = (/obj/item/weapon/cartridge/signal/toxins,/obj/item/weapon/cartridge/signal/toxins{pixel_x = -4; pixel_y = 2},/obj/item/weapon/cartridge/signal/toxins{pixel_x = 4; pixel_y = 6},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 4},/obj/machinery/camera{c_tag = "Research Director's Office"; dir = 1; network = list("Research","SS13")},/obj/item/clothing/glasses/welding/superior,/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/table/glass,/turf/simulated/floor/plasteel{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/hor) "bUx" = (/obj/structure/closet/secure_closet/RD,/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/plasteel{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/hor) "bUy" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 8},/turf/simulated/floor/plasteel{dir = 2; icon_state = "cafeteria"; tag = "icon-cafeteria (NORTHEAST)"},/area/crew_quarters/hor) @@ -5148,7 +5148,7 @@ "bUZ" = (/turf/simulated/wall,/area/ntrep) "bVa" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable,/obj/structure/disposalpipe/segment,/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "representative"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area/ntrep) "bVb" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"},/obj/machinery/door/airlock/command{name = "NT Representative's Office"; req_access_txt = "73"},/turf/simulated/floor/wood,/area/ntrep) -"bVc" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable,/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "representative"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area/blueshield) +"bVc" = (/obj/effect/landmark{name = "blobstart"},/turf/simulated/floor/plating,/area/maintenance/apmaint) "bVd" = (/obj/structure/disposalpipe/segment,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/machinery/door/firedoor,/turf/simulated/floor/plasteel,/area/hallway/primary/central/south) "bVe" = (/obj/structure/sign/directions/engineering,/obj/structure/sign/directions/science{dir = 4; pixel_x = 0; pixel_y = -7},/obj/structure/sign/directions/medical{dir = 4; pixel_y = 7},/turf/simulated/wall,/area/janitor) "bVf" = (/turf/simulated/wall,/area/janitor) @@ -5227,7 +5227,7 @@ "bWA" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/wood,/area/blueshield) "bWB" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/wood,/area/blueshield) "bWC" = (/obj/machinery/light{dir = 1},/obj/machinery/power/apc{dir = 4; name = "Blueshield Office APC"; pixel_x = 24; pixel_y = -3},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/obj/machinery/status_display{density = 0; layer = 4; pixel_x = 0; pixel_y = 32},/turf/simulated/floor/wood,/area/blueshield) -"bWD" = (/obj/structure/table,/obj/item/weapon/folder/blue,/obj/item/weapon/stamp/hop,/obj/item/device/eftpos,/obj/item/weapon/book/manual/sop_service,/obj/item/weapon/book/manual/sop_supply,/turf/simulated/floor/plasteel,/area/crew_quarters/heads) +"bWD" = (/obj/structure/table,/obj/item/weapon/book/manual/sop_general,/obj/item/weapon/storage/fancy/donut_box,/turf/simulated/floor/wood,/area/bridge/meeting_room) "bWE" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk{dir = 1},/turf/simulated/floor/wood,/area/ntrep) "bWF" = (/obj/structure/cable{d1 = 1; d2 = 4; icon_state = "1-4"},/turf/simulated/floor/wood,/area/ntrep) "bWG" = (/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0},/turf/simulated/floor/wood,/area/ntrep) @@ -5414,7 +5414,7 @@ "caf" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{dir = 2; icon_state = "whitebluecorner"; tag = "icon-whitebluecorner"},/area/medical/medbay2) "cag" = (/obj/machinery/vending/medical,/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel{tag = "icon-whiteblue (SOUTHEAST)"; icon_state = "whiteblue"; dir = 6},/area/medical/medbay2) "cah" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/structure/disposalpipe/segment,/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "cmooffice"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area/medical/cmo) -"cai" = (/obj/machinery/hologram/holopad,/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/cmo) +"cai" = (/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/cmo) "caj" = (/obj/structure/stool/bed/chair/office/dark{dir = 1},/obj/effect/landmark/start{name = "Chief Medical Officer"},/turf/simulated/floor/plasteel{icon_state = "white"},/area/medical/cmo) "cak" = (/obj/machinery/prize_counter,/turf/simulated/floor/wood,/area/crew_quarters/bar) "cal" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "cmooffice"; name = "Privacy Shutters"; opacity = 0},/turf/simulated/floor/plating,/area/medical/cmo) @@ -5544,7 +5544,7 @@ "ccF" = (/obj/structure/disposalpipe/segment{dir = 2; icon_state = "pipe-c"},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers{dir = 9},/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/light/small{dir = 4},/turf/simulated/floor/plating,/area/maintenance/apmaint) "ccG" = (/obj/machinery/keycard_auth{pixel_x = -24; pixel_y = 0},/obj/machinery/door/window{dir = 1; name = "Desk Door"; req_access_txt = "67"},/turf/simulated/floor/wood,/area/blueshield) "ccH" = (/obj/structure/table/woodentable,/obj/item/ashtray/glass{pixel_x = -4; pixel_y = -4},/obj/item/weapon/lighter/zippo/blue{pixel_x = 7; pixel_y = 4},/turf/simulated/floor/plasteel{icon_state = "bcarpet05"},/area/blueshield) -"ccI" = (/obj/structure/table/woodentable,/obj/item/weapon/paper_bin,/obj/item/weapon/pen/blue,/obj/item/weapon/folder/blue{pixel_x = 4; pixel_y = 6},/obj/item/weapon/paper/blueshield,/turf/simulated/floor/plasteel{icon_state = "bcarpet05"},/area/blueshield) +"ccI" = (/obj/structure/table/woodentable,/obj/item/weapon/book/manual/security_space_law,/obj/item/weapon/coin/plasma,/obj/item/weapon/book/manual/sop_general,/obj/item/weapon/book/manual/sop_command,/obj/item/device/megaphone,/turf/simulated/floor/wood,/area/crew_quarters/captain) "ccJ" = (/obj/structure/sign/poster/legit{pixel_x = 32},/obj/machinery/photocopier,/turf/simulated/floor/wood,/area/blueshield) "ccK" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 6},/turf/simulated/wall,/area/ntrep) "ccL" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply{dir = 4},/obj/machinery/photocopier,/turf/simulated/floor/wood,/area/ntrep) @@ -5707,8 +5707,8 @@ "cfM" = (/obj/structure/grille,/obj/structure/window/plasmareinforced{dir = 4},/obj/structure/window/plasmareinforced{dir = 8},/obj/structure/window/plasmareinforced,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Biohazard"; name = "Biohazard Shutter"; opacity = 0},/turf/simulated/floor/plating,/area/toxins/mixing) "cfN" = (/turf/simulated/floor/plasteel/airless{dir = 4; icon_state = "warning"},/area/toxins/test_area) "cfO" = (/turf/simulated/floor/plasteel/airless{tag = "icon-warningcorner (NORTH)"; icon_state = "warningcorner"; dir = 1},/area/toxins/test_area) -"cfP" = (/obj/machinery/light/small{dir = 1},/obj/structure/stool,/turf/simulated/floor/plating,/area/maintenance/aft) -"cfQ" = (/obj/effect/landmark{name = "blobstart"},/turf/simulated/floor/plating,/area/maintenance/aft) +"cfP" = (/obj/machinery/light/small{dir = 1},/obj/structure/stool,/turf/simulated/floor/plating,/area/maintenance/apmaint) +"cfQ" = (/obj/structure/closet,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/apmaint) "cfR" = (/turf/simulated/floor/plating,/area/maintenance/aft) "cfS" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/turf/simulated/floor/plating,/area/maintenance/apmaint) "cfT" = (/obj/structure/closet/secure_closet/blueshield,/obj/machinery/firealarm{dir = 8; pixel_x = -24},/turf/simulated/floor/wood,/area/blueshield) @@ -5784,9 +5784,9 @@ "chl" = (/turf/simulated/floor/plasteel/airless{icon_state = "warning"},/area/toxins/test_area) "chm" = (/turf/simulated/floor/plasteel/airless{dir = 6; icon_state = "warning"},/area/toxins/test_area) "chn" = (/turf/simulated/floor/plasteel/airless{dir = 10; icon_state = "warning"},/area/toxins/test_area) -"cho" = (/obj/structure/table,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/aft) -"chp" = (/obj/structure/closet,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/aft) -"chq" = (/obj/structure/rack{dir = 1},/obj/effect/spawner/lootdrop/maintenance{lootcount = 2; name = "2maintenance loot spawner"},/turf/simulated/floor/plating,/area/maintenance/aft) +"cho" = (/obj/structure/table,/obj/effect/spawner/lootdrop/maintenance,/turf/simulated/floor/plating,/area/maintenance/apmaint) +"chp" = (/obj/structure/rack{dir = 1},/obj/effect/spawner/lootdrop/maintenance{lootcount = 2; name = "2maintenance loot spawner"},/turf/simulated/floor/plating,/area/maintenance/apmaint) +"chq" = (/obj/structure/closet/emcloset,/turf/simulated/floor/plasteel{icon_state = "caution"; dir = 4},/area/hallway/primary/aft) "chr" = (/turf/simulated/wall/r_wall,/area/blueshield) "chs" = (/obj/machinery/status_display{density = 0; layer = 4; pixel_x = -32; pixel_y = 0},/obj/structure/disposalpipe/junction{tag = "icon-pipe-j2"; icon_state = "pipe-j2"; dir = 2},/turf/simulated/floor/plasteel{dir = 8; icon_state = "cautioncorner"},/area/hallway/primary/aft) "cht" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/machinery/atmospherics/unary/vent_scrubber{on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel,/area/hallway/primary/aft) @@ -6135,7 +6135,7 @@ "cnY" = (/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/weapon/circuitboard/powermonitor{pixel_x = -2; pixel_y = 2},/obj/item/weapon/circuitboard/stationalert_all{pixel_x = 1; pixel_y = -1},/obj/item/weapon/circuitboard/atmos_alert{pixel_x = 3; pixel_y = -3},/obj/item/weapon/circuitboard/thermomachine,/obj/item/weapon/circuitboard/smes{pixel_x = 4},/turf/simulated/floor/plating,/area/storage/tech) "cnZ" = (/obj/machinery/light_switch{pixel_x = 27},/turf/simulated/floor/plating,/area/storage/tech) "coa" = (/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{dir = 2; icon_state = "yellowcorner"},/area/hallway/primary/aft) -"cob" = (/obj/structure/closet/emcloset,/turf/simulated/floor/plasteel{icon_state = "caution"; dir = 4},/area/hallway/secondary/construction{name = "\improper Engineering Training"}) +"cob" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/disposalpipe/segment,/obj/machinery/computer/guestpass/hop{pixel_x = 28},/turf/simulated/floor/plasteel,/area/crew_quarters/heads) "coc" = (/obj/machinery/door/firedoor{dir = 1; name = "Firelock North"},/obj/machinery/door/airlock/glass_engineering{name = "Engineering"; req_access_txt = "0"; req_one_access_txt = "11;24"},/turf/simulated/floor/plasteel,/area/engine/controlroom) "cod" = (/turf/simulated/wall,/area/engine/controlroom) "coe" = (/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers{dir = 8; initialize_directions = 11; level = 1},/turf/simulated/wall/r_wall,/area/construction) @@ -7063,7 +7063,7 @@ "cFQ" = (/obj/structure/rack{dir = 8; layer = 2.9},/obj/item/clothing/shoes/magboots,/obj/item/clothing/suit/space/rig/engineering,/obj/item/clothing/mask/breath,/obj/item/clothing/head/helmet/space/rig/engineering,/obj/machinery/firealarm{dir = 2; pixel_y = 24},/turf/simulated/floor/plasteel,/area/engine/hardsuitstorage) "cFR" = (/obj/machinery/power/apc{dir = 4; name = "CE Office APC"; pixel_x = 24; pixel_y = 0; shock_proof = 1},/obj/structure/cable{d2 = 8; icon_state = "0-8"},/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) "cFS" = (/obj/effect/spawner/window/reinforced,/obj/structure/cable{icon_state = "0-2"; pixel_y = 1; d2 = 2},/turf/simulated/floor/plating,/area/engine/chiefs_office) -"cFT" = (/obj/machinery/keycard_auth{pixel_x = 0; pixel_y = 24},/obj/structure/table/reinforced,/obj/item/weapon/rcd,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/stock_parts/cell/high{charge = 100; maxcharge = 15000},/obj/item/weapon/stock_parts/cell/high{charge = 100; maxcharge = 15000},/obj/item/clothing/glasses/meson{pixel_y = 4},/obj/item/device/megaphone,/mob/living/simple_animal/parrot/Poly,/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) +"cFT" = (/obj/machinery/keycard_auth{pixel_x = 0; pixel_y = 24},/obj/structure/table/reinforced,/obj/item/weapon/rcd,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/stock_parts/cell/high{charge = 100; maxcharge = 15000},/obj/item/weapon/stock_parts/cell/high{charge = 100; maxcharge = 15000},/obj/item/clothing/glasses/meson{pixel_y = 4},/obj/item/device/megaphone,/obj/item/device/lock_buster,/mob/living/simple_animal/parrot/Poly,/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) "cFU" = (/obj/machinery/atmospherics/unary/vent_scrubber{dir = 8; on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/structure/closet/firecloset,/obj/machinery/requests_console{department = "Atmospherics"; departmentType = 3; name = "Atmospherics Requests Console"; pixel_x = -30},/turf/simulated/floor/plasteel,/area/atmos) "cFV" = (/obj/machinery/door_control{id = "atmos"; name = "Atmospherics Lockdown"; pixel_x = 10; pixel_y = 24; req_access_txt = "24"},/obj/machinery/door_control{desc = "A remote control-switch for the engineering security doors."; id = "Engineering"; name = "Engineering Lockdown"; pixel_x = -10; pixel_y = 24; req_access_txt = "10"},/obj/machinery/door_control{desc = "A remote control-switch for secure storage."; id = "Secure Storage"; name = "Engineering Secure Storage"; pixel_x = 0; pixel_y = 24; req_access_txt = "11"},/obj/machinery/light_switch{pixel_y = 38},/obj/machinery/atmospherics/unary/vent_pump{dir = 1; external_pressure_bound = 101; on = 1; pressure_checks = 1},/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) "cFW" = (/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) @@ -7232,7 +7232,7 @@ "cJd" = (/obj/machinery/computer/station_alert,/turf/simulated/floor/plasteel,/area/engine/engineering) "cJe" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/turf/simulated/floor/plasteel,/area/engine/engineering) "cJf" = (/obj/effect/spawner/window/reinforced,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plating,/area/engine/hardsuitstorage) -"cJg" = (/obj/effect/spawner/window/reinforced,/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plating,/area/engine/hardsuitstorage) +"cJg" = (/obj/machinery/door/firedoor,/obj/machinery/door/airlock/glass_engineering{name = "Storage"; req_access_txt = "11"; req_one_access_txt = null},/turf/simulated/floor/plasteel,/area/engine/hardsuitstorage) "cJh" = (/obj/structure/sink{icon_state = "sink"; dir = 8; pixel_x = -12; pixel_y = 2},/obj/machinery/alarm{dir = 4; icon_state = "alarm0"; pixel_x = -22; pixel_y = 0},/turf/simulated/floor/plasteel{tag = "icon-whitegreen (WEST)"; icon_state = "whitegreen"; dir = 8},/area/medical/virology) "cJi" = (/obj/machinery/camera{c_tag = "Engineering Chief Engineer's Office"; dir = 4; network = list("SS13")},/obj/item/device/radio/intercom{name = "station intercom (General)"; pixel_x = -28; pixel_y = 0},/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/machinery/firealarm{dir = 1; pixel_y = -24},/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) "cJj" = (/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) @@ -7337,7 +7337,7 @@ "cLe" = (/obj/machinery/door/airlock/maintenance{req_access_txt = "12"},/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cLf" = (/obj/structure/closet/crate,/obj/item/clothing/under/color/lightpurple,/obj/item/weapon/spacecash/c200,/turf/simulated/floor/plating,/area/maintenance/asmaint2) "cLg" = (/obj/effect/spawner/window,/turf/simulated/floor/plating,/area/maintenance/asmaint) -"cLh" = (/obj/machinery/door/firedoor,/obj/structure/cable{d1 = 4; d2 = 8; icon_state = "4-8"; pixel_x = 0; tag = ""},/obj/machinery/door/airlock/glass_engineering{name = "Storage"; req_access_txt = "11"; req_one_access_txt = null},/turf/simulated/floor/plasteel,/area/engine/hardsuitstorage) +"cLh" = (/obj/machinery/disposal,/obj/structure/disposalpipe/trunk,/obj/machinery/light_switch{pixel_x = -25},/turf/simulated/floor/plasteel{icon_state = "grimy"},/area/chapel/office) "cLi" = (/obj/effect/spawner/window/reinforced,/obj/structure/disposalpipe/segment{dir = 4},/obj/structure/disposalpipe/segment,/obj/structure/cable,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "xenobio4"; name = "Containment Blast Doors"; opacity = 0},/turf/simulated/floor/plating,/area/toxins/xenobiology) "cLj" = (/obj/machinery/door/window/southright{name = "Containment Pen"; req_access_txt = "55"},/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "xenobio4"; name = "Containment Blast Doors"; opacity = 0},/turf/simulated/floor/engine,/area/toxins/xenobiology) "cLk" = (/obj/effect/spawner/window/reinforced,/obj/structure/disposalpipe/segment{dir = 4},/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "xenobio4"; name = "Containment Blast Doors"; opacity = 0},/obj/structure/cable,/turf/simulated/floor/plating,/area/toxins/xenobiology) @@ -8498,7 +8498,7 @@ "dhv" = (/obj/structure/rack,/obj/item/weapon/pneumatic_cannon,/obj/item/weapon/harpoon,/obj/item/weapon/harpoon,/obj/item/weapon/harpoon,/obj/item/weapon/harpoon,/obj/item/weapon/tank/nitrogen,/obj/machinery/light/spot{tag = "icon-tube1 (EAST)"; icon_state = "tube1"; dir = 4},/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox) "dhw" = (/obj/structure/shuttle/engine/propulsion{tag = "icon-propulsion_l"; icon_state = "propulsion_l"},/turf/space,/area/shuttle/vox) "dhx" = (/obj/structure/rack,/obj/item/clothing/accessory/storage/black_vest,/obj/item/clothing/suit/space/vox/pressure,/obj/item/clothing/head/helmet/space/vox/pressure,/obj/item/clothing/mask/breath,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox) -"dhy" = (/obj/structure/rack,/obj/item/weapon/gun/launcher/spikethrower,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox) +"dhy" = (/obj/structure/rack,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox) "dhz" = (/obj/structure/rack,/obj/item/clothing/accessory/storage/black_vest,/obj/item/clothing/suit/space/vox/stealth,/obj/item/clothing/head/helmet/space/vox/stealth,/obj/item/clothing/mask/breath,/turf/simulated/shuttle/floor4/vox,/area/shuttle/vox) "dhA" = (/obj/structure/grille,/obj/structure/shuttle/window{tag = "icon-window5_end (NORTH)"; icon = 'icons/turf/shuttle.dmi'; icon_state = "window5_end"; dir = 1},/turf/simulated/shuttle/plating/vox,/area/shuttle/vox) "dhB" = (/obj/structure/grille,/obj/structure/shuttle/window{tag = "icon-window5_end"; icon = 'icons/turf/shuttle.dmi'; icon_state = "window5_end"; dir = 2},/turf/simulated/shuttle/plating/vox,/area/shuttle/vox) @@ -8520,7 +8520,7 @@ "dhR" = (/obj/structure/closet/syndicate/suits,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "dhS" = (/obj/effect/landmark{name = "Syndicate-Uplink"; tag = ""},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "dhT" = (/obj/structure/table,/obj/item/device/aicard,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) -"dhU" = (/obj/structure/stool{pixel_y = 8},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) +"dhU" = (/obj/structure/stool,/turf/simulated/floor/plasteel,/area/crew_quarters/locker) "dhV" = (/obj/structure/sign/securearea{desc = "A warning sign which reads 'EXTERNAL AIRLOCK'"; icon_state = "space"; layer = 4; name = "EXTERNAL AIRLOCK"; pixel_x = 0},/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/shuttle/syndicate) "dhW" = (/obj/machinery/door/airlock/external{frequency = 1331; icon_state = "door_locked"; id_tag = "synd_outer"; locked = 0; name = "Ship External Access"; req_access = null; req_access_txt = "150"},/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "smindicate"; name = "Outer Airlock"; opacity = 0},/obj/machinery/door_control{id = "smindicate"; name = "External Door Control"; pixel_x = -26; pixel_y = -2; req_access_txt = "150"},/obj/docking_port/mobile{dheight = 9; dir = 2; dwidth = 5; height = 22; id = "syndicate"; name = "syndicate infiltrator"; roundstart_move = "syndicate_away"; width = 18},/obj/docking_port/stationary{dheight = 9; dir = 2; dwidth = 5; height = 22; id = "syndicate_nw"; name = "northwest of station"; width = 18},/turf/simulated/shuttle/plating,/area/shuttle/syndicate) "dhX" = (/turf/space,/turf/simulated/shuttle/wall{dir = 1; icon_state = "diagonalWall3"},/area/shuttle/syndicate) @@ -8537,7 +8537,7 @@ "dii" = (/obj/docking_port/stationary{dir = 2; dwidth = 2; height = 18; id = "skipjack_nw"; name = "northwest of SS13"; width = 19},/turf/space,/area/space) "dij" = (/obj/machinery/door/window{base_state = "right"; dir = 4; icon_state = "right"; name = "Equipment Room"; req_access_txt = "150"},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "dik" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1331; id_tag = "synd_pump"},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) -"dil" = (/obj/effect/spawner/window/reinforced,/turf/unsimulated/floor{icon_state = "floor4"},/area/shuttle/syndicate) +"dil" = (/obj/machinery/hologram/holopad,/obj/machinery/light_switch{pixel_x = 0; pixel_y = 28},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/chapel/main) "dim" = (/obj/structure/rack,/obj/item/clothing/suit/space/syndicate/black/red,/obj/item/clothing/head/helmet/space/syndicate/black/red,/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 1; frequency = 1331; id_tag = "synd_pump"},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "din" = (/obj/item/device/radio/intercom/syndicate{pixel_x = -28},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "dio" = (/obj/docking_port/stationary{dheight = 9; dir = 2; dwidth = 5; height = 22; id = "syndicate_ne"; name = "northeast of station"; width = 18},/turf/space,/area/space) @@ -8565,7 +8565,7 @@ "diK" = (/obj/structure/table,/obj/item/weapon/gun/syringe,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "diL" = (/obj/structure/window/reinforced{dir = 1},/obj/structure/window/reinforced{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "diM" = (/obj/machinery/door/window{dir = 1; name = "Secure Storage"; req_access_txt = "150"},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) -"diN" = (/obj/structure/table,/obj/item/device/radio/beacon/syndicate/bomb{pixel_y = 5},/obj/item/device/radio/beacon/syndicate/bomb,/turf/unsimulated/floor{icon_state = "floor4"},/area/shuttle/syndicate) +"diN" = (/obj/structure/table,/obj/item/weapon/folder/blue,/obj/item/weapon/stamp/hop,/obj/item/device/eftpos,/obj/item/weapon/book/manual/sop_service,/obj/item/weapon/book/manual/sop_supply,/obj/item/weapon/book/manual/sop_command,/turf/simulated/floor/plasteel,/area/crew_quarters/heads) "diO" = (/obj/structure/table,/obj/item/weapon/grenade/syndieminibomb{pixel_x = 4; pixel_y = 2; pixel_z = 0},/obj/item/weapon/grenade/syndieminibomb{pixel_x = -1},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "diP" = (/obj/structure/mirror{pixel_x = 28},/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "diQ" = (/obj/machinery/telecomms/allinone{intercept = 1},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) @@ -8735,13 +8735,42 @@ "dlY" = (/obj/structure/table,/obj/item/weapon/storage/firstaid/regular{pixel_x = -2; pixel_y = 4},/obj/item/weapon/book/manual/sop_engineering,/turf/simulated/floor/plasteel,/area/engine/break_room) "dlZ" = (/obj/structure/table,/obj/machinery/atmospherics/pipe/simple/hidden/supply,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/storage/box/monkeycubes,/obj/item/weapon/book/manual/sop_science,/turf/simulated/floor/plasteel{icon_state = "white"},/area/toxins/xenobiology) "dma" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; tag = ""},/obj/structure/table/reinforced,/obj/item/weapon/clipboard,/obj/item/weapon/folder/yellow,/obj/item/weapon/stamp/ce,/obj/item/weapon/book/manual/sop_engineering,/turf/simulated/floor/plasteel{dir = 8; icon_state = "neutralfull"},/area/engine/chiefs_office) -"dmb" = (/obj/item/weapon/storage/fancy/donut_box,/obj/structure/table,/obj/item/weapon/book/manual/sop_general,/turf/simulated/floor/wood,/area/bridge/meeting_room) -"dmc" = (/obj/structure/table/woodentable,/obj/item/weapon/book/manual/security_space_law,/obj/item/weapon/coin/plasma,/obj/item/device/megaphone,/obj/item/weapon/book/manual/sop_general,/turf/simulated/floor/wood,/area/crew_quarters/captain) -"dmd" = (/obj/machinery/light{dir = 1},/obj/structure/bookcase,/obj/item/weapon/book/manual/sop_engineering,/obj/item/weapon/book/manual/sop_medical,/obj/item/weapon/book/manual/sop_science,/obj/item/weapon/book/manual/sop_security,/obj/item/weapon/book/manual/sop_service,/obj/item/weapon/book/manual/sop_supply,/obj/item/weapon/book/manual/sop_general,/obj/item/weapon/book/manual/sop_legal,/turf/simulated/floor/wood,/area/ntrep) +"dmb" = (/obj/machinery/light{dir = 1},/obj/structure/bookcase,/obj/item/weapon/book/manual/sop_engineering,/obj/item/weapon/book/manual/sop_medical,/obj/item/weapon/book/manual/sop_science,/obj/item/weapon/book/manual/sop_security,/obj/item/weapon/book/manual/sop_service,/obj/item/weapon/book/manual/sop_supply,/obj/item/weapon/book/manual/sop_general,/obj/item/weapon/book/manual/sop_legal,/obj/item/weapon/book/manual/sop_command,/turf/simulated/floor/wood,/area/ntrep) +"dmc" = (/obj/structure/table/woodentable,/obj/item/weapon/paper_bin,/obj/item/weapon/pen/blue,/obj/item/weapon/folder/blue{pixel_x = 4; pixel_y = 6},/obj/item/weapon/paper/blueshield,/obj/item/weapon/book/manual/sop_command,/turf/simulated/floor/plasteel{icon_state = "bcarpet05"},/area/blueshield) +"dmd" = (/turf/simulated/shuttle/wall{icon_state = "swall12"; dir = 2},/area/shuttle/trade/sol) "dme" = (/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/engine/mechanic_workshop) "dmf" = (/obj/machinery/door/firedoor{dir = 8; name = "Firelock West"},/obj/machinery/door/airlock/glass_engineering{name = "Mechanic Workshop"; req_access_txt = "70"; req_one_access_txt = "0"},/obj/structure/disposalpipe/segment{dir = 4},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/engine/mechanic_workshop) "dmg" = (/obj/item/device/radio/intercom{pixel_y = -30},/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers,/obj/machinery/light/small,/obj/structure/stool/bed/chair/wood/wings{tag = "icon-wooden_chair_wings (WEST)"; icon_state = "wooden_chair_wings"; dir = 8},/turf/simulated/floor/wood,/area/crew_quarters/bar) "dmh" = (/obj/machinery/camera{c_tag = "Bar South"; dir = 1; network = list("SS13")},/obj/machinery/atmospherics/unary/vent_scrubber{dir = 1; on = 1; scrub_N2O = 1; scrub_Toxins = 1},/obj/machinery/gameboard,/turf/simulated/floor/wood,/area/crew_quarters/bar) +"dmi" = (/turf/simulated/shuttle/wall{icon_state = "swall_s6"; dir = 2},/area/shuttle/trade/sol) +"dmj" = (/turf/simulated/shuttle/wall{icon_state = "swall14"; dir = 2},/area/shuttle/trade/sol) +"dmk" = (/obj/machinery/door/airlock/external{frequency = 1450; icon_state = "door_locked"; id_tag = "trade_sol_outer"; locked = 1; name = "External Access"; req_access = null; req_access_txt = "160"},/turf/simulated/shuttle/plating,/area/shuttle/trade/sol) +"dml" = (/obj/structure/window/full/shuttle,/obj/structure/grille,/turf/simulated/shuttle/plating,/area/shuttle/trade/sol) +"dmm" = (/obj/structure/grille,/obj/structure/shuttle/window,/turf/simulated/shuttle/plating,/area/shuttle/trade/sol) +"dmn" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f10"; dir = 2},/area/shuttle/trade/sol) +"dmo" = (/obj/structure/shuttle/engine/heater{dir = 8},/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating,/area/shuttle/trade/sol) +"dmp" = (/obj/structure/shuttle/engine/propulsion{icon_state = "burst_l"; dir = 4},/turf/space,/area/shuttle/trade/sol) +"dmq" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/turf/simulated/shuttle/wall{icon_state = "swall3"; dir = 2},/area/shuttle/trade/sol) +"dmr" = (/obj/machinery/atmospherics/unary/vent_pump/high_volume{dir = 4; frequency = 1450; id_tag = "trade_sol_pump"; req_access_txt = "160"; req_one_access_txt = "0"},/obj/machinery/airlock_sensor{frequency = 1450; id_tag = "trade_sol_sensor"; pixel_x = 25; pixel_y = 12},/obj/machinery/embedded_controller/radio/airlock/airlock_controller{frequency = 1450; id_tag = "trade_sol"; pixel_x = 25; req_access_txt = "160"; tag_airpump = "trade_sol_pump"; tag_chamber_sensor = "trade_sol_sensor"; tag_exterior_door = "trade_sol_outer"; tag_interior_door = "trade_sol_inner"},/turf/simulated/shuttle/plating,/area/shuttle/trade/sol) +"dms" = (/obj/structure/closet/crate,/turf/simulated/shuttle/floor,/area/shuttle/trade/sol) +"dmt" = (/obj/machinery/atmospherics/unary/portables_connector{dir = 8},/obj/machinery/portable_atmospherics/canister/air,/turf/simulated/shuttle/floor,/area/shuttle/trade/sol) +"dmu" = (/obj/machinery/light/spot{tag = "icon-tube1 (NORTH)"; icon_state = "tube1"; dir = 1},/obj/machinery/computer/shuttle/trade/sol,/turf/simulated/shuttle/floor,/area/shuttle/trade/sol) +"dmv" = (/obj/structure/stool/bed/chair,/turf/simulated/shuttle/floor,/area/shuttle/trade/sol) +"dmw" = (/obj/structure/shuttle/window,/obj/structure/grille,/turf/simulated/shuttle/plating,/area/shuttle/trade/sol) +"dmx" = (/obj/structure/shuttle/engine/propulsion{icon_state = "propulsion"; dir = 4},/turf/space,/area/shuttle/trade/sol) +"dmy" = (/turf/simulated/shuttle/wall{icon_state = "swallc4"},/area/shuttle/trade/sol) +"dmz" = (/obj/machinery/door/airlock/external{frequency = 1450; icon_state = "door_locked"; id_tag = "trade_sol_inner"; locked = 1; name = "External Access"; req_access = null; req_access_txt = "160"},/turf/simulated/shuttle/plating,/area/shuttle/trade/sol) +"dmA" = (/turf/simulated/shuttle/floor,/area/shuttle/trade/sol) +"dmB" = (/obj/machinery/door/airlock/shuttle{id_tag = "s_docking_airlock"; req_access_txt = "160"},/obj/docking_port/mobile{dir = 8; dwidth = 2; height = 11; id = "trade_sol"; name = "sol trade shuttle"; roundstart_move = "trade_sol_base"; width = 5},/obj/docking_port/stationary{dir = 8; dwidth = 2; height = 11; id = "trade_sol_offstation"; lock_shuttle_doors = 1; name = "northwest of Cyberiad"; width = 5},/turf/simulated/shuttle/floor,/area/shuttle/trade/sol) +"dmC" = (/obj/structure/shuttle/engine/propulsion{icon_state = "burst_r"; dir = 4},/turf/space,/area/shuttle/trade/sol) +"dmD" = (/obj/machinery/light/spot,/turf/simulated/shuttle/floor,/area/shuttle/trade/sol) +"dmE" = (/obj/machinery/access_button{command = "cycle_interior"; frequency = 1450; master_tag = "trade_sol"; name = "interior access button"; pixel_x = 25; pixel_y = 25; req_access_txt = "160"},/turf/simulated/shuttle/floor,/area/shuttle/trade/sol) +"dmF" = (/obj/structure/stool/bed/chair{dir = 1},/obj/machinery/light/spot,/turf/simulated/shuttle/floor,/area/shuttle/trade/sol) +"dmG" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/shuttle/floor,/area/shuttle/trade/sol) +"dmH" = (/turf/simulated/shuttle/wall{icon_state = "swall_s5"; dir = 2},/area/shuttle/trade/sol) +"dmI" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "swall_f9"; dir = 2},/area/shuttle/trade/sol) +"dmJ" = (/obj/docking_port/stationary{dir = 8; dwidth = 2; height = 11; id = "trade_dock"; name = "port bay 4 at Cyberiad"; width = 5},/turf/space,/area/space) +"dmK" = (/obj/machinery/door/airlock/external{id_tag = "trade_dock"},/turf/simulated/floor/plating,/area/hallway/secondary/entry) (1,1,1) = {" bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik @@ -8791,15 +8820,15 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhNcaVdhObFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdhPaafaafaafaafbFldhNcaVdhOdhQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikaalaalaalaalaalaalaalaamaanaaoaapaalaalaalaalbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhRcaVcaVdhSbFldhNcaVdhObFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaaqaaraasaataauaaybnHbnIaavaayaazaaAaaBaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhRcaVdhUdhTbFldhNcaVdhObFlaafdhWdhVdhXbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaaCaaDaaEaaFaayaayaawaaGaaHaayaazaazaaIaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhRcaVayLdhTbFldhNcaVdhObFlaafdhWdhVdhXbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaaCaaDaaEaaFaayaayaawaaGaaHaayaazaazaaIaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhYcaVcaVdhZbFldiacaVcczdicdibdibdibbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaaqaayaaKaaLaaMaayaaNaaOaavaaPaataataalaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhRcaVcaVcaVdidcaVcaVdiedigdifdifdihbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdiibikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaataataataaQaaRaaSaawaaGaaHaaxaaTaaUaaVaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhRcaVcaVcaVdijcaVcaVcaVdildikdikdimbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaaWaaXaaYaaZabaabbabcabdabeabfabgabhabhaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldhRcaVcaVcaVdijcaVcaVcaVaVUdikdikdimbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalaaWaaXaaYaaZabaabbabcabdabeabfabgabhabhaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdhPaafaafaafaafaafaafdincaVcaVaafaafaafaafaafaafdhXbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabiabjabkablabmabnaboabpabqabraatabsabtaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdiobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldipdipdiqdisdirbFlditcaVcaVbFldiudiwdivdiydixbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikaalabuaalabvabwabxabxaalaalabyaaoaalaalabzaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFlcaVcaVcaVdhUcaVdizcaVcaVcaVdiAcaVdhUcaVdhUdiBbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabBaatabCabDabEabFbikbikbikbikbikaalabGaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikabAcQScJadgjbikbikbikabAbikbikbikdgjbikbikbikabAdiCdgldgjbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFlcaVcaVcaVayLcaVdizcaVcaVcaVdiAcaVayLcaVayLdiBbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabBaatabCabDabEabFbikbikbikbikbikaalabGaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikabAcQScJadgjbikbikbikabAbikbikbikdgjbikbikbikabAdiCdgldgjbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldiDdiEcaVcaVcaVdiFcaVcaVcaVdiGcaVcaVcaVcaVdiHbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabBaatabCabHaalbikbikbikbikbikbikaalaalaalbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgmdgodgndgmbikbikabAdgmdgpdgrdgqdgmdgjbikbikdgmdgsdgtdgmbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldiIdiEcaVdiKdiJbFldiLdiMdiLbFldiNdiOcaVcaVcaVbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikaalaalaalaalabuaatabIabJaalaalaalaalbikbikbikabKabLabLabKbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgmdgvdgudgmbikabAdgwdgydgxdgAdgzdgydgwdgjbikdgmdgBdgCdgmbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldiIdiEcaVdiKdiJbFldiLdiMdiLbFlaWldiOcaVcaVcaVbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikaalaalaalaalabuaatabIabJaalaalaalaalbikbikbikabKabLabLabKbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgmdgvdgudgmbikabAdgwdgydgxdgAdgzdgydgwdgjbikdgmdgBdgCdgmbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFlcaVcaVdiPbFlaafbFlcaVdiRdiQbFlaafbFlcaVcaVcaVbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabMabNabOabPabQabRabSabTabUabVaalbikbikbikbikabKabLabWabKbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgmdgEdgDdgFbikdgHdgGdgydgydgIdgydgydgGdgJbikdgLdgKdgMdgmbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldiSdiUdiTbFlbikbFldiVdiVdiVbFlbikbFldiWdiYdiXbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaalabXabYabZacaacbaccacdaceacfacfaalbikbikbikbikbikabKabLabLabKbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgwdgNdgwbikbikdgOdgGdgydgPdgQdgydgydgGdgRbikbikdgwdgNdgwbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbFldiVdiVdiVbFlbikcVGdiZdjbdjadelbikbFldiVdiVdiVbFlbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacgacgacgacgacgacgachaciacjackaclaalacmbikbikbikbikbikabKabLabLabKbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdgwdgNdgwdgwdgwdgwdgwdgwdgwdgSdgwdgwdgwdgwdgwdgwdgwdgNdgwbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik @@ -8818,11 +8847,11 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaeAafyafAafyaeAafyafAafyaeAbikagSahCahDahEahFahGahHahIahJahKahLahMahNagvahOahRahQairahSahTahUahVahWahXahYahZahUaiaaibaicaidahYahZahUahUahAadaadaadaadaadaaieaieaieahAbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikagQaabaabaabahBaabaabaabagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGacGafxacGacGbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaeAafyafyafAaeAafyafyafAaeAbikagSaifaigaihagSaiiaijaikailaimainaioaipagvaiqaisahhamuaitaiuahUaivaiwaixaiyaizaiAaiBaiCaiDaiEaiFaiGbOIaiHahAaieaieaieaieaieaieaieaieahAbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikagQbikbikbikaiIbikbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikaabbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaeAafAafyaiJaeAafAafyaiKaeAbikagSaiLaiMaiNagSaiOaiOaiOaiOaiPaiQaiRaiSagvaiTaiUaiVaiWaiXaiYahUaiZajaajbajcajdajeajfajgaiDaiEajhaiGajhajiahAaieaieaieaieaieaieaieaieahAagQagQajjaabagQagQagQagQagQagQagQagQagQagQagQagQagQagQaabaabajkajlajmaabaabagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabajnaabafxbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikaeAajoajpajqajrajoajpajqajsajtajuajuajuajuajuajuajuajuajvajwajxajyajzajAajBajCajDajEajFajGahUajHajIajJajKajdajeajKajgajLaiEaiCaiCajMajNajOaieaieaieaieaieaieaieaieahAaabaabaabaabaabaabbikaabbikaabaabaabaabaabaabaabaabbikbikbikajkajPajmbikbikagQbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGacGacGafxafxaabaabbikajQbikaabaabafxafxacGacGacGbikbikbikbikbikbikbikbikbikbikbikbikaeAajRajSajTafyajUajVajWakcajtajYajZakaakbaknakdakdajuakeakfakgakhakiajBakjakkaklakmalJajFakoakpamwakqajKakraksaktakuakvakwakxakxakzaiCakAaieaieaieaieaieaieaieaieahAaabakBakCakCakCakDakCakCakCakCakDakCakCakCakCakEaabbikbikbikajkajPajmbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikbikaabbikaabbikbikajQbikbikaabbikaabbikbikacGbikbikbikbikbikbikbikbikbikbikbikbikaeAakFafyakGakHakIakJakKakLajtakMakNakOakOakPakQakRajuakSakTakUakVakiakWakXakYakZalaalbalcaldaleaAEalfalgalhalialjalkallalmaiCaiCaiCalnajOaieaieaieaieaieaieaieaieahAaabaloaabaabaabaloaabbikbikaabaloaabaabbikbikaloaabbikaabaabajkajPajmbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGaabalpalpalpalpalpbikalqbikalpalpalpalpalpaabacGbikbikbikbikbikbikbikbikbikbikbikbikaeAalralsakGafyaltakJalualvajtalwalxalyalzakQakQakRajualAalBalCalDalEajBalFalGaklalHalIajFajXalKalLalLalMajdalNalOalPalQaiCaiFaiGaiCalRahAahAahAahAahAahAahAahAahAahAaabaloaabbikajkajlajmbikbikajkajlajmbikbikajkajlajmaabaabbikajkajPajmbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikalSalTalTalTalTalUalValWalXalXalXalXalYbikacGbikbikbikamaalZaowanxambbikbikbikamcaeAaeAaeAamdamdameamfamgamdajuamhamiamjamkamlammamnajuamoampamqakVamrajGamsamtaXNamvaYjajGamxamyamzamAamBamCamDamEamFamGaiCajhamHamIamJahAamKamKamKamKamKbikbikbikbikaabaloaabbikajkajPajmbikbikajkajPajmbikbikajkajPajmbikbikbikajkajPajmbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdmidmddmkdmjdmldmddmddmmdmddmddmnbikbikbikbikbikbikbikbikbikafxaabajnaabafxbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikaeAajoajpajqajrajoajpajqajsajtajuajuajuajuajuajuajuajuajvajwajxajyajzajAajBajCajDajEajFajGahUajHajIajJajKajdajeajKajgajLaiEaiCaiCajMajNajOaieaieaieaieaieaieaieaieahAaabaabaabaabaabaabbikaabbikaabaabaabaabaabaabaabaabbikbikbikajkajPajmbikbikagQbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdmpdmodmrdmqdmtdmsdmsdmsdmvdmudmwbikbikbikacGacGacGafxafxaabaabbikajQbikaabaabafxafxacGacGacGbikbikbikbikbikbikbikbikbikbikbikbikaeAajRajSajTafyajUajVajWakcajtajYajZakaakbaknakdakdajuakeakfakgakhakiajBakjakkaklakmalJajFakoakpamwakqajKakraksaktakuakvakwakxakxakzaiCakAaieaieaieaieaieaieaieaieahAaabakBakCakCakCakDakCakCakCakCakDakCakCakCakCakEaabbikbikbikajkajPajmbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdmxdmodmzdmydmsdmAdmAdmAdmAdmAdmBbikbikbikacGbikbikaabbikaabbikbikajQbikbikaabbikaabbikbikacGbikbikbikbikbikbikbikbikbikbikbikbikaeAakFafyakGakHakIakJakKakLajtakMakNakOakOakPakQakRajuakSakTakUakVakiakWakXakYakZalaalbalcaldaleaAEalfalgalhalialjalkallalmaiCaiCaiCalnajOaieaieaieaieaieaieaieaieahAaabaloaabaabaabaloaabbikbikaabaloaabaabbikbikaloaabbikaabaabajkajPajmbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdmCdmodmEdmDdmAdmAdmAdmAdmGdmFdmwbikbikbikacGaabalpalpalpalpalpbikalqbikalpalpalpalpalpaabacGbikbikbikbikbikbikbikbikbikbikbikbikaeAalralsakGafyaltakJalualvajtalwalxalyalzakQakQakRajualAalBalCalDalEajBalFalGaklalHalIajFajXalKalLalLalMajdalNalOalPalQaiCaiFaiGaiCalRahAahAahAahAahAahAahAahAahAahAaabaloaabbikajkajlajmbikbikajkajlajmbikbikajkajlajmaabaabbikajkajPajmbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdmHdmddmddmddmldmddmddmmdmddmddmIbikbikbikacGbikalSalTalTalTalTalUalValWalXalXalXalXalYbikacGbikbikbikamaalZaowanxambbikbikbikamcaeAaeAaeAamdamdameamfamgamdajuamhamiamjamkamlammamnajuamoampamqakVamrajGamsamtaXNamvaYjajGamxamyamzamAamBamCamDamEamFamGaiCajhamHamIamJahAamKamKamKamKamKbikbikbikbikaabaloaabbikajkajPajmbikbikajkajPajmbikbikajkajPajmbikbikbikajkajPajmbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGaabamLamLamLamLamLbikamMbikamLamLamLamLamLaabacGbikbikbikamOamNamQamPamOamRamSamSamTamUamVamWamXamYamZanaanbancajuajuandaneajuajuajuajuajuanfanganhanianfajGajBajCanjajEajFajGankanlanmannahUahUahUahUannanoanpanmahUahAayjahAanrantansansanubikbikbikbikbikaloaabbikajkajPajmbikbikajkajPajmbikbikajkajPajmbikbikbikajkajPajmbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikbikbikaabbikbikbikanvbikbikbikaabbikbikbikaabbikbikbikaEEanwanzanyanBanAanDanCanAanGanGanHanIanJanKanLanManNanOanPanQanRanSanTanSanSanUanVanWanXanYanSanZaoaaobaocaodaoeaofaogaohanSaoiaojaokaolaomaonaooaopaoqaoraosaplaotaovaEHaouaoyaoxbikbikbikbikbikaloaabbikajkajPajmbikbikajkajPajmbikbikajkajPajmbikbikbikajkajPajmbikbikagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGaabalpalpalpalpalpbikamMbikalpalpalpalpalpaabacGbikbikbikamOanEaoAanFamOamRamSamSamSaoBaoHaoIaoJaoKaoLaoMaoNaoOaoPaoQaoRaoSaoTaoUaoVaoWaoXaoYaoWaoZapaaoTapbapcapdaoTaoTapdaoXapcapeaoTaoTapbapcaoVapfapgaphapiapjapkaplapmapnaovaozansansapobikaacapqaacbikaloaabbikajkajPajmbikbikajkajPajmbikbikajkajPajmbikaabaabajkajPajmaabaabagQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik @@ -8837,73 +8866,73 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikapsapsapsapsapsbikaahbikbikbikbikaabbikaabbikbikaabbikavtawkawlbikbikaabbikbikaabbikbikbikbikbikbikbikbikbikbikawmawmawmawmawmawmapwapwawnapwasUasUasUawoawpawqawrawrawsawrawsawrawrawtasZasZasvawvawwawuawvawwawuawyawzawzawzawzawzapOawAawBawCawCawDawCawEawFavUawGawHawIavVawJawKawLawMavWbikbikbikbikbikbikbikbikbikbikbikaabaabbikbikbikbikbikaabbikavZawNavZbikaabbikaabbikbikbikaabaabbikbikbikbikbikasMawOawPavlawQawRawSawTatJawUawVawWawXasMawYaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikapsapsapsapsapsbikbikbikbikbikbikaabbikaabbikbikaabavtavtawZaxaavtbikaabbikbikaabbikbikbikbikbikbikbikbikbikbikawmaxbaxcaxdaxeaxfaxgaxhaxiaxhaxjaxhaxhaxkaxlaxlaxlaxlaxlaxmaxnaxoaxlaxlaxlaxlaxpaxlaxlaxlaxlaxqaxraxsaxtaxuaxvaxwaxxapWaxyaxzaxAaxBaxCaxDaxEaxFavUaxGaxHaxIavVaxKaxLaxJaAZavWbikbikbikbikbikbikbikbikbikbikaabaabbikbikbikbikbikbikaabavZavZaxMavZavZaabbikaabbikbikbikbikaabaabbikbikbikbikasMaxNaxOavlasMavlavlaxPaxQasMasMasMasMasMasMaabaabbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikapsapsapsbikbikbikbikbikbikaabaabbikaabbikbikaabaxRaxSaxTaxUaxRaxVaxVbikbikaabbikbikbikbikbikbikbikbikbikbikawmaxWaxXaxYaxZayaaybaycaydayeayfaxqaxqaygaxqaxqaxqaxqaxqayhaxqaxqaxqaxqaxqaxqayiaxqaxqaxqaxqaSWaxqaykaxqaylaxqaymaynapWayoaypayqayraysaytaxEayuavUayvaywayxayyayzayAayBawMavWbikbikbikbikbikbikbikbikbikaabaabbikbikbikbikbikbikbikaabayCayDayEayFayCaabbikaabbikbikaabbikbikaabaabbikbikayGasMavlasMavlayHayIayHayJayHayHayHayKayGbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikaxVaxVaxVaxVaxVaabaabaxRayLayMayNaxRayOaxVbikbikaabbikbikbikbikbikbikbikbikbikbikawmayPayQayRaySayTawmayUayVayWayXayYayZazaazbazcayXayXayXazdayXayXayXayXayXayXazeazfazgazgazgazhaziazjaziazkazlazmaznapWazoazoazoazoazoazoaxEaxFavUazpaxHazqavVcscazraxJcvYavWbikbikbikbikbikbikbikbikaabaabbikbikbikbikbikbikbikbikaabayCazsaztazuayCaabbikaabbikbikaabbikbikayGazvayGazvayGayKayHayHayHayHayHayHayHayHayHazwazxayGbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikaxVaxVaxVaxVaxVaabaabaxRazsayMayNaxRayOaxVbikbikaabbikbikbikbikbikbikbikbikbikbikawmayPayQayRaySayTawmayUayVayWayXayYayZazaazbazcayXayXayXazdayXayXayXayXayXayXazeazfazgazgazgazhaziazjaziazkazlazmaznapWazoazoazoazoazoazoaxEaxFavUazpaxHazqavVcscazraxJcvYavWbikbikbikbikbikbikbikbikaabaabbikbikbikbikbikbikbikbikaabayCaFCaztazuayCaabbikaabbikbikaabbikbikayGazvayGazvayGayKayHayHayHayHayHayHayHayHayHazwazxayGbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabbikazyazzazybikbikbikaxVaxVaxVaxVazAazBazCaxVbikbikaxRazDazEazFazGazHaxVbikbikaabbikbikbikbikbikbikbikbikbikbikawmawmawmawmawmawmawmazIazIazJazKazKazLazMazNazOazPazPazOazQazOazRazRazRazRazRazRazSazRazRazTazUazVazWazIazXazIazYazIazIaqVazZaovaovaovaovaAaaxFavUaAbaxHaAcavVaAdayAayBawMavWbikbikbikbikbikbikbikbikaabaabbikbikbikbikazyaAeazybikaabayCaAfaAgaAhayCaAiaAiaAiaAiaAiazvazvazvayGaAjayHazwazxayJayHayJayJayJayGaAkayGayGayGayGayGbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabbikaAlaAmaAlbikbikaabaxVaAnaAoaApazHaAqazHaxVaAlaAlaxRaxRaAraAsazGazHaxVaxVaAlaAlaAlaxVaxVbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikazJaAtaAuaAvazMaAwazOaAxaAyaAzaAAaABaACaADbssaAFaAGaAHaAIaAJaAKaALaxqaxraAMaANaAOaAPaAQaAPaAPaAPaARaAPaAPaAPaAPaASaATaAUaAVaAWaAXaAYcNsaBaaUadcuavWaabaBbaBcaBcaBcaBcaBcaBdaabaabbikbikbikbikazvaBeazvbikaAiayCayCaBfaBgayCaBhayHayHayHayJaBiayHaBjayGayHayHayHaBkayJayHayGaBlaBmayGayHaBnayGbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabbikaAlaAmaAlbikbikaabaxVaAnaAoaApazHaAqazHaxVaAlaAlaxRaxRaAraAsazGazHaxVaxVaAlaAlaAlaxVaxVbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikazJaAtaAuaAvazMaAwazOaAxaAyaAzaAAaABaACaADbfTaAFaAGaAHaAIaAJaAKaALaxqaxraAMaANaAOaAPaAQaAPaAPaAPaARaAPaAPaAPaAPaASaATaAUaAVaAWaAXaAYcNsaBaaUadcuavWaabaBbaBcaBcaBcaBcaBcaBdaabaabbikbikbikbikazvaBeazvbikaAiayCayCaBfaBgayCaBhayHayHayHayJaBiayHaBjayGayHayHayHaBkayJayHayGaBlaBmayGayHaBnayGbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikappaBpaBobikaBqaBsaBraabaabaAlazHaAlbikbikaabaxVaBuaBvaBwaBxaByaBzaxVaBAazHaBBaBCaBDaBEaBEaBEaBEaBEaBEaBEaBEaBFaxVbikaBGbikbikbikbikbikbikbikbikbikbikbikbikbikbikaBHaBIaBJaBKazMaAwazOaBLafvaBNaAAaABaBOaBPaBPaBPaBPaBPaAIbjlaAKaxlaxqaxrazIaBQaBRaBSaBTaBSaBSaBUaBVaBWaBWaBWaBWaBWaBWaBXaBYaBZaCaaCbaCcaCdaCeavWavWaCfaCgaChaChaChaChaChaCgaCfaabbikbikbikbikazvaCiaCjbikaAiaCkaClaCmaCnayHayHayHayJayHayJaCoayHayHayGayHaCpaCqaCoaAkayHayGaCraCsayGayHaCtayGbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaCuaBtaCvaBtaCuaCwaCxaCwaCuaabaAlaCzaCAbikbikaxVaxVaxVaxVaxVaCBaCCaCDaCEaCFaCGaCGaCHaCIaCIaCJaCKaxVazHaxVaxVaxVaCLaxVbikaabbikbikbikbikbikbikaabaabaabaabaabaabaabaabaCMaCNaCOaBKazMaAwazOaCPaCQaCRaAAaCSaCTaBPaCUaBPaCVaCVaAIaBPaAKaxlaxqaCWazIaCXaBRaCYaCZaDaaDbaDcaDdaDeaDfaDgaDhaDiaDjaDkaDlaDmaDnaDoaDpaDqaDraDsaDtaCfaCgaChaChaChaChaChaCgaCfaabaabaabaabazvazvaDuaDvazvaAiaDwayHaDxayHayKayHayGayGaDyayGayGaDzayJayJaCoaDAaDBayHayGayHaDCaDCaDCaDCaDCaDCaDCaDCaDCaDDaDDaDDaDDaacaDDaDDaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaDEaBtaCyaBtaDEaCwaDFaCwaDEaxVaAlaDHaDIaAlaAlaxVazHazHazHazHazHazHazHaCBaCLaxVaxVaxVaxVaxVaDJaxVaxVazHaDKaxVaDLaCLaxVaxVaxVbikbikbikbikbikaDMaDMaDMaDMaDMaDMaDMaDMaabaCMaDNaDOaDPaDQaDRaDSaDTaDUaDVaDWaABaDXaBPaDYaDZaEaaEbaEcaEdaAKaxlaxqaxrazIatsaEeaEfaCZaDaaDbaEgaEhaEhaEhaEhaEhaEhaEhaEhaEhaEhaEiaEjaEkaElaEmaEnaEoaEpaCgaChaChaChaChaChaCgaCfaCfaCfbikbikazvayHaEqaEraBhaEsaDAaCoaDxayHaEtayIaEuaAkayHayHayHayHaEvayHayHaDAaEwayHaDzayHaDCaExaEyaEzaDCaEAaEBaECaDCaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaDEaDGcUCaEDaDEaEFddzaEGaEJaEKazHaELaEMaENaDKaEOazHaxVaxVaxVaxVaxVaxVaxVaCLaxVaEPaEQaERaxVaESaETaEUazHaEOaxVaENaEVaBEaBFaEWbikbikbikbikbikaEXaEYaEZaFaaFbaFcaFdaDMaabaCMaFeaFfaFgaCMaFhazOaFiaFjaFkaFlaABaFnaBPaFoaFpaFqaFraFsaFtaFuaFvaydaFwaFxaFyaFzaFAaCZaDaaDbaFBaEhaFCaFCaFCaEhaEhaFDaFEaFEaFFaEiaFGaFHaFIaFIaFJaFKaFLaFMaChaChaChaChaChaFNaFOaFPaFQbikbikazvayHayHaFRayHaEsaFSayHaFTaFUaFUaFUaFUaFVaFUaFWayHayHayHayHayHayHayHayHayJayIaDCaFXaFYaFYaDCaFZaGaaGbaDCbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaDEaGcaGdaGeaDEaGcaGdaGeaEJaBzazHaGfazHazHazHazHazHaxVaGgaGhaGiaGjaGkaxVaCLaxVaEQaGlaEPaGmaGnaGoaxVaGpaxVaxVaxVaxVaGpaCLaEWbikazyazyazyazyaGqaEYaGraGsaGtaGuaGvaGwaDMaCMaBHaGxaGxaGxaGyaGzaGAaGzaGzaGzaGBaGCaGDaGEaGFaGFaGFaGFaGGaGHaGIaxqaGJazIatsaGKaGLaCZaDaaDbaEgaFCaGMaGMaGNaFCaEhaGOaGPaGPaGQaGRaFGaGSaGTaGUaGVaEhaGWaFQaChaChaChaChaChaFQaGXaGYaFQaabaabayGayHayHayJayJaEsaGZaGZaAiaAiaAiaEsaEsaEsayGaHaaHbayGayJayJayGayJayJayGayGaHcaHdaHeaHfaHgaHhaHiaFXaHjaDCbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaCuaDEaEIaHlaCuaDEaEIaHlaCuaxVaCBaxVaxVaxVaxVaxVazHaxVazHaHnaHoazHazHaxVaCLaxVaHpaabaHpaxVaBvaGoaxVaHqaHraxVaENaBzaxVaAwaDMaDMaHsaHsaHsaHsaHsaHsaHsaHsaHsaGvaGvaGwaHtaHuaHvaHwaHxaHyaHzaHAaHBaHBaHBaHBaHCaHDaHEaHFaHGaHBaHBaHHaHHaHIaHJaHKaHLaHMaHNaGKaHOaHPaHPaDbaEgaFCaHQaHRaHSaFCaEhaGOaGPaGPaGQaHTaFGaGSaGUaGUaGVaEhaGWaFQaChaChaChaChaChaFQaHUaGYaFQbikbikayGaHVayHayHaHWayJaHXazwaHYaHZayKayGaFSayKayGaIaayHayGaIbayHayGaIcaIdaIeaFUaIfaFUaIgaIhaIiaIjaIkaIlaImaDCaDDaDDaacaacaDDaDDaDDaDDaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaInaIoaIoaIoaIqaIoaIoaIoaIsaItaIuaIuaIuaIuaIvaxVazHaxVaIwaIxaIyazHaIzaGpaCLaxVaxVaxVaxVaxVaxVaGpaxVazHaIyaCBazHazHaGvaIAaIBaICaIDaIDaIDaIDaIEaIDaIDaIFaIGaICaIHaIIaIIaIIaIIaIIaIIaIIaIJaIKaIKaIKaIKaILaIMaIKaINaIKaIOaILaIKaIKaIKaIKaIPaIQaIRaISaITaFzaIUaIVaHPaIWaEgaFCaIXaIYbvsaFCaEhaIZaJaaJaaJbaEiaFGaJcaJdaJdaJeaEhaJfaJgaChaChaChaChaChaJhaJiaJjaFQbikbikayGayHayHayHayHayHayHaIeaFUaFUaFUaFUaFUaFUaFUaCmayHayHayHayHaDzayHayHaDxayHaJkaJlaJmaJnaJoaFYaFYaFYaJpaDCaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaInaJqaJraJsaJtaJuaJvaJwaJxaJvaJyaJzaJvaJvaJAaxVazHaxVaJBazHazHaJCaJDaxVaEVaBFazHazHazHazHazHazHaGpaJEazHaxVaEKaEKaDMaJFaDMaJGaJHaJIaJIaJIaJJaJIaJIaJIaJKaJGaJLaJMaJMaJMaJMaJMaJMaJMaGvaIKaJNaJOaJPaJQaJRawxaJTaJUaJVaJWaJXaJOaJYaIKaJZaxqaKaazIaKbaGKaKcaKdaKdaKeaKfaKgaKhaKiaKiaKjaKkaKlaKjaKkaKkaKmaKnaKoaEhaEhaKpaEhaKqaKraChaChaChaChaChaKraCfaCfaCfayGayGayGayKayJayJaAkayGayGaDxayJayGaKsayJayGaAkayGaDxaHVayJayGaAkayGayHaHVaDxayHaKtaDCaKuaIhaKvaKwaKxaIhaKyaDCaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaDEaDGcUCaEDaDEaEFddzaEGaEJaEKazHaELaEMaENaDKaEOazHaxVaxVaxVaxVaxVaxVaxVaCLaxVaEPaEQaERaxVaESaETaEUazHaEOaxVaENaEVaBEaBFaEWbikbikbikbikbikaEXaEYaEZaFaaFbaFcaFdaDMaabaCMaFeaFfaFgaCMaFhazOaFiaFjaFkaFlaABaFnaBPaFoaFpaFqaFraFsaFtaFuaFvaydaFwaFxaFyaFzaFAaCZaDaaDbaFBaEhaHTaHTaHTaEhaEhaFDaFEaFEaFFaEiaFGaFHaFIaFIaFJaFKaFLaFMaChaChaChaChaChaFNaFOaFPaFQbikbikazvayHayHaFRayHaEsaFSayHaFTaFUaFUaFUaFUaFVaFUaFWayHayHayHayHayHayHayHayHayJayIaDCaFXaFYaFYaDCaFZaGaaGbaDCbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaDEaGcaGdaGeaDEaGcaGdaGeaEJaBzazHaGfazHazHazHazHazHaxVaGgaGhaGiaGjaGkaxVaCLaxVaEQaGlaEPaGmaGnaGoaxVaGpaxVaxVaxVaxVaGpaCLaEWbikazyazyazyazyaGqaEYaGraGsaGtaGuaGvaGwaDMaCMaBHaGxaGxaGxaGyaGzaGAaGzaGzaGzaGBaGCaGDaGEaGFaGFaGFaGFaGGaGHaGIaxqaGJazIatsaGKaGLaCZaDaaDbaEgaHTaGMaGMaGNaHTaEhaGOaGPaGPaGQaGRaFGaGSaGTaGUaGVaEhaGWaFQaChaChaChaChaChaFQaGXaGYaFQaabaabayGayHayHayJayJaEsaGZaGZaAiaAiaAiaEsaEsaEsayGaHaaHbayGayJayJayGayJayJayGayGaHcaHdaHeaHfaHgaHhaHiaFXaHjaDCbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbjNaInaCuaDEaEIaHlaCuaDEaEIaHlaCuaxVaCBaxVaxVaxVaxVaxVazHaxVazHaHnaHoazHazHaxVaCLaxVaHpaabaHpaxVaBvaGoaxVaHqaHraxVaENaBzaxVaAwaDMaDMaHsaHsaHsaHsaHsaHsaHsaHsaHsaGvaGvaGwaHtaHuaHvaHwaHxaHyaHzaHAaHBaHBaHBaHBaHCaHDaHEaHFaHGaHBaHBaHHaHHaHIaHJaHKaHLaHMaHNaGKaHOaHPaHPaDbaEgaHTaHQaHRaHSaHTaEhaGOaGPaGPaGQaKhaFGaGSaGUaGUaGVaEhaGWaFQaChaChaChaChaChaFQaHUaGYaFQbikbikayGaHVayHayHaHWayJaHXazwaHYaHZayKayGaFSayKayGaIaayHayGaIbayHayGaIcaIdaIeaFUaIfaFUaIgaIhaIiaIjaIkaIlaImaDCaDDaDDaacaacaDDaDDaDDaDDaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdmJdmKaGddmKaIoaIoaIoaIqaIoaIoaIoaIsaItaIuaIuaIuaIuaIvaxVazHaxVaIwaIxaIyazHaIzaGpaCLaxVaxVaxVaxVaxVaxVaGpaxVazHaIyaCBazHazHaGvaIAaIBaICaIDaIDaIDaIDaIEaIDaIDaIFaIGaICaIHaIIaIIaIIaIIaIIaIIaIIaIJaIKaIKaIKaIKaILaIMaIKaINaIKaIOaILaIKaIKaIKaIKaIPaIQaIRaISaITaFzaIUaIVaHPaIWaEgaHTaIXaIYbvsaHTaEhaIZaJaaJaaJbaEiaFGaJcaJdaJdaJeaEhaJfaJgaChaChaChaChaChaJhaJiaJjaFQbikbikayGayHayHayHayHayHayHaIeaFUaFUaFUaFUaFUaFUaFUaCmayHayHayHayHaDzayHayHaDxayHaJkaJlaJmaJnaJoaFYaFYaFYaJpaDCaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaInaInaKzaJqaJraJsaJtaJuaJvaJwaJxaJvaJyaJzaJvaJvaJAaxVazHaxVaJBazHazHaJCaJDaxVaEVaBFazHazHazHazHazHazHaGpaJEazHaxVaEKaEKaDMaJFaDMaJGaJHaJIaJIaJIaJJaJIaJIaJIaJKaJGaJLaJMaJMaJMaJMaJMaJMaJMaGvaIKaJNaJOaJPaJQaJRawxaJTaJUaJVaJWaJXaJOaJYaIKaJZaxqaKaazIaKbaGKaKcaKdaKdaKeaKfaKgaSsaKiaKiaKjaKkaKlaKjaKkaKkaKmaKnaKoaEhaEhaKpaEhaKqaKraChaChaChaChaChaKraCfaCfaCfayGayGayGayKayJayJaAkayGayGaDxayJayGaKsayJayGaAkayGaDxaHVayJayGaAkayGayHaHVaDxayHaKtaDCaKuaIhaKvaKwaKxaIhaKyaDCaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabaabaDEaKzaKAaKzaKBaJraJraKCaKzaKAaKzaKDaKEaKFaKGaxVazHaGpaGpaxVaxVaxVaKHaKHaKHazNaKHaKHaKHaKHaKHaGvaDMaDMaDMaDMaDMaDMaDMaJFaKIaJGbikaabbikaabbikaabbikaabbikaJGaJLaJMaKJaKKaKLaKMaKNaJMaGvaIKaKOaKOaKPaKQaKRaKSaKTaKSaKUaKVaKWaKOaKOaIKaJZaxqaKXazIaKbaGKaGLaCZaDaaDbaEgaKYaKZaLaaLbaLcaLcaLdaLeaLcaLeaLfaLgaLhaLiaLjaLkaLlaCfaKraChaChaChaChaChaKrayGaCtayHaLmaLnayJayGayJaCtayHayGaCtaDxayGaLoayHayGaLpayHayJaLqaLrayGaLsayHayJaAkaAkaDxaAkaLtaDCaLuaIhaLvaLwaLvaIhaLxaDCaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabaLyaCuaLzaGdaKzaLAaLBaLCaLDaKzaGdaLEaInaCuaLFaLGaxVazHazHazHazHazHazHaKHaLHaLIaLJaLKaLLaLMaLHaKHaLNaLOaIDaIDaIDaIDaIDaIDaLPaLQaJGaabaLRaLRaLRaLRaLRaLRaLRaabaJGaJLaJMaLSaLTaLUaLVaLSaJMaGvaIKaIKaIKaIKaLWaLXaJOaLYaJOaLXaLZaIKaIKaIKaIKaJZaxqaMaazIaKbaGKaFAaCZaDaaDbaFBaMbaMcaMcaMcaMcaMcaMcaMcaMdaMcaMeaMeaMeaMeaMeaMfayGaCfaKraChaChaChaChaChaKrayGayGayHaMgaLnayJaMhayGayHayHayGayHaDxayJayHayHayGayHayHayJaDxayIayGayHayHayJaMiayHaDxayHaMjaMkaMkaDCaDCaDCaDCaDCaDCaDCaDDaDDaDDaDDaDDaabbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaInaKAaKzaKzaKzaKzaKzaKzaKAaInaMlaCuaMmaMnaMoaMoaMoaMoaMoaMoaMpaKHaLHaMqaLJaMraMqaMqaLHaKHaMsaMtaMuaMuaMuaMuaMuaMuaMuaMuaMvbikaLRaMwaMxaMyaMzaMAaLRbikaJGaJLaJMaMBaMCaMDaMEaLSaJMaGvaIKaMFaMFaKPaMGaMHaKSaKTaKSaMHaMIaMJaKOaKOaIKaJZaxqaKaazIaMKaBRaMLaCZaDaaDbaEgaMbaMcaMMaMNaMOaMOaMcaMPaMQaMRaMeaMSaMTaMUaMeaMVayGbikaMWaMXaMXaMXaMXaMXaMYbikayGayHaMZaNaayJayJayGayGayJayJaNbaNcayJayGazxayGayGayJayJaNdaNeayGayGayGaHYaMiayHaDxayHaMjazwayKaFSayGaNfaNgaNfayGayGayGaabaabaabaabaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaNhaNiaNjaNiaNiaNkaNlaNiaNiaNjaNmaNnaCuaKBaNoaMoaNpaNqaNraNsaNtaNuaKHaLHaMqaLJaNvaMqaMqaLHaKHaNwaNxaNyaNzaNAaNBaNCaNDaNEaNFaMvaabaLRaNGaNHaNIaNJaNKaLRaabaJGaJLaJMaNLaNMaNNaNOaNPaJMaGvaIKaJNaJOaNQaNRaLXaJOaNSaJOaLXaNTaNUaJOaJYaIKaJZaxqaNVazIaKbaEeaEfaCZaDaaDbaNWaNXaMcaNYaMQaMQaMQaNZaOaaObaOcaMeaOdaOeaOfaOgaOhazxbikbikbikbikbikbikbikbikbikayGaOiaOjaOkaOlaOmayGaEtayHaHVaDxayHayGbikayGayHayHayHayHaDxaOnaOoaOpaOpaOpaOpaOqaOraOsaOtaOuaOvaOuaOwaOxaOxaOyaOzaOAaOBaOCaOCbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaNhaNmaNiaODaOEaOFaOGaOHaOIaOJaOKaOLaOMaONaOOaKzaKBaOPaMoaOQaORaOSaOTaOSaOUaKHaOVaMqaOWaOXaOYaOXaOZaPaaPbaPcaPdaPdaPdaPdaPdaPdaPeaPfaMvbikaLRaPgaNHaPhaNJaPiaLRbikaJGaJLaJMaPjaPkaPlaPmaPnaJMaGvaIKaPoaPoaKPaPpaMHaKSaPqaKSaMHaPraKWaPsaPsaIKaPtazUaPuazIaKbaEeaPvaPvaPvaPvaPwaPxaPyaPzaPAaPBaPBaPBaPCaPBaPDaPEaPFaPGaPHaPEaPIaPJazxayGayGayGayGayGayGayGayGayGayGayGayGaBMayGayGayGayGayHaDxaOiazvaabazvayHaPLaPMaPNaPOaPPaPQaPRaPRaPRaPRaPSaPTaPUaPVaPWaPXaPWaPYaPWaPWaPZaQaaQbaQbaQcaQdaQeaQeaQeaQeaQeaQeaQeaQeaQeabLadbbikbikbikbikbikbikbikaaabdBaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaONaQgaQhaQiaOMaQjaOFaQjaOFaQjaOFaQjaOMaQkaQlaKzaKBaQmaMoaQnaQoaQpaQqaQraQsaKHaQtaMqaQuaQvaQwaQxaQyaKHaQzaPdaPdaPdaPdaPdaPdaPdaPeaQAaMvaabaLRaQBaQCaQDaQEaQFaLRaabaJGaJLaJMaQGaQHaQIaQJaQKaJMaGvaIKaIKaIKaIKaQLaLXaJOaLYaJOaLXaQMaIKaIKaIKaIKaQNaQOaQPazIaMKaQQaQRaQRaQRaQSaQTaQUaQVaQWaQXaQVaQYaQZaRaaQVaRbaRcaRdaReaRfaMeaRgaRhaRiaRjaRjaRhaRkaRlaRlaRlaRlaRlaRmaRnaRlaRoaRpaRqaRraRsaRvaRuaTkaRwaRxaRwaRyaRzayHayGaRAaRBaRCaRDaREaRFaRGaRHaRIaRJaRIaRKaRLaRMaRNaROaRPaRQaRRaRSaRTaRUaQdaRVaRWaRXaRYaRZaSaaSbaScaSdaprbikbikbikbikbikbikbikaaabfmbifbieaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaSfaOFaOFaNjaOMaQjaOFaQjaSgaQjaOFaQjaOMaQkaQlaKzaKBaShaMoaMoaSiaSjaSkaSjaMoaKHaKHaKHaKHaSlaSmaSnaSoaKHaSpaSqaSraPdaPdaSsaPdaStaSuaSvaMvbikaLRaLRaSwaSxaSwaLRaLRbikaJGaJLaJMaSyaSzaSAaQJaSBaJMaGvaIKaJNaJOaSCaNRaLXaJOaLYaJOaLXaNTaSDaIKaIKaIKaSEaSFaSGaSHaSIaSJamKamKaSKaSLaSMaSNaMcaSOaMQaMcaSPaMcaSQaMcaSRaSSaSTaSUaSVaTeaSXaSYaSZaTaaTbaTcaTdaTbaTbaUjaTbaSYaTfaSYaOvaTgaSYaThaTiaTjaTmaTlaToaTnaTqaTpaWIaTraOuaTsaTtaTuaTvaTwaTxaTyaTzaRHaTAaTBaRIaTCaTDaTEaTFaROaTGaRQaRRaRSaTHaTIaQdaTJaTKaTKaTLaScaScaScaScaSdaprbikbikbikbikbikbikaaabfmbigbijbihbieaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaONaTMaTNaQiaOMaQjaOFaQjaOFaQjaOFaQjaOMaQkaQlaKzaKBaTOaTPaTQaTRaTSaTSaJraTTaTUaTVaTWaTXaTYaTZaMqcoCaKHaUbaUcaUdaUeaUfaUgaUhaUiaUZaUkaMvbikaabbikaUlaUmaUlbikaabbikaCuaJLaJMaUnaUoaUpaUqaUraJMaGvaIKaUsaUtaKPaUuaUvaKSaUwaKSaUxaUyaUzaIKaUAaUBaUCaUDaUEaUFaUGaUHbikbikaSKaUIaUJaUKaMcaULaUMaMQaMQaUNaMQaMQaMQaUOaMeaUPaMeaUQaURaMeaUSaMeaUTaUUaUVaUWaUXaUYaUTbwNaVaaVbaVcaVbaVbaVbaVbaVdaWLaVbaVeaVfaWFaWBaVbaVhayHaRDaViaTvaVjaVkaVlaVmaVnaVoaVpaVqaRIaVraVsaVtaVuaVvaTGaRQaRRaRSaRTaVwaQdaVxaTKaTKaTLaScaScaScaScaSdaprbikbikbikbikbikbikbdBblqbjMbmKbjMbqQbdBbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaVyaVzaNiaODaOMaOFaVAaVBaOFaOFaVCaVAaOMaONaVDaKzaKBaVEaVFaVGaVHaVGaVGaVGaVGaVGaVIaJraKHaVJaVKaVJaKHaKHaVLaVMaVLaMuaMuaMuaMuaVLaVNaVOaMvaVPaVQaVQaVRaVSaVRaVQaVQaVTaVUaVVaJMaVWaJMaVXaVYaVZaJMaWaaIKaIKaIKaIKaWbaWcaWdaWeaWdaWcaWbaIKaIKaWfaUDaUDaUDaUDaWgaWhaWiaWjaWkaSKaWlaUJaWmaMcaMcaMcaMcaMcaMcaMcaMeaMeaUOaWnaWoaWpaWqaWraWsaWuaWtaUTaWvaWwaWxaWyaWzaUTaWAaWGaWCaWDaWCaWEaWHaYDaWNaYFaWJaWKaYGaWMaYEaVbaWOaRtaWPaWQaWRaVjbtTcvIaVmaWTaRIaWUaWVaWWaWXaWYaTFaTFaRIaRIaRQaRRaRSaTHaWZaQdaXaaXbaXcaXdaXeaXfaScaScaXgaprbikbikbikbikbikaaabfmbqRbmKbmKbmKbqSbieaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaNhaNiaNjaNiaNiaNkaNlaNiaNiaNjaNmaNnaCuaKBaNoaMoaNpaNqaNraNsaNtaNuaKHaLHaMqaLJaNvaMqaMqaLHaKHaNwaNxaNyaNzaNAaNBaNCaNDaNEaNFaMvaabaLRaNGaNHaNIaNJaNKaLRaabaJGaJLaJMaNLaNMaNNaNOaNPaJMaGvaIKaJNaJOaNQaNRaLXaJOaNSaJOaLXaNTaNUaJOaJYaIKaJZaxqaNVazIaKbaEeaEfaCZaDaaDbaNWaNXaMcaNYaMQaMQaMQaNZaOaaObaOcaMeaOdaOeaOfaOgaOhazxbikbikbikbikbikbikbikbikbikayGaOiaOjaOkaOlaOmayGaEtayHaHVaDxayHayGbikayGayHayHayHayHaDxaOnaOoaOpaOpaOpaOpaOqaOraOsaOtaOuaOvaOuaOwaOxaOxaOyaOzaOAaOBbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaNhaNmaNiaODaOEaOFaOGaOHaOIaOJaOKaOLaOMaONaOOaKzaKBaOPaMoaOQaORaOSaOTaOSaOUaKHaOVaMqaOWaOXaOYaOXaOZaPaaPbaPcaPdaPdaPdaPdaPdaPdaPeaPfaMvbikaLRaPgaNHaPhaNJaPiaLRbikaJGaJLaJMaPjaPkaPlaPmaPnaJMaGvaIKaPoaPoaKPaPpaMHaKSaPqaKSaMHaPraKWaPsaPsaIKaPtazUaPuazIaKbaEeaPvaPvaPvaPvaPwaPxaPyaPzaPAaPBaPBaPBaPCaPBaPDaPEaPFaPGaPHaPEaPIaPJazxayGayGayGayGayGayGayGayGayGayGayGayGaBMayGayGayGayGayHaDxaOiazvaabazvayHaPLaPMaPNaPOaPPaPQaPRaPRaPRaPRaPSaPTaPUaPVaPWaPXaPWaPYaPWaPWaPZaQabpqaQbaQcaQdaQeaQeaQeaQeaQeaQeaQeaQeaQeabLadbbikbikbikbikbikbikbikaaabdBaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaONaQgaQhaQiaOMaQjaOFaQjaOFaQjaOFaQjaOMaQkaQlaKzaKBaQmaMoaQnaQoaQpaQqaQraQsaKHaQtaMqaQuaQvaQwaQxaQyaKHaQzaPdaPdaPdaPdaPdaPdaPdaPeaQAaMvaabaLRaQBaQCaQDaQEaQFaLRaabaJGaJLaJMaQGaQHaQIaQJaQKaJMaGvaIKaIKaIKaIKaQLaLXaJOaLYaJOaLXaQMaIKaIKaIKaIKaQNaQOaQPazIaMKaQQaQRaQRaQRaQSaQTaQUaQVaQWaQXaQVaQYaQZaRaaQVaRbaRcaRdaReaRfaMeaRgaRhaRiaRjaRjaRhaRkaRlaRlaRlaRlaRlaRmaRnaRlaRoaRpaRqaRraRsaRvaRuaTkaRwaRxaRwaRyaRzayHayGaRAaRBaRCaRDaREaRFaRGaRHaRIaRJaRIaRKaRLaRMaRNaROaRPaOCbbVaTCaRTaRUaQdaRVaRWaRXaRYaRZaSaaSbaScaSdaprbikbikbikbikbikbikbikaaabfmbifbieaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaSfaOFaOFaNjaOMaQjaOFaQjaSgaQjaOFaQjaOMaQkaQlaKzaKBaShaMoaMoaSiaSjaSkaSjaMoaKHaKHaKHaKHaSlaSmaSnaSoaKHaSpaSqaSraPdaPdaZVaPdaStaSuaSvaMvbikaLRaLRaSwaSxaSwaLRaLRbikaJGaJLaJMaSyaSzaSAaQJaSBaJMaGvaIKaJNaJOaSCaNRaLXaJOaLYaJOaLXaNTaSDaIKaIKaIKaSEaSFaSGaSHaSIaSJamKamKaSKaSLaSMaSNaMcaSOaMQaMcaSPaMcaSQaMcaSRaSSaSTaSUaSVaTeaSXaSYaSZaTaaTbaTcaTdaTbaTbaUjaTbaSYaTfaSYaOvaTgaSYaThaTiaTjaTmaTlaToaTnaTqaTpaWIaTraOuaTsaTtaTuaTvaTwaTxaTyaTzaRHaTAaTBaRIcLhaTDaTEaTFaROaTGaRQaRRaRSaTHaTIaQdaTJaTKaTKaTLaScaScaScaScaSdaprbikbikbikbikbikbikaaabfmbigbijbihbieaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaONaTMaTNaQiaOMaQjaOFaQjaOFaQjaOFaQjaOMaQkaQlaKzaKBaTOaTPaTQaTRaTSaTSaJraTTaTUaTVaTWaTXaTYaTZaMqcoCaKHaUbaUcaUdaUeaUfaUgaUhaUiaUZaUkaMvbikaabbikaUlaUmaUlbikaabbikaJGaJLaJMaUnaUoaUpaUqaUraJMaGvaIKaUsaUtaKPaUuaUvaKSaUwaKSaUxaUyaUzaIKaUAaUBaUCaUDaUEaUFaUGaUHbikbikaSKaUIaUJaUKaMcaULaUMaMQaMQaUNaMQaMQaMQaUOaMeaUPaMeaUQaURaMeaUSaMeaUTaUUaUVaUWaUXaUYaUTbwNaVaaVbaVcaVbaVbaVbaVbaVdaWLaVbaVeaVfaWFaWBaVbaVhayHaRDaViaTvaVjaVkaVlaVmaVnaVoaVpaVqaRIaVraVsaVtaVuaVvaTGaRQaRRaRSaRTaVwaQdaVxaTKaTKaTLaScaScaScaScaSdaprbikbikbikbikbikbikbdBblqbjMbmKbjMbqQbdBbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaVyaVzaNiaODaOMaOFaVAaVBaOFaOFaVCaVAaOMaONaVDaKzaKBaVEaVFaVGaVHaVGaVGaVGaVGaVGaVIaJraKHaVJaVKaVJaKHaKHaVLaVMaVLaMuaMuaMuaMuaVLaVNaVOaMvaVPaVQaVQaVRaVSaVRaVQaVQaVTaJGaVVaJMaVWaJMaVXaVYaVZaJMaWaaIKaIKaIKaIKaWbaWcaWdaWeaWdaWcaWbaIKaIKaWfaUDaUDaUDaUDaWgaWhaWiaWjaWkaSKbKgaUJaWmaMcaMcaMcaMcaMcaMcaMcaMeaMeaUOaWnaWoaWpaWqaWraWsaWuaWtaUTaWvaWwaWxaWyaWzaUTaWAaWGaWCaWDaWCaWEaWHaYDaWNaYFaWJaWKaYGaWMaYEaVbaWOaRtaWPaWQaWRaVjbtTcvIaVmaWTaRIaWUaWVaWWaWXaWYaTFaTFaRIaRIaRQaRRaRSaTHaWZaQdaXaaXbaXcaXdaXeaXfaScaScaXgaprbikbikbikbikbikaaabfmbqRbmKbmKbmKbqSbieaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaVyaNiaNjaNiaNiaNkaNlaNiaNiaNjaVzaXhaCuaXiaVEaInaXjaXjaXkaXjaXlaDEaXmaXnaJraXoaXpaXqaXqaXraXsaXqaXtaXqaXqaXqaXuaXqaXqaXvaXwaXxaXyaXzaXAaXyaXBaXyaXyaXyaXyaXCaXDaXEaXqaXqaXFaXGaXHaXIaXJaXKaXLaXMaXRaXPaXPaXPaXPaXPaXPaXPaXQaXWaXXaXSaXTaXUaXVaXYaZHaXZaUDaUDaYaaYbaYcaYbaYcaYdaYeaYfaYgaYhaYiaMeaYkbBvaYmaYlaYnaYnaYoaYpaYqaYraUTaYsaYtaYuaYuaYvaUTaYwaYxaYyaYzaYAaYAaYBaYCaYHbbFbalbbHbbGbbJaVgaVbaVhaKsaRDaYIaYJaYJaYKaYLaYJaYMaRIaYNaYOaRIaYPaYQaTFaYRaRIaYSaYTaYUaRSaQbaQbaQdaYVaQeaYWaYXaQeaQeaQeaQeaQeabLadbbikbikbikbikbqUbqTbqVbmKbmKbrUbthbmKbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaInaYYaKzaKzaKzaKzaKzaKzaYYaInaMlaCuaYZaZaaInaZbaZcaZdaZdaZeaDEaZfaXnaZgaZhaXpaZiaZjaZkaZlaZlaZmaZnaZnaZnaZoaZpaZpaZqaZraZsaZlaZlaZtaZpaZvaZwaZxaZxaZyaZzaZAaZuaZuaZuaZBaXGaXHaXIaXJaXJaXJaXJaZCaXJaXJaXJaXJaXJaXJaZDaZEaZNaZFaZGaZJaZIaZLaZKaZMaZNaZNaZNaZOaZPaZPaZPaZQaYiaYiaYiaZRaZSaYiaMebbsaZUaYnaYnaZVaYnaZWaZXaYqaZYaUTaZZbaababbacbadaUTbaebafbagbahbaibajaVbaVbbbKbbLaVbaVbbakbbMbakaVbaVhayHaRDbamaTvaTvaTvbanaTvbaoaRIaRIaRIaRIaRIaRIaRIbapaRIaRSaRSaRRaRSbaqbaraQbbasbatbaubavbawbaxbaybazbaAbikbikbikbikaaabtibtjbtibtibtibtkbtibtlbtibtjbtiaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabaabaLyaCuaInaGdaKzbaBbaCbaDbaEaKzaGdaInaInaCubaFaVEaInbaGbaHaZdaZdaZeaDEbaIaXnaJraZhaXpaXqbaJbaKbaLbaLbaMbaNbaObaLbaPbaLbaQbaLbaRbaSbaLbaLbaWbaLbaLbaUbaVbaLbaWbaXbaYbaZaXqaXqbbabbbbbcbbdbbebbfbbebbgbbhbbgbbgbbgbbgbbgbbgbbibbjbbkbbkbbkbbkbblbbkbbmbbnbbkbbkbbobbpbbqbbqbbqbbqbbqbbqbbqbbraYiaYiaMebcTbbtbbubbvbbvbbwbbxaZXaYqbbyaUTaUTaUTaUTaUTbbzaUTbbAbbBbbCbbDaWCbbEaVbbdfbdcbdgbbIbkZbjrcSNcIgaVbaVhaHYaRDbbNbbOaTvbbPbbQaTvbbRbbRaRDbbSbbTbbUaQbbbVbbWbbXaRSaRSbbYbbZaQbbcaaQbbcbbatbccbcdbcebatbatbcfbaAbikbikbikbikbqUbtmbwlbutbwmbtmbmKbutbwmbtmbwlbutbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabaabaDEaInaYYaKzaKBaJraJraKCaKzaYYaKzbcgbchbcibcjaInbckbckaXkbckaXlaDEbclaXnaJraDEbcmbcmbcnbcobcobcobcobcobcobcpbcqbcobcobcobcobcobcobcrbcsbctbctbcubctbcvbcwbcxbcvbcvbcybczbcAbcmbcBbcBbcCbcCbcCbcDbcDbcDbcDbcDbcDbcDbcDbcEbcFbcFbcGbcFbcHbcHbcHbcHbcIbcJbcHbcEbcKbcKbcKbcKbcKbcKbcKbcKbcLbcLbcLaMebcMbcNbcObcObcObcObcPbcQbcRbmwbcUaZTbcVbcWbcXbcYaUTaUTbcZbdabdbbdabdaaVbcYtbdddcnbdebdebdecZrcZqaVbbdhbdiaRDbdjaTvbbPbbPbbQbbPaTvbdkaRDbdlbdmbdnaQbaRSbdobdpbdqbdqbdrbdsbdtbdubdvbdwbdxbdybdzbavbatbatbdAbaAbikbikbikbikbqUbwnbmKbutbBQbtmbmKbutbBQbtmbmKbFmbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaInaYYaKzaKzaKzaKzaKzaKzaYYaInaMlaCuaYZaZaaInaZbaZcaZdaZdaZeaDEaZfaXnaZgaZhaXpaZiaZjaZkaZlaZlaZmaZnaZnaZnaZoaZpaZpaZqaZraZsaZlaZlaZtaZpaZvaZwaZxaZxaZyaZzaZAaZuaZuaZuaZBaXGaXHaXIaXJaXJaXJaXJaZCaXJaXJaXJaXJaXJaXJaZDaZEaZNaZFaZGaZJaZIaZLaZKaZMaZNaZNaZNaZOaZPaZPaZPaZQaYiaYiaYiaZRaZSaYiaMebbsaZUaYnaYnbcMaYnaZWaZXaYqaZYaUTaZZbaababbacbadaUTbaebafbagbahbaibajaVbaVbbbKbbLaVbaVbbakbbMbakaVbaVhayHaRDbamaTvaTvaTvbanaTvbaoaRIaRIaRIaRIaRIaRIaRIbapaRIaRSaRSaRRaRSbaqbaraQbbasbatbaubavbawbaxbaybazbaAbikbikbikbikaaabtibtjbtibtibtibtkbtibtlbtibtjbtiaQfbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabaabaLyaCuaInaGdaKzbaBbaCbaDbaEaKzaGdaInaInaCubaFaVEaInbaGbaHaZdaZdaZeaDEbaIaXnaJraZhaXpaXqbaJbaKbaLbaLbaMbaNbaObaLbaPbaLbaQbaLbaRbaSbaLbaLbaWbaLbaLbaUbaVbaLbaWbaXbaYbaZaXqaXqbbabbbbbcbbdbbebbfbbebbgbbhbbgbbgbbgbbgbbgbbgbbibbjbbkbbkbbkbbkbblbbkbbmbbnbbkbbkbbobbpbbqbbqbbqbbqbbqbbqbbqbbraYiaYiaMebcTbbtbbubbvbbvbbwbbxaZXaYqbbyaUTaUTaUTaUTaUTbbzaUTbbAbbBbbCbbDaWCbbEaVbbdfbdcbdgbbIbkZbjrcSNcIgaVbaVhaHYaRDbbNbbOaTvbbPbbQaTvbbRbbRaRDbbSbbTbbUaQbdilbbWbbXaRSaRSbbYbbZaQbbcaaQbbcbbatbccbcdbcebatbatbcfbaAbikbikbikbikbqUbtmbwlbutbwmbtmbmKbutbwmbtmbwlbutbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabaabaDEaInaYYaKzaKBaJraJraKCaKzaYYaKzbcgbchbcibcjaInbckbckaXkbckaXlaDEbclaXnaJraDEbcmbcmbcnbcobcobcobcobcobcobcpbcqbcobcobcobcobcobcobcrbcsbctbctbcubctbcvbcwbcxbcvbcvbcybczbcAbcmbcBbcBbcCbcCbcCbcDbcDbcDbcDbcDbcDbcDbcDbcEbcFbcFbcGbcFbcHbcHbcHbcHbcIbcJbcHbcEbcKbcKbcKbcKbcKbcKbcKbcKbcLbcLbcLaMebcObcNbcPbcPbcPbcPbgRbcQbcRbmwbcUaZTbcVbcWbcXbcYaUTaUTbcZbdabdbbdabdaaVbcYtbdddcnbdebdebdecZrcZqaVbbdhbdiaRDbdjaTvbbPbbPbbQbbPaTvbdkaRDbdlbdmbdnaQbaRSbdobdpbdqbdqbdrbdsbdtbdubdvbdwbdxbdybdzbavbatbatbdAbaAbikbikbikbikbqUbwnbmKbutbBQbtmbmKbutbBQbtmbmKbFmbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbdCbdDaJrbdEbdFbdGbdHbdIbdJbdHbdKbdLbdHbdHbdMbdNbdObdPbdQbdQbdQbdRbdQbdSbdTaDEbdUbdVbdWbcobdXbdYbdZbeabebbecbedbeebefbegbehbeibcobejbekbctbelbembenbcvbeobepbeqbcvberbesbetberberberbeuaXJaXObcDbikbikbikbikbikbikbikbcEbevbewbexbeybezbeAbeBbeCbeDbeEbeFbcEbikbikbikbikbikbikbikbcKbeGaYibeHaMebeIbcNbmwbmwbmwbmwbmwbeJbeKbmwbmwbmwbnMbeMbeMbeNbeObePbeQbeRbeSbeTbeUaVbbeVbeWdlHbeYbeYbeXbeZbfaaVbaVhayHaRDbfbbfcaTvbbPbbQaTvbfdbfdaRDaRDbfeaRDaQbbffbbWbbZbfgbfgbfhbbZaQbaQbaQbbfibatbfjbfjbfkbfjbatbflbaAaabbikbikaabbdBbtmbmKbutbBQbtmbmKbutbBQbtmbmKbutbdBbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbdCbfnbfobfnbfnbfnbfnbfnbfnbfobfnbfnbfpaJrbfqbfrbfsaJrbftaJrbfubfvbfwbfxbfyaDEbdVbdVbfzbcobfAbecbecbecbecbecbedbfBbecbecbecbfCbcobejbfDbctbfEbfFbfGbcvbfHbfIbfJbcvbfKbfLbfMbfNbfObesbeuaXJaXObcDbikbikbikbikbcEbcEbcEbcEbfPbfQbfRbfSbfTbfUbfVbfWbfXbfYbfZbcEbcEbcEbcEbikbikbikbikbcKbeGaYibgabgbbgcbgdbgebgfbgcbggbghbgibgjbgkbglbmwbeLbgmbeMbgnbgobeMbgpbgqbgrbgsbeMbgtbgubgvdlHbeYbeYbeXbgwbgxaVbaVhaKsaRDbdjaTvbbPbbPbbQbbPaTvaTvbgybgzaTvbgAaQbbgBbgCbgDbfgbfgbgEbgDbgFaQbbgGbgHbatbgIbgIbgJbgIbatbdAbaAbgKbaAbaAbaAbqUbtmbmKbutbGVbtmbmKbutbGVbtmbmKbutbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaCuaCuaInaInaInaInaInaInaInaInaInaCuaDEbgLbgMbgNbgNbgNbgNbgNbgNbgObgNbgNbgNaDEbdVbejbgPbcobgQbecbecbgRbgSbgTbgUbgRbecbecbecbgVbcobejbekbctbgWbgXbgYbcvbgZbhabhbbcvbhcbhdbhebhfbhgbesbhhbhiaXObcDbcDbhjbcEbcEbcEbhkbhlbhmbhnbhobhobhpbhqbhobhrbhobhsbhtbhubhvbhwbhxbcEbcEbcEbhjbcKbcKbeGaYiaYiaMebhybhzbgkbhAbmwbhBbhCbmwbhDbhEbglbmwbnMbeMbeMbhFbcSbhHbhIbhJbhKbhLbeMbhMbgubhNdlHbeYbeYbhObhPbhQaVbaVhayHaRDbhRbhSbhTbbPbbQbhUaTvaTvbhVaTvbhWbhXaQbbhYbhZbiabfgbfgbibbiabicaQbbidbgHbatbatbatbavbatbatbKnbIzbPfbNjbiibPfddJbmKbmKbmKbmKbmKbmKbmKbmKbmKbmKbutbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikblsbltbltblubltbltbltblvbltbltbmPaabaInaLAaJtbilbgNbimbinbiobipbiqbirbisbitbgNbiubivbiwbixbcobiybecbecbgRbgTbizbiAbgRbecbecbiBbiCbcobejbekbctbctbiDbctbcvbiEbiFbiGbcvbiHbhfbiIbhfbiJbesbeubiKaXOaXPaXPbiLbiMbiNbcEbiObfRbiPbhobhobiQbiRbiSakybiSbiUbiVbiWbiXbiYbiZbjabcEbjbbiMbjcbjdbjebeGaYiaYibjfbmwbjgbmwbmwbmwbjhbjibmwbhDbjjbglbmwbeLbeMbeMbjkbBDbjmbjnbjobjpbhLbjqaVbdlJdlIdlKbeYbeYbeXbhPbjsaVbbjtbjuaRDbjvaRDaRDbjwbbQbjxbjyaTvbjzbjAaWSbjBbdvbjCbjDbjEbjFbjFbjGbjHbjIbdvbjJbjKbatbjLbatbavbatbatddAbaAbaAbaAbaAbgKbqUddBbmKbutbwmbtmbmKbutbwmbtmbmKddCbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbdCbfnbfobfnbfnbfnbfnbfnbfnbfobfnbfnbfpaJrbfqbfrbfsaJrbftaJrbfubfvbfwbfxbfyaDEbdVbdVbfzbcobfAbecbecbecbecbecbedbfBbecbecbecbfCbcobejbfDbctbfEbfFbfGbcvbfHbfIbfJbcvbfKbfLbfMbfNbfObesbeuaXJaXObcDbikbikbikbikbcEbcEbcEbcEbfPbfQbfRbfSbssbfUbfVbfWbfXbfYbfZbcEbcEbcEbcEbikbikbikbikbcKbeGaYibgabgbbgcbgdbgebgfbgcbggbghbgibgjbgkbglbmwbeLbgmbeMbgnbgobeMbgpbgqbgrbgsbeMbgtbgubgvdlHbeYbeYbeXbgwbgxaVbaVhaKsaRDbdjaTvbbPbbPbbQbbPaTvaTvbgybgzaTvbgAaQbbgBbgCbgDbfgbfgbgEbgDbgFaQbbgGbgHbatbgIbgIbgJbgIbatbdAbaAbgKbaAbaAbaAbqUbtmbmKbutbGVbtmbmKbutbGVbtmbmKbutbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaCuaCuaInaInaInaInaInaInaInaInaInaCuaDEbgLbgMbgNbgNbgNbgNbgNbgNbgObgNbgNbgNaDEbdVbejbgPbcobgQbecbecdhUbgSbgTbgUdhUbecbecbecbgVbcobejbekbctbgWbgXbgYbcvbgZbhabhbbcvbhcbhdbhebhfbhgbesbhhbhiaXObcDbcDbhjbcEbcEbcEbhkbhlbhmbhnbhobhobhpbhqbhobhrbhobhsbhtbhubhvbhwbhxbcEbcEbcEbhjbcKbcKbeGaYiaYiaMebhybhzbgkbhAbmwbhBbhCbmwbhDbhEbglbmwbnMbeMbeMbhFbcSbhHbhIbhJbhKbhLbeMbhMbgubhNdlHbeYbeYbhObhPbhQaVbaVhayHaRDbhRbhSbhTbbPbbQbhUaTvaTvbhVaTvbhWbhXaQbbhYbhZbiabfgbfgbibbiabicaQbbidbgHbatbatbatbavbatbatbKnbIzbPfbNjbiibPfddJbmKbmKbmKbmKbmKbmKbmKbmKbmKbmKbutbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikblsbltbltblubltbltbltblvbltbltbmPaabaInaLAaJtbilbgNbimbinbiobipbiqbirbisbitbgNbiubivbiwbixbcobiybecbecdhUbgTbizbiAdhUbecbecbiBbiCbcobejbekbctbctbiDbctbcvbiEbiFbiGbcvbiHbhfbiIbhfbiJbesbeubiKaXOaXPaXPbiLbiMbiNbcEbiObfRbiPbhobhobiQbiRbiSakybiSbiUbiVbiWbiXbiYbiZbjabcEbjbbiMbjcbjdbjebeGaYiaYibjfbmwbjgbmwbmwbmwbjhbjibmwbhDbjjbglbmwbeLbeMbeMbjkbBDbjmbjnbjobjpbhLbjqaVbdlJdlIdlKbeYbeYbeXbhPbjsaVbbjtbjuaRDbjvaRDaRDbjwbbQbjxbjyaTvbjzbjAaWSbjBbdvbjCbjDbjEbjFbjFbjGbjHbjIbdvbjJbjKbatbjLbatbavbatbatddAbaAbaAbaAbaAbgKbqUddBbmKbutbwmbtmbmKbutbwmbtmbmKddCbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikblsbohbptbojbpwbpwbqWbpwbpwbpwbqWblubjNaInaKzaKBbfqbgNbimbjObjPbimbjQbjRbjSbjTbgNbjUaFmbjWbcsbcobjXbjYbjZbkabkbbkcbkdbkebkebkebkfbkgbcobejbivbkhbkibkjbkkbcvbcvbcvbcvbcvbklbkmbknbkobkpbesbeubiKaXJaXJaXJbkqbkrbksbktbkubkvbhobkwbkxbkybkzbkAbkBbkCbkDbkEbkFbkGbkubkHbkIbkJbkKbkMbkLbkObkObkPaYibkQaMebmwbkRbkSbglbmwbkTbkUbmwbkVbkWbglbmwbnMbeMbeMbeMbeNbeMbkXbeMbjpbhLbkYaVbdlObhNbeXbeYbeYbeXbhPblaaVbblbblcbldbleblfblgblhblibljbljbljbljbljbljblkbllblmbfgbfgbfgbfgbfgbfgblnbloblpbgHbatbatbatbavbatbatddDbgKblrblrblrbaAbwmbtmbmKbutbBQbtmbmKbutbBQbtmbmKbutbwmbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbqYbqXbqXbqXbqXbqXbqXbqXbqXbqXbqXbqZbraaGdbraaJrbfqbgNblwbimblxblxblxblybimblzbgNblAblBbjWblCblCblCblCblDblCblEbecblFblGblHblHblIblJbcoblKblLblMblNblOblPblQblRblSblRblTblTblTblTblTblUberbeublVblWblXblYblZbmabmbbmcbmdbkBbmebmfbmgbmgbmgbmgbmhbmgbmibmjbmkbmlbmebmmbmnbcEbmobmpbmqbkNbmsbmtaYiaYibjfbmwbnCbmwbmwbmwaRebmwbmwbmvbmvbmwbmwbmxbeMbeMbmybmzbeMbeMbeMbmAbmBbmCaVbbgxbhNbeXbeXbeXbeXbhPbmDaVbbmEbmFbmFbmGbmFbmHbbPbbPbbPbbPbmIbbPbbPbbPbmJblobfgbfgbfgbfgbfgbfgbfgblnbloblpbgHbatbfjbfjbfkbfjbatddEbaAbmLbmMbmNbaAbBQbtmbmKbutbBQbtmbmKbutbBQbtmbmKbutbBQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbrcbrbbrebrdbrfbrfbrgbrfbrfbrfbrgbluaInaInaKzbrVbcjbmQbimbmRblxblxblxblybmRbimbgNbmSbmTbjWblCbmUbmVbmWbmXblCbmYbmZbnabcobnbbncbndbnebcobejbnfbngbngbnhbngbngbngbngbnibnjbnjbnjbnkbnjbnlbnmbnnbnobnpbnqbnqbnqbnqbnqbnqbnrbnsbnrbmgbmgbntbnubnvbnwbnxbnybntbnzbmgbnAbnBbnAbnAbnAbnAbnAbnAbnAbmtaYiaYiaMebnEbnDcakbnGbmwbnFbmwbnJdmhdmgbmwbpjaUTbnKbnLaUTaUTczObnNddybnNaUTaUTaVbbnObnPbnQbnQbnQbnQbnPbnRaVbbnSbmFbmFbmGbnTaRDbnUbnVbnWbnXbnYbnZboabobbocaQbbodaRSboebfgbfgboeaRSbofaQbbogbgHbatbgIbgIbgJbgIbatddDbgKblrblrblrbaAbGVbtmbmKbutbGVbtmbmKbutbGVbtmbmKbutbGVbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbrcbltbltblubltbltbltblvbltbltbtnaabaInboibdFbokbgNbjObjObjObimbolbombonboobgNbopboqbjWblCborblCbosbotblCboubovbowbcobnbbncbndbiCbcobejbnfbngboxboybozboAboBbngboCboDboEboFbnmbnmbnmbnmboGboHboIbnqboJboKboLboMboNboOboPboQbmgboRbnvboSboTboUboTboSbnvboVbmgboWboXboYboZbpabpbbpcbpdbnAbpebpfbpfbpgaMeaMeaMeaMebphbjfbphbpiaMeaURaMeaMeaUTaUTaUTaUTbplbpkbpkbpkbpkbpmbpJaVbbakbpnbakbpobpobakbpnbakaVbbnSbmFbmFbppbnTaRDaRDaRDaRDaRDbjvaRDaRDaRDaRDaQbbpqaQcaQcaQcaQcaQcaQcaQbaQbbprbpsbatbatbatbavbatbatddAbaAbaAbaAbaAbgKbqUddFbmKbmKbmKbmKbmKbmKbmKbmKbmKddGbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaLyaCuaKzaKzaKzaDEaDEaDEaDEaDEaDEbtobpubgNbgNbgNbgNbgNbgNbpvbgNbgNbgNbejbejbpxblCbpybpzbosbpAblCdlEbpCbpBbcobnbbncbndbecbcobejbnfbngbpDbpEbpFboAbpFbngboCbpGbpHbpIbmubpKbpLbnmbpMbpNboIbpObpPbpQbpRbpSbpSbpRbpTbpUbmgbpVbnvbnvbpWbpXboTboSbnvbpYbmkbpZbqabqbbqcbqdbqebqbbqfbnAbqgbqhbqibqjbqkbqlbqmbqnbqnbqnbqnbqnbqnbqobqpbqqbqnbqnbqsbqnbqnbqnbqnbqnbqnbqnbqndcZbqubqvbqvbqvbqvbqvbqvbqwbqlbqxbqybqyaHkbqAbqBbqAbqCbqAbqDbqEbqFbqAbqGbqHbqIbqJbqKbqKbqKbqKbqKbqKbqKbqLbqMbqNbqNbqNbqNbqObqNbqPbKnddHbPfddIbiibPfdlbbmKbmKbmKbmKddKbmKddKbmKbmKbmKddGbdBbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbtpbtqbtqbtqbtqbwpbwpbtqbtqbxZbikaabaInaLAaJtbzPbzObzRbzQbzQbzQbzQbzSbzUbzTbcsbdVbBFbrhblCblCblCbribotblCbcobcobcobcobnbbrjbrkbrlbcobrmbrnbngbrobrpboAbpFbrqbngboCbrrbpHbpIbpIbrsbrtbnmbrubpNboIbpObrvbrwbrxbrybrzbrAbpTbrBbmgbrCbpWbnvbrDbrEbrDbnvbpWbrFbnzbrGbqbbqbbqcbrHbqebqbbrIbnAbrJbqibqibqjbqkbqlbqnbqnbqnbqnbqnbqnbqnbrKbqnbqnbqnbqnbqnbqnbrLbrMbrMbrMbrMbrMbrMbrMbrMbrMbrMbrMbrMbrMbrMbrNbrObrPbqKbqKbrQbmFbmFbmFbmFbmFbmGbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbrRbmFbrSbrTbatbatbatbatbatbatbatddLbaAbgKbaAbaAbaAbqUddMddOddNbdBddPbdBddPbdBddQddMddObqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbBGbDCbBHdjhbDDdjidjidjkdjjbtqbxZbjNaInaInaKBbrWbrXbrYbrXbrXbrXbrXbrZbsabsbbcsbcsbscbsdblCbmUbsebsfbpAblCbsgbshbsgbcobcobcobcobsibcobsjbskbngbslbsmbpFbsnbsobngboCbnmbspbpIbpIbpIbsqbnmbsrbpNboIbpOdmbbrwbrxbstbsubrAbpTbsvbmgbswbsxbnvbsybszbsAboSbsBbsCbsDbsEbsFbsGbsHbsIbsJbqbbsKbnAbsLbsMbqibqjbqkbqlbqnbsNbqnbqnbqnbqnbsObsPbsPbsPbsPbsQbqnbqnbqnbqnbsRbqnbsNbsSbqnbsTbsUbsVbqnbsWbsXbsXbsYbsZbtabtbbmFbmFbmFbmFbmFbmFbmFbtcbtdbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbtebtfbtfbtgddSddRddUddTddTddTddTddVddWbaAaabbikbikaabbqUddXddZddYdeabqUbikbqUdecdebdecdecbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbBGbDCbBHdjhbDDdjidjidjkdjjbtqbxZbjNaInaInaKBbrWbrXbrYbrXbrXbrXbrXbrZbsabsbbcsbcsbscbsdblCbmUbsebsfbpAblCbsgbshbsgbcobcobcobcobsibcobsjbskbngbslbsmbpFbsnbsobngboCbnmbspbpIbpIbpIbsqbnmbsrbpNboIbpObWDbrwbrxbstbsubrAbpTbsvbmgbswbsxbnvbsybszbsAboSbsBbsCbsDbsEbsFbsGbsHbsIbsJbqbbsKbnAbsLbsMbqibqjbqkbqlbqnbsNbqnbqnbqnbqnbsObsPbsPbsPbsPbsQbqnbqnbqnbqnbsRbqnbsNbsSbqnbsTbsUbsVbqnbsWbsXbsXbsYbsZbtabtbbmFbmFbmFbmFbmFbmFbmFbtcbtdbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbmFbtebtfbtfbtgddSddRddUddTddTddTddTddVddWbaAaabbikbikaabbqUddXddZddYdeabqUbikbqUdecdebdecdecbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbBGbDCdjldjidjidjidjidjidjidjideHdjnaGddjnaJrbtrbrXbtsbttbtubtvbtwbrZbtxbtybtzbtzbtAbtBblCblCblCbosbtCborbcsbcsbcsbcsbtDbejbejbskbejbsjbskbngbtEbtFbtGbtHboAbngbtIbnmbtJbpIbpIbpIbtKbtLbtMbpNbtNbnqbtObtPbpRbpRbpRbpRbpTbtQbmgbtRbtSbmgbmgbmgbmgbmgbmgbmgbnzbnAbqrbtUbtVbtWbtXbtYbtZbnAbvubuabuabucbucbucbucbucbucbucbudbudbuebufbugbugbufbuebudbudbuhbuhbuhbuhbuhbuhbuibuibujbuibuibuibuibuibukafkbumbunbmFbmFbuobuobupbupbupbupbupbuqbtfbtfbtebtfbmFbtfbtfbtfbtfburbusbusbusbusdedbuubuubuubuubuubuubuubuubuubikbikbikbikbdBddYddYddYdeebqUbikbqUdefdebdebdegbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbBGbDCdjodjpdjpdjidjpdjpdjpbtqdjqaInaInaInaKBbuvbrXbuwbuxbuxbuxbuybrZbejbuzbuAbuBbuCbuDblCbmUbuEbosbuFborbuGbuHbuIbuJbuKbuLbuLbuMbuLbuNbuObngbuPbuQbuRbuSbuTbuUbuVbnmbuWbpIbpIbuXbuYbuZbtMbpNbvabnqbvbbvcbvdbvebvfbvgbvhbnqbnqbvibvjbvkbvlbvmbvlbvnbvjbikbvobnAbvpbvqbvrdmcbtXbqbbvtbnAbxebvwbxfbucbzcbvybvzbvAbvBbvCbvDbvEbvFbvGbvHbvHbvGbvIbvJbvKbuhbvLbvMbvNbvObuhbvPbvQbvRbvSbvTbvUbvUbvVbukafNbvXbvYbvZbvYbwabwabupbwbbwcbwdbupbwebwfbwebupbwgbtfburbusbwhbwibwhbusbwjbwkbusdeicngbxXbwobikbikbikbikbikbikbikbikbikbikbqUddXddZddYdejbqUbikbqUdekdekdekdekbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjrbtqbtqbtqbtqbtqbtqbtqbtqdjqbikbikaInbwqbdFbwrbrXbwsbrXbwtbuxbwubwvbrZbwwbwxbwybwzbuDblCblCblCblCblCblCbwAbwBbwCbwDbwEbngbngbngbngbngbngbngbwFbngbngbngbwGbngbwHbwIbwJbpIbpIbpIbwKbtLbwLbpNbwMbnqbIDbvcbnrbnrbnrbnqbwObnqbwPbwQbwRbwSbwTbwUbwVbwWbwXbwYbwZbnAbxabqbbxbbxcbtXbxdbqbbnAbzbbxgbANbucbxhbxibxjbxkbxlbxmbxnbvHbvHbvHbvHbvHbvHbvHbvHbxobxpbxqbxrbxsbxtbuhbxubxvbxwbxxbxybxzbxvbxAbukbDdbvXbxCbxDbxEbxFbxFbxGbxHbxIbxJbxKbxLbxMbxNbupbxObxPbxQbusbxRbxSbxTbxUbxUbxVbusbxWbxXbxYbwobikbikbikbikbikbikbikbikbikbikbDybtldemdemdemdenbikdeodepdepdepbtlbDzbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbBGbDCdjodjpdjpdjidjpdjpdjpbtqdjqaInaInaInaKBbuvbrXbuwbuxbuxbuxbuybrZbejbuzbuAbuBbuCbuDblCbmUbuEbosbuFborbuGbuHbuIbuJbuKbuLbuLbuMbuLbuNbuObngbuPbuQbuRbuSbuTbuUbuVbnmbuWbpIbpIbuXbuYbuZbtMbpNbvabnqbvbbvcbvdbvebvfbvgbvhbnqbnqbvibvjbvkbvlbvmbvlbvnbvjbikbvobnAbvpbvqbvrccIbtXbqbbvtbnAbxebvwbxfbucbzcbvybvzbvAbvBbvCbvDbvEbvFbvGbvHbvHbvGbvIbvJbvKbuhbvLbvMbvNbvObuhbvPbvQbvRbvSbvTbvUbvUbvVbukafNbvXbvYbvZbvYbwabwabupbwbbwcbwdbupbwebwfbwebupbwgbtfburbusbwhbwibwhbusbwjbwkbusdeicngbxXbwobikbikbikbikbikbikbikbikbikbikbqUddXddZddYdejbqUbikbqUdekdekdekdekbqUbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjrbtqbtqbtqbtqbtqbtqbtqbtqdjqbikbikaInbwqbdFbwrbrXbwsbrXbwtbuxbwubwvbrZbwwbwxbwybwzbuDblCblCblCblCblCblCbwAbwBbwCbwDbwEbngbngbngbngbngbngbngbwFbngbngbngbwGbngbwHbwIbwJbpIbpIbpIbwKbtLbwLbpNbwMbnqbIDbvcbnrbnrbnrbnqbwObnqbwPbwQbwRbwSbwTbwUbwVbwWbwXbwYbwZbnAbxabqbbxbbxcbtXbxdbqbbnAbzbbxgbANbucbxhbxibxjbxkbxlbxmbxnbvHbvHbvHbvHbvHbvHbvHbvHbxobxpbxqbxrbxsbxtbuhbxubxvbxwbxxbxybxzbxvbxAbukbDdbvXbxCbxDbxEbxFbxFbxGbxHbxIbxJbxKbxLbxMbxNbupbxObxPbxQbusbxRbxSbxTbLSbxUbxVbusbxWbxXbxYbwobikbikbikbikbikbikbikbikbikbikbDybtldemdemdemdenbikdeodepdepdepbtlbDzbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaLyaCuaKzaKzaInaInaInaInaInaInaInaKBaJrbyabrXbybbycbydbyebyebyfbygbyhbyibyibyjbykbtzbtzbtzbtzbtzbtzbylbymbymbynbyobngbypbyqbyrbysbytbyubyvbywbngbyxbyybyzbuVbtLbwJbpIbpIbyAbnmbnmbyBbyCbyDbyEbyFbyGbyHbyIbyJbyKbyLbyMbyNbyObwXbyPbyQbyPbyQbyRbwXbwYbySbyTbyUbyVbyWbyXbyYbyZbzabyTbAObvwbvwbucbzebzdcSCbzfbzgbucbxnbvHbvHbvHbvHbvHbvHbvHbzhbzibzjbzkbzlbxqbzmbuhbznbzobzpbxxbxAbxzbzqbzrbukbIbbztbzubzvbzvbzwbzxbzybzzbzAbzAbzAbzBbzAbzCbzDbzEbzFbzGbzHbzIbzJbzKbzKbzKbzLbusbzMbxXbzNbwobikbikbikbikbikbikbikbikbikbikbikbDyderderderbDzbikbDyderderderbDzbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaIndjtdjsdjuaIoaIoaIobdFaJraJrbrXbzVbrXbzWbzXbzYbzZbrXbcsbAabAabAbbAcbAbbAbbAbbAcbAbbcsbcsbngbngbngbAdbngbAebAebAebAebAebAebyvbAfbAgbAhbAibAjbAkbAlbAmbAnbAobApbAqbArbAsbAtbAubAvbAwbAwbAxbAybAzbAAbABbACbADbAEbvjbAFbwVbAGbwTbAHbvjbikbAIbAJbAKbALbAJbAJbAJbAJbAMbnAbCBbvwbCCbAPbAQbARbASbATbAUbucbAVbAWbAXbAYbAZbBabBbbBcbvHbBdbuhbBebzlbBfbBgbuhbBhbBibxwbxxbxAbxzbxvbxAbukbDdbvXbBjbBkbBlbBmbBnbBobBpbBqbBrbBsbBtbBubKpbupbBwbBxbBybusbBzbBAbBBbxUbBCbKwbusbzMbxXbBEbwobikbikbikbikaabaabaabaabaabaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaIndjwdjvdjuaJqaJqbBIbBJaJqbBKbrXbBLbycbBMbBNbBObBPbrXbikaabaabdetdesdesdesdesdesdeubikbikbBRbBSbBTbBUbBVbAebAebAebAebAebAebBWbBXbBYbBZbCabCbbCcbCdbnmbnmbCebCfbnmbnmbCgbChbCibCjbCkbClbClbCmbClbCnbCobCpbCqbAEbvjbCrbvlbvlbvlbCsbvjbikbAIbAJbCtbCubCvbCwbCxbCybCzbCAbEsbvwbEtbucbvxbCDbCEbCFbCGbCHbCIbCJbCKbCLbCMbCNbCObCPbCQbCRbCSbCTbzlbCUbCVbuhbCWbCXbCYbCZbDabDbbDcbvVbukbIcbDebDfbDgbDgbDhbDibDjbDkbDlbDmbDnbDobDpbDqbupbDrbBxbDsbusbDtbDubDvbxUbxUbDwbusbxWbxXbDxbwobikbikbikbikaabbDAbFfbDBbFfbDBbFfbFgaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaIndjudjubDEaInaInaLyaCubDFbDGbrXbDHbycbycbycbrXbrXbrXbikbikbikdewdevdevdexdevdevdewbikbikbBRbDIbAebDJbDKbDKbDKbDKbDKbDLbDMbDKbDNbDObDPbDQbDRbDSbDTbnmbDUbpIbDVbDWbtLbDXbDYbDZbCjbCjbCpbEabEbbEcbEdbEebCpbvibAEbvjbEfbEgbEhbqtbEjbvjbikbEkbAJbElbEmbEnbEobEpbEobEqbErbFWbvwbHBbucbEubEubEvbEwbExbEybEzbEAbEBbECbEDbEDbEEbEFbEGbEHbuhbCTbEIaJSbuhbuhbuibEKbELbEMbuibukbukbukbENbIdbvXbEPbBkbBlbEQbDgbDjbERbESbESbETbxJbEUbEVbEWbEXbxPbEYbusbEZbFabxUbFbbFcbFdbusbzMbFebwobwobikbikbikbikaabbFhbFjbFibGSbFkbGTbFhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjydjydjydjydjAdjzdjydjydjydjydjBbikbikbikbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevdewbFnbBRbBRbFobFpbFqbFrbFrbFrbFpbAebyvbAfbAebAebAgbFsbFtbFubFvbFwbFxbFybpIbpIbFzbtLbDXbDYbFAbFBbFCbFDbFEbFFbFGbFHbFIbCpbFJbFKbwRbFLbFMbFNbFObFPbwXbwYbFQbAJbFRbFSbFTbEobFUbEobFVbErbJebvwbKObucbFYbFZbGabGbbGcbGdbGebGfbGgbGgbGhbGibGgbGgbGjbGkbGlbGmbGnbGobGpbGqbGrbGsbGtbGubGvbGwbKhbIebKjbKibvXbGBbGCbGDbGEbGFbxGbGGbESbESbGHbGIbEUbGJbupbGKbGKbGLbusbGMbGNbGObGPbxUbGQbusbzMbGRbwobikbikbikbikbikaabbGUbIybFibFkbFibKkbDBaabbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjCdjEdjDdjGdjFdjIdjHdjFdjJdjLdjKdjydjydjBbikbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevbGWbmrbNkbmrbGXbGYbGZbGYbGYbGYbGYbHabyvbAfbHbbngbngbHcbpIbAibFvbHdbtLbHebHfbHfbHgbHhbHibHjbHkbHlbHmbHnbHobHpbHqbHrbHsbCpbCqbAEbvjbEibHubHvbHwbHxbvjbikbEkbHybHzbHybHybHybHybHybHAbHybKPbvwbKObucbHCbHDbHDbHEbHFbEybHGbHHbHIbHJbHKbHLbHMbHIbHNbHObHPbHQbHRbHSbHTbHTbHUbHVbHWbHXbHYbLibLCbLBbNdbNcbNebIfbIfbIgbIhbIibxGbIjbxJbxJbIkbIlbEUbImbInbIobIpbIqbIrbIsbItbIubIvbIubusbusbIwbEXbGxbLDbLDbLDbLDbLDbGxbFhbFkbFibFkbFkbGTbFhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjydjHdjHdjHdjMdjFdjNdjNdjFdjOdjHdjHdjQdjPdjydjBbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevbLFbKmbIAbKmbIBbAebFqbFrbFrbFrbAebAebyvbAfbICbKobngbIEbpIbAibFvbIFbtLbIGbpIbrsbpIbIHbDXbvvbIIbHlbHmbIJbIKbILbIMbINbIObIPbIQbIRbISbISbITbIUbIVbvjbvjbikbEkbHybIWbIXbIYbIZbJabJbbJcbJdbMhbvwbKObCHbJfbJgbJhbJibJjbEybJkbJlbJmbJnbJobJpbJqbJrbJsbJtbJubJvbJwbJxbJybJzbJAbJBbJCbJDbJEbGwchEbIecnfcjubvYbJIbJJbJKbJLbJLbxGbJMbJNbJObxGbJPbEUbJQbxGbJRbJSbJTbJUbJVbJWbJXbJYbJZbKabKbbKcbKdbKebKfbKfbIxbJFbJHbKgbKlbFfbDBbNhbDBbFfbLEaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjydjHdjHdjHdjMdjFdjNdjNdjFdjOdjHdjHdjQdjPdjydjBbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevbLFbKmbIAbKmbIBbAebFqbFrbFrbFrbAebAebyvbAfbICbKobngbIEbpIbAibFvbIFbtLbIGbpIbrsbpIbIHbDXbvvbIIbHlbHmbIJbIKbILbIMbINbIObIPbIQbIRbISbISbITbIUbIVbvjbvjbikbEkbHybIWbIXbIYbIZbJabJbbJcbJdbMhbvwbKObCHbJfbJgbJhbJibJjbEybJkbJlbJmbJnbJobJpbJqbJrbJsbJtbJubJvbJwbJxbJybJzbJAbJBbJCbJDbJEbGwchEbIecnfcjubvYbJIbJJbJKbJLbJLbxGbJMbJNbJObxGbJPbEUbJQbxGbJRbJSbJTbJUbJVbJWbJXbJYbJZbKabKbbKcbKdbKebKfbKfbIxbJFbJHbGzbKlbFfbDBbNhbDBbFfbLEaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjydjSdjRdjUdjTdjVdjFdjWdjHdjXdjHdjHdjHdjHdjHdjMdjFbikbikbikbikbikbikbikbikbikbikdewdeCdevdevdevcOfdewbFnbBRbBRdezbAebFqbAebAebAebAebAebyvbAfbICbLwbngbLQbpIbKqbKrbpIbKsbpHbpIbpIbKtbtLbDXbvvbIIbHlbHmbCpbKubKvbqzbKxbKybKzbKAbKBbKCbKDbwXbKEbKFbwXbwYbwYbKGbHybKHbKIbKJbKKbKLbKLbKMbKNbMibvwbMjbucbEybKQbEubKRbKSbEybJkbKTbKUbKVbKWbKXbKYbKUbJkbKZbLabLbcchbLbbLcbLbbLdbLdbLebLfbLgbLhbLhcpLbLgbLgbLhbLhbLjbLkbLjbLjbxGbxGbxGbxGbxGbLlbLmbBobxGbLnbLobLpbLqbLqbLrbLsbLtbLubLvbLIbLxbLybLzbLAbLAbEObGAbHZbGxbGzbGzbGzbIabGxbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjZdjYdjHdjHdkadkadkadjFdjHdjHdjFdkbdkddkcdkfdkedkgdjFbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevbWobKmbIAbKmbFobLGbLHbAebAebAebLGbAebyvbAfbICbNrbngbLJbpIbAibFvbpIbnmbLKbpIbpIbLLbtLbDXbvvbLMbHlbLNbCpbLObLPbWDbLRbLSbKzbLTbLUbLVbLWbLXbLYbLZbMabikbikbikbHybMbbMcbMdbMdbMebMfbMgbHybNSbNRbKObNTbMkbMlbMmbMnbMobMpbMqbJlbMrbMsbMtbMubMvbMrbJkbKZbMwbMxbMybMzbMAbMBbLdbMCbMDbMEbLgbMFbMGbMHbMIbMJbMKbMLbKabMMbLqbLqbMNbMObLqbMPbMQbMRbMSbMTbLqbMUbiTbMWbMXbMYbMZbNabNbbNabNabNabIwbEXbGxbLDbLDbGxcnccndcnebOQbOSbUHbYdbGzbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkhdjYdjHdjHdjHdjHdjHdkidjHdjHdjFdjydjydjydjydjydjydkjbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevdeEdeDdeGdeDbNlbNmbNnbNnbNnbNnbNnbNobNpbNqbICbWSbngbNsbNtbNubNvbNwbNxbNybNybNybNzbNzbNAbvvbNBbNCbHmbCpbNDbNEbNFbKvbNGbKzbNHbNIbNJbNKbNLbFNbNMbMabikbikbikbHybNNbNObNPbNQbMebMfbMgbHybPibNUbQObPjbNVbNWbNXbNYbNZbOabObbOcbKUbKUbOdbOebKUbKUbJkbKZbOfbOgbOhbOibOjbOkbLdbOlbOmbOnbOobOpbOqbOrbOrbOsbOtbOubOvbOwbJVbJVbOxbJVbOybJVbOzbJVbOAbOBbOBbOCbODbOEbOFbOGbOHcsjbOJbOKbOLbNabOMbONbikbikbikbGxbORbJFbOPbOQbKgbOObNibGxbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkmdkldkodkndjHdjFdjHdjHdjFdjHdkqdkpdkrbikbikbikbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevdewbFnbBRbBRbngbngbBRbBRbBRbBRbBRbngbngbBRbBRbBRbngbOVbOVbOVbOWbOVbNzbOXbOYbOZbPabNzbDXbvvbPbbPcbPcbCpbCpbCpbCpbCpbPdbKzbISbIRbPebNKbPgbPhbMabMabvjbvjbvjbHybHzbHybHybHybHybHybHybHybQPbvwbQQbPkbPlbPmbPnbPlbPlbPobPpbPqbPrbPsbPtbPubPvbPwbMqbPxbPybPzbPAbPBbPCbPDbPEbPFbPGbPHbPIbPJbPKbPLbMHbPMbLhbLhbPNbPObPNbPPbPQbPPbPPbPPbPRbPSbPTbPTbPUbPVbPWbPXbOFbPYbPZbQabQbbQcbQdbNabOMbONbikbikbikbGxbNfbNgbGxbKgbGxbGxbKgbGxbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjZdjYdjHdjHdkadkadkadjFdjHdjHdjFdkbdkddkcdkfdkedkgdjFbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevbWobKmbIAbKmbFobLGbLHbAebAebAebLGbAebyvbAfbICbNrbngbLJbpIbAibFvbpIbnmbLKbpIbpIbLLbtLbDXbvvbLMbHlbLNbCpbLObLPdiNbLRcobbKzbLTbLUbLVbLWbLXbLYbLZbMabikbikbikbHybMbbMcbMdbMdbMebMfbMgbHybNSbNRbKObNTbMkbMlbMmbMnbMobMpbMqbJlbMrbMsbMtbMubMvbMrbJkbKZbMwbMxbMybMzbMAbMBbLdbMCbMDbMEbLgbMFbMGbMHbMIbMJbMKbMLbKabMMbLqbLqbMNbMObLqbMPbMQbMRbMSbMTbLqbMUbiTbMWbMXbMYbMZbNabNbbNabNabNabIwbEXbGxbLDbLDbGxcnccndcnebOQbOSbUHbYdbGzbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkhdjYdjHdjHdjHdjHdjHdkidjHdjHdjFdjydjydjydjydjydjydkjbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevdeEdeDdeGdeDbNlbNmbNnbNnbNnbNnbNnbNobNpbNqbICbWSbngbNsbNtbNubNvbNwbNxbNybNybNybNzbNzbNAbvvbNBbNCbHmbCpbNDbNEbNFbKvbNGbKzbNHbNIbNJbNKbNLbFNbNMbMabikbikbikbHybNNbNObNPbNQbMebMfbMgbHybPibNUbQObPjbNVbNWbNXbNYbNZbOabObbOcbKUbKUbOdbOebKUbKUbJkbKZbOfbOgbOhbOibOjbOkbLdbOlbOmbOnbOobOpbOqbOrbOrbOsbOtbOubOvbOwbJVbJVbOxbJVbOybJVbOzbJVbOAbOBbOBbOCbODbOEbOFbOGbOHcsjbOJbOKbOLbNabOMcxHbikbikbikbGxbORbJFbOPbOQbGzbOObNibGxbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkmdkldkodkndjHdjFdjHdjHdjFdjHdkqdkpdkrbikbikbikbikbikbikbikbikbikbikbikbikbikdewdevdevdevdevdevdewbFnbBRbBRbngbngbBRbBRbBRbBRbBRbngbngbBRbBRbBRbngbOVbOVbOVbOWbOVbNzbOXbOYbOZbPabNzbDXbvvbPbbPcbPcbCpbCpbCpbCpbCpbPdbKzbISbIRbPebNKbPgbPhbMabMabvjbvjbvjbHybHzbHybHybHybHybHybHybHybQPbvwbQQbPkbPlbPmbPnbPlbPlbPobPpbPqbPrbPsbPtbPubPvbPwbMqbPxbPybPzbPAbPBbPCbPDbPEbPFbPGbPHbPIbPJbPKbPLbMHbPMbLhbLhbPNbPObPNbPPbPQbPPbPPbPPbPRbPSbPTbPTbPUbPVbPWbPXbOFbPYbPZbQabQbbQcbQdbNabOMcxHbikbikbikbGxbNfbNgbGxbGzbGxbGxbGzbGxbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjydjydjydjydjydjydjFdjOdjHdksdjHdkudktdkvbikbikbikbikbikbikbikbikbikbikbikbikbikdeJdeIdevdeKdevdeLdeMbikbikbikbikbikbikbikbikbikbikbQgaabbikbikbikbikbOVbQhbQibQjbQkbNzbQlbQmbQnbQobNzbDXbvvbQpbQqbQrbQsbQtbQubQvbQwbQxbQybQzbQAbQBbQCbQDbQEbQFbQGbQHbQIbQJbQKbQLbQMbQRbuabQSbvwbShbSgbSibvwbSjbPlbQTbQUbQVbQWbQXbJkbQYbQZbRabRbbRcbRdbRebRfbRgbRhbRibLbbRjbOibRkbRlbRmbRnbRobRpbLgbRqbMHbMHbMHbRrbLhbPNbRsbRtbRubRvbRwbRxbRybPPbRzbRAbRBbPTbPTbRCbPWbRDbREbWHbRGbRHbRIbRJbRKbNabRLbwobikbikbikbGxbGxbGxbGxbikbikaabbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjxdjydkxdkwdkydkxdkzdjFdjHdjHdjFdjHdkBdkAdkCbikbikbikbikbikbikbikbikbikbikbikbikbikdeOdeNdePdePdePdeNdeQbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbOVbRMbRNbRObRPbNybRQbRRbRSbRTbNzbDXbRUbRVbvvbvvbFXbRWbubbQNbQMbRXbRYbRXbRZbSabSabSbbScbSdbSabSabSebSabSfbSabQMbQRbuabSlbSkbTJbTIbTLbTKbvwbPlbSmbQUbSnbSobSpbJkbSqbSrbSsbStbSubSvbSwbSxbJkbSybSzbLbbSAbSBbSBbSCbSDbSEbSFbSGbLgbSHbSIbMHbSJbSKbLhbPNbSLbSMbSNbSObSPbSQbSRbPPbSSbRAbSTbSTbPTbSUbSVbSWbSXbSYbSZbTabTbbTcbTdbNabOMbwobTebikbikbikbikbikbikbikbikaabbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjZdjYdkDdkDdkDdkDdkDdkEdjHdjHdjFdjydjydjydjydjydjydjBbikbikbikbikbikbikbikbikbikbikbikdeRdeSdeSdeSdeTbikbikbikbikbikbikbikbikbOUbOTbQebOTbQfbikbikbikbOVbOVbTjbTkbRObTlbNybTmbQnbTnbTobNzbDXbTpbTqbTrbTsbTtbTubTvbTwbTxbTybTzbTAbTBbTCbTCbTDbTEbTEbTEbTEbTEbTEbTFbTGbTHbTNbTMbTPbTOdlidjmdlkdljdllbPlbTQbQUbQVbTRbSpbJkbSqbSrbTSbTTbTUbTVbTWbTXbJsbTYbTZbLbbLbbUabUabLbbSDbLdbUbbUcbLgbUdbUebUfbUgbUhbLhbPNbUibUjbUkbUlbUmbUnbUobPPbUpbRAbSTbSTbPTbUqbUrbUsbUtbUubUvbUwbUxbUybUzbNabOMbUAbUBbUAbUCbUDbUCbUCbUCbikbikbikbikaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikaabaabaabaabaabbikbikbikbikaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkhdjYdkDdkDdkDdkFdkGdjFdjHdjHdjFdjHdjHdjHdkHdjHdkIdjFbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbTgbTfbTibThbTgbUIbUIbUIbOVbUJbUKbULbUMbUNbUObUPbUQbUQbURbNzbUSbUTbUUbUVbUVbUWbUXbUYbUVbUZbUZbVabVbbVcbUZbUZbVdbQMbQMbVebVfbVfbVfbVgbVhbVfbVfbVibVjbVkbVkbVlbVkbVmbVnbVkbVobVpbVqbPlbVrbVsbSqbVtbVubVvbVwbVxbVybVubJkbSybVzbVAbVBbVCbVDbVEbVFbVGbVHbVIbVJbVKbVLbVMbVNbVObLhbPNbPNbVPbVQbVRbVSbVRbVTbPPbVUbVVbVWbVWbPTbVXbVYbVZbNabNabNabNabNabNabNabNabOMbUAbWabWbbWcbWdbWdbWebUCbikbikbikbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikaabbWfbWfbWfbWfbWgbWgbWhbWhbWhbWhbWiaabaabbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkKdkJdkDdkLdkMdjFdjHdjHdkNdjHdjHdjHdkOdjHdkPdjFbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbQebUEbUFbUEbQebUIbWmbWlbOVbWnbWpbWqbWrbWsbNzbWtbWubWvbWwbNzbUTbUTbWxbUVbWybWzbWAbWBbWCbUZdmdbWEbWFbWGcAzbUZbWIbWJbWKbVfbWLbWMbWObWNbWPbWQbWRceLbWTbWUbWVbWWbWXbWYbWZbXabXbbXcbXdbXebXfbXgbXhbSrbXibXjbXkbXlbXmbXnbJsbXobXpbXqbXrbVDbXsbXsbXtbXubLgbXvbXwbXxbXybXzbXAbXBbLhbXCbXDbXEbXFbXEbXEbXGbXHbXIbXJbXKbXLbXMbPTbXNbXObPXbEXbxXbXPbXQbXRbXRbXQbXRbXSbUAbXTbXUbWcbWdbXWbXVbUCbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWfbXXbXYbXXbWgbWhbWhbXZbYabXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkhdjYdkDdkDdkDdkFdkGdjFdjHdjHdjFdjHdjHdjHdkHdjHdkIdjFbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbTgbTfbTibThbTgbUIbUIbUIbOVbUJbUKbULbUMbUNbUObUPbUQbUQbURbNzbUSbUTbUUbUVbUVbUWbUXbUYbUVbUZbUZbVabVbbONbUZbUZbVdbQMbQMbVebVfbVfbVfbVgbVhbVfbVfbVibVjbVkbVkbVlbVkbVmbVnbVkbVobVpbVqbPlbVrbVsbSqbVtbVubVvbVwbVxbVybVubJkbSybVzbVAbVBbVCbVDbVEbVFbVGbVHbVIbVJbVKbVLbVMbVNbVObLhbPNbPNbVPbVQbVRbVSbVRbVTbPPbVUbVVbVWbVWbPTbVXbVYbVZbNabNabNabNabNabNabNabNabOMbUAbWabWbbWcbWdbWdbWebUCbikbikbikbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikaabbWfbWfbWfbWfbWgbWgbWhbWhbWhbWhbWiaabaabbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkKdkJdkDdkLdkMdjFdjHdjHdkNdjHdjHdjHdkOdjHdkPdjFbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbQebUEbUFbUEbQebUIbWmbWlbOVbWnbWpbWqbWrbWsbNzbWtbWubWvbWwbNzbUTbUTbWxbUVbWybWzbWAbWBbWCbUZdmbbWEbWFbWGcAzbUZbWIbWJbWKbVfbWLbWMbWObWNbWPbWQbWRceLbWTbWUbWVbWWbWXbWYbWZbXabXbbXcbXdbXebXfbXgbXhbSrbXibXjbXkbXlbXmbXnbJsbXobXpbXqbXrbVDbXsbXsbXtbXubLgbXvbXwbXxbXybXzbXAbXBbLhbXCbXDbXEbXFbXEbXEbXGbXHbXIbXJbXKbXLbXMbPTbXNbXObPXbEXbxXbXPbXQbXRbXRbXQbXRbXSbUAbXTbXUbWcbWdbXWbXVbUCbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWfbXXbXYbXXbWgbWhbWhbXZbYabXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkQdkDdkDdkRdjFdjHdjHdjFdkSdjHdjHdkUdkTdjydkjbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbTgbUGbUEbUEdeycOWbTkbTkdeAbZAbTkbWqbYhbYibNzbNzbNzbNzbNzbNzbYjbUTbYkbYlbYmbYnbYnbYnbYobUZbYpbYqbYqbYqbYrbYsbYtbYubYvbYwbYxbYybYzbYAbYBbYCbVfbVibYDbVkbYEbYFbYGbYHbYIbVkbSmbQVbSnbSobYJbYKbYLbYMbYNbYObYPbYQbYRbVubYSbYTbYUbYVbYWbYXbYYbYZbZabZbbLgbLgbLgbLgbLgbZcbZdbZebLhbZfbXEbXEbZgbZhbXEbZibZjbZkbZlbRAbZmbZmbPTbPVbZnbPXbEXbUAbZobUAbUAbUAbUAbUAbUAbUAbZpbZqbUCbZrbZtbZsbUCaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacaacbZubXXbXXbZvbWhbWhbXZbXZbZwbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydkWdkVdkXdjFdjHdkYdjFdkZdladjHdjydjydkjbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbQebUFbUFbUFbQebUIbYfbYebZzbZAbTkbZBbZCbZDbZEbZFbZFbZFbZGbUTbUTbUTbWxbUVbZHbYnbZIbYnbZJbUZbYpbYqbZKbYqbZLbUZbZMbZNbZObVfbZPbZQbZRbZSbZTbZUbZVbZWbZXbZYbZZcaacabcaccadbVkbTQbQVbQVcaebYJbYKcafcagcahbXjcaicajcElcalcamcancaocapcaqcarcIfcasbXscatbVAcaucavcawcaxcaycazcaAbZjbZfcaBbXEbXEbXEcaCcaDbZjbZkcaEbRAbZmbZmbPTcaFcaGbPXbEXcaHcaIcaJbUAcaKcaLcaMcaNcaOcaPcaQbUCcaRcaScaTbUCbUAbUAbUAbUAbUAbUAbUAbUAbikbikbikbikbikaabbikbikbikbikbikbikbikcaUbWhbZubWhbWhbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdkkdjydjydjydjydjydjydjydjydjydjydkjbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbTgbWjbYbbWkbTgbUIbUIbUIbOVcaYcaZcaZcaZbOVbOVbUTcbacbacbbcbcbUTcbdcbebUVbZHbYnbYnbYncbfbUZbYpbYqbYqcbgcbhcbicbjcbkcblbVfbVfbVfbVfbVfcbmbVfbVfcbncbobVkbVkcbpbVkbVnbVkbVkbPlcbqcbqbPlccicbrcbscbtcbucbvcbwcbxcbycbzcbAcbBcaocapcbCcbDcbEcbFcbGcbHbVAcbIcbJcbKcbLcbMcbNcbOcbPcbQcbPcbRcbRcbRcbPcbScbPcbPcbTcbUbZmbZmbPTcbVbZnbPXcbWcbXcbYcbZccaccbccccccccdcceccfccgcckccjcdqcclcfeccmccnccoccpccqccrccscctaabaabaabaabaabaabaabaabbikbikbikbikbikbWgbWhccuccvccvbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbYcbOTbYgbOTbZxbikaabbikbOVbOVbUIbUIbUIbOVbikbUTccAccBccCccDbZFccEccFbUVccGccHccIbYnccJccKccLccMccNccOccPbUZccQccRccSccTccUccUccUccUccVccWccXccYccYccZccZcdacdbcdcbVibPlcddcdecdfcdgcdhbYKcdicbtcdjcdkcdlcdmbSwcdncdocdpcffcdrcdrcdscdrcdrcdrcdtbVAcducdvcdwcdxcdycdzcdAcbPcdBcdCcdDcdEcdFcdCcdGcdHcdCcdIcdJbRBbPTbPTcdKcdLcdMcdNcdOcdPcdQcdRcdScdTcdUcdVcdWcdXcdYcdZceacebceaceccebcebcebcedceecefcegcehaabbikbikbikbikaabbikbikbikbikbikbikbikbWhbWhceibXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbYcbOTbYgbOTbZxbikaabbikbOVbOVbUIbUIbUIbOVbikbUTccAccBccCccDbZFccEccFbUVccGccHdmcbYnccJccKccLccMccNccOccPbUZccQccRccSccTccUccUccUccUccVccWccXccYccYccZccZcdacdbcdcbVibPlcddcdecdfcdgcdhbYKcdicbtcdjcdkcdlcdmbSwcdncdocdpcffcdrcdrcdscdrcdrcdrcdtbVAcducdvcdwcdxcdycdzcdAcbPcdBcdCcdDcdEcdFcdCcdGcdHcdCcdIcdJbRBbPTbPTcdKcdLcdMcdNcdOcdPcdQcdRcdScdTcdUcdVcdWcdXcdYcdZceacebceaceccebcebcebcedceecefcegcehaabbikbikbikbikaabbikbikbikbikbikbikbikbWhbWhceibXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabaabaabaabaabaabaabaabaabaabaabaabaabaabaabaabcejbUTbUTbUTcekbUTbUTcelbUVcemcenceocepceqcercescetceucevcewccKcexceycezceAceBceBceBceBceCceDceEceFceGceFceHceIceJceKchvceMceNceOcePceQceRceSceTceUceVceWceXceYceZcfacfbcfccfgbMmbMmcfichOcgHceYchVcfjcfjcfkcfjcflcfmcfncfocbPcfpcfqcfrcfscfrcftcfucfvcdCbPTcfwbPTbPTcfxcfybZnbBxbEXbUAcfzbUAbUAcfAcfBcfCcfDcfEcebcfFcfGcfHcdUcfHcdUcfIcdUcdUbUAcfJcfKcfLcfMaabaabaabaabaabaabaabaabbikbikbikbikbikbWhbXZbXZbXZbXZbXZbXZcfNbXZcfObXZbXZbXZbXZbXZbWhbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcejcfPcfQcfRbUTcfSbUVcfTcfUcfVbZHcfWcfXcfYbYpcfZcgacgbcfXcgccgdcgecgfcgfcggcghcgicgjcgkcglcgmbGycgnbVicgobGybGycgpcgqcgrcgscgtceQcgucgvcgwcgxcgycgzbMVcgBcgCcgzcgzcgDcgEcgEcgEcgEcgEcgGcgFciOcgJcgJcgKcgLcgMcgNcgOcgPcbPcgQcgRcgScgTcgScgUcgVcfrcgWcgXcgYbBxcgZbBxcfybZnbBxbEXchachbchcbUAbUAbUAbUAbUAchdcdUchechfcfIcdUchgcdUbZpcdUchhbUAchichjchkbUAaabbikbikbikbikaabbikbikbikbikbikbikbikbWhchlchlchlchlchlchlchmbXZchnchlcfObXZbXZbXZbXZbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcejchochpchqbUTcfSchrchrchrchrchrchrbUZbUZbUZbUZbUZbUZbUZchschtchucWpchwchxchychychzchAcglbGybGychBchCchDbGybGybGycqOchFchGceOchHchIchJcgEchKchLchMbSqchLchNcfdcfdcfdcjncjlcjlcjlcjlckacgIbSqclPchPchQchRchSchTchUclQcbPchWchXcfrchYcfrchZciacibciccidciecifbBxcigcfybZncihbEXbFeciicijcikbwobxXbxXbUAcilcimcinciocipciqcirciscitciucivbUAciwciycixcizbikbikbikbikaahbikbikbikbikbikbikbikbikciAbXXbXXbXXbXXbXXbXXbXXciBciCbXZbXZbXZbXZciDbYabWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcejcfPbVccqsbUTcfSbUVcfTcfUcfVbZHcfWcfXcfYbYpcfZcgacgbcfXcgccgdcgecgfcgfcggcghcgicgjcgkcglcgmbGycgnbVicgobGybGycgpcgqcgrcgscgtceQcgucgvcgwcgxcgycgzbMVcgBcgCcgzcgzcgDcgEcgEcgEcgEcgEcgGcgFciOcgJcgJcgKcgLcgMcgNcgOcgPcbPcgQcgRcgScgTcgScgUcgVcfrcgWcgXcgYbBxcgZbBxcfybZnbBxbEXchachbchcbUAbUAbUAbUAbUAchdcdUchechfcfIcdUchgcdUbZpcdUchhbUAchichjchkbUAaabbikbikbikbikaabbikbikbikbikbikbikbikbWhchlchlchlchlchlchlchmbXZchnchlcfObXZbXZbXZbXZbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcejchocfQchpbUTcfSchrchrchrchrchrchrbUZbUZbUZbUZbUZbUZbUZchschtchucWpchwchxchychychzchAcglbGybGychBchCchDbGybGybGycqOchFchGceOchHchIchJcgEchKchLchMbSqchLchNcfdcfdcfdcjncjlcjlcjlcjlckacgIbSqclPchPchQchRchSchTchUclQcbPchWchXcfrchYcfrchZciacibciccidciecifbBxcigcfybZncihbEXbFeciicijcikbwobxXbxXbUAcilcimcinciocipciqcirciscitciucivbUAciwciycixcizbikbikbikbikaahbikbikbikbikbikbikbikbikciAbXXbXXbXXbXXbXXbXXbXXciBciCbXZbXZbXZbXZciDbYabWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcejcejcejcejbUTcfScejbikbikbikbikciEbaTciGciHciIciJciKciLciMciNcmPciPciQciRciSciSciTciUciVciWciWciWciWciXciWbGybGybPlciYciZcjacjbcjccjdchScjecjfcjgcjhcjicjjcjkcjlcfdcnicjpcjpcjpcjpckNclSckUcnjcjqcjrcjscjtcbAcwncjvcbPcjwcjxcjycjzcjAcfrcjBcbPcbPbEXcjCbEXbEXbEXcjDcjEcjFbEXbxXciicjGcjHbwobwobwobUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbUAbikbikbikbikbikaabbikbikbikbikbikbikbikbWhccvccvccvccvccvccvcjIbXZccuccvcjJbXZbXZbXZbXZbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcAjbikaabaabcjKcjKcjKcjKcjKcjKcjLcjKbUTcelcjMbikcjNcjOcjPcjQcjRcjScjTcjUcjVcjWcjXcjYcjZcosckbckcckdckeckfckgckhciVckickjckjckjckkciWbGybGycklcklcklcklckmcklckncknckocklcklckpcklckqckrckscktcksclZaPKcmacmmcmlcmocmnckzckAckBckCckDckEckFcdccbPcbPckGcbPckHcbPckIckJckKcgnckLckMckvckOckPckQckRckSckPbxXciickTbxXbxXckVckWckXchabxXbxXbxXbxXbxXbxXbxXckYckZbONbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhbXZbXZbXZbXZbXZbXZcfNbXZcjJbXZbXZbXZbXZbXZbWhbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikclaclbclbclbclccldcleclfclgclhclicjLcljcelcjMbikclkcllclmclnclocjSclpclqclrclsciLcltcgdcoaciPcluchyclvchyclwclxclyclzclAclAclAclBciWbGybGycklclCclDclEclFclGclHclHclIclJclKclLclMclNclOcotcfhcpwcmpcmrcmqctbcsZcuoctcckDclVclWclXckzclYcmtcmscmbcmbcmccmdcmecmfcmgcmhcmfcmfcmfcmicmfcmfcmjcmucnpcnlcqRcoXcrGcqScrHcrHcrIcrHcrHcrHcrHcrJcrKcrHcrHcrHcrMcmvbxXbONbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhbWhceibXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcmwcmxcmxcmxcmxcmycmzcmAcmBcmCcmCcmDcjKcmEcfScjMbikclkcmFcmGcmHcmIcmJcmKcmLcmIcmIcmMcmNcmOcpxcmQcmQcmRbHtchycmTcmUclyclAclAclAclAcmVciWbGybGycklcmWcmXcmYcmZcnacnbcnbbzsbvWbulbxBclHcnhcklcqQcfdcrLcjpcwscvxcwEcwCcxNcxIckDcnmcnncnockDbJGcumctecnqcnqcnqcnqcnqcnrcnscntcnucnvcnvcnwcnwcnvcnxcnycnzcnAcnBcnCcnDcnEcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcuncnFcnGbONbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcaUbWhbWhchlchlbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcnHcnIcnJcnKcnJcnLcnMcnNcnOcnPcnQcjKcnRcelcjMbikclkcnScnTcnUcnVcjScnWcnXcnYcnZciLcltcgdcbkcobcgfcoccodciPciPciPcoecofclAclAcogcohciWbGycoicklcojcokcolcomcomcomconcoocomcomcopclHcoqcorcrNcfdcupcjpcxVcxUcxVcxVcxNcEickDcowcoxcoyckDcozcuscoicoAcoAcoAcoAcoAcoDcoDcoDcoAcoAbikbikbikbikckPcoEcoFcoGcnCcoHcoIcoJcoKcoLcoMcoNcoOcoPcoQcoRcoScoTcoUcnCcuncoWcvtcoYcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcpacpbbWhbZubWhbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikcnHcpccpdcpecpfcmBcpgcphcpicmBcpjcpkcplcpmcjMbikcpncjOcpocjQcppcjScjScpqcprcpscptcpucpvcwqcobcgfcpycpzcpAcpBcpCciVcpDclAclAclAcpEciWbGybGycpFcpFcpGcpHcpIcpIcpIcyFcpJcpJcpJcpKcpFcpGcpMcqQcfdcrLcEjbjVcEYdbndbmcxNclRckDcoucpNcovckDbGycuscoAcoAaabaabbikbikbikbikbikbikbikbikbikbikbikcpRcpScpTcpUcpVcpWcpXcpXcpYcpXcpXcpXcpXcpXcpZcqacqbcqccqdbwocvvbXSbwobwoaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhcqhcqicqjbWhbWhbXZbXZcqkbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcAjbikaabaabcjKcjKcjKcjKcjKcjKcjLcjKbUTcelcjMbikcjNcjOcjPcjQcjRcjScjTcjUcjVcjWcjXcjYcjZcosckbckcckdckeckfckgckhciVckickjckjckjckkciWbGybGycklcklcklcklckmcklckncknckocklcklckpcklckqckrckscktcksclZaPKcmacmmcmlcmocmnckzckAckBckCckDckEckFcdccbPcbPckGcbPckHcbPckIckJckKcgnckLckMckvckOckPckQckRckSckPbxXciickTbxXbxXckVckWckXchabxXbxXbxXbxXbxXbxXbxXckYckZcxHbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhbXZbXZbXZbXZbXZbXZcfNbXZcjJbXZbXZbXZbXZbXZbWhbWhaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikclaclbclbclbclccldcleclfclgclhclicjLcljcelcjMbikclkcllclmclnclocjSclpclqclrclsciLcltcgdcoaciPcluchyclvchyclwclxclyclzclAclAclAclBciWbGybGycklclCclDclEclFclGclHclHclIclJclKclLclMclNclOcotcfhcpwcmpcmrcmqctbcsZcuoctcckDclVclWclXckzclYcmtcmscmbcmbcmccmdcmecmfcmgcmhcmfcmfcmfcmicmfcmfcmjcmucnpcnlcqRcoXcrGcqScrHcrHcrIcrHcrHcrHcrHcrJcrKcrHcrHcrHcrMcmvbxXcxHbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhbWhceibXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcmwcmxcmxcmxcmxcmycmzcmAcmBcmCcmCcmDcjKcmEcfScjMbikclkcmFcmGcmHcmIcmJcmKcmLcmIcmIcmMcmNcmOcpxcmQcmQcmRbHtchycmTcmUclyclAclAclAclAcmVciWbGybGycklcmWcmXcmYcmZcnacnbcnbbzsbvWbulbxBclHcnhcklcqQcfdcrLcjpcwscvxcwEcwCcxNcxIckDcnmcnncnockDbJGcumctecnqcnqcnqcnqcnqcnrcnscntcnucnvcnvcnwcnwcnvcnxcnycnzcnAcnBcnCcnDcnEcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcnCcuncnFcnGcxHbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcaUbWhbWhchlchlbXZbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcnHcnIcnJcnKcnJcnLcnMcnNcnOcnPcnQcjKcnRcelcjMbikclkcnScnTcnUcnVcjScnWcnXcnYcnZciLcltcgdcbkchqcgfcoccodciPciPciPcoecofclAclAcogcohciWbGycoicklcojcokcolcomcomcomconcoocomcomcopclHcoqcorcrNcfdcupcjpcxVcxUcxVcxVcxNcEickDcowcoxcoyckDcozcuscoicoAcoAcoAcoAcoAcoDcoDcoDcoAcoAbikbikbikbikckPcoEcoFcoGcnCcoHcoIcoJcoKcoLcoMcoNcoOcoPcoQcoRcoScoTcoUcnCcuncoWcvtcoYcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcoZcpacpbbWhbZubWhbXZbXZbXZbXZbXZbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikcnHcpccpdcpecpfcmBcpgcphcpicmBcpjcpkcplcpmcjMbikcpncjOcpocjQcppcjScjScpqcprcpscptcpucpvcwqchqcgfcpycpzcpAcpBcpCciVcpDclAclAclAcpEciWbGybGycpFcpFcpGcpHcpIcpIcpIcyFcpJcpJcpJcpKcpFcpGcpMcqQcfdcrLcEjbjVcEYdbndbmcxNclRckDcoucpNcovckDbGycuscoAcoAaabaabbikbikbikbikbikbikbikbikbikbikbikcpRcpScpTcpUcpVcpWcpXcpXcpYcpXcpXcpXcpXcpXcpZcqacqbcqccqdbwocvvbXSbwobwoaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWhcqhcqicqjbWhbWhbXZbXZcqkbXZbXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikcnHcqlcnJcqmcnJcqncqocqpcqqcnNcqrcjKcqscelcejbikbikbikbikciEcqtcqucqvcqvciLcqwciLcqxcgdcbkcqycqzcqAcqBcqCcqCcqCcqDcqEclAcqFclAcqGciWbGybGycpFcqHcqIcqJcqKcqLcqMcpFcqLcqMcqKcqNdehcqPcpMczecyWczgcEjdbpdbodbrdbqdbsctcckDcpOcpPcpQckDbGycuscoAcvyaabaabaabbikbikbikbikbikbikbikbikbikbikcpRcqUcqVcqWcqXcqYcqZcracrbcpXcpXcrccpXcpXcpZcqbcqbcqbcrdbwocvzbxXbwoaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWfcrhcribZvbWgbWhbWhbXZbYabXZbWhbWhaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikadbabLcrjcrjcrjcrjcrjcrjcrjcrjcrkcrkcrkcrkcrkcjKcjKcjKcjKcjKcjKcjKcekcrlcrmcrmcrmcrmcrmciEciLciLciLciLciLciLciLcrncgdcbkcrocrpcrqcrrcrscrtcrucrvcrwcrxcrycrzcrAciWbGybGycpFcrBcrCcqJcqKcqKcrDcpFcrEcqKcqKcqNcqKcrFcpMbGwbGwbGwcEjdbudbtdbvdbmdbxctcdbydbydbycoAcoAbGycuscoDcwpbikaabaabaabbikbikbikbikbikbikbikbikbikcpRczNczPcoBcrOcrPcrQcrRcrScpXcpXcpXcpXcrTcrUcrVcrWcrXcrYbwocvzbxXbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbWfbWfbWfbWfbWgbWgbWhbWhbWhbWhbWiaabaabbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikbikbikbikbikbikaSecsdcsecsfcsgcsgcshcsicspcskcslcsmcsncsocsrcsqcsqcsscsucstctzctzctAcsvcswcsxcsycsxcsxcsxcswcsxcsxcszcsAcsBcsCcgdcbkcsDcsEcsFcsGcgfcsHcmQcsIcsJcsKcsLcsMcsNcsObGybGycpFcsPcsQcsRcsScsTcsUcpFcsVcsTcsWcsXdlFcsYcwrbikbikbikcEjdbAdbzdbAdbAdbCdbBdbEdbDdbycwFbVibGycuscoDcwpbikbikaabaabaabbikbikbikbikbikbikbikbikctdckPcxGckSctdctfctgcthctictjctkctlcpXcpXctmctnctoctpctqbwocvzbxXcxHbikbikbikbikbikbikbikbikbikbikbikaahbikbikbikbikbikbikbikaabaabaabaabbikbikbikbikaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik @@ -8921,7 +8950,7 @@ bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbi bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabcFscFtcFtcFucFvcFwcFwcFwcFvcFwcFwcFwcFvcFwcFwcFxcFtcFtcFtcFtcFtcFycFzcFAcFBcFCcFDcFEcFFcFGcfRcwWcFHcDfcvKcvKcvKcFIcEBcECcFJcFKcFLcyrcFNcDucFPcFOcFQcFScFTcSpcFVcFWcFXcFScFYcFZcDwcGacDzcDzcDzcGbcBCcGccGccDFcGdcGecGfcGgcGhcGicGjcGkcGlcGmcGncDOcGocDQcGpcDTcDTcCKcHBcoDcEhclUcyMcyLcyNcFfclUcnkclTcFfclUcyQcyScyRcyTcyTclUcusbGycJOcoAbikckPcxOcxPcxOcGAcxRcqUcGBcJPcJJcqUdlWcGDcwAcwAcwAckPbikbikaabaabbikbikbikbikbikbwocyKcvzbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGbikaabbikaabaabcGFaabbikaabcGFaabbikaabcGFaabbikbikbikbikbikbikbikbikcDccDccDccGGcGHcFMcDdcGJcfRcGKcExcExcExcExcGLcExcFGcECcGMcGNcGOcGPcGQcGRcGScGTcGUcGVcGWcGXcGYcGZcHacHbcFYcELcDwcHccHdcDzcDzcHecBCcHfcHgcDFcHhcCAcHicHjcHkcHlcHmcHncHocHpcHocHqaabcCKcCKcCKcCKcCKcHBcoAcEhclUcIJcyVcyYcyXcEecEccEgcEfcHwcGucHZczVcIRcIQclUcusbGycJRcoAbikckPcxOcxOcxOcFjcHEcHFcHGcJScHIcCZcCZcCZcHJcHKcHLcHMbikbikbikaabaabbikbikbikbikbwobwocvzbwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikacGacGafxaabaabczocHOczqbikczocHOczqbikczocHOczqaabbikbikbikbikbikbikbikaabaabcDccDdcDdcDdcDdcHPcHQcHRcfRcHScfRcfRcEBcHTcfRcECcHUcHVcGOcHWcFNcHXcHYcIacIacIbcIccIdcIedmabRFcIbcIhcIicIjcIkcIlcImcIncIocIpcIqcGfcIrcIscItcIucIvcIwcIxcIycIzcIAcIBcICcIDcDPcDQcIEcIFcIFcCKcHBcoAcEhclUclUclUclUclUcJhcANcBRcJQcMccBScMecMdcMCcBVclUcuscGqcGrcGrcGrcJTcJTcJTcJTcJTcJUcKTcKbcKUcIUczbcIVczbcIWczbcIXcHMbikbikbikbikaabaabbikbikbikbikbwocvzbwoaabaabaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik -bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikczocHOczqaabczocHOczqbikczocHOczqbikbikbikaabbikbikbikbikaabaabaabbikbikaabaabcJbcJbcJbcJbcJbcJbcJbcJccJbcJbcECcJdcJecGOcHWcFNcJfcFNcJgcLhcDtcJicJjcFWcJkcFRcDtcJmcDzcDwcJncJocJpcIncJqcJrcJscJtcJucJvcJwcJtcJxcJycJzcJAcDFcJBcJCcJDcJEaabcEVcJFcJGcJHcCKcHBcoDcKWcKVcKVcKVcKXclUcFacyLcCLcFecyScCMcyTcyTcyScCNclUcuscGvbVibGycKYcKZcoAbikbikckPcJVcJWcJXcJYcJVcJWcJZcKacJVcJWcLackPaabaabaabaabaabaabaabaabaabaabbwocvzbwobwobwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjcbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik +bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikczocHOczqaabczocHOczqbikczocHOczqbikbikbikaabbikbikbikbikaabaabaabbikbikaabaabcJbcJbcJbcJbcJbcJbcJbcJccJbcJbcECcJdcJecGOcHWcFNcJfcFNcFNcJgcDtcJicJjcFWcJkcFRcDtcJmcDzcDwcJncJocJpcIncJqcJrcJscJtcJucJvcJwcJtcJxcJycJzcJAcDFcJBcJCcJDcJEaabcEVcJFcJGcJHcCKcHBcoDcKWcKVcKVcKVcKXclUcFacyLcCLcFecyScCMcyTcyTcyScCNclUcuscGvbVibGycKYcKZcoAbikbikckPcJVcJWcJXcJYcJVcJWcJZcKacJVcJWcLackPaabaabaabaabaabaabaabaabaabaabbwocvzbwobwobwobikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikdjcbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabczocHOczqbikczocHOczqbikczocHOczqaabbikbikbikbikbikbikbikaabaabbikbikaabaabaabcJbcKjcKjcKkcGIcKmcKmcKncKocKocKpcKqcKrcGOcHWcGOcKscGOcGOcGOcDtcKtcKucKvcKwcKxcKycKzcKAcKBcKCcKCcKCcKDcKEcKFcKGcKHcKIcHhcCAcKJcKKcKLcKMcKNcDFcJBcKOcKPcKQcKRcDQcKScIFcIFcCKcHBcoDcEhbVibVibVibYDclUcFgcCOcDXcNDcyScPocPMcyTcPVcPQclUcuscGvbVibGycyHbGycoAbikbikckPcLicLjcLkcwAcLlcLmcLncwAcLocLpcLqckPaabaabbikbikbikbikbikbikbikbikbwocvzbxXbxXbwoaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikafxaabczocHOczqbikczocHOczqaabczocHOczqaabaabaabbikaabbikbikaabaabbikbikbikaabbikbikcJbcKjcKjcKkcLscLscLscLtcLucLvcECcLwcLxcLycLzcLAcLBcLCcLDcLDcLEcLFcLGcGOcGOcGOcLHcLIcLJcLKcLLcLMcLNcLOcLPcECcLQcLQcLRcHhcCAcLScLTcLUcLVcLWcDFcLXcLYcLZcMacMbcCKcCKcCKcCKcCKcHBcoDcEhcLbbGybGybYDclUcNEczVczVcOtcDZcQMcRwcyTdbkcYuclUcuscGvczhbGychCcITcoAbikbikckPcMpcxOcxOcwAcMpcxOcxOcwAcMpcxOcxOckPbikaabaabbikbikbikbikbikbikbikbwocLccyJbxXbwobwobwocJNcJNaabaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik bikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikagiaabczocMqczqbikczocMqczqbikczocMqczqaabafxaabaabaabaabaabaabbikbikbikbikbikbikaabcJbcMrcMscLscLscLscMtcMucMucMucMucMucMucMucMvcMwcMxcMycMzcMzcMzcMAcMBdcpdcodcvcMzcMBcMDcMEcMFcLMcMGcLOcLPcMHcMIcMJcMKcMLcMMcMNcMOcKNcMPcMQcMRcMScMTcMUcIDcMVcDQcMWcMXcMXcCKcHBcoAcEhbVicozcLdbYDclUcOBczVcQgcPYcySdcydczcyTdcBdcAclUcuscGvbVibGybVibVicoAaabaabckPcNncBZcxOcwAcNncBZcxOcwAcNncBZcxOckPbikbikaabaabbikbikbikbikbikbikbwocvzcyJcLecyJcLfbwoaabaabaabbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbikbik diff --git a/_maps/map_files/cyberiad/z2.dmm b/_maps/map_files/cyberiad/z2.dmm index 46b1662d8d6..358042bd6f2 100644 --- a/_maps/map_files/cyberiad/z2.dmm +++ b/_maps/map_files/cyberiad/z2.dmm @@ -314,7 +314,7 @@ "gb" = (/obj/structure/table,/obj/machinery/kitchen_machine/microwave/upgraded,/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/ninja/holding) "gc" = (/obj/structure/table,/obj/item/clothing/head/that{pixel_x = 4; pixel_y = 6},/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/ninja/holding) "gd" = (/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) -"ge" = (/obj/structure/stool{pixel_y = 8},/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) +"ge" = (/obj/structure/stool,/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) "gf" = (/obj/item/device/camera,/turf/unsimulated/beach/sand,/area/ninja/holding) "gg" = (/obj/structure/toilet{dir = 8},/obj/structure/window/reinforced/tinted{dir = 1},/obj/machinery/door/window{dir = 8; name = "Tactical Toilet"; opacity = 1; req_access_txt = "150"},/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/syndicate_mothership) "gh" = (/obj/machinery/light{dir = 1; on = 1},/turf/simulated/floor/plating/airless,/area/syndicate_mothership) @@ -343,8 +343,8 @@ "gE" = (/obj/structure/table,/obj/item/weapon/lighter/zippo,/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/ninja/holding) "gF" = (/obj/structure/table,/obj/item/weapon/reagent_containers/food/drinks/cans/cola,/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/ninja/holding) "gG" = (/obj/structure/table,/obj/item/weapon/dice/d20,/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/ninja/holding) -"gH" = (/obj/structure/stool{pixel_y = 8},/obj/item/clothing/head/bandana{pixel_y = -10},/obj/item/clothing/glasses/sunglasses,/turf/unsimulated/beach/sand,/area/ninja/holding) -"gI" = (/obj/structure/stool{pixel_y = 8},/turf/unsimulated/beach/sand,/area/ninja/holding) +"gH" = (/obj/structure/stool,/obj/item/clothing/head/bandana{pixel_y = -10},/obj/item/clothing/glasses/sunglasses,/turf/unsimulated/beach/sand,/area/ninja/holding) +"gI" = (/obj/structure/stool,/turf/unsimulated/beach/sand,/area/ninja/holding) "gJ" = (/turf/simulated/floor/holofloor{dir = 8; icon_state = "green"},/area/holodeck/source_basketball) "gK" = (/obj/item/weapon/beach_ball/holoball,/turf/simulated/floor/holofloor,/area/holodeck/source_basketball) "gL" = (/turf/simulated/floor/holofloor{dir = 4; icon_state = "green"},/area/holodeck/source_basketball) @@ -364,7 +364,7 @@ "gZ" = (/obj/structure/stool,/turf/simulated/floor/holofloor{tag = "icon-carpet13-0 (EAST)"; icon_state = "carpet13-0"; dir = 4},/area/holodeck/source_meetinghall) "ha" = (/obj/structure/stool,/turf/simulated/floor/holofloor{tag = "icon-carpet9-0 (EAST)"; icon_state = "carpet9-0"; dir = 4},/area/holodeck/source_meetinghall) "hb" = (/turf/simulated/floor/beach/coastline,/area/holodeck/source_beach) -"hc" = (/obj/structure/stool{pixel_y = 8},/obj/machinery/computer/security/telescreen{name = "Entertainment monitor"; desc = "Damn, they better have /tg/thechannel on these things."; icon_state = "entertainment"; pixel_y = -30},/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) +"hc" = (/obj/structure/stool,/obj/machinery/computer/security/telescreen{name = "Entertainment monitor"; desc = "Damn, they better have /tg/thechannel on these things."; icon_state = "entertainment"; pixel_y = -30},/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) "hd" = (/obj/machinery/vending/snack,/obj/structure/window/reinforced{dir = 4},/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) "he" = (/turf/unsimulated/beach/coastline,/area/ninja/holding) "hf" = (/obj/item/clothing/head/collectable/paper,/turf/unsimulated/beach/coastline,/area/ninja/holding) @@ -381,7 +381,7 @@ "hq" = (/obj/structure/table/holotable,/obj/item/clothing/gloves/boxing/hologlove{icon_state = "boxinggreen"; item_state = "boxinggreen"},/turf/simulated/floor/holofloor{dir = 6; icon_state = "green"},/area/holodeck/source_boxingcourt) "hr" = (/obj/machinery/vending/cigarette,/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) "hs" = (/obj/structure/table,/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) -"ht" = (/obj/structure/stool{pixel_y = 8},/obj/machinery/light/spot,/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) +"ht" = (/obj/structure/stool,/obj/machinery/light/spot,/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) "hu" = (/obj/machinery/vending/cola,/obj/structure/window/reinforced{dir = 4},/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/ninja/holding) "hv" = (/turf/unsimulated/beach/water,/area/ninja/holding) "hw" = (/obj/machinery/light/spot,/turf/unsimulated/beach/water,/area/ninja/holding) @@ -627,15 +627,67 @@ "mc" = (/obj/item/trash/chips,/obj/machinery/light/spot,/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/area/wizard_station) "md" = (/obj/machinery/computer/mech_bay_power_console,/obj/structure/cable,/turf/simulated/floor/plasteel,/area/shuttle/gamma/space) "me" = (/obj/effect/decal/cleanable/blood,/turf/unsimulated/floor{dir = 8; icon_state = "chapel"},/area/wizard_station) +"mf" = (/obj/structure/stool,/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) "mg" = (/turf/space,/turf/simulated/shuttle/wall{icon_state = "diagonalWall3"},/area/shuttle/syndicate_elite/mothership) "mh" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/shuttle/syndicate_elite/mothership) "mi" = (/obj/machinery/door/airlock/external{name = "Shuttle Airlock"; req_access_txt = "150"},/obj/machinery/door/poddoor{icon_state = "pdoor1"; id_tag = "syndicate_elite"; name = "Front Hull Door"; opacity = 1},/turf/simulated/shuttle/plating,/area/shuttle/syndicate_elite/mothership) "mj" = (/turf/space,/turf/simulated/shuttle/wall{dir = 4; icon_state = "diagonalWall3"},/area/shuttle/syndicate_elite/mothership) +"mk" = (/obj/structure/stool,/obj/effect/landmark{name = "Syndicate-Spawn"},/obj/effect/decal/warning_stripes/east,/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) +"ml" = (/obj/structure/stool,/turf/unsimulated/floor{tag = "icon-dark"; icon_state = "dark"},/area/syndicate_mothership) +"mm" = (/obj/structure/stool,/obj/structure/sign/poster/legit{pixel_y = 32},/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/centcom/control) +"mn" = (/obj/structure/stool,/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/centcom/control) +"mo" = (/obj/structure/stool,/obj/machinery/light/spot{tag = "icon-tube1 (EAST)"; icon_state = "tube1"; dir = 4},/turf/unsimulated/floor{tag = "icon-redyellowfull"; icon_state = "redyellowfull"},/area/centcom/control) +"mp" = (/obj/structure/stool,/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/centcom/control) +"mq" = (/obj/structure/stool,/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/area/centcom/evac) +"mr" = (/turf/unsimulated/wall,/area/trader_station/sol) "ms" = (/turf/simulated/floor/plating/airless,/area/shuttle/syndicate_elite/mothership) "mt" = (/turf/space,/area/syndicate_mothership/elite_squad) "mu" = (/obj/effect/landmark{name = "Syndicate-Commando"; tag = "Commando"},/obj/machinery/light/spot,/turf/unsimulated/floor{icon_state = "dark"},/area/syndicate_mothership/elite_squad) "mv" = (/obj/machinery/light/spot,/turf/unsimulated/floor{icon_state = "dark"},/area/syndicate_mothership) +"mw" = (/turf/unsimulated/wall/fakeglass{tag = "icon-fakewindows (EAST)"; icon_state = "fakewindows"; dir = 4},/area/trader_station/sol) +"mx" = (/turf/unsimulated/wall/fakeglass{tag = "icon-fakewindows (WEST)"; icon_state = "fakewindows"; dir = 8},/area/trader_station/sol) +"my" = (/obj/machinery/computer/shuttle/trade/sol,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mz" = (/obj/machinery/vending/snack,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mA" = (/obj/machinery/light{dir = 4; icon_state = "tube1"},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mB" = (/turf/unsimulated/floor{dir = 8; icon_state = "browncorner"},/area/trader_station/sol) +"mC" = (/obj/machinery/door/airlock/external{id_tag = "trade_sol_base"; name = "Docking Port"},/turf/unsimulated/floor/plating,/area/trader_station/sol) +"mD" = (/obj/docking_port/stationary{dir = 8; dwidth = 2; height = 11; id = "trade_sol_base"; name = "docking bay 2 at Jupiter Station"; width = 5},/turf/space,/area/space) +"mE" = (/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mF" = (/turf/unsimulated/floor{dir = 8; icon_state = "brown"},/area/trader_station/sol) +"mG" = (/turf/unsimulated/floor{dir = 1; icon_state = "browncorner"},/area/trader_station/sol) +"mH" = (/turf/unsimulated/wall/fakeglass{icon_state = "fakewindows"; dir = 1},/area/trader_station/sol) +"mI" = (/obj/machinery/light{dir = 1; in_use = 1},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mJ" = (/obj/structure/stool/bed/chair/comfy/brown,/obj/effect/landmark{name = "traderstart_sol"},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mK" = (/turf/unsimulated/wall/fakeglass{icon_state = "fakewindows2"; dir = 1},/area/trader_station/sol) +"mL" = (/obj/structure/dispenser,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mM" = (/obj/structure/rack,/obj/effect/spawner/lootdrop/maintenance{lootcount = 4; name = "4maintenance loot spawner"},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mN" = (/obj/structure/rack,/obj/effect/spawner/lootdrop/trade_sol_rare,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mO" = (/obj/structure/rack,/obj/effect/spawner/lootdrop/trade_sol_common,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mP" = (/obj/structure/table/woodentable,/obj/item/weapon/dice/d20,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mQ" = (/obj/structure/stool/bed/chair/comfy/brown{dir = 4},/obj/effect/landmark{name = "traderstart_sol"},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mR" = (/obj/structure/table/woodentable,/obj/item/weapon/paper_bin,/obj/item/weapon/pen,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mS" = (/obj/structure/rack,/obj/item/weapon/storage/box/syndie_kit/space,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mT" = (/obj/structure/stool/bed/chair/comfy/brown{dir = 1},/obj/effect/landmark{name = "traderstart_sol"},/obj/machinery/light{dir = 4},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mU" = (/turf/unsimulated/wall/fakeglass{dir = 0; icon_state = "fakewindows"; tag = "icon-fakewindows (EAST)"},/area/trader_station/sol) +"mV" = (/obj/machinery/light,/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mW" = (/obj/machinery/door/airlock{name = "Toilet"; req_access_txt = "0"},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mX" = (/obj/machinery/light{dir = 8},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"mY" = (/obj/structure/urinal{pixel_y = 28},/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/trader_station/sol) +"mZ" = (/obj/item/weapon/mop,/obj/structure/mirror{pixel_x = 28},/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/trader_station/sol) +"na" = (/obj/structure/mopbucket,/obj/machinery/light{dir = 1},/obj/item/weapon/soap,/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/trader_station/sol) +"nb" = (/turf/unsimulated/floor{icon_state = "browncorner"},/area/trader_station/sol) +"nc" = (/turf/unsimulated/floor{icon_state = "brown"},/area/trader_station/sol) +"nd" = (/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/trader_station/sol) +"ne" = (/obj/structure/mirror{pixel_x = 28},/obj/structure/sink{dir = 4; icon_state = "sink"; pixel_x = 11; pixel_y = 0},/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/trader_station/sol) +"nf" = (/turf/unsimulated/wall/fakeglass{icon_state = "fakewindows"; dir = 8},/area/trader_station/sol) +"ng" = (/turf/unsimulated/wall/fakeglass{tag = "icon-fakewindows2 (WEST)"; icon_state = "fakewindows2"; dir = 8},/area/trader_station/sol) +"nh" = (/turf/unsimulated/wall/fakeglass{tag = "icon-fakewindows (NORTHEAST)"; icon_state = "fakewindows"; dir = 5},/area/trader_station/sol) +"ni" = (/turf/unsimulated/wall{desc = "It opens and closes."; icon = 'icons/obj/doors/Doormining.dmi'; icon_state = "door_closed"; name = "Docking Bay 2"},/area/trader_station/sol) "nj" = (/turf/unsimulated/wall,/area/syndicate_mothership) +"nk" = (/obj/structure/toilet{dir = 8},/obj/structure/window/reinforced/tinted{dir = 1},/obj/machinery/door/window{dir = 8; name = "Toilet"; opacity = 1; req_access_txt = "0"},/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/trader_station/sol) +"nl" = (/turf/unsimulated/wall/fakeglass{tag = "icon-fakewindows2 (NORTH)"; icon_state = "fakewindows2"; dir = 1},/area/trader_station/sol) +"nm" = (/obj/machinery/light{dir = 4},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/trader_station/sol) +"nn" = (/obj/docking_port/stationary/transit{dir = 8; dwidth = 2; height = 11; id = "trade_sol_transit"; name = "trade_sol in transit"; turf_type = /turf/space/transit/horizontal; width = 5},/turf/space/transit/horizontal,/area/space) "oB" = (/turf/unsimulated/wall/fakeglass{tag = "icon-fakewindows (WEST)"; icon_state = "fakewindows"; dir = 8},/area/syndicate_mothership) "oC" = (/turf/unsimulated/wall/fakeglass{tag = "icon-fakewindows (EAST)"; icon_state = "fakewindows"; dir = 4},/area/syndicate_mothership) "oH" = (/obj/structure/table,/obj/item/weapon/storage/fancy/crayons,/obj/item/weapon/storage/fancy/crayons,/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/syndicate_mothership) @@ -646,13 +698,11 @@ "oQ" = (/obj/machinery/vending/syndisnack,/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) "oR" = (/obj/machinery/vending/syndicigs,/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) "pa" = (/obj/structure/noticeboard{pixel_x = -32},/obj/item/weapon/paper/syndimemo,/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) -"pb" = (/obj/structure/stool{pixel_y = 8},/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) "pc" = (/mob/living/simple_animal/pet/fox/Syndifox,/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) "pd" = (/obj/effect/decal/warning_stripes/southeastcorner,/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) "pe" = (/obj/effect/decal/warning_stripes/south,/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) "pl" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) "pm" = (/obj/structure/table/woodentable,/obj/item/weapon/reagent_containers/food/drinks/cans/beer{pixel_x = -2; pixel_y = 5},/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) -"po" = (/obj/structure/stool{pixel_y = 8},/obj/effect/landmark{name = "Syndicate-Spawn"},/obj/effect/decal/warning_stripes/east,/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/syndicate_mothership) "pp" = (/obj/machinery/computer/telecrystals/uplinker,/turf/unsimulated/floor{icon_state = "floor4"},/area/syndicate_mothership) "pu" = (/turf/unsimulated/wall/fakeglass{tag = "icon-fakewindows (NORTHWEST)"; icon_state = "fakewindows"; dir = 9},/area/syndicate_mothership) "pv" = (/turf/unsimulated/wall/fakeglass{tag = "icon-fakewindows2 (WEST)"; icon_state = "fakewindows2"; dir = 8},/area/syndicate_mothership) @@ -688,7 +738,6 @@ "qL" = (/obj/machinery/light{icon_state = "tube1"; dir = 8},/turf/unsimulated/floor{tag = "icon-dark"; icon_state = "dark"},/area/syndicate_mothership) "qM" = (/turf/unsimulated/floor{tag = "icon-dark"; icon_state = "dark"},/area/syndicate_mothership) "qX" = (/turf/unsimulated/wall/fakeglass{dir = 8; icon_state = "fakewindows3"; tag = "icon-fakewindows (WEST)"},/area/syndicate_mothership) -"qY" = (/obj/structure/stool{pixel_y = 8},/turf/unsimulated/floor{tag = "icon-dark"; icon_state = "dark"},/area/syndicate_mothership) "re" = (/obj/structure/closet/syndicate/personal,/turf/unsimulated/floor{icon_state = "vault"; dir = 8},/area/syndicate_mothership) "rf" = (/obj/structure/table,/obj/item/weapon/gun/energy/ionrifle,/turf/unsimulated/floor{tag = "icon-dark"; icon_state = "dark"},/area/syndicate_mothership) "rE" = (/turf/unsimulated/wall,/area/start) @@ -727,10 +776,8 @@ "sx" = (/obj/machinery/door/airlock/centcom{name = "Living Quarters"; opacity = 1; req_access_txt = "102"},/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/centcom/control) "sy" = (/turf/unsimulated/floor{tag = "icon-redyellowfull"; icon_state = "redyellowfull"},/area/centcom/control) "sz" = (/obj/machinery/atm{pixel_y = 24},/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/centcom/control) -"sA" = (/obj/structure/stool{pixel_y = 8},/obj/structure/sign/poster/legit{pixel_y = 32},/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/centcom/control) "sB" = (/obj/item/weapon/reagent_containers/food/condiment/peppermill{pixel_x = 2; pixel_y = 6},/obj/structure/table,/turf/unsimulated/floor{tag = "icon-redyellowfull"; icon_state = "redyellowfull"},/area/centcom/control) "sC" = (/obj/item/weapon/reagent_containers/food/drinks/cans/cola,/obj/structure/table,/turf/unsimulated/floor{tag = "icon-redyellowfull"; icon_state = "redyellowfull"},/area/centcom/control) -"sD" = (/obj/structure/stool{pixel_y = 8},/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/centcom/control) "sE" = (/turf/unsimulated/floor{icon_state = "bar"; dir = 2},/area/centcom/control) "sF" = (/obj/structure/closet/secure_closet/bar{req_access = null; req_access_txt = "102"},/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/centcom/control) "sG" = (/obj/structure/reagent_dispensers/beerkeg,/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/centcom/control) @@ -742,7 +789,6 @@ "sM" = (/obj/item/weapon/reagent_containers/food/drinks/cans/beer,/obj/structure/table,/turf/unsimulated/floor{tag = "icon-redyellowfull"; icon_state = "redyellowfull"},/area/centcom/control) "sN" = (/obj/structure/table,/obj/machinery/juicer{pixel_y = 6},/turf/unsimulated/floor{tag = "icon-redyellowfull"; icon_state = "redyellowfull"},/area/centcom/control) "sO" = (/obj/structure/piano,/turf/unsimulated/floor{tag = "icon-redyellowfull"; icon_state = "redyellowfull"},/area/centcom/control) -"sP" = (/obj/structure/stool{pixel_y = 8},/obj/machinery/light/spot{tag = "icon-tube1 (EAST)"; icon_state = "tube1"; dir = 4},/turf/unsimulated/floor{tag = "icon-redyellowfull"; icon_state = "redyellowfull"},/area/centcom/control) "sQ" = (/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/centcom/control) "sR" = (/obj/structure/closet/secure_closet/freezer/meat{req_access_txt = "102"},/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/centcom/control) "sS" = (/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/centcom/control) @@ -751,7 +797,6 @@ "sV" = (/obj/structure/table,/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/centcom/control) "sW" = (/obj/machinery/door/airlock/centcom{name = "Freezer"; opacity = 1; req_access_txt = "102"},/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/centcom/control) "sX" = (/turf/unsimulated/wall,/area/centcom/specops) -"sY" = (/obj/structure/stool{pixel_y = 8},/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/centcom/control) "sZ" = (/obj/structure/table,/obj/machinery/processor{pixel_x = 0; pixel_y = 10},/turf/unsimulated/floor{icon_state = "cafeteria"; dir = 2},/area/centcom/control) "ta" = (/obj/machinery/mech_bay_recharge_port/upgraded,/turf/unsimulated/floor{icon_state = "bot"},/area/centcom/specops) "tb" = (/obj/machinery/camera{c_tag = "CentComm Special Ops. Assault Armor North"; dir = 2; network = list("ERT","CentComm")},/obj/mecha/combat/marauder/seraph/loaded,/turf/unsimulated/floor{icon_state = "delivery"; dir = 6},/area/centcom/specops) @@ -907,7 +952,7 @@ "wc" = (/turf/unsimulated/floor{tag = "icon-warning (NORTHWEST)"; icon_state = "warning"; dir = 9},/area/centcom/specops) "wd" = (/turf/unsimulated/floor{dir = 5; icon_state = "warning"},/area/centcom/specops) "we" = (/turf/space,/area/centcom/specops) -"wf" = (/obj/item/weapon/gun/projectile/automatic/pistol/m2411,/obj/item/ammo_box/magazine/m45,/obj/item/ammo_box/magazine/m45,/obj/item/ammo_box/magazine/m45,/obj/structure/closet{icon_closed = "cabinet_closed"; icon_opened = "cabinet_open"; icon_state = "cabinet_closed"},/obj/item/clothing/head/helmet/space/deathsquad/beret,/obj/item/clothing/shoes/combat,/obj/item/clothing/under/syndicate/combat,/obj/item/clothing/gloves/combat,/obj/item/clothing/suit/space/deathsquad/officer,/obj/item/clothing/under/rank/centcom/captain,/obj/item/weapon/storage/box/handcuffs,/obj/item/weapon/storage/box/flashbangs,/obj/item/clothing/mask/gas,/obj/item/weapon/tank/emergency_oxygen/double,/turf/unsimulated/floor{icon_state = "grimy"},/area/centcom/specops) +"wf" = (/obj/item/weapon/gun/projectile/automatic/pistol/m1911,/obj/item/ammo_box/magazine/m45,/obj/item/ammo_box/magazine/m45,/obj/item/ammo_box/magazine/m45,/obj/structure/closet{icon_closed = "cabinet_closed"; icon_opened = "cabinet_open"; icon_state = "cabinet_closed"},/obj/item/clothing/head/helmet/space/deathsquad/beret,/obj/item/clothing/shoes/combat,/obj/item/clothing/under/syndicate/combat,/obj/item/clothing/gloves/combat,/obj/item/clothing/suit/space/deathsquad/officer,/obj/item/clothing/under/rank/centcom/captain,/obj/item/weapon/storage/box/handcuffs,/obj/item/weapon/storage/box/flashbangs,/obj/item/clothing/mask/gas,/obj/item/weapon/tank/emergency_oxygen/double,/turf/unsimulated/floor{icon_state = "grimy"},/area/centcom/specops) "wg" = (/obj/machinery/telecomms/relay/preset/centcom,/turf/unsimulated/floor{icon_state = "grimy"},/area/centcom/specops) "wh" = (/obj/machinery/recharge_station/upgraded,/turf/unsimulated/floor{icon_state = "grimy"},/area/centcom/specops) "wi" = (/turf/unsimulated/wall{icon = 'icons/obj/library.dmi'; icon_state = "book-5"; name = "bookcase (Tactics)"},/area/centcom/specops) @@ -1005,7 +1050,6 @@ "zd" = (/obj/machinery/vending/boozeomat,/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/area/centcom/evac) "ze" = (/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/area/centcom/evac) "zf" = (/obj/structure/table,/obj/item/weapon/reagent_containers/food/drinks/cans/cola,/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/area/centcom/evac) -"zg" = (/obj/structure/stool{pixel_y = 8},/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/area/centcom/evac) "zh" = (/obj/machinery/computer/card,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/centcom/evac) "zi" = (/obj/structure/stool/bed/chair{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/centcom/evac) "zj" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/centcom/evac) @@ -1136,12 +1180,12 @@ "EY" = (/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/turf/unsimulated/wall{dir = 4; icon = 'icons/turf/shuttle.dmi'; icon_state = "window5"; name = "window"; opacity = 0; tag = "icon-window5 (EAST)"},/area/admin) "EZ" = (/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/turf/unsimulated/wall{dir = 2; icon = 'icons/turf/shuttle.dmi'; icon_state = "window5"; name = "window"; opacity = 0; tag = "icon-window5"},/area/admin) "Fa" = (/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "ADMINCHEMLOCKDOWN"; name = "Security Doors"; opacity = 0},/obj/machinery/door/airlock/hatch{name = "Chem Lab"; req_access_txt = "0"},/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/admin) -"Fb" = (/obj/structure/rack,/obj/item/ammo_box/magazine/m762,/obj/item/ammo_box/magazine/m762,/obj/item/ammo_box/magazine/m762,/obj/item/ammo_box/magazine/m762,/obj/item/weapon/gun/projectile/automatic/l6_saw,/obj/item/weapon/gun/projectile/automatic/l6_saw{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) +"Fb" = (/obj/structure/rack,/obj/item/ammo_box/magazine/mm556x45,/obj/item/ammo_box/magazine/mm556x45,/obj/item/ammo_box/magazine/mm556x45,/obj/item/ammo_box/magazine/mm556x45,/obj/item/weapon/gun/projectile/automatic/l6_saw,/obj/item/weapon/gun/projectile/automatic/l6_saw{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) "Fc" = (/obj/structure/rack,/obj/item/weapon/gun/projectile/automatic/proto,/obj/item/weapon/gun/projectile/automatic/proto{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) "Fd" = (/obj/structure/rack,/obj/item/ammo_box/magazine/m556,/obj/item/ammo_box/magazine/m556,/obj/item/ammo_box/magazine/m556,/obj/item/ammo_box/magazine/m556,/obj/item/ammo_box/magazine/m556,/obj/item/ammo_box/magazine/m556,/obj/item/ammo_box/a40mm,/obj/item/ammo_box/a40mm,/obj/item/ammo_box/a40mm,/obj/item/ammo_box/a40mm,/obj/item/weapon/gun/projectile/automatic/m90,/obj/item/weapon/gun/projectile/automatic/m90{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) "Fe" = (/obj/structure/mirror{dir = 4; pixel_x = 0; pixel_y = -32},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) "Ff" = (/obj/machinery/optable,/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/admin) -"Fh" = (/obj/structure/table,/obj/item/weapon/gun/energy/pulse_rifle/pistol,/obj/machinery/door_control{desc = "A remote control switch to lock down the admin lab."; icon_state = "doorctrl0"; id = "ADMINCHEMLOCKDOWN"; name = "Lockdown"; pixel_y = 24; req_access_txt = "0"},/turf/unsimulated/floor{dir = 9; icon_state = "carpetside"},/area/admin) +"Fh" = (/obj/structure/table,/obj/item/weapon/gun/energy/pulse/pistol,/obj/machinery/door_control{desc = "A remote control switch to lock down the admin lab."; icon_state = "doorctrl0"; id = "ADMINCHEMLOCKDOWN"; name = "Lockdown"; pixel_y = 24; req_access_txt = "0"},/turf/unsimulated/floor{dir = 9; icon_state = "carpetside"},/area/admin) "Fi" = (/turf/unsimulated/floor{dir = 1; icon_state = "carpetside"},/area/admin) "Fj" = (/obj/machinery/computer/secure_data,/obj/item/weapon/paper/sop,/turf/unsimulated/floor{dir = 5; icon_state = "carpetside"},/area/admin) "Fk" = (/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/turf/unsimulated/wall{dir = 8; icon = 'icons/turf/shuttle.dmi'; icon_state = "diagonalWall3"},/area/admin) @@ -1163,7 +1207,7 @@ "FA" = (/obj/structure/table,/obj/structure/window/reinforced,/obj/item/weapon/paper_bin,/obj/item/weapon/pen,/turf/unsimulated/floor{dir = 10; icon_state = "carpetside"},/area/admin) "FB" = (/obj/structure/table,/obj/machinery/door/window/southleft{name = "security checkpoint"; req_access_txt = "0"},/turf/unsimulated/floor{dir = 2; icon_state = "carpetside"},/area/admin) "FC" = (/obj/structure/table,/obj/structure/window/reinforced,/obj/machinery/recharger,/turf/unsimulated/floor{dir = 6; icon_state = "carpetside"},/area/admin) -"FD" = (/obj/machinery/recharger/wallcharger{pixel_x = 30},/obj/structure/rack,/obj/item/weapon/gun/energy/pulse_rifle/pistol/m1911,/obj/item/weapon/gun/energy/pulse_rifle/pistol/m1911{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) +"FD" = (/obj/machinery/recharger/wallcharger{pixel_x = 30},/obj/structure/rack,/obj/item/weapon/gun/energy/pulse/pistol/m1911,/obj/item/weapon/gun/energy/pulse/pistol/m1911{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) "FE" = (/obj/structure/table,/obj/item/weapon/tank/oxygen/yellow,/obj/random/bomb_supply,/obj/item/clothing/under/rebeloutfit,/obj/item/clothing/suit/poncho/ponchoshame,/obj/item/clothing/head/sombrero/shamebrero,/turf/unsimulated/floor{tag = "icon-dark"; icon_state = "dark"},/area/admin) "FF" = (/obj/machinery/door/airlock/hatch{name = "Tool Storage"; req_access_txt = "0"},/turf/unsimulated/floor{tag = "icon-dark"; icon_state = "dark"},/area/admin) "FG" = (/obj/structure/table,/obj/item/weapon/FixOVein,/obj/item/weapon/retractor,/obj/item/weapon/cautery,/turf/unsimulated/floor{icon_state = "freezerfloor"; dir = 2},/area/admin) @@ -1174,8 +1218,8 @@ "FL" = (/turf/simulated/wall/r_wall,/area/adminconstruction) "FM" = (/obj/structure/rack,/obj/item/weapon/gun/energy/meteorgun,/obj/item/weapon/gun/energy/meteorgun{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) "FN" = (/obj/structure/rack,/obj/item/weapon/twohanded/knighthammer{pixel_x = -3; pixel_y = 3},/obj/item/weapon/twohanded/mjollnir,/obj/item/weapon/twohanded/singularityhammer{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) -"FO" = (/obj/structure/rack,/obj/item/weapon/gun/energy/crossbow,/obj/item/weapon/gun/energy/crossbow{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) -"FP" = (/obj/machinery/recharger/wallcharger{pixel_x = 30},/obj/structure/rack,/obj/item/weapon/gun/energy/pulse_rifle,/obj/item/weapon/gun/energy/pulse_rifle{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) +"FO" = (/obj/structure/rack,/obj/item/weapon/gun/energy/kinetic_accelerator/crossbow,/obj/item/weapon/gun/energy/kinetic_accelerator/crossbow{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) +"FP" = (/obj/machinery/recharger/wallcharger{pixel_x = 30},/obj/structure/rack,/obj/item/weapon/gun/energy/pulse,/obj/item/weapon/gun/energy/pulse{pixel_x = 3; pixel_y = -3},/turf/unsimulated/floor{tag = "icon-floor"; icon_state = "floor"},/area/admin) "FQ" = (/obj/structure/table,/obj/random/tool,/obj/item/clothing/gloves/color/yellow,/obj/item/weapon/pinpointer/advpinpointer,/turf/unsimulated/floor{tag = "icon-dark"; icon_state = "dark"},/area/admin) "FR" = (/obj/structure/table,/obj/item/weapon/grenade/syndieminibomb{pixel_x = 4; pixel_y = 2; pixel_z = 0},/obj/item/weapon/grenade/syndieminibomb{pixel_x = -1},/turf/unsimulated/floor{tag = "icon-dark"; icon_state = "dark"},/area/admin) "FS" = (/obj/structure/table,/obj/machinery/recharger{pixel_y = 0},/obj/item/toy/cards/deck/syndicate/black,/turf/unsimulated/floor{tag = "icon-dark"; icon_state = "dark"},/area/admin) @@ -1371,39 +1415,39 @@ ckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckck ckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihiiijikiliminihioipiqihaNaNirisisisisisitaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatauauauataNaNaNaNaNaNaNaNaNaNaNbZbZbZbZbZbZbZaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNbZbZbZbZbZbZbZaNaNaNaNaN ckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihikikikikikikikixiyizihaNaNisiAiBiCiDiEitaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatauayauataNaNaNaNaNaNaNaNaNaNaNbZdEdEdEdEdEbZbZbZbZbZbZbZbZbZbZbZbZbZbZbZbZbZdFdFdFdFdFbZaNaNaNaNaN ckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihiLiLikikikiMihiNiOiPihaNaNisiQiRiRiRiQititititaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatauauauataNaNaNaNaNaNaNaNaNbZbZbZiZiZiZiZiZjajbjcjcjcjcjcjcjcjcjcjcjcjcjcjbjaiZiZiZiZiZbZbZbZaNaNaN -ckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihikikikikjdjdihihjeihihaNaNisiQjfjfjfiQitjgjhitaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatatatatataFaGaGaGaGaGaGaGaHatataIatataNaNaNaNaNaNaNaNaNbZjljmbZbZbZbZbZjnjojpjpjpjpjpjpjpjpjpjpjpjpjpjqjnbZbZbZbZbZjmjrbZaNaNaN -ckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihjAjAikjBjCjDihjEjejFihaNaNisiQjGjHjIiQititititititititititititaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataJaJaJaKauauauauauauauauaKaKaKauaJataNaNaNaNaNaNaNaNaNbZjljmbZbZbZbZbZjnjojpjpjpjpjpjpjpjpjpjpjpjpjpjqjnbZbZbZbZbZjmjrbZaNaNaN -ckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihkbikikjBkckdihkekfkgihaNaNisiQkhjHjIiQkikjkkklkmknkjkokpkqkrksaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataKauauauauauauauaMauauauauauauauaJataNaNaNaNaNaNaNaNaNbZjljmbZbZbZbZbZjnjojpjpjpjpjpkBkCkBjpjpjpjpjpjqjnbZbZbZbZbZjmjrbZaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihkJikikikikihihihihihihaNaNisiQkhjHjIiQkKkjknknkLknkjknkrkrkrksaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatbhauauauauauaubibibiauauauauauauaJataNaNaNaNaNaNaNaNaNbZjljmbZbZbZbZbZjnjojpjpjpjpjpkBkTkBjpjpjpjpjpjqjnbZbZbZbZbZjmjrbZaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihkWkXkYkZiklalblcldleihaNaNisiQjHjHjHlflglhknknkLknkjkokpkrkrksaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatbhauauauauaubjbibibibjauauauauauaKataNaNaNaNaNaNaNaNaNbZjljmbZbZbZbZbZjnjojpjpjpjpjpjpjpjpjpjpjpjpjpjqjnbZbZbZbZbZjmjrbZaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihlolplqikikiklrlsltluihaNaNisiQlvjHjHlwlglhknknknknlxknkrkrkrksaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatbhauauauauauaubjbjbjauauauauauauauataNaNaNaNaNaNaNaNaNbZbZbZlBlBlBlBlBlClDjpjpjpjpjpjplEjpjpjpjpjpjplDlClBlBlBlBlBbZbZbZaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihlGlplqikikiklHlIlHlIihaNaNisiQlJjHlKiQkKkjknknkLknkjkokpkrkrksaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatauauauauauauauauauauauauauauauauauataNaNaNaNaNaNaNaNaNaNaNbZlWlWlWlWlWbZbZbZbZbZbZbZbZbZbZbZbZbZbZbZbZbZlXlXlXlXlXbZaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihlomambkJmcladclumeddihaNaNismgmhmimhmjkikjknknkLknkjknkrkrkrksaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatauauaKaJaJaKauauauauauauauauauauauataNaNaNaNaNaNaNaNaNaNaNbZbZbZbZbZbZbZaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNbZbZbZbZbZbZbZaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihihihihihihihihihihihihaNaNisaNmgmsmjaNmtkjknknmuknkjkokpmvkrksaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatatbkatatatatatatatatatatatatatbkatataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNititititititititititititititititititaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatblblataNaNaNaNaNaNaNaNaNaNaNatblblataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckbmckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatblblataNaNaNaNaNaNaNaNaNaNaNatblblataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckaackckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNatatblblatatatatatatatatatatatatatblblatataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckaEckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababababababacababababababababababababababababababnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNbnaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababababacabababababababababababababababababababababababababnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababababadababababababababababababaeababacabafababnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckawckckckckckaxckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababababababababababababababafabafababababafabababnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababababababababababababacababadababacafabadabababnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababababababagagagagagagagababababahababacabahabababacabababnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababaiaNaNaNaNaNaNaNaiacabababababajagagakagakababafabnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababaNaNaNaNaNaNaNaNaNalabababacamnjnjoBoCnjnjanagagagnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababaNaNaNaNaNaNaNaNaNalabababaonjnjoHoIoIoJnjnjnjnjnjnjnjnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababaNaNaNaNaNaNaNaNaNalababadaonjaLoOoOoOoOoPoQoRnjfYjMfZnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababaiaNaNaNaNaNaNaNaiababababaSnjpaoOpbpbpcoOpdpepWpXpXganjnjnjnjnjnjnjnjnjnjnjnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababaNaNaNaNaNaTagagababaUamnjplpbpmjNpboOpoppnjpXggnjnjghgjgigxgxhggxgxhxhGnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababaNaNaNaNaNpupvpvpvpvpvoCnjoOpbpwpxpboOpoppnjnjnjnjnjgjgiiuiwiviFiviHiGhxnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababaiaNaNaNaNaNaNaNaNaNpypzpApzpzpzpzpCoOJboOoOoOoOpoppnjnjnjnjnjgjiIiwiviJiSiKiviHiTnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababaNaNaNaNaNaNaNaNaNaNpFaVoBpvpvpvoCnjpHpbpbpboOoOpoppoBpvpvpvpvpvpviviJiSiUiSiKiviTnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +ckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihikikikikjdjdihihjeihihaNaNisiQjfjfjfiQitjgjhitaNaNaNaNaNaNaNaNaNaNmrmrmrmrmrmrmrmrmrmrmrmrmrmxmwatatatatataFaGaGaGaGaGaGaGaHatataIatataNaNaNaNaNaNaNaNaNbZjljmbZbZbZbZbZjnjojpjpjpjpjpjpjpjpjpjpjpjpjpjqjnbZbZbZbZbZjmjrbZaNaNaN +ckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihjAjAikjBjCjDihjEjejFihaNaNisiQjGjHjIiQititititititititititititaNaNmraNaNaNaNaNaNaNaNaNaNaNmrmzmyataJaJaJaKauauauauauauauauaKaKaKauaJataNaNaNaNaNaNaNaNaNbZjljmbZbZbZbZbZjnjojpjpjpjpjpjpjpjpjpjpjpjpjpjqjnbZbZbZbZbZjmjrbZaNaNaN +ckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihkbikikjBkckdihkekfkgihaNaNisiQkhjHjIiQkikjkkklkmknkjkokpkqkrksaNaNmraNaNaNaNaNaNaNaNaNaNaNmrmBmAataKauauauauauauauaMauauauauauauauaJataNaNaNaNaNaNaNaNaNbZjljmbZbZbZbZbZjnjojpjpjpjpjpkBkCkBjpjpjpjpjpjqjnbZbZbZbZbZjmjrbZaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihkJikikikikihihihihihihaNaNisiQkhjHjIiQkKkjknknkLknkjknkrkrkrksaNaNmraNaNaNaNaNaNaNaNaNaNmDmCmFmEatbhauauauauauaubibibiauauauauauauaJataNaNaNaNaNaNaNaNaNbZjljmbZbZbZbZbZjnjojpjpjpjpjpkBkTkBjpjpjpjpjpjqjnbZbZbZbZbZjmjrbZaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihkWkXkYkZiklalblcldleihaNaNisiQjHjHjHlflglhknknkLknkjkokpkrkrksaNaNmraNaNaNaNaNaNaNaNaNaNaNmrmGmEatbhauauauauaubjbibibibjauauauauauaKataNaNaNaNaNaNaNaNaNbZjljmbZbZbZbZbZjnjojpjpjpjpjpjpjpjpjpjpjpjpjpjqjnbZbZbZbZbZjmjrbZaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihlolplqikikiklrlsltluihaNaNisiQlvjHjHlwlglhknknknknlxknkrkrkrksaNaNmraNaNaNaNaNaNaNaNaNaNaNmrmEmEatbhauauauauauaubjbjbjauauauauauauauataNaNaNaNaNaNaNaNaNbZbZbZlBlBlBlBlBlClDjpjpjpjpjpjplEjpjpjpjpjpjplDlClBlBlBlBlBbZbZbZaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihlGlplqikikiklHlIlHlIihaNaNisiQlJjHlKiQkKkjknknkLknkjkokpkrkrksaNaNmrmrmrmrmrmrmrmrmrmrmrmrmrmEmEatauauauauauauauauauauauauauauauauauataNaNaNaNaNaNaNaNaNaNaNbZlWlWlWlWlWbZbZbZbZbZbZbZbZbZbZbZbZbZbZbZbZbZlXlXlXlXlXbZaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihlomambkJmcladclumeddihaNaNismgmhmimhmjkikjknknkLknkjknkrkrkrksaNaNaNaNaNaNmHmEmEmEmImEmEmEmEmEmJatauauaKaJaJaKauauauauauauauauauauauataNaNaNaNaNaNaNaNaNaNaNbZbZbZbZbZbZbZaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNbZbZbZbZbZbZbZaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNihihihihihihihihihihihihaNaNisaNmgmsmjaNmtkjknknmuknkjkokpmvkrksaNaNaNaNaNaNmKmEmLmNmMmOmOmMmEmQmPatatbkatatatatatatatatatatatatatbkatataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNititititititititititititititititititaNaNaNaNaNaNmKmEmEmEmEmEmEmEmEmQmRatblblataNaNaNaNaNaNaNaNaNaNaNatblblataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckbmckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNmKmEmMmOmOmOmSmMmEmEmTatblblataNaNaNaNaNaNaNaNaNaNaNatblblataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckaackckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjnjaNaNaNaNaNaNmUmVmEmEmEmEmEmEmEmEatatblblatatatatatatatatatatatatatblblatataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckaEckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababababababacababababababababababababababababababnjaNaNaNaNaNmrmrmrmWmrmXmOmOmMmEmEataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNbnaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababababacabababababababababababababababababababababababababnjaNaNaNaNaNmrmYnamZmrmEmEmEmEnbncataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababababadababababababababababababaeababacabafababnjaNaNaNaNaNmrndndnemrnfngngngnhniataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckawckckckckckaxckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababababababababababababababafabafababababafabababnjaNaNaNaNaNmrndnkmrmraNaNaNaNnlmEataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababababababababababababacababadababacafabadabababnjaNaNaNaNaNmrmrmrmrmraNaNaNaNnlmEataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababababababagagagagagagagababababahababacabahabababacabababnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNnlmEataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababaiaNaNaNaNaNaNaNaiacabababababajagagakagakababafabnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNnlnmataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababaNaNaNaNaNaNaNaNaNalabababacamnjnjoBoCnjnjanagagagnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNnlmEataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababaNaNaNaNaNaNaNaNaNalabababaonjnjoHoIoIoJnjnjnjnjnjnjnjnjaNaNaNaNaNaNaNaNaNaNaNaNnlmEataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababaNaNaNaNaNaNaNaNaNalababadaonjaLoOoOoOoOoPoQoRnjfYjMfZnjaNaNaNaNaNaNaNaNaNaNaNaNnlmEataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababaiaNaNaNaNaNaNaNaiababababaSnjpaoOmfmfpcoOpdpepWpXpXganjnjnjnjnjnjnjnjnjnjnjnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababaNaNaNaNaNaTagagababaUamnjplmfpmjNmfoOmkppnjpXggnjnjghgjgigxgxhggxgxhxhGnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabababababababaNaNaNaNaNpupvpvpvpvpvoCnjoOmfpwpxmfoOmkppnjnjnjnjnjgjgiiuiwiviFiviHiGhxnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababaiaNaNaNaNaNaNaNaNaNpypzpApzpzpzpzpCoOJboOoOoOoOmkppnjnjnjnjnjgjiIiwiviJiSiKiviHiTnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababaNaNaNaNaNaNaNaNaNaNpFaVoBpvpvpvoCnjpHmfmfmfoOoOmkppoBpvpvpvpvpvpviviJiSiUiSiKiviTnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababaNaNaNaNaNaNaNaNaNaNaNaWaNaiababaXnjpRpSpTpSjOoOpUpViWiViViXiViViWiFiSiYjjjiiSiFiTnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjaYabaNaNaNaNaNaNaNaNaNaNaNaNaNaNaZabaonjqfqgqhqiqjoOoOoOoBpvpvpvpvpvpviviJiSjkiSiSiviTnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababaNaNaNaNaNaNaNaNaNaNaNaNaNaNalabaonjnjppqtqrqunjqwoOnjnjnjnjnjgjiIjsiviJiSiKivjtiTnjaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjababaNaNaNaNaNaNaNaNaNaNaNaNaNaNanabababnjnjnjnjnjnjqDqDqEqFqGqHnjgjjvjujsivjwivjtjxjynjaNaNaNatatatatatatatatatatatatatatatatatatatatataNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabaiaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaiabababbababbaXnjqLqMqMqMqMqMnjjzgjjvjJjJjKjJjJjyjznjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNalababacababaoqXqMqMqMqMqMqYnjnjnjnjnjnjnjnjnjnjnjnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNalababacababaoqXqMqMqMqMqMmlnjnjnjnjnjnjnjnjnjnjnjnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNalababadbcakamnjrerererererfnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNalababaonjnjnjnjnjnjnjnjnjnjnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckckaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNnjabaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNbdabababnjaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN @@ -1459,12 +1503,12 @@ aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsqsqsqsqsqaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsqsrssstsqsqsqsqsusvsvsvsqsqsqsqsqsqsqsqsqsqsqsqsqaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsqswsssssxsyszsAsBsCsDsEsEsysysqsFsGsHsIsqsJsKsLsqaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsqsqsqsqsqsysEsDsMsNsDsEsEsOsPsqsQsQsQsQsqsRsSsTsqaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsqswsssssxsyszmmsBsCmnsEsEsysysqsFsGsHsIsqsJsKsLsqaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsqsqsqsqsqsysEmnsMsNmnsEsEsOmosqsQsQsQsQsqsRsSsTsqaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsvsEsEsEsEsEsEsEsEsysysqsQsUsVsVsqsqsWsqsqdVaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsXsXsXsXsXsXsXsqaNaNaNsvsEsEsEsEsEsEsEsEsEsEsusQsYsYsQsQsQsQsZsqsqdVaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXtatbtctdtdtesqsqsqsqsqsEsEsDsMsCsDsEsEsEsEsEsQsQsQsQtfsQsQtgsqsqsqdVaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNthtitititititititititjtktitititjtltmtntdtdtdsqsrssstsqtosEsDsMtpsDsEsEsEsEsutqsQsQsQtrsQsQtssqsqsqsqdVaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsXsXsXsXsXsXsXsqaNaNaNsvsEsEsEsEsEsEsEsEsEsEsusQmpmpsQsQsQsQsZsqsqdVaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXtatbtctdtdtesqsqsqsqsqsEsEmnsMsCmnsEsEsEsEsEsQsQsQsQtfsQsQtgsqsqsqdVaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNthtitititititititititjtktitititjtltmtntdtdtdsqsrssstsqtosEmnsMtpmnsEsEsEsEsutqsQsQsQtrsQsQtssqsqsqsqdVaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXtatttutdtdtdsqswsssssxsEsEsEsEsEsEsEsEsEsEsqsusususususususqsqdWdXsqsqsqsqsqsqsqsqsqsqsqsqsqdVaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNthtitititititititititvtktitititvtwtmtntdtdtdsqsqsqsqsqsqsqtxsqsqsqsqsEsEtysqtztztztztztztzsudZdYebeasuecegefeieheCemeTeSeVeUeWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXtatttutdtdtAsqtBtCtDsqtEtFtFtFtFtGsqsEsEtHsqtztztztztztztzsufbfatLfcsufdflfefnfmfpfofrfqfEfsfFaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN @@ -1496,9 +1540,9 @@ aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbW aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNxdxmxXxYwNxXxYxfyGytyGwNwNwNyHxzxzxzaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNyiyvyvyKyLyMyNyMyOyMyNyMyPyKyvyvyiaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNwKxyyQyQyQyRwNxfypxdwKyqwNwNwNwKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNySyFyvyTyMyNyNyNyNyNyNyNyMyTyvywyUaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNwKwKwKwKxdxdwKwKxmwNxfxdxLwKwNwNwNwNwKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNySylyoyWyXyYyZyNzazbyNzcykylyUaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNwKzdzezfzgzezewKxmwNxfypxdwKyqwNwNwNwKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNyizhzizjzkyNzazbyNyyyiaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNwKzlzezmzgzezeznxmwNxfyGytyGwNwNwNygxzxzxzaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNyizqzrzryZyNzazbyNyMyiaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNwKztzezuzgzezewKxyyQzvwKwKwKyqwNwNyrcnytcnaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNyizxzrzrzyyNyMyMyNyNaBaCaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNwKzdzezfmqzezewKxmwNxfypxdwKyqwNwNwNwKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNyizhzizjzkyNzazbyNyyyiaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNwKzlzezmmqzezeznxmwNxfyGytyGwNwNwNygxzxzxzaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNyizqzrzryZyNzazbyNyMyiaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNwKztzezumqzezewKxyyQzvwKwKwKyqwNwNyrcnytcnaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNyizxzrzrzyyNyMyMyNyNaBaCaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNwKztzezezezezewKwKzBwKwKxLwKwNwNwNyHxzxzxzaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNykylylylyoyNzazbyNzHyiaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNcjcjcjcjcjcjcjcjcjcjcjcjcjcjcjytytytwKxLwKxZxZxZxZwKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNyizOzOzPzQyNzazbyNzRyiaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNcjcpcpcpcpcpcpcpcpcpcpcpcpcpcqytytytwKxLwKxzxzxzxzwKaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNzVzWzWzWzXyNzazbyNyMyiaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN @@ -1539,25 +1583,25 @@ aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbW aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDtaNaNaNaNaNDuaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDvDtDwDxDyDyDyDzDwDuDvaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDtDADBDCDDDEDFDGDHDADuaNaNaNaNaNaNDuaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDIDJDKDKDKDKDKDLDADwDMDwDMDwDMDwDwDuaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDNDODKDPcQDRDKDSDADTDKDUDKDVDWDXDYDADuaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDNDZDKEaEbEcDKEdDADKDKDKDKDKDKDKEeDIaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEfEgEhDKDKDKEhEiDAEjDKEkDKElDWDXDYEfaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDADwDwDKDKDKDwDwDADKDKDKDKDKDKDKEmDAEnaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDuaNDADwDwDMEoDMDwDwDwDwDwDMEpDMDwDwDwEnaNDtDwEqErErEsDwDuaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDADwDwEtDKDKDKDKDKDKDKDKDKDKDKDKEuDAEnaNDtDwEvEwExEyEwEzDwEAaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEBDKECDKDKDKDKDKDKDKDKDKDKDKDKDKDKDAaNaNaNEDEEEFEwEwEwEGEDaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDADwDwDwDwDwDMEHDMDwDwDwDwDwEIDKDKDAaNaNaNEJEKEwEwEwEwELEJaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEnaNEMDAENEOEPDKDKEQERESETEuDADKDKDAaNaNDtDAEUEwEVEWEwEXDAaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWjLbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEYDKDKDKDKDKDKDKDKDKDKEYDKDKDADwEZDwDwDwFaDwDwFaDwDAaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDAFbFcFdDKDKDKFeFeFeDKEHDKDKDAFfEwEwdfDADKDAFhFiFjDAaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEYDKDKDKDKDKFkDwDwDwDwDADKDKDAEwEwFlFmDADKDAFnFoFpDIaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDAFqFrFsDKFtDAFuFvFwFxDADKDKDAFyEwEwFzDADKDAFAFBFCDNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEYDKDKDKDKFDDAFEFvFvFvFFDKDKDAFGEwEwFHDADKDKDKDKDKEfaNaNaNaNDtDwFIFJFKDwDuaNaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDAFMFNFODKFPDAFQFvFRFSDADKDKDAFTFUEwEwFVDKDKDKDKDKDAaNaNaNDtDwFWFXFXFXFYDwDuaNaNaNaNaNaN -aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNFLFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFLaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDtDwDwDwDwDwDwDwDwDwDwDwGaDKDKGbDwDwDwDwDwDwDwDwGcDwDADuaNDtDwFWFXFXFXFXFXFYDADuaNaNaNaNaN -aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNFLFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFLaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDtDAGdGeGfGgGhGiGjGbDAGaDKDKDKDKDKDKGbDwDwDwDwDwGaDKGbDwDwGkDwFWFXFXFXGlFXFXFXFYDAaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDtDADBDCDDDEDFDGDHDADuaNaNaNaNaNaNDuaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDIDJDKDKDKDKDKDLDADwDMDwDMDwDMDwDwDuaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDNDODKDPcQDRDKDSDADTDKDUDKDVDWDXDYDADuaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDNDZDKEaEbEcDKEdDADKDKDKDKDKDKDKEeDIaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEfEgEhDKDKDKEhEiDAEjDKEkDKElDWDXDYEfaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDADwDwDKDKDKDwDwDADKDKDKDKDKDKDKEmDAEnaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDuaNDADwDwDMEoDMDwDwDwDwDwDMEpDMDwDwDwEnaNDtDwEqErErEsDwDuaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDADwDwEtDKDKDKDKDKDKDKDKDKDKDKDKEuDAEnaNDtDwEvEwExEyEwEzDwEAaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEBDKECDKDKDKDKDKDKDKDKDKDKDKDKDKDKDAaNaNaNEDEEEFEwEwEwEGEDaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWnnbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDADwDwDwDwDwDMEHDMDwDwDwDwDwEIDKDKDAaNaNaNEJEKEwEwEwEwELEJaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEnaNEMDAENEOEPDKDKEQERESETEuDADKDKDAaNaNDtDAEUEwEVEWEwEXDAaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWjLbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEYDKDKDKDKDKDKDKDKDKDKEYDKDKDADwEZDwDwDwFaDwDwFaDwDAaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDAFbFcFdDKDKDKFeFeFeDKEHDKDKDAFfEwEwdfDADKDAFhFiFjDAaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEYDKDKDKDKDKFkDwDwDwDwDADKDKDAEwEwFlFmDADKDAFnFoFpDIaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDAFqFrFsDKFtDAFuFvFwFxDADKDKDAFyEwEwFzDADKDAFAFBFCDNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEYDKDKDKDKFDDAFEFvFvFvFFDKDKDAFGEwEwFHDADKDKDKDKDKEfaNaNaNaNDtDwFIFJFKDwDuaNaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLFLaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDAFMFNFODKFPDAFQFvFRFSDADKDKDAFTFUEwEwFVDKDKDKDKDKDAaNaNaNDtDwFWFXFXFXFYDwDuaNaNaNaNaNaN +aNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNFLFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFLaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDtDwDwDwDwDwDwDwDwDwDwDwGaDKDKGbDwDwDwDwDwDwDwDwGcDwDADuaNDtDwFWFXFXFXFXFXFYDADuaNaNaNaNaN +aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWbWaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNFLFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFLaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDtDAGdGeGfGgGhGiGjGbDAGaDKDKDKDKDKDKGbDwDwDwDwDwGaDKGbDwDwGkDwFWFXFXFXGlFXFXFXFYDAaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNFLFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFLaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDIGmDKDKGnDKDKDKDKDKGoDKDKGpGpGpGpDKDKDKDKDKDKDKDKDKDKGqFXFXFXFXFXFXGrGsGtFXFXFXGuaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNFLFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFLaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNDNGvGwDKDKDKDKDKDKDKGoDKDKGpGpGpGpDKDKDKDKDKDKDKDKDKDKGqFXFXFXFXFXGxGyGrGrGxFXFXGzaNaNaNaNaN aNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNFLFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFZFLaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNaNEfGADKDKGBDKDKDKDKDKGoDKDKGpGpGpGpDKDKDKDKDKDKDKDKDKFkDwDwGkDwGCFXFXGxGxGxFXFXGDDAaNaNaNaNaN diff --git a/_maps/map_files/cyberiad/z6.dmm b/_maps/map_files/cyberiad/z6.dmm index 104c590cccc..da5594a4405 100644 --- a/_maps/map_files/cyberiad/z6.dmm +++ b/_maps/map_files/cyberiad/z6.dmm @@ -648,7 +648,7 @@ "mx" = (/obj/structure/table,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) "my" = (/obj/structure/window/reinforced{dir = 8},/turf/simulated/floor/engine,/area/syndicate_depot) "mz" = (/turf/simulated/floor/engine,/area/syndicate_depot) -"mA" = (/obj/structure/closet/crate{name = "munitions crate"},/obj/item/weapon/storage/box/donkpockets,/obj/item/ammo_box/magazine/m762,/obj/item/weapon/gun/projectile/automatic/m90,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) +"mA" = (/obj/structure/closet/crate{name = "munitions crate"},/obj/item/weapon/storage/box/donkpockets,/obj/item/ammo_box/magazine/mm556x45,/obj/item/weapon/gun/projectile/automatic/m90,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) "mB" = (/obj/machinery/door/window{base_state = "right"; dir = 8; icon_state = "right"; name = "Telepad"; req_access_txt = "0"},/turf/simulated/floor/engine,/area/syndicate_depot) "mC" = (/obj/machinery/telepad,/turf/simulated/floor/engine,/area/syndicate_depot) "mD" = (/obj/structure/closet/crate{name = "munitions crate"},/obj/item/ammo_box/magazine/m12g/dragon,/obj/item/ammo_box/magazine/m12g/dragon,/obj/item/weapon/storage/fancy/cigarettes/cigpack_syndicate,/obj/item/weapon/storage/firstaid/tactical,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) diff --git a/code/ATMOSPHERICS/components/binary_devices/circulator.dm b/code/ATMOSPHERICS/components/binary_devices/circulator.dm index 3e2f13ccab1..8ce7b1ce0ba 100644 --- a/code/ATMOSPHERICS/components/binary_devices/circulator.dm +++ b/code/ATMOSPHERICS/components/binary_devices/circulator.dm @@ -66,3 +66,13 @@ icon_state = "circ-off" return 1 + +/obj/machinery/atmospherics/binary/circulator/attackby(var/obj/item/W as obj, var/mob/user as mob, params) + if(istype(W, /obj/item/weapon/wrench)) + var/turf/T = get_turf(src) + if(!istype(T, /turf/simulated)) + return ..() + anchored = !anchored + to_chat(user, "You [(anchored) ? "fasten" : "loosen"] \the [src] to the floor") + playsound(loc, 'sound/items/Ratchet.ogg', 50, 1) + else return ..() diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index bf620aad6e3..ca293307099 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -53,3 +53,11 @@ #define AI_ON 1 #define AI_IDLE 2 #define AI_OFF 3 + +//Gun Stuff + #define SAWN_INTACT 0 + #define SAWN_OFF 1 + + #define WEAPON_LIGHT 0 + #define WEAPON_MEDIUM 1 + #define WEAPON_HEAVY 2 diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index 212a19f79e8..f57e096e0ec 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -2,8 +2,8 @@ #define STOPSPRESSUREDMAGE 1 //This flag is used on the flags variable for SUIT and HEAD items which stop pressure damage. Note that the flag 1 was previous used as ONBACK, so it is possible for some code to use (flags & 1) when checking if something can be put on your back. Replace this code with (inv_flags & SLOT_BACK) if you see it anywhere To successfully stop you taking all pressure damage you must have both a suit and head item with this flag. #define NODROP 2 // This flag makes it so that an item literally cannot be removed at all, or at least that's how it should be. Only deleted. #define NOBLUDGEON 4 // when an item has this it produces no "X has been hit by Y with Z" message with the default handler -#define AIRTIGHT 8 // mask allows internals -//#define USEDELAY 16 // 1 second extra delay on use (Can be used once every 2s) +#define AIRTIGHT 8 // mask allows internals +#define HANDSLOW 16 // If an item has this flag, it will slow you to carry it #define NOSHIELD 32 // weapon not affected by shield #define CONDUCT 64 // conducts electricity (metal etc.) #define ABSTRACT 128 // for all things that are technically items but used for various different stuff, made it 128 because it could conflict with other flags other way diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 5e31e40a7a6..d36405db5d1 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -238,4 +238,20 @@ #define REGION_RESEARCH 4 #define REGION_ENGINEERING 5 #define REGION_SUPPLY 6 -#define REGION_COMMAND 7 \ No newline at end of file +#define REGION_COMMAND 7 +#define REGION_CENTCOMM 8 + +//Matricies +#define MATRIX_DEFAULT list(1, 0, 0, 0,\ + 0, 1, 0, 0,\ + 0, 0, 1, 0,\ + 0, 0, 0, 1) + +#define MATRIX_GREYSCALE list(0.3, 0.3, 0.3, 0,\ + 0.3, 0.3, 0.3, 0,\ + 0.3, 0.3, 0.3, 0,\ + 0, 0, 0, 1) +//Gun trigger guards +#define TRIGGER_GUARD_ALLOW_ALL -1 +#define TRIGGER_GUARD_NONE 0 +#define TRIGGER_GUARD_NORMAL 1 diff --git a/code/__DEFINES/mob.dm b/code/__DEFINES/mob.dm index 8cb7556ab3e..82ca895b42d 100644 --- a/code/__DEFINES/mob.dm +++ b/code/__DEFINES/mob.dm @@ -76,7 +76,11 @@ #define APPEARANCE_FACIAL_HAIR_COLOR 128 #define APPEARANCE_EYE_COLOR 256 #define APPEARANCE_ALL_HAIR APPEARANCE_HAIR|APPEARANCE_HAIR_COLOR|APPEARANCE_FACIAL_HAIR|APPEARANCE_FACIAL_HAIR_COLOR -#define APPEARANCE_ALL 511 +#define APPEARANCE_HEAD_ACCESSORY 512 +#define APPEARANCE_MARKINGS 1024 +#define APPEARANCE_BODY_ACCESSORY 2048 +#define APPEARANCE_ALL_BODY APPEARANCE_ALL_HAIR|APPEARANCE_HEAD_ACCESSORY|APPEARANCE_MARKINGS|APPEARANCE_BODY_ACCESSORY +#define APPEARANCE_ALL 4095 // Intents #define I_HELP "help" diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm index 96ae9ea6281..12722c0a2bb 100644 --- a/code/__DEFINES/role_preferences.dm +++ b/code/__DEFINES/role_preferences.dm @@ -27,6 +27,7 @@ #define ROLE_HOG_GOD "hand of god: god" // We're prolly gonna port this one day or another #define ROLE_HOG_CULTIST "hand of god: cultist" #define ROLE_RAIDER "vox raider" +#define ROLE_TRADER "trader" #define ROLE_VAMPIRE "vampire" #define ROLE_MUTINEER "mutineer" // Role tags for EVERYONE! @@ -71,4 +72,5 @@ var/global/list/special_roles = list( ROLE_REVENANT, ROLE_GUARDIAN, ROLE_MORPH, + ROLE_TRADER, ) diff --git a/code/__HELPERS/AnimationLibrary.dm b/code/__HELPERS/AnimationLibrary.dm new file mode 100644 index 00000000000..65225d37363 --- /dev/null +++ b/code/__HELPERS/AnimationLibrary.dm @@ -0,0 +1,190 @@ +/* + * A file intended to store various animation procs for re-use. + * A fair majority of these are copy-pasted from Goon and may not function as expected without tweaking. + * The spin from being thrown will interrupt most of these animations as will grabs, account for that accordingly. + */ + +/proc/animate_fade_grayscale(var/atom/A, var/time = 5) + if(!istype(A) && !istype(A, /client)) + return + A.color = MATRIX_DEFAULT + animate(A, color = MATRIX_GREYSCALE, time = time, easing = SINE_EASING) + +/proc/animate_melt_pixel(var/atom/A) + if(!istype(A)) + return + animate(A, pixel_y = 0, time = 50 - A.pixel_y, alpha = 175, easing = BOUNCE_EASING) + animate(alpha = 0, easing = LINEAR_EASING) + +/proc/animate_explode_pixel(var/atom/A) + if(!istype(A)) + return + var/floatdegrees = rand(5, 20) + var/side = pick(-1, 1) + animate(A, pixel_x = rand(-64, 64), pixel_y = rand(-64, 64), transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = 10, alpha = 0, easing = SINE_EASING) + +/proc/animate_float(var/atom/A, var/loopnum = -1, floatspeed = 20, random_side = 1) + if(!istype(A)) + return + var/floatdegrees = rand(5, 20) + var/side = 1 + if(random_side) + side = pick(-1, 1) + + spawn(rand(1,10)) + animate(A, pixel_y = 32, transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING) + animate(pixel_y = 0, transform = matrix(floatdegrees * (side == 1 ? -1:1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING) + +/proc/animate_levitate(var/atom/A, var/loopnum = -1, floatspeed = 20, random_side = 1) + if(!istype(A)) + return + var/floatdegrees = rand(5, 20) + var/side = 1 + if(random_side) + side = pick(-1, 1) + + spawn(rand(1,10)) + animate(A, pixel_y = 8, transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING) + animate(pixel_y = 0, transform = null, time = floatspeed, loop = loopnum, easing = SINE_EASING) + +/proc/animate_ghostly_presence(var/atom/A, var/loopnum = -1, floatspeed = 20, random_side = 1) + if(!istype(A)) + return + var/floatdegrees = rand(5, 20) + var/side = 1 + if(random_side) + side = pick(-1, 1) + + spawn(rand(1,10)) + animate(A, pixel_y = 8, transform = matrix(floatdegrees * (side == 1 ? 1:-1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING) + animate(pixel_y = 0, transform = matrix(floatdegrees * (side == 1 ? -1:1), MATRIX_ROTATE), time = floatspeed, loop = loopnum, easing = SINE_EASING) + +/proc/animate_fading_leap_up(var/atom/A) + if(!istype(A)) + return + var/matrix/M = matrix() + var/do_loops = 15 + while (do_loops > 0) + do_loops-- + animate(A, transform = M, pixel_z = A.pixel_z + 12, alpha = A.alpha - 17, time = 1, loop = 1, easing = LINEAR_EASING) + M.Scale(1.2,1.2) + sleep(1) + A.alpha = 0 + +/proc/animate_fading_leap_down(var/atom/A) + if(!istype(A)) + return + var/matrix/M = matrix() + var/do_loops = 15 + M.Scale(18,18) + while(do_loops > 0) + do_loops-- + animate(A, transform = M, pixel_z = A.pixel_z - 12, alpha = A.alpha + 17, time = 1, loop = 1, easing = LINEAR_EASING) + M.Scale(0.8,0.8) + sleep(1) + animate(A, transform = M, pixel_z = 0, alpha = 255, time = 1, loop = 1, easing = LINEAR_EASING) + +/proc/animate_shake(var/atom/A, var/amount = 5, var/x_severity = 2, var/y_severity = 2) + // Wiggles the sprite around on its tile then returns it to normal + if(!istype(A)) + return + if(!isnum(amount) || !isnum(x_severity) || !isnum(y_severity)) + return + amount = max(1,min(amount,50)) + x_severity = max(-32,min(x_severity,32)) + y_severity = max(-32,min(y_severity,32)) + + var/x_severity_inverse = 0 - x_severity + var/y_severity_inverse = 0 - y_severity + + animate(A, transform = null, pixel_y = rand(y_severity_inverse,y_severity), pixel_x = rand(x_severity_inverse,x_severity),time = 1,loop = amount, easing = ELASTIC_EASING) + spawn(amount) + animate(A, transform = null, pixel_y = 0, pixel_x = 0,time = 1,loop = 1, easing = LINEAR_EASING) + +/proc/animate_teleport(var/atom/A) + if(!istype(A)) + return + var/matrix/M = matrix(1, 3, MATRIX_SCALE) + animate(A, transform = M, pixel_y = 32, time = 10, alpha = 50, easing = CIRCULAR_EASING) + M.Scale(0,4) + animate(transform = M, time = 5, color = "#1111ff", alpha = 0, easing = CIRCULAR_EASING) + animate(transform = null, time = 5, color = "#ffffff", alpha = 255, pixel_y = 0, easing = ELASTIC_EASING) + +/proc/animate_teleport_wiz(var/atom/A) + if(!istype(A)) + return + var/matrix/M = matrix(0, 4, MATRIX_SCALE) + animate(A, color = "#ddddff", time = 20, alpha = 70, easing = LINEAR_EASING) + animate(transform = M, pixel_y = 32, time = 20, color = "#2222ff", alpha = 0, easing = CIRCULAR_EASING) + animate(time = 8, transform = M, alpha = 5) //Do nothing, essentially + animate(transform = null, time = 5, color = "#ffffff", alpha = 255, pixel_y = 0, easing = ELASTIC_EASING) + +/proc/animate_rainbow_glow_old(var/atom/A) + if(!istype(A)) + return + animate(A, color = "#FF0000", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#00FF00", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#0000FF", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + +/proc/animate_rainbow_glow(var/atom/A) + if(!istype(A)) + return + animate(A, color = "#FF0000", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#FFFF00", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#00FF00", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#00FFFF", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#0000FF", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + animate(color = "#FF00FF", time = rand(5,10), loop = -1, easing = LINEAR_EASING) + +/proc/animate_fade_to_color_fill(var/atom/A, var/the_color, var/time) + if(!istype(A) || !the_color || !time) + return + animate(A, color = the_color, time = time, easing = LINEAR_EASING) + +/proc/animate_flash_color_fill(var/atom/A, var/the_color, var/loops, var/time) + if(!istype(A) || !the_color || !time || !loops) + return + animate(A, color = the_color, time = time, easing = LINEAR_EASING) + animate(color = "#FFFFFF", time = 5, loop = loops, easing = LINEAR_EASING) + +/proc/animate_flash_color_fill_inherit(var/atom/A, var/the_color, var/loops, var/time) + if(!istype(A) || !the_color || !time || !loops) + return + var/color_old = A.color + animate(A, color = the_color, time = time, loop = loops, easing = LINEAR_EASING) + animate(A, color = color_old, time = time, loop = loops, easing = LINEAR_EASING) + +/proc/animate_clownspell(var/atom/A) + if(!istype(A)) + return + animate(A, transform = matrix(1.3, MATRIX_SCALE), time = 5, color = "#00ff00", easing = BACK_EASING) + animate(transform = null, time = 5, color = "#ffffff", easing = ELASTIC_EASING) + +/proc/animate_wiggle_then_reset(var/atom/A, var/loops = 5, var/speed = 5, var/x_var = 3, var/y_var = 3) + if(!istype(A) || !loops || !speed) + return + animate(A, pixel_x = rand(-x_var, x_var), pixel_y = rand(-y_var, y_var), time = speed * 2,loop = loops, easing = rand(2,7)) + animate(pixel_x = 0, pixel_y = 0, time = speed, easing = rand(2,7)) + +/proc/animate_spin(var/atom/A, var/dir = "L", var/T = 1, var/looping = -1) + if(!istype(A)) + return + + var/matrix/M = A.transform + var/turn = -90 + if(dir == "R") + turn = 90 + + animate(A, transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping) + animate(transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping) + animate(transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping) + animate(transform = matrix(M, turn, MATRIX_ROTATE | MATRIX_MODIFY), time = T, loop = looping) + +/proc/animate_shockwave(var/atom/A) + if(!istype(A)) + return + var/punchstr = rand(10, 20) + var/original_y = A.pixel_y + animate(A, transform = matrix(punchstr, MATRIX_ROTATE), pixel_y = 16, time = 2, color = "#eeeeee", easing = BOUNCE_EASING) + animate(transform = matrix(-punchstr, MATRIX_ROTATE), pixel_y = original_y, time = 2, color = "#ffffff", easing = BOUNCE_EASING) + animate(transform = null, time = 3, easing = BOUNCE_EASING) \ No newline at end of file diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 5f4be64c9db..948602def06 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -64,12 +64,6 @@ return 1 return 0 -//Empties the list by setting the length to 0. Hopefully the elements get garbage collected -/proc/clearlist(list/list) - if(istype(list)) - list.len = 0 - return - //Removes any null entries from the list /proc/listclearnulls(list/list) if(istype(list)) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index f8980d61ddd..3d1648fa77a 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -52,7 +52,7 @@ proc/random_hair_style(var/gender, species = "Human") if(valid_hairstyles.len) h_style = pick(valid_hairstyles) - return h_style + return h_style proc/GetOppositeDir(var/dir) switch(dir) diff --git a/code/_globalvars/configuration.dm b/code/_globalvars/configuration.dm index 4cfa038cd1e..5b41171d557 100644 --- a/code/_globalvars/configuration.dm +++ b/code/_globalvars/configuration.dm @@ -4,7 +4,7 @@ var/host = null var/join_motd = null var/station_name = "NSS Cyberiad" var/game_version = "Custom ParaCode" -var/changelog_hash = "" +var/changelog_hash = md5('html/changelog.html') //used to check if the CL changed var/game_year = (text2num(time2text(world.realtime, "YYYY")) + 544) var/aliens_allowed = 1 @@ -35,4 +35,4 @@ var/MAX_EX_FLAME_RANGE = 14 var/eventchance = 10 //% per 5 mins var/event = 0 var/hadevent = 0 -var/blobevent = 0 \ No newline at end of file +var/blobevent = 0 diff --git a/code/_globalvars/lists/reagents.dm b/code/_globalvars/lists/reagents.dm index f6639796b97..8417275d780 100644 --- a/code/_globalvars/lists/reagents.dm +++ b/code/_globalvars/lists/reagents.dm @@ -55,7 +55,7 @@ var/global/list/blocked_chems = list("polonium", "initropidril", "concentrated_i "syndicate_nanites", "ripping_tendrils", "boiling_oil", "envenomed_filaments", "lexorin_jelly", "kinetic", "cryogenic_liquid", "dark_matter", "b_sorium", - "reagent", "life") + "reagent", "life","dragonsbreath") //List of chems/mixtures that can't grow in plants (in addition to the global random chem blacklist) var/global/list/plant_blocked_chems = list() //filled in /datum/reagents/New() with chems that have can_grow_in_plants = 0 \ No newline at end of file diff --git a/code/_onclick/ai.dm b/code/_onclick/ai.dm index b44ba964628..db5a0bbcd0f 100644 --- a/code/_onclick/ai.dm +++ b/code/_onclick/ai.dm @@ -45,7 +45,7 @@ if(modifiers["middle"]) MiddleClickOn(A) if(controlled_mech) //Are we piloting a mech? Placed here so the modifiers are not overridden. - controlled_mech.click_action(A, src) //Override AI normal click behavior. + controlled_mech.click_action(A, src, params) //Override AI normal click behavior. return if(modifiers["shift"]) ShiftClickOn(A) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index d135e62ae69..fa1d696a067 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -74,7 +74,7 @@ if(!locate(/turf) in list(A,A.loc)) // Prevents inventory from being drilled return var/obj/mecha/M = loc - return M.click_action(A,src) + return M.click_action(A, src, params) if(restrained()) changeNext_move(CLICK_CD_HANDCUFFED) //Doing shit in cuffs shall be vey slow @@ -167,9 +167,8 @@ animals lunging, etc. */ /mob/proc/RangedAttack(var/atom/A, var/params) - if(ishuman(src) && (istype(src:gloves, /obj/item/clothing/gloves/color/yellow/power)) && a_intent == I_HARM) - PowerGlove(A) - if(!mutations.len) return + if(!mutations.len) + return if((LASER in mutations) && a_intent == I_HARM) LaserEyes(A) // moved into a proc below return @@ -319,61 +318,8 @@ LE.current = T LE.yo = U.y - T.y LE.xo = U.x - T.x - spawn(1) - LE.process() + LE.fire() -/mob/proc/PowerGlove(atom/A) - return - -/mob/living/carbon/human/PowerGlove(atom/A) - var/obj/item/clothing/gloves/color/yellow/power/G = src:gloves - var/time = 100 - var/turf/T = get_turf(src) - var/turf/U = get_turf(A) - var/obj/structure/cable/cable = locate() in T - if(!cable || !istype(cable)) - to_chat(src, "There is no cable here to power the gloves.") - return - if(world.time < G.next_shock) - to_chat(src, "[G] aren't ready to shock again!") - return - src.visible_message("[name] fires an arc of electricity!", \ - "You fire an arc of electricity!", \ - "You hear the loud crackle of electricity!") - var/datum/powernet/PN = cable.get_powernet() - var/available = 0 - var/obj/item/projectile/beam/lightning/L = new /obj/item/projectile/beam/lightning/(get_turf(src)) - if(PN) - available = PN.avail - L.damage = PN.get_electrocute_damage() - if(available >= 5000000) - L.damage = 205 - if(L.damage >= 200) - time = 200 - else if(L.damage >= 100) - time = 150 - var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread - s.set_up(5, 1, src) - s.start() - if(L.damage <= 0) - qdel(L) - if(L) - playsound(get_turf(src), 'sound/effects/eleczap.ogg', 75, 1) - L.tang = L.adjustAngle(get_angle(U,T)) - L.icon = midicon - L.icon_state = "[L.tang]" - L.firer = usr - L.def_zone = get_organ_target() - L.original = src - L.current = U - L.starting = U - L.yo = U.y - T.y - L.xo = U.x - T.x - spawn( 1 ) - L.process() - - next_move = world.time + 12 - G.next_shock = world.time + time // Simple helper to face what you clicked on, in case it should be needed in more than one place /mob/proc/face_atom(var/atom/A) @@ -419,4 +365,4 @@ else var/turf/T = screen_loc2turf(modifiers["screen-loc"], get_turf(usr)) T.Click(location, control, params) - return 1 \ No newline at end of file + return 1 diff --git a/code/_onclick/click_override.dm b/code/_onclick/click_override.dm index 092398ee174..d37b7368b8f 100644 --- a/code/_onclick/click_override.dm +++ b/code/_onclick/click_override.dm @@ -40,4 +40,29 @@ newObject.loc = get_turf(A) to_chat(user, "You release the power you had stored up, summoning \a [newObject.name]! ") usr.loc.visible_message("[user] waves \his hand and summons \a [newObject.name]") - ..() \ No newline at end of file + ..() + +/datum/middleClickOverride/power_gloves + var/last_shocked = 0 + var/shock_delay = 120 + +/datum/middleClickOverride/power_gloves/onClick(var/atom/A, var/mob/living/user) + if(user.incapacitated()) + return + if(world.time < last_shocked + shock_delay) + to_chat(user, "The gloves are still recharging.") + return + if(!isliving(A)) + to_chat(user, "Shocking an inanimate object would be pointless.") + return + var/mob/living/L = A + var/turf/T = get_turf(user) + var/obj/structure/cable/C = locate() in T + if(!C || !istype(C)) + to_chat(user, "There is no cable here to power the gloves.") + return + user.visible_message("[user.name] fires an arc of electricity at [L]!", "You fire an arc of electricity at [L]!", "You hear the loud crackle of electricity!") + var/datum/powernet/PN = C.get_powernet() + user.Beam(L,icon_state="lightning[rand(1,12)]",icon='icons/effects/effects.dmi',time=5) + electrocute_mob(L, PN, user) + last_shocked = world.time diff --git a/code/_onclick/hud/action.dm b/code/_onclick/hud/action.dm index 0a891be21f5..4744b789712 100644 --- a/code/_onclick/hud/action.dm +++ b/code/_onclick/hud/action.dm @@ -50,7 +50,8 @@ T.client.screen -= button qdel(button) button = null - T.actions.Remove(src) + if(T.actions) + T.actions.Remove(src) T.update_action_buttons() owner = null return @@ -216,11 +217,25 @@ check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_LYING|AB_CHECK_ALIVE|AB_CHECK_INSIDE /datum/action/item_action/CheckRemoval(mob/living/user) - return !(target in user) + return get(target, /mob/living) != user /datum/action/item_action/hands_free check_flags = AB_CHECK_ALIVE|AB_CHECK_INSIDE +// for clothing accessories like holsters +/datum/action/item_action/accessory + check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_LYING|AB_CHECK_ALIVE + +/datum/action/item_action/accessory/Checks() + . = ..() + if(!.) + return 0 + if(target.loc == owner) + return 1 + if(istype(target.loc, /obj/item/clothing/under) && target.loc.loc == owner) + return 1 + return 0 + ///prset for organ actions /datum/action/item_action/organ_action check_flags = AB_CHECK_ALIVE diff --git a/code/_onclick/oldcode.dm b/code/_onclick/oldcode.dm index b3f2c1dde05..89b1131a6f0 100644 --- a/code/_onclick/oldcode.dm +++ b/code/_onclick/oldcode.dm @@ -369,8 +369,7 @@ A.current = T A.yo = U.y - T.y A.xo = U.x - T.x - spawn( 1 ) - A.process() + A.fire() usr.next_move = world.time + 6 return diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index a70875a7090..d07b6e3eb73 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -126,6 +126,7 @@ proc/get_id_photo(var/mob/living/carbon/human/H) var/icon/preview_icon = null + var/obj/item/organ/external/head/head_organ = H.get_organ("head") var/g = "m" if (H.gender == FEMALE) @@ -170,32 +171,32 @@ proc/get_id_photo(var/mob/living/carbon/human/H) eyes_s.Blend(rgb(H.r_eyes, H.g_eyes, H.b_eyes), ICON_ADD) face_s.Blend(eyes_s, ICON_OVERLAY) - var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style] + var/datum/sprite_accessory/hair_style = hair_styles_list[head_organ.h_style] if(hair_style) var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") // I'll want to make a species-specific proc for this sooner or later // But this'll do for now - if(H.get_species() == "Slime People") + if(head_organ.species.name == "Slime People") hair_s.Blend(rgb(H.r_skin, H.g_skin, H.b_skin, 160), ICON_ADD) else - hair_s.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD) + hair_s.Blend(rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair), ICON_ADD) face_s.Blend(hair_s, ICON_OVERLAY) //Head Accessory - if(H.species.bodyflags & HAS_HEAD_ACCESSORY) - var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[H.ha_style] + if(head_organ.species.bodyflags & HAS_HEAD_ACCESSORY) + var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[head_organ.ha_style] if(head_accessory_style && head_accessory_style.species_allowed) var/icon/head_accessory_s = new/icon("icon" = head_accessory_style.icon, "icon_state" = "[head_accessory_style.icon_state]_s") - head_accessory_s.Blend(rgb(H.r_headacc, H.g_headacc, H.b_headacc), ICON_ADD) + head_accessory_s.Blend(rgb(head_organ.r_headacc, head_organ.g_headacc, head_organ.b_headacc), ICON_ADD) face_s.Blend(head_accessory_s, ICON_OVERLAY) - var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style] + var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[head_organ.f_style] if(facial_hair_style && facial_hair_style.species_allowed) var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") - if(H.get_species() == "Slime People") + if(head_organ.species.name == "Slime People") facial_s.Blend(rgb(H.r_skin, H.g_skin, H.b_skin, 160), ICON_ADD) else - facial_s.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD) + facial_s.Blend(rgb(head_organ.r_facial, head_organ.g_facial, head_organ.b_facial), ICON_ADD) face_s.Blend(facial_s, ICON_OVERLAY) //Markings diff --git a/code/datums/diseases/advance/symptoms/beard.dm b/code/datums/diseases/advance/symptoms/beard.dm index 1dda9b46f7f..2ce411367f8 100644 --- a/code/datums/diseases/advance/symptoms/beard.dm +++ b/code/datums/diseases/advance/symptoms/beard.dm @@ -30,20 +30,21 @@ BONUS var/mob/living/M = A.affected_mob if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M + var/obj/item/organ/external/head/head_organ = H.get_organ("head") switch(A.stage) if(1, 2) to_chat(H, "Your chin itches.") - if(H.f_style == "Shaved") - H.f_style = "Jensen Beard" - H.update_hair() + if(head_organ.f_style == "Shaved") + head_organ.f_style = "Jensen Beard" + H.update_fhair() if(3, 4) to_chat(H, "You feel tough.") - if(!(H.f_style == "Dwarf Beard") && !(H.f_style == "Very Long Beard") && !(H.f_style == "Full Beard")) - H.f_style = "Full Beard" - H.update_hair() + if(!(head_organ.f_style == "Dwarf Beard") && !(head_organ.f_style == "Very Long Beard") && !(head_organ.f_style == "Full Beard")) + head_organ.f_style = "Full Beard" + H.update_fhair() else to_chat(H, "You feel manly!") - if(!(H.f_style == "Dwarf Beard") && !(H.f_style == "Very Long Beard")) - H.f_style = pick("Dwarf Beard", "Very Long Beard") - H.update_hair() + if(!(head_organ.f_style == "Dwarf Beard") && !(head_organ.f_style == "Very Long Beard")) + head_organ.f_style = pick("Dwarf Beard", "Very Long Beard") + H.update_fhair() return \ No newline at end of file diff --git a/code/datums/diseases/advance/symptoms/sensory.dm b/code/datums/diseases/advance/symptoms/sensory.dm index b25c4bacf47..99f670c258e 100644 --- a/code/datums/diseases/advance/symptoms/sensory.dm +++ b/code/datums/diseases/advance/symptoms/sensory.dm @@ -31,7 +31,7 @@ Bonus switch(A.stage) if(2) if(M.reagents.get_reagent_amount("oculine")<10) - M.reagents.add_reagent("oculine"=10) + M.reagents.add_reagent("oculine", 10) to_chat(M, "Your hearing feels clearer and crisp.") if(3) if(M.reagents.get_reagent_amount("antihol") < 10 && M.reagents.get_reagent_amount("oculine") < 10 ) diff --git a/code/datums/diseases/advance/symptoms/shedding.dm b/code/datums/diseases/advance/symptoms/shedding.dm index f7f52984c0b..e79b87d1d4b 100644 --- a/code/datums/diseases/advance/symptoms/shedding.dm +++ b/code/datums/diseases/advance/symptoms/shedding.dm @@ -31,18 +31,20 @@ BONUS to_chat(M, "[pick("Your scalp itches.", "Your skin feels flakey.")]") if(istype(M, /mob/living/carbon/human)) var/mob/living/carbon/human/H = M + var/obj/item/organ/external/head/head_organ = H.get_organ("head") switch(A.stage) if(3, 4) - if(!(H.h_style == "Bald") && !(H.h_style == "Balding Hair")) + if(!(head_organ.h_style == "Bald") && !(head_organ.h_style == "Balding Hair")) to_chat(H, "Your hair starts to fall out in clumps...") spawn(50) - H.h_style = "Balding Hair" + head_organ.h_style = "Balding Hair" H.update_hair() if(5) - if(!(H.f_style == "Shaved") || !(H.h_style == "Bald")) + if(!(head_organ.f_style == "Shaved") || !(head_organ.h_style == "Bald")) to_chat(H, "Your hair starts to fall out in clumps...") spawn(50) - H.f_style = "Shaved" - H.h_style = "Bald" + head_organ.f_style = "Shaved" + head_organ.h_style = "Bald" H.update_hair() + H.update_fhair() return \ No newline at end of file diff --git a/code/datums/spells/dumbfire.dm b/code/datums/spells/dumbfire.dm index c1eb4889a93..7b5c77b7d21 100644 --- a/code/datums/spells/dumbfire.dm +++ b/code/datums/spells/dumbfire.dm @@ -79,8 +79,11 @@ qdel(trail) current_loc = projectile.loc + var/matrix/M = new + M.Turn(dir2angle(projectile.dir)) + projectile.transform = M sleep(proj_step_delay) if(projectile) - qdel(projectile) \ No newline at end of file + qdel(projectile) diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index 247d481f1be..be25ea14f1f 100644 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -234,9 +234,9 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine /datum/supply_packs/security/taser name = "Stun Guns Crate" - contains = list(/obj/item/weapon/gun/energy/advtaser, - /obj/item/weapon/gun/energy/advtaser, - /obj/item/weapon/gun/energy/advtaser) + contains = list(/obj/item/weapon/gun/energy/gun/advtaser, + /obj/item/weapon/gun/energy/gun/advtaser, + /obj/item/weapon/gun/energy/gun/advtaser) cost = 15 containername = "stun gun crate" diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 7b30a0bb9a6..0488f60ac03 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -308,7 +308,7 @@ var/list/uplink_items = list() reference = "AIRJ" item = /obj/item/clothing/under/contortionist cost = 6 - job = list("Atmospheric Technician") + job = list("Life Support Specialist") //Stimulants @@ -410,6 +410,13 @@ var/list/uplink_items = list() item = /obj/item/weapon/twohanded/chainsaw cost = 13 +/datum/uplink_item/dangerous/batterer + name = "Mind Batterer" + desc = "A device that has a chance of knocking down people around you for a long amount of time. 50% chance per person. The user is unaffected. Has 5 charges." + reference = "BTR" + item = /obj/item/device/batterer + cost = 5 + /datum/uplink_item/dangerous/manhacks name = "Viscerator Delivery Grenade" desc = "A unique grenade that deploys a swarm of viscerators upon activation, which will chase down and shred any non-operatives in the area." @@ -605,10 +612,10 @@ var/list/uplink_items = list() gamemodes = list(/datum/game_mode/nuclear) /datum/uplink_item/ammo/machinegun - name = "Box Magazine - 7.62x51mm" - desc = "A 50-round magazine of 7.62x51mm ammunition for use in the L6 SAW machine gun. By the time you need to use this, you'll already be on a pile of corpses." + name = "Box Magazine - 5.56x45mm" + desc = "A 50-round magazine of 5.56x45mm ammunition for use in the L6 SAW machine gun. By the time you need to use this, you'll already be on a pile of corpses." reference = "762" - item = /obj/item/ammo_box/magazine/m762 + item = /obj/item/ammo_box/magazine/mm556x45 cost = 12 gamemodes = list(/datum/game_mode/nuclear) surplus = 0 @@ -644,7 +651,7 @@ var/list/uplink_items = list() /datum/uplink_item/stealthy_weapons/sleepy_pen name = "Sleepy Pen" - desc = "A syringe disguised as a functional pen. It's filled with a potent anaesthetic. \The pen holds two doses of the mixture. The pen can be refilled." + desc = "A syringe disguised as a functional pen. It's filled with a potent anaesthetic. \ The pen holds two doses of the mixture. The pen can be refilled." reference = "SP" item = /obj/item/weapon/pen/sleepy cost = 8 @@ -699,7 +706,7 @@ var/list/uplink_items = list() /datum/uplink_item/stealthy_weapons/dehy_carp name = "Dehydrated Space Carp" - desc = "Just add water to make your very own hostile to everything space carp. It looks just like a plushie." + desc = "Just add water to make your very own hostile to everything space carp. It looks just like a plushie. The first person to squeeze it will be registered as its owner, who it will not attack. If no owner is registered, it'll just attack everyone." reference = "DSC" item = /obj/item/toy/carpplushie/dehy_carp cost = 3 @@ -1016,7 +1023,7 @@ var/list/uplink_items = list() /datum/uplink_item/implants/uplink name = "Uplink Implant" - desc = "An implant injected into the body, and later activated using a bodily gesture to open an uplink with 5 telecrystals. The ability for an agent to open an uplink after their possessions have been stripped from them makes this implant excellent for escaping confinement." + desc = "An implant injected into the body, and later activated using a bodily gesture to open an uplink with 10 telecrystals. The ability for an agent to open an uplink after their possessions have been stripped from them makes this implant excellent for escaping confinement." reference = "UI" item = /obj/item/weapon/implanter/uplink cost = 14 diff --git a/code/defines/vox_sounds.dm b/code/defines/vox_sounds.dm index 6f9bcf122fd..98442569e5b 100644 --- a/code/defines/vox_sounds.dm +++ b/code/defines/vox_sounds.dm @@ -16,6 +16,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "across" = 'sound/vox_fem/across.ogg', "activate" = 'sound/vox_fem/activate.ogg', "activated" = 'sound/vox_fem/activated.ogg', +"active" = 'sound/vox_fem/active.ogg', "activity" = 'sound/vox_fem/activity.ogg', "adios" = 'sound/vox_fem/adios.ogg', "administration" = 'sound/vox_fem/administration.ogg', @@ -24,7 +25,9 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "after" = 'sound/vox_fem/after.ogg', "agent" = 'sound/vox_fem/agent.ogg', "ai" = 'sound/vox_fem/ai.ogg', +"airlock" = 'sound/vox_fem/airlock.ogg', "alarm" = 'sound/vox_fem/alarm.ogg', +"alcohol" = 'sound/vox_fem/alcohol.ogg', "alert" = 'sound/vox_fem/alert.ogg', "alien" = 'sound/vox_fem/alien.ogg', "aligned" = 'sound/vox_fem/aligned.ogg', @@ -51,6 +54,8 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "armory" = 'sound/vox_fem/armory.ogg', "array" = 'sound/vox_fem/array.ogg', "arrest" = 'sound/vox_fem/arrest.ogg', +"arrival" = 'sound/vox_fem/arrival.ogg', +"arrivals" = 'sound/vox_fem/arrivals.ogg', "asimov" = 'sound/vox_fem/asimov.ogg', "ass" = 'sound/vox_fem/ass.ogg', "asshole" = 'sound/vox_fem/asshole.ogg', @@ -74,8 +79,10 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "base" = 'sound/vox_fem/base.ogg', "bay" = 'sound/vox_fem/bay.ogg', "be" = 'sound/vox_fem/be.ogg', +"becoming" = 'sound/vox_fem/becoming.ogg', "been" = 'sound/vox_fem/been.ogg', "before" = 'sound/vox_fem/before.ogg', +"between" = 'sound/vox_fem/between.ogg', "beyond" = 'sound/vox_fem/beyond.ogg', "biohazard" = 'sound/vox_fem/biohazard.ogg', "biological" = 'sound/vox_fem/biological.ogg', @@ -86,6 +93,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "bizwarn" = 'sound/vox_fem/bizwarn.ogg', "black" = 'sound/vox_fem/black.ogg', "blast" = 'sound/vox_fem/blast.ogg', +"blob" = 'sound/vox_fem/blob.ogg', "blocked" = 'sound/vox_fem/blocked.ogg', "bloop" = 'sound/vox_fem/bloop.ogg', "blue" = 'sound/vox_fem/blue.ogg', @@ -104,6 +112,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "breached" = 'sound/vox_fem/breached.ogg', "break" = 'sound/vox_fem/break.ogg', "bridge" = 'sound/vox_fem/bridge.ogg', +"briefing" = 'sound/vox_fem/briefing.ogg', "brig" = 'sound/vox_fem/brig.ogg', "bust" = 'sound/vox_fem/bust.ogg', "but" = 'sound/vox_fem/but.ogg', @@ -115,6 +124,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "cage" = 'sound/vox_fem/cage.ogg', "call" = 'sound/vox_fem/call.ogg', "called" = 'sound/vox_fem/called.ogg', +"camp" = 'sound/vox_fem/camp.ogg', "can" = 'sound/vox_fem/can.ogg', "canal" = 'sound/vox_fem/canal.ogg', "cancer" = 'sound/vox_fem/cancer.ogg', @@ -130,11 +140,13 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "center" = 'sound/vox_fem/center.ogg', "centi" = 'sound/vox_fem/centi.ogg', "central" = 'sound/vox_fem/central.ogg', +"chair" = 'sound/vox_fem/chair.ogg', "chamber" = 'sound/vox_fem/chamber.ogg', "changed" = 'sound/vox_fem/changed.ogg', "changeling" = 'sound/vox_fem/changeling.ogg', "changelings" = 'sound/vox_fem/changelings.ogg', "changer" = 'sound/vox_fem/changer.ogg', +"chapel" = 'sound/vox_fem/chapel.ogg', "charlie" = 'sound/vox_fem/charlie.ogg', "check" = 'sound/vox_fem/check.ogg', "checkpoint" = 'sound/vox_fem/checkpoint.ogg', @@ -147,6 +159,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "clear" = 'sound/vox_fem/clear.ogg', "clearance" = 'sound/vox_fem/clearance.ogg', "close" = 'sound/vox_fem/close.ogg', +"closet" = 'sound/vox_fem/closet.ogg', "clown" = 'sound/vox_fem/clown.ogg', "clowns" = 'sound/vox_fem/clowns.ogg', "cmo" = 'sound/vox_fem/cmo.ogg', @@ -179,6 +192,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "cryogenic" = 'sound/vox_fem/cryogenic.ogg', "cunt" = 'sound/vox_fem/cunt.ogg', "cunts" = 'sound/vox_fem/cunts.ogg', +"cyberiad" = 'sound/vox_fem/cyberiad.ogg', "cyborg" = 'sound/vox_fem/cyborg.ogg', "cyborgs" = 'sound/vox_fem/cyborgs.ogg', "d" = 'sound/vox_fem/d.ogg', @@ -190,6 +204,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "deactivated" = 'sound/vox_fem/deactivated.ogg', "dead" = 'sound/vox_fem/dead.ogg', "death" = 'sound/vox_fem/death.ogg', +"declared" = 'sound/vox_fem/declared.ogg', "decompression" = 'sound/vox_fem/decompression.ogg', "decontamination" = 'sound/vox_fem/decontamination.ogg', "deeoo" = 'sound/vox_fem/deeoo.ogg', @@ -206,11 +221,13 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "destroyed" = 'sound/vox_fem/destroyed.ogg', "detain" = 'sound/vox_fem/detain.ogg', "detected" = 'sound/vox_fem/detected.ogg', +"detective" = 'sound/vox_fem/detective.ogg', "detonation" = 'sound/vox_fem/detonation.ogg', "device" = 'sound/vox_fem/device.ogg', "did" = 'sound/vox_fem/did.ogg', "die" = 'sound/vox_fem/die.ogg', "dimensional" = 'sound/vox_fem/dimensional.ogg', +"diona" = 'sound/vox_fem/diona.ogg', "dirt" = 'sound/vox_fem/dirt.ogg', "disengaged" = 'sound/vox_fem/disengaged.ogg', "dish" = 'sound/vox_fem/dish.ogg', @@ -218,12 +235,18 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "distance" = 'sound/vox_fem/distance.ogg', "distortion" = 'sound/vox_fem/distortion.ogg', "do" = 'sound/vox_fem/do.ogg', +"dock" = 'sound/vox_fem/dock.ogg', +"docked" = 'sound/vox_fem/docked.ogg', +"docking" = 'sound/vox_fem/docking.ogg', +"docks" = 'sound/vox_fem/docks.ogg', "doctor" = 'sound/vox_fem/doctor.ogg', "doctors" = 'sound/vox_fem/doctors.ogg', "doop" = 'sound/vox_fem/doop.ogg', "door" = 'sound/vox_fem/door.ogg', "dorms" = 'sound/vox_fem/dorms.ogg', "down" = 'sound/vox_fem/down.ogg', +"drask" = 'sound/vox_fem/drask.ogg', +"drunk" = 'sound/vox_fem/drunk.ogg', "dual" = 'sound/vox_fem/dual.ogg', "duct" = 'sound/vox_fem/duct.ogg', "e" = 'sound/vox_fem/e.ogg', @@ -240,6 +263,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "elevator" = 'sound/vox_fem/elevator.ogg', "eleven" = 'sound/vox_fem/eleven.ogg', "eliminate" = 'sound/vox_fem/eliminate.ogg', +"emag" = 'sound/vox_fem/emag.ogg', "emergency" = 'sound/vox_fem/emergency.ogg', "energy" = 'sound/vox_fem/energy.ogg', "engage" = 'sound/vox_fem/engage.ogg', @@ -251,9 +275,11 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "enter" = 'sound/vox_fem/enter.ogg', "entry" = 'sound/vox_fem/entry.ogg', "environment" = 'sound/vox_fem/environment.ogg', +"equipment" = 'sound/vox_fem/equipment.ogg', "error" = 'sound/vox_fem/error.ogg', "escape" = 'sound/vox_fem/escape.ogg', "evacuate" = 'sound/vox_fem/evacuate.ogg', +"evacuation" = 'sound/vox_fem/evacuation.ogg', "every" = 'sound/vox_fem/every.ogg', "everywhere" = 'sound/vox_fem/everywhere.ogg', "exchange" = 'sound/vox_fem/exchange.ogg', @@ -262,6 +288,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "expect" = 'sound/vox_fem/expect.ogg', "experiment" = 'sound/vox_fem/experiment.ogg', "experimental" = 'sound/vox_fem/experimental.ogg', +"experimentor" = 'sound/vox_fem/experimentor.ogg', "explode" = 'sound/vox_fem/explode.ogg', "explosion" = 'sound/vox_fem/explosion.ogg', "exposure" = 'sound/vox_fem/exposure.ogg', @@ -310,6 +337,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "fuel" = 'sound/vox_fem/fuel.ogg', "g" = 'sound/vox_fem/g.ogg', "gas" = 'sound/vox_fem/gas.ogg', +"gateway" = 'sound/vox_fem/gateway.ogg', "get" = 'sound/vox_fem/get.ogg', "glory" = 'sound/vox_fem/glory.ogg', "go" = 'sound/vox_fem/go.ogg', @@ -332,6 +360,8 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "hacker" = 'sound/vox_fem/hacker.ogg', "hackers" = 'sound/vox_fem/hackers.ogg', "hacking" = 'sound/vox_fem/hacking.ogg', +"hail" = 'sound/vox_fem/hail.ogg', +"hallway" = 'sound/vox_fem/hallway.ogg', "handling" = 'sound/vox_fem/handling.ogg', "hangar" = 'sound/vox_fem/hangar.ogg', "happening" = 'sound/vox_fem/happening.ogg', @@ -352,6 +382,8 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "highest" = 'sound/vox_fem/highest.ogg', "hit" = 'sound/vox_fem/hit.ogg', "hole" = 'sound/vox_fem/hole.ogg', +"holoparasite" = 'sound/vox_fem/holoparasite.ogg', +"honk" = 'sound/vox_fem/honk.ogg', "hop" = 'sound/vox_fem/hop.ogg', "hos" = 'sound/vox_fem/hos.ogg', "hostile" = 'sound/vox_fem/hostile.ogg', @@ -359,6 +391,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "hotel" = 'sound/vox_fem/hotel.ogg', "hour" = 'sound/vox_fem/hour.ogg', "hours" = 'sound/vox_fem/hours.ogg', +"hull" = 'sound/vox_fem/hull.ogg', "human" = 'sound/vox_fem/human.ogg', "humans" = 'sound/vox_fem/humans.ogg', "hundred" = 'sound/vox_fem/hundred.ogg', @@ -367,10 +400,12 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "hydroponics" = 'sound/vox_fem/hydroponics.ogg', "i" = 'sound/vox_fem/i.ogg', "iaa" = 'sound/vox_fem/iaa.ogg', +"ian" = 'sound/vox_fem/ian.ogg', "idiot" = 'sound/vox_fem/idiot.ogg', "illegal" = 'sound/vox_fem/illegal.ogg', "immediate" = 'sound/vox_fem/immediate.ogg', "immediately" = 'sound/vox_fem/immediately.ogg', +"imminent" = 'sound/vox_fem/imminent.ogg', "in" = 'sound/vox_fem/in.ogg', "inches" = 'sound/vox_fem/inches.ogg', "india" = 'sound/vox_fem/india.ogg', @@ -380,7 +415,9 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "inspection" = 'sound/vox_fem/inspection.ogg', "inspector" = 'sound/vox_fem/inspector.ogg', "interchange" = 'sound/vox_fem/interchange.ogg', +"interested" = 'sound/vox_fem/interested.ogg', "intruder" = 'sound/vox_fem/intruder.ogg', +"intruders" = 'sound/vox_fem/intruders.ogg', "invalid" = 'sound/vox_fem/invalid.ogg', "invasion" = 'sound/vox_fem/invasion.ogg', "is" = 'sound/vox_fem/is.ogg', @@ -390,6 +427,8 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "juliet" = 'sound/vox_fem/juliet.ogg', "k" = 'sound/vox_fem/k.ogg', "key" = 'sound/vox_fem/key.ogg', +"kida" = 'sound/vox_fem/kida.ogg', +"kidan" = 'sound/vox_fem/kidan.ogg', "kill" = 'sound/vox_fem/kill.ogg', "killed" = 'sound/vox_fem/killed.ogg', "killing" = 'sound/vox_fem/killing.ogg', @@ -398,6 +437,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "kitchen" = 'sound/vox_fem/kitchen.ogg', "l" = 'sound/vox_fem/l.ogg', "lab" = 'sound/vox_fem/lab.ogg', +"labor" = 'sound/vox_fem/labor.ogg', "lambda" = 'sound/vox_fem/lambda.ogg', "laser" = 'sound/vox_fem/laser.ogg', "last" = 'sound/vox_fem/last.ogg', @@ -411,6 +451,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "legal" = 'sound/vox_fem/legal.ogg', "level" = 'sound/vox_fem/level.ogg', "lever" = 'sound/vox_fem/lever.ogg', +"library" = 'sound/vox_fem/library.ogg', "lie" = 'sound/vox_fem/lie.ogg', "lieutenant" = 'sound/vox_fem/lieutenant.ogg', "life" = 'sound/vox_fem/life.ogg', @@ -457,8 +498,13 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "military" = 'sound/vox_fem/military.ogg', "milli" = 'sound/vox_fem/milli.ogg', "million" = 'sound/vox_fem/million.ogg', +"mime" = 'sound/vox_fem/mime.ogg', +"mimes" = 'sound/vox_fem/mimes.ogg', "minefield" = 'sound/vox_fem/minefield.ogg', +"miner" = 'sound/vox_fem/miner.ogg', +"miners" = 'sound/vox_fem/miners.ogg', "minimum" = 'sound/vox_fem/minimum.ogg', +"mining" = 'sound/vox_fem/mining.ogg', "minus" = 'sound/vox_fem/minus.ogg', "minutes" = 'sound/vox_fem/minutes.ogg', "mister" = 'sound/vox_fem/mister.ogg', @@ -473,6 +519,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "must" = 'sound/vox_fem/must.ogg', "my" = 'sound/vox_fem/my.ogg', "n" = 'sound/vox_fem/n.ogg', +"n2o" = 'sound/vox_fem/n2o.ogg', "nanotrasen" = 'sound/vox_fem/nanotrasen.ogg', "nearest" = 'sound/vox_fem/nearest.ogg', "negative" = 'sound/vox_fem/negative.ogg', @@ -488,20 +535,25 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "not" = 'sound/vox_fem/not.ogg', "november" = 'sound/vox_fem/november.ogg', "now" = 'sound/vox_fem/now.ogg', +"nuke" = 'sound/vox_fem/nuke.ogg', "number" = 'sound/vox_fem/number.ogg', "o" = 'sound/vox_fem/o.ogg', "objective" = 'sound/vox_fem/objective.ogg', "observation" = 'sound/vox_fem/observation.ogg', "obtain" = 'sound/vox_fem/obtain.ogg', "of" = 'sound/vox_fem/of.ogg', +"office" = 'sound/vox_fem/office.ogg', "officer" = 'sound/vox_fem/officer.ogg', "ok" = 'sound/vox_fem/ok.ogg', "on" = 'sound/vox_fem/on.ogg', "one" = 'sound/vox_fem/one.ogg', +"op" = 'sound/vox_fem/op.ogg', "open" = 'sound/vox_fem/open.ogg', "operating" = 'sound/vox_fem/operating.ogg', +"operational" = 'sound/vox_fem/operational.ogg', "operations" = 'sound/vox_fem/operations.ogg', "operative" = 'sound/vox_fem/operative.ogg', +"ops" = 'sound/vox_fem/ops.ogg', "option" = 'sound/vox_fem/option.ogg', "or" = 'sound/vox_fem/or.ogg', "order" = 'sound/vox_fem/order.ogg', @@ -526,7 +578,10 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "plasma" = 'sound/vox_fem/plasma.ogg', "platform" = 'sound/vox_fem/platform.ogg', "please" = 'sound/vox_fem/please.ogg', +"pod" = 'sound/vox_fem/pod.ogg', +"pods" = 'sound/vox_fem/pods.ogg', "point" = 'sound/vox_fem/point.ogg', +"poly" = 'sound/vox_fem/poly.ogg', "port" = 'sound/vox_fem/port.ogg', "portal" = 'sound/vox_fem/portal.ogg', "power" = 'sound/vox_fem/power.ogg', @@ -540,6 +595,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "propulsion" = 'sound/vox_fem/propulsion.ogg', "prosecute" = 'sound/vox_fem/prosecute.ogg', "protective" = 'sound/vox_fem/protective.ogg', +"pun" = 'sound/vox_fem/pun.ogg', "push" = 'sound/vox_fem/push.ogg', "q" = 'sound/vox_fem/q.ogg', "qm" = 'sound/vox_fem/qm.ogg', @@ -569,10 +625,12 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "released" = 'sound/vox_fem/released.ogg', "remaining" = 'sound/vox_fem/remaining.ogg', "removal" = 'sound/vox_fem/removal.ogg', +"renault" = 'sound/vox_fem/renault.ogg', "renegade" = 'sound/vox_fem/renegade.ogg', "repair" = 'sound/vox_fem/repair.ogg', "report" = 'sound/vox_fem/report.ogg', "reports" = 'sound/vox_fem/reports.ogg', +"representative" = 'sound/vox_fem/representative.ogg', "request" = 'sound/vox_fem/request.ogg', "requested" = 'sound/vox_fem/requested.ogg', "required" = 'sound/vox_fem/required.ogg', @@ -591,6 +649,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "room" = 'sound/vox_fem/room.ogg', "round" = 'sound/vox_fem/round.ogg', "run" = 'sound/vox_fem/run.ogg', +"runtime" = 'sound/vox_fem/runtime.ogg', "s" = 'sound/vox_fem/s.ogg', "safe" = 'sound/vox_fem/safe.ogg', "safety" = 'sound/vox_fem/safety.ogg', @@ -601,6 +660,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "science" = 'sound/vox_fem/science.ogg', "scream" = 'sound/vox_fem/scream.ogg', "screen" = 'sound/vox_fem/screen.ogg', +"scrubbers" = 'sound/vox_fem/scrubbers.ogg', "search" = 'sound/vox_fem/search.ogg', "second" = 'sound/vox_fem/second.ogg', "secondary" = 'sound/vox_fem/secondary.ogg', @@ -612,6 +672,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "select" = 'sound/vox_fem/select.ogg', "selected" = 'sound/vox_fem/selected.ogg', "sensors" = 'sound/vox_fem/sensors.ogg', +"sequencer" = 'sound/vox_fem/sequencer.ogg', "service" = 'sound/vox_fem/service.ogg', "seven" = 'sound/vox_fem/seven.ogg', "seventeen" = 'sound/vox_fem/seventeen.ogg', @@ -642,6 +703,9 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "sixteen" = 'sound/vox_fem/sixteen.ogg', "sixty" = 'sound/vox_fem/sixty.ogg', "skipjack" = 'sound/vox_fem/skipjack.ogg', +"skree" = 'sound/vox_fem/skree.ogg', +"skrek" = 'sound/vox_fem/skrek.ogg', +"skrell" = 'sound/vox_fem/skrell.ogg', "slime" = 'sound/vox_fem/slime.ogg', "slow" = 'sound/vox_fem/slow.ogg', "smoke" = 'sound/vox_fem/smoke.ogg', @@ -654,6 +718,9 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "son" = 'sound/vox_fem/son.ogg', "sorry" = 'sound/vox_fem/sorry.ogg', "south" = 'sound/vox_fem/south.ogg', +"space" = 'sound/vox_fem/space.ogg', +"spider" = 'sound/vox_fem/spider.ogg', +"spiders" = 'sound/vox_fem/spiders.ogg', "squad" = 'sound/vox_fem/squad.ogg', "square" = 'sound/vox_fem/square.ogg', "ss13" = 'sound/vox_fem/ss13.ogg', @@ -664,8 +731,10 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "status" = 'sound/vox_fem/status.ogg', "sterile" = 'sound/vox_fem/sterile.ogg', "sterilization" = 'sound/vox_fem/sterilization.ogg', +"still" = 'sound/vox_fem/still.ogg', "storage" = 'sound/vox_fem/storage.ogg', "stuck" = 'sound/vox_fem/stuck.ogg', +"stupid" = 'sound/vox_fem/stupid.ogg', "sub" = 'sound/vox_fem/sub.ogg', "subsurface" = 'sound/vox_fem/subsurface.ogg', "sudden" = 'sound/vox_fem/sudden.ogg', @@ -679,7 +748,10 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "surrender" = 'sound/vox_fem/surrender.ogg', "surround" = 'sound/vox_fem/surround.ogg', "surrounded" = 'sound/vox_fem/surrounded.ogg', +"swarmer" = 'sound/vox_fem/swarmer.ogg', +"swarmers" = 'sound/vox_fem/swarmers.ogg', "switch" = 'sound/vox_fem/switch.ogg', +"sword" = 'sound/vox_fem/sword.ogg', "syndicate" = 'sound/vox_fem/syndicate.ogg', "system" = 'sound/vox_fem/system.ogg', "systems" = 'sound/vox_fem/systems.ogg', @@ -692,13 +764,19 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "tank" = 'sound/vox_fem/tank.ogg', "target" = 'sound/vox_fem/target.ogg', "team" = 'sound/vox_fem/team.ogg', +"technology" = 'sound/vox_fem/technology.ogg', "telecomms" = 'sound/vox_fem/telecomms.ogg', +"teleport" = 'sound/vox_fem/teleport.ogg', +"teleported" = 'sound/vox_fem/teleported.ogg', +"teleporter" = 'sound/vox_fem/teleporter.ogg', +"teleporting" = 'sound/vox_fem/teleporting.ogg', "temperature" = 'sound/vox_fem/temperature.ogg', "temporal" = 'sound/vox_fem/temporal.ogg', "ten" = 'sound/vox_fem/ten.ogg', "terminal" = 'sound/vox_fem/terminal.ogg', "terminated" = 'sound/vox_fem/terminated.ogg', "termination" = 'sound/vox_fem/termination.ogg', +"tesla" = 'sound/vox_fem/tesla.ogg', "test" = 'sound/vox_fem/test.ogg', "that" = 'sound/vox_fem/that.ogg', "the" = 'sound/vox_fem/the.ogg', @@ -716,6 +794,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "tide" = 'sound/vox_fem/tide.ogg', "time" = 'sound/vox_fem/time.ogg', "to" = 'sound/vox_fem/to.ogg', +"tool" = 'sound/vox_fem/tool.ogg', "top" = 'sound/vox_fem/top.ogg', "topside" = 'sound/vox_fem/topside.ogg', "touch" = 'sound/vox_fem/touch.ogg', @@ -735,6 +814,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "twenty" = 'sound/vox_fem/twenty.ogg', "two" = 'sound/vox_fem/two.ogg', "u" = 'sound/vox_fem/u.ogg', +"unathi" = 'sound/vox_fem/unathi.ogg', "unauthorized" = 'sound/vox_fem/unauthorized.ogg', "under" = 'sound/vox_fem/under.ogg', "uniform" = 'sound/vox_fem/uniform.ogg', @@ -753,13 +833,16 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "used" = 'sound/vox_fem/used.ogg', "user" = 'sound/vox_fem/user.ogg', "v" = 'sound/vox_fem/v.ogg', +"vacant" = 'sound/vox_fem/vacant.ogg', "vacate" = 'sound/vox_fem/vacate.ogg', "valid" = 'sound/vox_fem/valid.ogg', "vampire" = 'sound/vox_fem/vampire.ogg', "vampires" = 'sound/vox_fem/vampires.ogg', "vapor" = 'sound/vox_fem/vapor.ogg', +"vault" = 'sound/vox_fem/vault.ogg', "vent" = 'sound/vox_fem/vent.ogg', "ventilation" = 'sound/vox_fem/ventilation.ogg', +"vents" = 'sound/vox_fem/vents.ogg', "victor" = 'sound/vox_fem/victor.ogg', "violated" = 'sound/vox_fem/violated.ogg', "violation" = 'sound/vox_fem/violation.ogg', @@ -767,6 +850,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "voltage" = 'sound/vox_fem/voltage.ogg', "vox" = 'sound/vox_fem/vox.ogg', "vox_login" = 'sound/vox_fem/vox_login.ogg', +"vulpkanin" = 'sound/vox_fem/vulpkanin.ogg', "w" = 'sound/vox_fem/w.ogg', "walk" = 'sound/vox_fem/walk.ogg', "wall" = 'sound/vox_fem/wall.ogg', @@ -783,12 +867,15 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "weapon" = 'sound/vox_fem/weapon.ogg', "weed" = 'sound/vox_fem/weed.ogg', "welcome" = 'sound/vox_fem/welcome.ogg', +"weld" = 'sound/vox_fem/weld.ogg', "west" = 'sound/vox_fem/west.ogg', "whiskey" = 'sound/vox_fem/whiskey.ogg', "white" = 'sound/vox_fem/white.ogg', "wiggle" = 'sound/vox_fem/wiggle.ogg', "wilco" = 'sound/vox_fem/wilco.ogg', "will" = 'sound/vox_fem/will.ogg', +"window" = 'sound/vox_fem/window.ogg', +"windows" = 'sound/vox_fem/windows.ogg', "with" = 'sound/vox_fem/with.ogg', "without" = 'sound/vox_fem/without.ogg', "wizard" = 'sound/vox_fem/wizard.ogg', @@ -807,6 +894,7 @@ var/list/vox_sounds = list("," = 'sound/vox_fem/,.ogg', "year" = 'sound/vox_fem/year.ogg', "yellow" = 'sound/vox_fem/yellow.ogg', "yes" = 'sound/vox_fem/yes.ogg', +"yet" = 'sound/vox_fem/yet.ogg', "you" = 'sound/vox_fem/you.ogg', "your" = 'sound/vox_fem/your.ogg', "yourself" = 'sound/vox_fem/yourself.ogg', diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 1706763b824..6ad3a69258d 100644 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -438,6 +438,14 @@ var/list/ghostteleportlocs = list() name = "Syndicate Infiltrator" icon_state = "shuttle" +/area/shuttle/trade + name = "Trade Shuttle" + icon_state = "shuttle" + requires_power = 0 + +/area/shuttle/trade/sol + name = "Sol Freighter" + /area/airtunnel1/ // referenced in airtunnel.dm:759 /area/dummy/ // Referenced in engine.dm:261 @@ -675,6 +683,14 @@ var/list/ghostteleportlocs = list() icon_state = "southeast" requires_power = 0 +/area/trader_station + name = "Trade Base" + icon_state = "yellow" + requires_power = 0 + +/area/trader_station/sol + name = "Jupiter Station 6" + /area/vox_station/mining name = "\improper Nearby Mining Asteroid" icon_state = "north" diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 92c894cba10..b169deeee10 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -331,4 +331,4 @@ /atom/movable/CanPass(atom/movable/mover, turf/target, height=1.5) if(buckled_mob == mover) return 1 - return ..() \ No newline at end of file + return ..() diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index a15170a3956..93d7cc473dc 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -133,19 +133,20 @@ var/global/list/bad_blocks[0] ResetUI(1) // Hair // FIXME: Species-specific defaults pls - if(!character.h_style) - character.h_style = "Skinhead" - var/hair = hair_styles_list.Find(character.h_style) + var/obj/item/organ/external/head/H = character.get_organ("head") + if(!H.h_style) + H.h_style = "Skinhead" + var/hair = hair_styles_list.Find(H.h_style) // Facial Hair - if(!character.f_style) - character.f_style = "Shaved" - var/beard = facial_hair_styles_list.Find(character.f_style) + if(!H.f_style) + H.f_style = "Shaved" + var/beard = facial_hair_styles_list.Find(H.f_style) // Head Accessory - if(!character.ha_style) - character.ha_style = "None" - var/headacc = head_accessory_styles_list.Find(character.ha_style) + if(!H.ha_style) + H.ha_style = "None" + var/headacc = head_accessory_styles_list.Find(H.ha_style) /*// Body Accessory if(!character.body_accessory) @@ -157,13 +158,13 @@ var/global/list/bad_blocks[0] character.m_style = "None" var/marks = marking_styles_list.Find(character.m_style) - SetUIValueRange(DNA_UI_HAIR_R, character.r_hair, 255, 1) - SetUIValueRange(DNA_UI_HAIR_G, character.g_hair, 255, 1) - SetUIValueRange(DNA_UI_HAIR_B, character.b_hair, 255, 1) + SetUIValueRange(DNA_UI_HAIR_R, H.r_hair, 255, 1) + SetUIValueRange(DNA_UI_HAIR_G, H.g_hair, 255, 1) + SetUIValueRange(DNA_UI_HAIR_B, H.b_hair, 255, 1) - SetUIValueRange(DNA_UI_BEARD_R, character.r_facial, 255, 1) - SetUIValueRange(DNA_UI_BEARD_G, character.g_facial, 255, 1) - SetUIValueRange(DNA_UI_BEARD_B, character.b_facial, 255, 1) + SetUIValueRange(DNA_UI_BEARD_R, H.r_facial, 255, 1) + SetUIValueRange(DNA_UI_BEARD_G, H.g_facial, 255, 1) + SetUIValueRange(DNA_UI_BEARD_B, H.b_facial, 255, 1) SetUIValueRange(DNA_UI_EYES_R, character.r_eyes, 255, 1) SetUIValueRange(DNA_UI_EYES_G, character.g_eyes, 255, 1) @@ -173,9 +174,9 @@ var/global/list/bad_blocks[0] SetUIValueRange(DNA_UI_SKIN_G, character.g_skin, 255, 1) SetUIValueRange(DNA_UI_SKIN_B, character.b_skin, 255, 1) - SetUIValueRange(DNA_UI_HACC_R, character.r_headacc, 255, 1) - SetUIValueRange(DNA_UI_HACC_G, character.g_headacc, 255, 1) - SetUIValueRange(DNA_UI_HACC_B, character.b_headacc, 255, 1) + SetUIValueRange(DNA_UI_HACC_R, H.r_headacc, 255, 1) + SetUIValueRange(DNA_UI_HACC_G, H.g_headacc, 255, 1) + SetUIValueRange(DNA_UI_HACC_B, H.b_headacc, 255, 1) SetUIValueRange(DNA_UI_MARK_R, character.r_markings, 255, 1) SetUIValueRange(DNA_UI_MARK_G, character.g_markings, 255, 1) diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm index 781c3a1d230..53f248d1e91 100644 --- a/code/game/dna/dna2_helpers.dm +++ b/code/game/dna/dna2_helpers.dm @@ -131,13 +131,14 @@ src.dna.UpdateUI() dna.check_integrity() var/mob/living/carbon/human/H = src - H.r_hair = dna.GetUIValueRange(DNA_UI_HAIR_R, 255) - H.g_hair = dna.GetUIValueRange(DNA_UI_HAIR_G, 255) - H.b_hair = dna.GetUIValueRange(DNA_UI_HAIR_B, 255) + var/obj/item/organ/external/head/head_organ = H.get_organ("head") + head_organ.r_hair = dna.GetUIValueRange(DNA_UI_HAIR_R, 255) + head_organ.g_hair = dna.GetUIValueRange(DNA_UI_HAIR_G, 255) + head_organ.b_hair = dna.GetUIValueRange(DNA_UI_HAIR_B, 255) - H.r_facial = dna.GetUIValueRange(DNA_UI_BEARD_R, 255) - H.g_facial = dna.GetUIValueRange(DNA_UI_BEARD_G, 255) - H.b_facial = dna.GetUIValueRange(DNA_UI_BEARD_B, 255) + head_organ.r_facial = dna.GetUIValueRange(DNA_UI_BEARD_R, 255) + head_organ.g_facial = dna.GetUIValueRange(DNA_UI_BEARD_G, 255) + head_organ.b_facial = dna.GetUIValueRange(DNA_UI_BEARD_B, 255) H.r_skin = dna.GetUIValueRange(DNA_UI_SKIN_R, 255) H.g_skin = dna.GetUIValueRange(DNA_UI_SKIN_G, 255) @@ -147,9 +148,9 @@ H.g_eyes = dna.GetUIValueRange(DNA_UI_EYES_G, 255) H.b_eyes = dna.GetUIValueRange(DNA_UI_EYES_B, 255) - H.r_headacc = dna.GetUIValueRange(DNA_UI_HACC_R, 255) - H.g_headacc = dna.GetUIValueRange(DNA_UI_HACC_G, 255) - H.b_headacc = dna.GetUIValueRange(DNA_UI_HACC_B, 255) + head_organ.r_headacc = dna.GetUIValueRange(DNA_UI_HACC_R, 255) + head_organ.g_headacc = dna.GetUIValueRange(DNA_UI_HACC_G, 255) + head_organ.b_headacc = dna.GetUIValueRange(DNA_UI_HACC_B, 255) H.r_markings = dna.GetUIValueRange(DNA_UI_MARK_R, 255) H.g_markings = dna.GetUIValueRange(DNA_UI_MARK_G, 255) @@ -168,17 +169,17 @@ //Hair var/hair = dna.GetUIValueRange(DNA_UI_HAIR_STYLE,hair_styles_list.len) if((0 < hair) && (hair <= hair_styles_list.len)) - H.h_style = hair_styles_list[hair] + head_organ.h_style = hair_styles_list[hair] //Facial Hair var/beard = dna.GetUIValueRange(DNA_UI_BEARD_STYLE,facial_hair_styles_list.len) if((0 < beard) && (beard <= facial_hair_styles_list.len)) - H.f_style = facial_hair_styles_list[beard] + head_organ.f_style = facial_hair_styles_list[beard] //Head Accessories var/headacc = dna.GetUIValueRange(DNA_UI_HACC_STYLE,head_accessory_styles_list.len) if((0 < headacc) && (headacc <= head_accessory_styles_list.len)) - H.ha_style = head_accessory_styles_list[headacc] + head_organ.ha_style = head_accessory_styles_list[headacc] //Markings var/marks = dna.GetUIValueRange(DNA_UI_MARK_STYLE,marking_styles_list.len) diff --git a/code/game/dna/genes/powers.dm b/code/game/dna/genes/powers.dm index 2aca5878f83..eb33cef7ccf 100644 --- a/code/game/dna/genes/powers.dm +++ b/code/game/dna/genes/powers.dm @@ -144,8 +144,8 @@ /datum/dna/gene/basic/tk name="Telekenesis" - activation_messages=list("You feel smarter.") - deactivation_messages=("You feel dumber.") + activation_messages = list("You feel smarter.") + deactivation_messages = list("You feel dumber.") mutation=TK activation_prob=10 diff --git a/code/game/dna/genes/vg_powers.dm b/code/game/dna/genes/vg_powers.dm index 8a854c7980d..13f334c010b 100644 --- a/code/game/dna/genes/vg_powers.dm +++ b/code/game/dna/genes/vg_powers.dm @@ -37,61 +37,7 @@ to_chat(usr, "\red You can't change your appearance right now!") return var/mob/living/carbon/human/M=usr - - var/new_facial = input("Please select facial hair color.", "Character Generation",rgb(M.r_facial,M.g_facial,M.b_facial)) as null|color - if(new_facial) - M.r_facial = hex2num(copytext(new_facial, 2, 4)) - M.g_facial = hex2num(copytext(new_facial, 4, 6)) - M.b_facial = hex2num(copytext(new_facial, 6, 8)) - - var/new_hair = input("Please select hair color.", "Character Generation",rgb(M.r_hair,M.g_hair,M.b_hair)) as null|color - if(new_facial) - M.r_hair = hex2num(copytext(new_hair, 2, 4)) - M.g_hair = hex2num(copytext(new_hair, 4, 6)) - M.b_hair = hex2num(copytext(new_hair, 6, 8)) - - var/new_eyes = input("Please select eye color.", "Character Generation",rgb(M.r_eyes,M.g_eyes,M.b_eyes)) as null|color - if(new_eyes) - M.r_eyes = hex2num(copytext(new_eyes, 2, 4)) - M.g_eyes = hex2num(copytext(new_eyes, 4, 6)) - M.b_eyes = hex2num(copytext(new_eyes, 6, 8)) - - var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation", "[35-M.s_tone]") as null|text - - if (!new_tone) - new_tone = 35 - M.s_tone = max(min(round(text2num(new_tone)), 220), 1) - M.s_tone = -M.s_tone + 35 - - // hair - var/list/all_hairs = subtypesof(/datum/sprite_accessory/hair) - var/list/hairs = list() - - // loop through potential hairs - for(var/x in all_hairs) - var/datum/sprite_accessory/hair/H = new x // create new hair datum based on type x - hairs.Add(H.name) // add hair name to hairs - qdel(H) // delete the hair after it's all done - - var/new_style = input("Please select hair style", "Character Generation",M.h_style) as null|anything in hairs - - // if new style selected (not cancel) - if (new_style) - M.h_style = new_style - - // facial hair - var/list/all_fhairs = subtypesof(/datum/sprite_accessory/facial_hair) - var/list/fhairs = list() - - for(var/x in all_fhairs) - var/datum/sprite_accessory/facial_hair/H = new x - fhairs.Add(H.name) - qdel(H) - - new_style = input("Please select facial style", "Character Generation",M.f_style) as null|anything in fhairs - - if(new_style) - M.f_style = new_style + var/obj/item/organ/external/head/head_organ = M.get_organ("head") var/new_gender = alert(usr, "Please select gender.", "Character Generation", "Male", "Female") if (new_gender) @@ -99,8 +45,93 @@ M.change_gender(MALE) else M.change_gender(FEMALE) + + var/new_eyes = input("Please select eye color.", "Character Generation", rgb(M.r_eyes,M.g_eyes,M.b_eyes)) as null|color + if(new_eyes) + M.r_eyes = hex2num(copytext(new_eyes, 2, 4)) + M.g_eyes = hex2num(copytext(new_eyes, 4, 6)) + M.b_eyes = hex2num(copytext(new_eyes, 6, 8)) + M.change_eye_color(M.r_eyes, M.g_eyes, M.b_eyes) + + // hair + var/list/valid_hairstyles = M.generate_valid_hairstyles() + var/new_style = input("Please select hair style", "Character Generation", head_organ.h_style) as null|anything in valid_hairstyles + + // if new style selected (not cancel) + if (new_style) + head_organ.h_style = new_style + + var/new_hair = input("Please select hair color.", "Character Generation", rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair)) as null|color + if(new_hair) + head_organ.r_hair = hex2num(copytext(new_hair, 2, 4)) + head_organ.g_hair = hex2num(copytext(new_hair, 4, 6)) + head_organ.b_hair = hex2num(copytext(new_hair, 6, 8)) + + // facial hair + var/list/valid_facial_hairstyles = M.generate_valid_facial_hairstyles() + new_style = input("Please select facial style", "Character Generation", head_organ.f_style) as null|anything in valid_facial_hairstyles + + if(new_style) + head_organ.f_style = new_style + + var/new_facial = input("Please select facial hair color.", "Character Generation", rgb(head_organ.r_facial, head_organ.g_facial, head_organ.b_facial)) as null|color + if(new_facial) + head_organ.r_facial = hex2num(copytext(new_facial, 2, 4)) + head_organ.g_facial = hex2num(copytext(new_facial, 4, 6)) + head_organ.b_facial = hex2num(copytext(new_facial, 6, 8)) + + //Head accessory. + if(head_organ.species.bodyflags & HAS_HEAD_ACCESSORY) + var/list/valid_head_accessories = M.generate_valid_head_accessories() + var/new_head_accessory = input("Please select head accessory style", "Character Generation", head_organ.ha_style) as null|anything in valid_head_accessories + if(new_head_accessory) + head_organ.ha_style = new_head_accessory + + var/new_head_accessory_colour = input("Please select head accessory colour.", "Character Generation", rgb(head_organ.r_headacc, head_organ.g_headacc, head_organ.b_headacc)) as null|color + if(new_head_accessory_colour) + head_organ.r_headacc = hex2num(copytext(new_head_accessory_colour, 2, 4)) + head_organ.g_headacc = hex2num(copytext(new_head_accessory_colour, 4, 6)) + head_organ.b_headacc = hex2num(copytext(new_head_accessory_colour, 6, 8)) + + //Body markings. + if(M.species.bodyflags & HAS_MARKINGS) + var/list/valid_markings = M.generate_valid_markings() + var/new_marking = input("Please select marking style", "Character Generation", M.m_style) as null|anything in valid_markings + if(new_marking) + M.m_style = new_marking + + var/new_marking_colour = input("Please select marking colour.", "Character Generation", rgb(M.r_markings, M.g_markings, M.b_markings)) as null|color + if(new_marking_colour) + M.r_markings = hex2num(copytext(new_marking_colour, 2, 4)) + M.g_markings = hex2num(copytext(new_marking_colour, 4, 6)) + M.b_markings = hex2num(copytext(new_marking_colour, 6, 8)) + + //Body accessory. + if(M.species.tail && M.species.bodyflags & HAS_TAIL) + var/list/valid_body_accessories = M.generate_valid_body_accessories() + if(valid_body_accessories.len > 1) //By default valid_body_accessories will always have at the very least a 'none' entry populating the list, even if the user's species is not present in any of the list items. + var/new_body_accessory = input("Please select body accessory style", "Character Generation", M.body_accessory) as null|anything in valid_body_accessories + if(new_body_accessory) + M.body_accessory = body_accessory_by_name[new_body_accessory] + + //Skin tone. + if(M.species.bodyflags & HAS_SKIN_TONE) + var/new_tone = input("Please select skin tone level: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation", "[M.s_tone]") as null|text + if (!new_tone) + new_tone = 35 + M.s_tone = 35 - max(min(round(text2num(new_tone)), 220), 1) + + //Skin colour. + if(M.species.bodyflags & HAS_SKIN_COLOR) + var/new_body_colour = input("Please select body colour.", "Character Generation", rgb(M.r_skin, M.g_skin, M.b_skin)) as null|color + if(new_body_colour) + M.r_skin = hex2num(copytext(new_body_colour, 2, 4)) + M.g_skin = hex2num(copytext(new_body_colour, 4, 6)) + M.b_skin = hex2num(copytext(new_body_colour, 6, 8)) + + M.force_update_limbs() M.regenerate_icons() - M.check_dna() + M.update_dna() M.visible_message("\blue \The [src] morphs and changes [M.get_visible_gender() == MALE ? "his" : M.get_visible_gender() == FEMALE ? "her" : "their"] appearance!", "\blue You change your appearance!", "\red Oh, god! What the hell was that? It sounded like flesh getting squished and bone ground into a different shape!") diff --git a/code/game/gamemodes/blob/blobs/blob_mobs.dm b/code/game/gamemodes/blob/blobs/blob_mobs.dm index a35505470fa..d60748f8dae 100644 --- a/code/game/gamemodes/blob/blobs/blob_mobs.dm +++ b/code/game/gamemodes/blob/blobs/blob_mobs.dm @@ -68,6 +68,7 @@ ..() /mob/living/simple_animal/hostile/blob/blobspore/proc/Zombify(var/mob/living/carbon/human/H) + var/obj/item/organ/external/head/head_organ = H.get_organ("head") is_zombie = 1 if(H.wear_suit) var/obj/item/clothing/suit/armor/A = H.wear_suit @@ -82,7 +83,7 @@ icon = H.icon speak_emote = list("groans") icon_state = "zombie2_s" - H.h_style = null + head_organ.h_style = null H.update_hair() human_overlays = H.overlays update_icons() @@ -90,6 +91,8 @@ loc.visible_message("The corpse of [H.name] suddenly rises!") /mob/living/simple_animal/hostile/blob/blobspore/death() + ..() + // On death, create a small smoke of harmful gas (s-Acid) var/datum/effect/system/chem_smoke_spread/S = new var/turf/location = get_turf(src) @@ -107,7 +110,6 @@ S.set_up(reagents, 1, 1, location, 15, 1) // only 1-2 smoke cloud S.start() - ghostize() qdel(src) /mob/living/simple_animal/hostile/blob/blobspore/Destroy() diff --git a/code/game/gamemodes/changeling/changeling.dm b/code/game/gamemodes/changeling/changeling.dm index caead8e0a61..4c6a0881d36 100644 --- a/code/game/gamemodes/changeling/changeling.dm +++ b/code/game/gamemodes/changeling/changeling.dm @@ -14,9 +14,6 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon" required_enemies = 1 recommended_enemies = 4 - uplink_welcome = "Syndicate Uplink Console:" - uplink_uses = 20 - var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target var/const/prob_right_murder_target_h = 50 // upper bound on probability of naimg the right assassination target diff --git a/code/game/gamemodes/changeling/changeling_power.dm b/code/game/gamemodes/changeling/changeling_power.dm index 6d03a864692..8e8e824d85e 100644 --- a/code/game/gamemodes/changeling/changeling_power.dm +++ b/code/game/gamemodes/changeling/changeling_power.dm @@ -73,6 +73,12 @@ return 0 return 1 +/obj/effect/proc_holder/changeling/proc/transfer_changeling_powers(var/mob/living/carbon/user, var/mob/living/carbon/target) + if(istype(target, /mob/living/carbon)) // so we don't runtime, I don't even know why it's necessary as it needs a grab + var/datum/changeling/c = user.mind.changeling + var/datum/changeling/t = target.mind.changeling + c.purchasedpowers = t.purchasedpowers + //used in /mob/Stat() /obj/effect/proc_holder/changeling/proc/can_be_used_by(var/mob/user) if(!ishuman(user)) diff --git a/code/game/gamemodes/changeling/powers/swap_form.dm b/code/game/gamemodes/changeling/powers/swap_form.dm index ad8b9381dff..188c5fb437b 100644 --- a/code/game/gamemodes/changeling/powers/swap_form.dm +++ b/code/game/gamemodes/changeling/powers/swap_form.dm @@ -50,6 +50,8 @@ user.key = ghost.key user.Paralyse(2) - user.remove_language("Changeling") target.add_language("Changeling") + user.remove_language("Changeling") + transfer_changeling_powers(user, target) + to_chat(target, "Our genes cry out as we swap our [user] form for [target].") diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm index 07ead9ebd6d..f85f123d9ea 100644 --- a/code/game/gamemodes/cult/cult.dm +++ b/code/game/gamemodes/cult/cult.dm @@ -34,9 +34,6 @@ required_enemies = 3 recommended_enemies = 4 - uplink_welcome = "Nar-Sie Uplink Console:" - uplink_uses = 20 - var/datum/mind/sacrifice_target = null var/finished = 0 diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm index e3e16efc4e6..a5dcef8d4e7 100644 --- a/code/game/gamemodes/extended/extended.dm +++ b/code/game/gamemodes/extended/extended.dm @@ -3,9 +3,6 @@ config_tag = "extended" required_players = 0 - uplink_welcome = "Syndicate Uplink Console:" - uplink_uses = 20 - /datum/game_mode/announce() to_chat(world, "The current game mode is - Extended Role-Playing!") to_chat(world, "Just have fun and role-play!") diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 00ff9c707c6..a16d120bb4d 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -30,7 +30,7 @@ var/newscaster_announcements = null var/ert_disabled = 0 var/uplink_welcome = "Syndicate Uplink Console:" - var/uplink_uses = 10 + var/uplink_uses = 20 var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds) var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm index 28ebdeae677..952b43d5f37 100644 --- a/code/game/gamemodes/heist/heist.dm +++ b/code/game/gamemodes/heist/heist.dm @@ -94,6 +94,7 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' newname += pick(list("ti","hi","ki","ya","ta","ha","ka","ya","chi","cha","kah")) var/mob/living/carbon/human/vox = newraider.current + var/obj/item/organ/external/head/head_organ = vox.get_organ("head") vox.real_name = capitalize(newname) vox.name = vox.real_name @@ -105,8 +106,8 @@ var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' vox.add_language("Vox-pidgin") vox.add_language("Galactic Common") vox.add_language("Tradeband") - vox.h_style = "Short Vox Quills" - vox.f_style = "Shaved" + head_organ.h_style = "Short Vox Quills" + head_organ.f_style = "Shaved" for(var/obj/item/organ/external/limb in vox.organs) limb.status &= ~(ORGAN_DESTROYED | ORGAN_ROBOT) diff --git a/code/game/gamemodes/malfunction/Malf_Modules.dm b/code/game/gamemodes/malfunction/Malf_Modules.dm index 803a7ba0d80..3c8b96935ec 100644 --- a/code/game/gamemodes/malfunction/Malf_Modules.dm +++ b/code/game/gamemodes/malfunction/Malf_Modules.dm @@ -72,7 +72,7 @@ rcd light flash thingy on matter drain if(T.z in config.station_levels) // Increase health by 37.5% of original max, decrease delays between shots to 66% turret.health += initial(turret.health) * 3 / 8 - turret.eprojectile = /obj/item/projectile/beam/heavylaser //Once you see it, you will know what it means to FEAR. + turret.eprojectile = /obj/item/projectile/beam/laser/heavylaser //Once you see it, you will know what it means to FEAR. turret.eshot_sound = 'sound/weapons/lasercannonfire.ogg' to_chat(src, "Turrets upgraded.") /datum/AI_Module/large/destroy_rcd diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index d5d3c3e87e1..214c5210c14 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -8,9 +8,6 @@ required_enemies = 1 recommended_enemies = 1 - uplink_welcome = "Crazy AI Uplink Console:" - uplink_uses = 10 - var/AI_win_timeleft = 1500 //started at 1500, in case I change this for testing round end. var/malf_mode_declared = 0 var/station_captured = 0 diff --git a/code/game/gamemodes/meteor/meteor.dm b/code/game/gamemodes/meteor/meteor.dm index a8c8fec6f51..6df3df1dd19 100644 --- a/code/game/gamemodes/meteor/meteor.dm +++ b/code/game/gamemodes/meteor/meteor.dm @@ -5,9 +5,6 @@ var/wave = 1 required_players = 35 - uplink_welcome = "EVIL METEOR Uplink Console:" - uplink_uses = 10 - /datum/game_mode/meteor/announce() to_chat(world, "The current game mode is - Meteor!") diff --git a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm index 5107ff7cab4..930ec3df35d 100644 --- a/code/game/gamemodes/miniantags/abduction/abduction_gear.dm +++ b/code/game/gamemodes/miniantags/abduction/abduction_gear.dm @@ -14,7 +14,7 @@ origin_tech = "materials=5;biotech=4;powerstorage=5;abductor=3" armor = list(melee = 15, bullet = 15, laser = 15, energy = 15, bomb = 15, bio = 15, rad = 15) action_button_name = "Activate" - action_button_is_hands_free = 1 + action_button_custom_type = /datum/action/item_action/hands_free var/mode = VEST_STEALTH var/stealth_active = 0 var/combat_cooldown = 10 @@ -308,14 +308,7 @@ icon_state = "alienpistol" item_state = "alienpistol" origin_tech = "combat=5;materials=4;powerstorage=3;abductor=3" - -/obj/item/weapon/gun/energy/decloner/alien/special_check(user) - if(istype(user, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - if(H.get_species() != "Abductor") - to_chat(user, "UNAUTHORIZED -- UNAUTHORIZED") - return 0 - return 1 + restricted_species = list("Abductor") /obj/item/weapon/paper/abductor name = "Dissection Guide" @@ -631,4 +624,4 @@ Congratulations! You are now trained for xenobiology research!"} icon_state = "abductor" icon_closed = "abductor" icon_opened = "abductoropen" - material_drop = /obj/item/stack/sheet/mineral/abductor \ No newline at end of file + material_drop = /obj/item/stack/sheet/mineral/abductor diff --git a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm index 44b37ed22e5..8adf07a60ba 100644 --- a/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm +++ b/code/game/gamemodes/miniantags/abduction/machinery/experiment.dm @@ -43,12 +43,28 @@ experimentUI(user) +/obj/machinery/abductor/experiment/proc/dissection_icon(mob/living/carbon/human/H) + var/icon/I = icon(H.stand_icon) + + var/icon/splat = icon(H.species.damage_overlays, "30") + splat.Blend(icon(H.species.damage_mask, "torso"), ICON_MULTIPLY) + splat.Blend(H.species.blood_color, ICON_MULTIPLY) + I.Blend(splat, ICON_OVERLAY) + + return I + /obj/machinery/abductor/experiment/proc/experimentUI(mob/user) var/dat dat += "

Experiment

" if(occupant) - dat += "
" - dat += "" + var/icon/H = icon(dissection_icon(occupant), dir = SOUTH) + if(H) + user << browse_rsc(H, "dissection_img.png") + dat += "
" + dat += "" + dat += "" + else + dat += "ERR: Unable to retrieve image data for occupant." dat += "Probe
" dat += "Dissect
" dat += "Analyze
" diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm index 315e48ba983..5cfe1324849 100644 --- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm +++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm @@ -68,6 +68,7 @@ projectilesound = 'sound/weapons/taser2.ogg' AIStatus = AI_OFF var/resources = 0 //Resource points, generated by consuming metal/glass + loot = list(/obj/effect/decal/cleanable/blood/gibs/robot, /obj/item/weapon/ore/bluespace_crystal/artificial) /mob/living/simple_animal/hostile/swarmer/Login() ..() @@ -91,7 +92,6 @@ /mob/living/simple_animal/hostile/swarmer/death() ..() - new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) ghostize() qdel(src) @@ -155,30 +155,17 @@ S.DisIntegrate(src) toggle_cam(S, 0) -/obj/machinery/particle_accelerator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) +/obj/structure/particle_accelerator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) to_chat(S, "Disrupting the power grid would bring no benefit to us. Aborting.") -/obj/structure/particle_accelerator/fuel_chamber/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) +/obj/machinery/particle_accelerator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) // Since the console is still parented to this to_chat(S, "Disrupting the power grid would bring no benefit to us. Aborting.") -/obj/structure/particle_accelerator/particle_emitter/center/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) - to_chat(S, "Disrupting the power grid would bring no benefit to us. Aborting.") - -/obj/structure/particle_accelerator/particle_emitter/left/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) - to_chat(S, "Disrupting the power grid would bring no benefit to us. Aborting.") - -/obj/structure/particle_accelerator/particle_emitter/right/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) - to_chat(S, "Disrupting the power grid would bring no benefit to us. Aborting.") - -/obj/structure/particle_accelerator/particle_emitter/end_cap/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) - to_chat(S, "Disrupting the power grid would bring no benefit to us. Aborting.") - -/obj/structure/particle_accelerator/particle_emitter/power_box/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) - to_chat(S, "Disrupting the power grid would bring no benefit to us. Aborting.") - - /obj/machinery/field/generator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) - S.DisIntegrate(src) + if(!active) + S.DisIntegrate(src) + return + to_chat(S, "An inhospitable area may be created as a result of destroying this object. Aborting.") /obj/machinery/gravity_generator/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) S.DisIntegrate(src) @@ -233,7 +220,7 @@ /turf/simulated/wall/swarmer_act(mob/living/simple_animal/hostile/swarmer/S) for(var/turf/T in range(1, src)) - if(istype(T, /turf/space) || istype(T.loc, /area/space)) + if(istype(T, /turf/space) || istype(T.loc, /area/space) || istype(T, /turf/simulated/floor/plating/airless)) to_chat(S, "Destroying this object has the potential to cause a hull breach. Aborting.") return ..() diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm index dbb56523e4e..c50b4b04700 100644 --- a/code/game/gamemodes/miniantags/guardian/guardian.dm +++ b/code/game/gamemodes/miniantags/guardian/guardian.dm @@ -785,7 +785,7 @@ /obj/item/weapon/guardiancreator/tech name = "holoparasite injector" desc = "It contains alien nanoswarm of unknown origin. Though capable of near sorcerous feats via use of hardlight holograms and nanomachines, it requires an organic host as a home base and source of fuel." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/obj/hypo.dmi' icon_state = "combat_hypo" theme = "tech" mob_name = "Holoparasite" diff --git a/code/game/gamemodes/miniantags/slaughter/slaughter.dm b/code/game/gamemodes/miniantags/slaughter/slaughter.dm index 6f97740f8d5..e255394e7af 100644 --- a/code/game/gamemodes/miniantags/slaughter/slaughter.dm +++ b/code/game/gamemodes/miniantags/slaughter/slaughter.dm @@ -42,6 +42,7 @@ var/cooldown = 0 var/gorecooldown = 0 var/vialspawned = FALSE + loot = list(/obj/effect/decal/cleanable/blood/innards, /obj/effect/decal/cleanable/blood, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic, /obj/item/organ/internal/heart/demon) var/playstyle_string = "You are the Slaughter Demon, a terrible creature from another existence. You have a single desire: To kill. \ You may Ctrl+Click on blood pools to travel through them, appearing and dissaapearing from the station at will. \ Pulling a dead or critical mob while you enter a pool will pull them in with you, allowing you to feast. \ @@ -79,17 +80,14 @@ else speed = 0 +/obj/effect/decal/cleanable/blood/innards + icon = 'icons/obj/surgery.dmi' + icon_state = "innards" + name = "pile of viscera" + desc = "A repulsive pile of guts and gore." + /mob/living/simple_animal/slaughter/death() ..() - var/obj/effect/decal/cleanable/blood/innards = new (get_turf(src)) - innards.icon = 'icons/obj/surgery.dmi' - innards.icon_state = "innards" - innards.name = "pile of viscera" - innards.desc = "A repulsive pile of guts and gore." - new /obj/effect/decal/cleanable/blood(loc) - new /obj/effect/gibspawner/generic(get_turf(src)) - new /obj/effect/gibspawner/generic(get_turf(src)) - new /obj/item/organ/internal/heart/demon(loc) playsound(get_turf(src),'sound/misc/demon_dies.ogg', 200, 1) visible_message("[src] screams in anger as it collapses into a puddle of viscera, its most recent meals spilling out of it.") for(var/mob/living/M in consumed_mobs) diff --git a/code/game/gamemodes/mutiny/mutiny.dm b/code/game/gamemodes/mutiny/mutiny.dm index 92b45e223a5..73876652e23 100644 --- a/code/game/gamemodes/mutiny/mutiny.dm +++ b/code/game/gamemodes/mutiny/mutiny.dm @@ -19,9 +19,6 @@ datum/game_mode/mutiny required_players = 20 ert_disabled = 1 - uplink_welcome = "Mutineers Uplink Console:" - uplink_uses = 0 - New() fluff = new(src) diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index e10dce617fa..9ebd3a28ab7 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -11,9 +11,6 @@ proc/issyndicate(mob/living/M as mob) required_enemies = 5 recommended_enemies = 5 - uplink_welcome = "Corporate Backed Uplink Console:" - uplink_uses = 120 - var/const/agents_possible = 5 //If we ever need more syndicate agents. var/nukes_left = 1 // Call 3714-PRAY right now and order more nukes! Limited offer! @@ -133,6 +130,8 @@ proc/issyndicate(mob/living/M as mob) /datum/game_mode/proc/create_syndicate(var/datum/mind/synd_mind) // So we don't have inferior species as ops - randomize a human var/mob/living/carbon/human/M = synd_mind.current + var/obj/item/organ/external/head/head_organ = M.get_organ("head") + M.set_species("Human",1) M.dna.ready_dna(M) // Quadriplegic Nuke Ops won't be participating in the paralympics @@ -149,18 +148,18 @@ proc/issyndicate(mob/living/M as mob) if(prob(5)) facial_hair_style = pick(facial_hair_styles_list) - M.r_facial = hex2num(copytext(hair_c, 2, 4)) - M.g_facial = hex2num(copytext(hair_c, 4, 6)) - M.b_facial = hex2num(copytext(hair_c, 6, 8)) - M.r_hair = hex2num(copytext(hair_c, 2, 4)) - M.g_hair = hex2num(copytext(hair_c, 4, 6)) - M.b_hair = hex2num(copytext(hair_c, 6, 8)) + head_organ.r_facial = hex2num(copytext(hair_c, 2, 4)) + head_organ.g_facial = hex2num(copytext(hair_c, 4, 6)) + head_organ.b_facial = hex2num(copytext(hair_c, 6, 8)) + head_organ.r_hair = hex2num(copytext(hair_c, 2, 4)) + head_organ.g_hair = hex2num(copytext(hair_c, 4, 6)) + head_organ.b_hair = hex2num(copytext(hair_c, 6, 8)) M.r_eyes = hex2num(copytext(eye_c, 2, 4)) M.g_eyes = hex2num(copytext(eye_c, 4, 6)) M.b_eyes = hex2num(copytext(eye_c, 6, 8)) M.s_tone = skin_tone - M.h_style = hair_style - M.f_style = facial_hair_style + head_organ.h_style = hair_style + head_organ.f_style = facial_hair_style M.body_accessory = null /datum/game_mode/proc/prepare_syndicate_leader(var/datum/mind/synd_mind, var/nuke_code) diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 25b3727ec3a..6ef7350e4ad 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -247,6 +247,7 @@ var/list/potential_theft_objectives=subtypesof(/datum/theft_objective) \ return 1 return 0 +/datum/objective/protect/mindslave //subytpe for mindslave implants /datum/objective/hijack martyr_compatible = 0 //Technically you won't get both anyway. @@ -804,4 +805,50 @@ var/global/vox_kills = 0 //Used to check the Inviolate. explanation_text = "Follow the Inviolate. Minimise death and loss of resources." check_completion() if(vox_kills > MAX_VOX_KILLS) return 0 - return 1 \ No newline at end of file + return 1 + +// Traders + +/datum/objective/trade // Yes, I know there's no check_completion. The objectives exist only to tell the traders what to get. +/datum/objective/trade/proc/choose_target(var/station) + return + +/datum/objective/trade/stock // Stock or spare parts. + var/target_rating = 1 +/datum/objective/trade/stock/choose_target(var/station) + var/itemname + switch(rand(1,8)) + if(1) + target = /obj/item/weapon/stock_parts/cell + target_amount = 10 + target_rating = 3 + itemname = "ten high-capacity power cells" + if(2) + target = /obj/item/weapon/stock_parts/manipulator + target_amount = 20 + itemname = "twenty micro manipulators" + if(3) + target = /obj/item/weapon/stock_parts/matter_bin + target_amount = 20 + itemname = "twenty matter bins" + if(4) + target = /obj/item/weapon/stock_parts/micro_laser + target_amount = 15 + itemname = "fifteen micro-lasers" + if(5) + target = /obj/item/weapon/stock_parts/capacitor + target_amount = 15 + itemname = "fifteen capacitors" + if(6) + target = /obj/item/weapon/stock_parts/subspace/filter + target_amount = 4 + itemname = "four hyperwave filters" + if(7) + target = /obj/item/solar_assembly + target_amount = 10 + itemname = "ten solar panel assemblies" + if(8) + target = /obj/item/device/flash + target_amount = 6 + itemname = "six flashes" + explanation_text = "We are running low on spare parts. Trade for [itemname]." \ No newline at end of file diff --git a/code/game/gamemodes/steal_items.dm b/code/game/gamemodes/steal_items.dm index fd648b05c7d..25d2807432e 100644 --- a/code/game/gamemodes/steal_items.dm +++ b/code/game/gamemodes/steal_items.dm @@ -35,7 +35,7 @@ /datum/theft_objective/hoslaser name = "the head of security's recreated antique laser gun" - typepath = /obj/item/weapon/gun/energy/hos + typepath = /obj/item/weapon/gun/energy/gun/hos protected_jobs = list("Head Of Security") /datum/theft_objective/hand_tele @@ -244,4 +244,4 @@ datum/theft_objective/ai/check_special_completion(var/obj/item/device/aicard/C) typepath = /obj/item/stack/sheet/mineral/uranium min=10 max=30 - step=5 \ No newline at end of file + step=5 diff --git a/code/game/gamemodes/traitor/traitor.dm b/code/game/gamemodes/traitor/traitor.dm index c7fcd59dfe4..76a47e82749 100644 --- a/code/game/gamemodes/traitor/traitor.dm +++ b/code/game/gamemodes/traitor/traitor.dm @@ -16,10 +16,6 @@ required_enemies = 1 recommended_enemies = 4 - - uplink_welcome = "Syndicate Uplink Console:" - uplink_uses = 20 - var/traitors_possible = 4 //hard limit on traitors if scaling is turned off var/const/traitor_scaling_coeff = 5.0 //how much does the amount of players get divided by to determine traitors @@ -370,10 +366,11 @@ traitor_mind.special_role = null traitor_mind.som = null slaved.leave_serv_hud(traitor_mind) + for(var/datum/objective/protect/mindslave/MS in traitor_mind.objectives) + traitor_mind.objectives -= MS update_traitor_icons_removed(traitor_mind) -// to_chat(world, "Removed [traitor_mind.current.name] from traitor shit") - to_chat(traitor_mind.current, "\red The fog clouding your mind clears. You remember nothing from the moment you were implanted until now.(You don't remember who implanted you)") + to_chat(traitor_mind.current, "You are no longer a mindslave; you have complete and free control of your own faculties, once more!") /datum/game_mode/proc/assign_exchange_role(var/datum/mind/owner) //set faction diff --git a/code/game/gamemodes/vampire/traitor_vamp.dm b/code/game/gamemodes/vampire/traitor_vamp.dm index e94fbfeb199..9d4cb42b545 100644 --- a/code/game/gamemodes/vampire/traitor_vamp.dm +++ b/code/game/gamemodes/vampire/traitor_vamp.dm @@ -7,6 +7,7 @@ required_enemies = 1 // how many of each type are required recommended_enemies = 3 var/protected_species_vampire = list("Machine") + var/special_job_protection = list("Chaplain") //this must exist or else Chaplain can role for Vampire. That said, we don't want to rule out him getting traitor, either /datum/game_mode/traitor/vampire/announce() to_chat(world, "The current game mode is - Traitor+Vampire!") @@ -22,6 +23,8 @@ for(var/mob/new_player/player in player_list) if((player.mind in possible_vampires) && (player.client.prefs.species in protected_species_vampire)) possible_vampires -= player.mind + if((player.mind in possible_vampires) && (player.mind.assigned_role in special_job_protection)) + possible_vampires -= player.mind if(possible_vampires.len > 0) var/datum/mind/vampire = pick(possible_vampires) diff --git a/code/game/gamemodes/vampire/vampire.dm b/code/game/gamemodes/vampire/vampire.dm index 92f08ecc586..0d5ec7afcc4 100644 --- a/code/game/gamemodes/vampire/vampire.dm +++ b/code/game/gamemodes/vampire/vampire.dm @@ -4,6 +4,7 @@ var/list/datum/mind/vampires = list() var/list/datum/mind/vampire_enthralled = list() //those controlled by a vampire var/list/vampire_thralls = list() //vammpires controlling somebody + /datum/game_mode/vampire name = "vampire" config_tag = "vampire" @@ -14,9 +15,6 @@ required_enemies = 1 recommended_enemies = 4 - uplink_welcome = "Syndicate Uplink Console:" - uplink_uses = 20 - var/const/prob_int_murder_target = 50 // intercept names the assassination target half the time var/const/prob_right_murder_target_l = 25 // lower bound on probability of naming right assassination target var/const/prob_right_murder_target_h = 50 // upper bound on probability of naimg the right assassination target @@ -353,8 +351,7 @@ You are weak to holy things and starlight. Don't go into space and avoid the Cha vampire_mind.som = null slaved.leave_serv_hud(vampire_mind) update_vampire_icons_removed(vampire_mind) -// to_chat(world, "Removed [vampire_mind.current.name] from vampire shit") - to_chat(vampire_mind.current, "\red The fog clouding your mind clears. You remember nothing from the moment you were enthralled until now.") + vampire_mind.current.visible_message("[vampire_mind.current] looks as though a burden has been lifted!", "The dark fog in your mind clears as you regain control of your own faculties, you are no longer a vampire thrall!") if(vampire_mind.current.hud_used) vampire_mind.current.hud_used.remove_vampire_hud() diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index bc7ba9276f5..8e04d98504b 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -267,6 +267,10 @@ W.destroy() playsound(usr.loc, 'sound/effects/creepyshriek.ogg', 100, 1) + +/proc/isvampirethrall(mob/living/M as mob) + return istype(M) && M.mind && ticker && ticker.mode && (M.mind in ticker.mode.vampire_enthralled) + /obj/effect/proc_holder/spell/vampire/targetted/enthrall name = "Enthrall (300)" desc = "You use a large portion of your power to sway those loyal to none to be loyal to you only." diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm index eb1e8bce930..f2c10d7fc10 100644 --- a/code/game/gamemodes/wizard/rightandwrong.dm +++ b/code/game/gamemodes/wizard/rightandwrong.dm @@ -20,7 +20,7 @@ if(!summon_type) switch (randomizeguns) if("taser") - new /obj/item/weapon/gun/energy/advtaser(get_turf(H)) + new /obj/item/weapon/gun/energy/gun/advtaser(get_turf(H)) if("egun") new /obj/item/weapon/gun/energy/gun(get_turf(H)) if("laser") @@ -34,7 +34,7 @@ if("gyrojet") new /obj/item/weapon/gun/projectile/automatic/gyropistol(get_turf(H)) if("pulse") - new /obj/item/weapon/gun/energy/pulse_rifle(get_turf(H)) + new /obj/item/weapon/gun/energy/pulse(get_turf(H)) if("suppressed") new /obj/item/weapon/gun/projectile/automatic/pistol(get_turf(H)) new /obj/item/weapon/suppressor(get_turf(H)) @@ -71,7 +71,7 @@ if("turret") new /obj/item/weapon/gun/energy/gun/turret(get_turf(H)) if("pulsecarbine") - new /obj/item/weapon/gun/energy/pulse_rifle/carbine(get_turf(H)) + new /obj/item/weapon/gun/energy/pulse/carbine(get_turf(H)) if("decloner") new /obj/item/weapon/gun/energy/decloner(get_turf(H)) if("mindflayer") diff --git a/code/game/gamemodes/wizard/wizard.dm b/code/game/gamemodes/wizard/wizard.dm index 32d73ff33f7..9caa009f2e6 100644 --- a/code/game/gamemodes/wizard/wizard.dm +++ b/code/game/gamemodes/wizard/wizard.dm @@ -8,9 +8,6 @@ required_enemies = 1 recommended_enemies = 1 - uplink_welcome = "Wizardly Uplink Console:" - uplink_uses = 20 - var/use_huds = 0 var/finished = 0 var/but_wait_theres_more = 0 diff --git a/code/game/jobs/access.dm b/code/game/jobs/access.dm index e3649f5e445..c1ab67a3f03 100644 --- a/code/game/jobs/access.dm +++ b/code/game/jobs/access.dm @@ -98,6 +98,10 @@ /var/const/access_syndicate_leader = 151//Nuke Op Leader Access /var/const/access_vox = 152//Vox Access +//Trade Stations + +var/const/access_trade_sol = 160 + //MONEY /var/const/access_crate_cash = 200 @@ -267,6 +271,8 @@ return list(access_mailsorting, access_mining, access_mining_station, access_mineral_storeroom, access_cargo, access_qm) if(REGION_COMMAND) //command return list(access_heads, access_RC_announce, access_keycard_auth, access_change_ids, access_ai_upload, access_teleporter, access_eva, access_tcomsat, access_gateway, access_all_personal_lockers, access_heads_vault, access_blueshield, access_ntrep, access_hop, access_captain) + if(REGION_CENTCOMM) //because why the heck not + return get_all_centcom_access() + get_all_accesses() /proc/get_region_accesses_name(code) switch(code) @@ -286,6 +292,8 @@ return "Supply" if(REGION_COMMAND) //command return "Command" + if(REGION_CENTCOMM) //CC + return "CentComm" /proc/get_access_desc(A) @@ -600,4 +608,3 @@ proc/get_all_job_icons() //For all existing HUD icons return return "Unknown" //Return unknown if none of the above apply - diff --git a/code/game/jobs/job/security.dm b/code/game/jobs/job/security.dm index 3b13ceb6b64..31c82b2a203 100644 --- a/code/game/jobs/job/security.dm +++ b/code/game/jobs/job/security.dm @@ -77,7 +77,7 @@ H.equip_or_collect(new /obj/item/clothing/glasses/hud/security/sunglasses(H), slot_glasses) // H.equip_or_collect(new /obj/item/clothing/mask/gas(H), slot_wear_mask) //Grab one from the armory you donk H.equip_or_collect(new /obj/item/device/flash(H), slot_l_store) - H.equip_or_collect(new /obj/item/weapon/gun/energy/advtaser(H), slot_s_store) + H.equip_or_collect(new /obj/item/weapon/gun/energy/gun/advtaser(H), slot_s_store) if(H.backbag == 1) H.equip_or_collect(new /obj/item/weapon/storage/box/survival(H), slot_r_hand) H.equip_or_collect(new /obj/item/weapon/restraints/handcuffs(H), slot_l_hand) @@ -175,7 +175,7 @@ H.equip_to_slot_or_del(new /obj/item/clothing/head/helmet(H), slot_head) H.equip_or_collect(new /obj/item/device/pda/security(H), slot_wear_pda) H.equip_or_collect(new /obj/item/clothing/gloves/color/black(H), slot_gloves) - H.equip_or_collect(new /obj/item/weapon/gun/energy/advtaser(H), slot_s_store) + H.equip_or_collect(new /obj/item/weapon/gun/energy/gun/advtaser(H), slot_s_store) H.equip_or_collect(new /obj/item/device/flash(H), slot_l_store) if(H.backbag == 1) H.equip_or_collect(new /obj/item/weapon/storage/box/survival(H), slot_r_hand) @@ -249,7 +249,7 @@ H.equip_or_collect(new /obj/item/clothing/shoes/jackboots(H), slot_shoes) H.equip_or_collect(new /obj/item/device/pda/security(H), slot_wear_pda) H.equip_or_collect(new /obj/item/clothing/gloves/color/black(H), slot_gloves) - H.equip_or_collect(new /obj/item/weapon/gun/energy/advtaser(H), slot_s_store) + H.equip_or_collect(new /obj/item/weapon/gun/energy/gun/advtaser(H), slot_s_store) H.equip_or_collect(new /obj/item/device/flash(H), slot_l_store) if(H.backbag == 1) H.equip_or_collect(new /obj/item/weapon/storage/box/survival(H), slot_r_hand) diff --git a/code/game/jobs/job/supervisor.dm b/code/game/jobs/job/supervisor.dm index 2475df770b3..d0281c4b7c1 100644 --- a/code/game/jobs/job/supervisor.dm +++ b/code/game/jobs/job/supervisor.dm @@ -174,10 +174,10 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) if(H.backbag == 1) H.equip_or_collect(new /obj/item/weapon/storage/box/deathimp(H), slot_r_hand) - H.equip_or_collect(new /obj/item/weapon/gun/energy/blueshield(H), slot_l_hand) + H.equip_or_collect(new /obj/item/weapon/gun/energy/gun/blueshield(H), slot_l_hand) else H.equip_or_collect(new /obj/item/weapon/storage/box/deathimp(H.back), slot_in_backpack) - H.equip_or_collect(new /obj/item/weapon/gun/energy/blueshield(H.back), slot_in_backpack) + H.equip_or_collect(new /obj/item/weapon/gun/energy/gun/blueshield(H.back), slot_in_backpack) var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(H) L.imp_in = H L.implanted = 1 @@ -263,4 +263,4 @@ var/datum/announcement/minor/captain_announcement = new(do_newscast = 1) L.imp_in = H L.implanted = 1 H.sec_hud_set_implants() - return 1 \ No newline at end of file + return 1 diff --git a/code/game/jobs/job/support.dm b/code/game/jobs/job/support.dm index 210edd98c98..12f01822cde 100644 --- a/code/game/jobs/job/support.dm +++ b/code/game/jobs/job/support.dm @@ -244,6 +244,10 @@ H.equip_or_collect(new /obj/item/toy/crayon/rainbow(H), slot_in_backpack) H.equip_or_collect(new /obj/item/weapon/storage/fancy/crayons(H), slot_in_backpack) H.equip_or_collect(new /obj/item/weapon/reagent_containers/spray/waterflower(H), slot_in_backpack) + if(H.get_species() == "Machine") + var/obj/item/organ/internal/cyberimp/brain/clown_voice/implant + implant = new + implant.insert(H) H.mutations.Add(CLUMSY) H.dna.SetSEState(COMICBLOCK,1,1) genemutcheck(H,COMICBLOCK,null,MUTCHK_FORCED) diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 238e071ebe9..31ad9f145ee 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -73,6 +73,7 @@ if(M.environment_smash) M.do_attack_animation(src) visible_message("[M.name] smashes [src] apart!") + go_out() qdel(src) return @@ -183,7 +184,10 @@ data["dialysis"] = connected.filtering if (connected.beaker) data["isBeakerLoaded"] = 1 - data["beakerFreeSpace"] = round(connected.beaker.reagents.maximum_volume - connected.beaker.reagents.total_volume) + if(connected.beaker.reagents) + data["beakerFreeSpace"] = round(connected.beaker.reagents.maximum_volume - connected.beaker.reagents.total_volume) + else + data["beakerFreeSpace"] = 0 var/chemicals[0] for (var/re in connected.injection_chems) @@ -354,15 +358,21 @@ to_chat(occupant, "You no longer feel reliant on [R.name]!") occupant.reagents.addiction_list.Remove(R) + for(var/mob/M as mob in src) // makes sure that simple mobs don't get stuck inside a sleeper when they resist out of occupant's grasp + if(M == occupant) + continue + else + M.forceMove(src.loc) + updateDialog() return /obj/machinery/sleeper/blob_act() if(prob(75)) - for(var/atom/movable/A as mob|obj in src) - A.forceMove(src.loc) - A.blob_act() + var/atom/movable/A = occupant + go_out() + A.blob_act() qdel(src) return @@ -404,11 +414,14 @@ orient = "RIGHT" dir = 4 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + return if(exchange_parts(user, G)) return - default_deconstruction_crowbar(G) + if(istype(G, /obj/item/weapon/crowbar)) + default_deconstruction_crowbar(G) + return if(istype(G, /obj/item/weapon/grab)) if(panel_open) @@ -453,24 +466,23 @@ if(1.0) for(var/atom/movable/A as mob|obj in src) A.forceMove(src.loc) - ex_act(severity) + A.ex_act(severity) qdel(src) return if(2.0) if(prob(50)) for(var/atom/movable/A as mob|obj in src) A.forceMove(src.loc) - ex_act(severity) + A.ex_act(severity) qdel(src) return if(3.0) if(prob(25)) for(var/atom/movable/A as mob|obj in src) A.forceMove(src.loc) - ex_act(severity) + A.ex_act(severity) qdel(src) return - return /obj/machinery/sleeper/emp_act(severity) if(filtering) diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm index 45ee6e0f4c9..897e3ee51c8 100644 --- a/code/game/machinery/adv_med.dm +++ b/code/game/machinery/adv_med.dm @@ -19,6 +19,13 @@ else set_light(0) +/obj/machinery/bodyscanner/process() + for(var/mob/M as mob in src) // makes sure that simple mobs don't get stuck inside a sleeper when they resist out of occupant's grasp + if(M == occupant) + continue + else + M.forceMove(src.loc) + /obj/machinery/bodyscanner/New() ..() component_parts = list() @@ -59,11 +66,14 @@ else dir = 4 playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + return if(exchange_parts(user, G)) return - default_deconstruction_crowbar(G) + if(istype(G, /obj/item/weapon/crowbar)) + default_deconstruction_crowbar(G) + return if(istype(G, /obj/item/weapon/grab)) var/obj/item/weapon/grab/TYPECAST_YOUR_SHIT = G @@ -161,39 +171,40 @@ switch(severity) if(1.0) for(var/atom/movable/A as mob|obj in src) - A.loc = src.loc - ex_act(severity) - //Foreach goto(35) - //SN src = null + A.forceMove(src.loc) + A.ex_act(severity) qdel(src) return if(2.0) if (prob(50)) for(var/atom/movable/A as mob|obj in src) - A.loc = src.loc - ex_act(severity) - //Foreach goto(108) - //SN src = null + A.forceMove(src.loc) + A.ex_act(severity) qdel(src) return if(3.0) if (prob(25)) for(var/atom/movable/A as mob|obj in src) - A.loc = src.loc - ex_act(severity) - //Foreach goto(181) - //SN src = null + A.forceMove(src.loc) + A.ex_act(severity) qdel(src) return - else - return /obj/machinery/bodyscanner/blob_act() if(prob(50)) - for(var/atom/movable/A as mob|obj in src) - A.loc = src.loc + var/atom/movable/A = occupant + go_out() + A.blob_act() qdel(src) +/obj/machinery/bodyscanner/attack_animal(var/mob/living/simple_animal/M)//Stop putting hostile mobs in things guise + if(M.environment_smash) + M.do_attack_animation(src) + visible_message("[M.name] smashes [src] apart!") + go_out() + qdel(src) + return + /obj/machinery/body_scanconsole var/obj/machinery/bodyscanner/connected var/delete @@ -249,6 +260,13 @@ if(prob(50)) qdel(src) +/obj/machinery/body_scanconsole/attack_animal(var/mob/living/simple_animal/M)//Stop putting hostile mobs in things guise + if(M.environment_smash) + M.do_attack_animation(src) + visible_message("[M.name] smashes [src] apart!") + qdel(src) + return + /obj/machinery/body_scanconsole/proc/findscanner() var/obj/machinery/bodyscanner/bodyscannernew = null // Loop through every direction diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index 873e08030a7..9aa7cfe2c7b 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -151,6 +151,9 @@ qdel(src) return else if(istype(W, /obj/item/device/analyzer) && panel_open) //XRay + if(!user.unEquip(W)) + to_chat(user, "[W] is stuck!") + return if(!isXRay()) upgradeXRay() qdel(W) @@ -158,14 +161,19 @@ else to_chat(user, "[msg2]") - else if(istype(W, /obj/item/stack/sheet/mineral/plasma) && panel_open) + else if(istype(W, /obj/item/stack/sheet/mineral/plasma) && panel_open) + if(!user.unEquip(W)) + to_chat(user, "[W] is stuck!") + return if(!isEmpProof()) upgradeEmpProof() to_chat(user, "[msg]") qdel(W) else to_chat(user, "[msg2]") - else if(istype(W, /obj/item/device/assembly/prox_sensor) && panel_open) + else if(istype(W, /obj/item/device/assembly/prox_sensor) && panel_open) + if(!user.unEquip(W)) + return if(!isMotion()) upgradeMotion() to_chat(user, "[msg]") diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm index 5b77c8f00fc..5b7d035d461 100644 --- a/code/game/machinery/camera/camera_assembly.dm +++ b/code/game/machinery/camera/camera_assembly.dm @@ -20,10 +20,9 @@ 4 = Screwdriver panel closed and is fully built (you cannot attach upgrades) */ -/obj/item/weapon/camera_assembly/attackby(obj/item/W as obj, mob/living/user as mob, params) +/obj/item/weapon/camera_assembly/attackby(obj/item/W, mob/living/user, params) switch(state) - if(0) // State 0 if(iswrench(W) && isturf(src.loc)) @@ -116,7 +115,6 @@ return else if(iswirecutter(W)) - new/obj/item/stack/cable_coil(get_turf(src), 2) playsound(src.loc, 'sound/items/Wirecutter.ogg', 50, 1) to_chat(user, "You cut the wires from the circuits.") @@ -125,9 +123,12 @@ // Upgrades! if(is_type_in_list(W, possible_upgrades) && !is_type_in_list(W, upgrades)) // Is a possible upgrade and isn't in the camera already. + if(!user.unEquip(W)) + to_chat(user, "[W] is stuck!") + return to_chat(user, "You attach \the [W] into the assembly inner circuits.") upgrades += W - user.drop_item(W) + user.drop_item() W.loc = src return diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 0948c8ae3a1..d3cc5f089a0 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -967,7 +967,9 @@ name = "Spaceport Security" desc = "The Premier security forces for all spaceports found along the Orion Trail." faction = list("orion") - corpse = /obj/effect/landmark/mobcorpse/orionsecurity + loot = list(/obj/effect/landmark/mobcorpse/orionsecurity, + /obj/item/weapon/gun/projectile/automatic/c20r, + /obj/item/weapon/shield/energy) /obj/effect/landmark/mobcorpse/orionsecurity name = "Spaceport Security" diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm index 90b415c99bf..73779c170e0 100644 --- a/code/game/machinery/computer/communications.dm +++ b/code/game/machinery/computer/communications.dm @@ -273,6 +273,17 @@ src.emagged = 0 setMenuState(usr,COMM_SCREEN_MAIN) + if("AcceptDocking") + to_chat(usr, "Docking request accepted!") + trade_dock_timelimit = world.time + 1200 + trade_dockrequest_timelimit = 0 + command_announcement.Announce("Docking request for trading ship approved, please dock at port bay 4.", "Docking Request") + if("DenyDocking") + to_chat(usr, "Docking requeset denied!") + trade_dock_timelimit = 0 + trade_dockrequest_timelimit = 0 + command_announcement.Announce("Docking request for trading ship denied.", "Docking request") + nanomanager.update_uis(src) return 1 @@ -358,6 +369,11 @@ data["shuttle"] = shuttle + if(trade_dockrequest_timelimit > world.time) + data["dock_request"] = 1 + else + data["dock_request"] = 0 + // update the ui if it exists, returns null if no ui is passed/found ui = nanomanager.try_update_ui(user, src, ui_key, ui, data) if (!ui) diff --git a/code/game/machinery/computer/pod_tracking_console.dm b/code/game/machinery/computer/pod_tracking_console.dm index 5ac31a0f567..6817d265a0f 100644 --- a/code/game/machinery/computer/pod_tracking_console.dm +++ b/code/game/machinery/computer/pod_tracking_console.dm @@ -17,17 +17,20 @@ var/data[0] var/list/pods[0] for(var/obj/item/device/spacepod_equipment/misc/tracker/TR in world) - var/obj/spacepod/myPod = TR.my_atom + var/obj/spacepod/my_pod = TR.my_atom var/enabled = TR.enabled - if(myPod && enabled) - var/podname = capitalize(sanitize(myPod.name)) - var/occupant = "None" - var/occupant2 = "None" - if(myPod.occupant) - occupant = myPod.occupant.name - if(myPod.occupant2) - occupant2 = myPod.occupant2.name - pods.Add(list(list("pod" = "\ref[myPod]", "name" = podname, "occupant" = occupant, "occupant2" = occupant2, "x" = myPod.x, "y" = myPod.y, "z" = myPod.z))) + if(my_pod && enabled) + var/podname = capitalize(sanitize(my_pod.name)) + var/list/chairs = list() + if(my_pod.pilot || my_pod.passengers) + if(my_pod.pilot) + chairs += list("pilot" = my_pod.pilot.name) + var/i = 1 + for(var/mob/M in my_pod.passengers) + chairs += list("passenger [i]" = M.name) + i++ + + pods.Add(list(list("pod" = "\ref[my_pod]", "name" = podname) + chairs + list("x" = my_pod.x, "y" = my_pod.y, "z" = my_pod.z))) data["pods"] = pods diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm index ccdd9b3f276..42875f58019 100644 --- a/code/game/machinery/computer/robot.dm +++ b/code/game/machinery/computer/robot.dm @@ -71,7 +71,7 @@ to_chat(user, "Access Denied. This robot is not linked to you.") return // Cyborgs may blow up themselves via the console - if(isrobot(user) && user != target) + if((isrobot(user) && user != target) || !is_authenticated(user)) to_chat(user, "Access Denied.") return var/choice = input("Really detonate [target.name]?") in list ("Yes", "No") diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 6b13dbe95e3..4c820d26857 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -698,6 +698,17 @@ obj/item/weapon/circuitboard/rdserver /obj/item/weapon/stock_parts/capacitor = 2, /obj/item/weapon/stock_parts/console_screen = 1) +/obj/item/weapon/circuitboard/teleporter_perma + name = "circuit board (Permanent Teleporter)" + build_path = /obj/machinery/teleport/perma + board_type = "machine" + origin_tech = "programming=3;engineering=5;bluespace=5;materials=4" + frame_desc = "Requires 3 Bluespace Crystals and 1 Matter Bin." + req_components = list( + /obj/item/weapon/ore/bluespace_crystal = 3, + /obj/item/weapon/stock_parts/matter_bin = 1) + var/target + /obj/item/weapon/circuitboard/telesci_pad name = "Circuit board (Telepad)" build_path = /obj/machinery/telepad diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index dedcd52164a..68ff1bf64c1 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -489,6 +489,7 @@ to_chat(M, "If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.") occupant = M + name = "[name] ([occupant.name])" time_entered = world.time if(findtext("[M.key]","@",1,2)) @@ -581,6 +582,7 @@ to_chat(L, "[on_enter_occupant_message]") to_chat(L, "If you ghost, log out or close your client now, your character will shortly be permanently removed from the round.") occupant = L + name = "[name] ([occupant.name])" time_entered = world.time if(findtext("[L.key]","@",1,2)) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 26d159e959a..9c361225866 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -58,6 +58,7 @@ var/doorDeni = 'sound/machines/DeniedBeep.ogg' // i'm thinkin' Deni's var/boltUp = 'sound/machines/BoltsUp.ogg' var/boltDown = 'sound/machines/BoltsDown.ogg' + var/is_special = 0 /obj/machinery/door/airlock/command name = "Airlock" @@ -126,6 +127,7 @@ hackProof = 1 aiControlDisabled = 1 unacidable = 1 + is_special = 1 /obj/machinery/door/airlock/maintenance_hatch name = "Maintenance Hatch" @@ -304,6 +306,7 @@ desc = "A mysterious alien airlock with a complicated opening mechanism." hackProof = 1 icon = 'icons/obj/doors/Doorplasma.dmi' + is_special = 1 /obj/machinery/door/airlock/alien/bumpopen(mob/living/user as mob) if(istype(user,/mob/living/carbon/alien) || isrobot(user) || isAI(user)) @@ -1066,4 +1069,4 @@ About the new airlock wires panel: src.unlock() src.open() src.lock() - return \ No newline at end of file + return diff --git a/code/game/machinery/gameboard.dm b/code/game/machinery/gameboard.dm index b331930b325..a19f34af99b 100644 --- a/code/game/machinery/gameboard.dm +++ b/code/game/machinery/gameboard.dm @@ -2,59 +2,68 @@ name = "Virtual Gameboard" icon = 'icons/obj/stationobjs.dmi' icon_state = "gboard_on" - desc = "A holographic table allowing the crew to have fun™ on boring shifts! One player per board." + desc = "A holographic table allowing the crew to have fun(TM) on boring shifts! One player per board." density = 1 anchored = 1 use_power = 1 + var/cooling_down = 0 + light_color = LIGHT_COLOR_LIGHTBLUE /obj/machinery/gameboard/New() - ..() - component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/gameboard(null) - component_parts += new /obj/item/weapon/stock_parts/micro_laser(null) - component_parts += new /obj/item/stack/cable_coil(null, 3) - component_parts += new /obj/item/stack/sheet/glass(null, 1) - RefreshParts() + ..() + component_parts = list() + component_parts += new /obj/item/weapon/circuitboard/gameboard(null) + component_parts += new /obj/item/weapon/stock_parts/micro_laser(null) + component_parts += new /obj/item/stack/cable_coil(null, 3) + component_parts += new /obj/item/stack/sheet/glass(null, 1) + RefreshParts() /obj/machinery/gameboard/power_change() - . = ..() - update_icon() + . = ..() + update_icon() + if(stat & NOPOWER) + set_light(0) + else + set_light(3, 3) /obj/machinery/gameboard/update_icon() - if(stat & NOPOWER) - icon_state = "gboard_off" - else - icon_state = "gboard_on" + if(stat & NOPOWER) + icon_state = "gboard_off" + else + icon_state = "gboard_on" /obj/machinery/gameboard/attack_hand(mob/user) - . = ..() - if(.) - return - if(src.in_use) - to_chat(user, "This gameboard is already in use!") - return - interact(user) + . = ..() + if(.) + return + if(src.in_use) + to_chat(user, "This gameboard is already in use!") + return + if(!anchored) + to_chat(user, "The gameboard is not secured!") + return + interact(user) /obj/machinery/gameboard/interact(mob/user) - . = ..() - if(.) - return + . = ..() + if(.) + return - var/dat - dat = replacetext(file2text('html/chess.html'), "\[hsrc]", "\ref[src]") - var/datum/asset/simple/chess/assets = get_asset_datum(/datum/asset/simple/chess) - assets.send(user) + var/dat + dat = replacetext(file2text('html/chess.html'), "\[hsrc]", "\ref[src]") + var/datum/asset/simple/chess/assets = get_asset_datum(/datum/asset/simple/chess) + assets.send(user) - var/datum/browser/popup = new(user, "SpessChess", name, 500, 800, src) - popup.set_content(dat) - popup.add_stylesheet("chess.css", 'html/browser/chess.css') - popup.add_script("garbochess.js", 'html/browser/garbochess.js') - //popup.add_script("boardui.js", 'html/browser/boardui.js') - popup.add_script("jquery-1.8.2.min.js", 'html/browser/jquery-1.8.2.min.js') - popup.add_script("jquery-ui-1.8.24.custom.min.js", 'html/browser/jquery-ui-1.8.24.custom.min.js') - popup.set_window_options("titlebar=0") - popup.open() - user.set_machine(src) + var/datum/browser/popup = new(user, "SpessChess", name, 500, 800, src) + popup.set_content(dat) + popup.add_stylesheet("chess.css", 'html/browser/chess.css') + popup.add_script("garbochess.js", 'html/browser/garbochess.js') + //popup.add_script("boardui.js", 'html/browser/boardui.js') + popup.add_script("jquery-1.8.2.min.js", 'html/browser/jquery-1.8.2.min.js') + popup.add_script("jquery-ui-1.8.24.custom.min.js", 'html/browser/jquery-ui-1.8.24.custom.min.js') + popup.set_window_options("titlebar=0") + popup.open() + user.set_machine(src) /obj/machinery/gameboard/proc/close_game() //yes, shamelessly copied over from arcade_base in_use = 0 @@ -65,15 +74,27 @@ return /obj/machinery/gameboard/Topic(var/href, var/list/href_list) - . = ..() - var/prize = /obj/item/stack/tickets - if (.) - return + . = ..() + var/prize = /obj/item/stack/tickets + if(.) + return - if (href_list["checkmate"]) - visible_message("[src.name] beeps, \"WINNER!\"") - new prize(get_turf(src), 80) - close_game() + if(href_list["checkmate"]) + if(cooling_down) + message_admins("Too many checkmates on chessboard, possible HREF exploits: [key_name_admin(usr)] on [src] (JMP)") + return + visible_message("[src.name] beeps, \"WINNER!\"") + new prize(get_turf(src), 80) + close_game() + cooling_down = 1 + spawn(600) + cooling_down = 0 - if (href_list["close"]) - close_game() \ No newline at end of file + if(href_list["close"]) + close_game() + +/obj/machinery/gameboard/attackby(var/obj/item/weapon/G as obj, var/mob/user as mob, params) + if(istype(G, /obj/item/weapon/wrench)) + default_unfasten_wrench(user, G) + else if(istype(G, /obj/item/weapon/crowbar)) + default_deconstruction_crowbar(G, ignore_panel = 1) diff --git a/code/game/machinery/guestpass.dm b/code/game/machinery/guestpass.dm index b63307c3db8..bf1d69e7437 100644 --- a/code/game/machinery/guestpass.dm +++ b/code/game/machinery/guestpass.dm @@ -58,6 +58,9 @@ else to_chat(user, "There is already ID card inside.") +/obj/machinery/computer/guestpass/proc/get_changeable_accesses() + return giver.access + /obj/machinery/computer/guestpass/attack_ai(var/mob/user as mob) return attack_hand(user) @@ -84,7 +87,7 @@ dat += "Duration (minutes): [duration] m
" dat += "Access to areas:
" if (giver && giver.access) - for (var/A in giver.access) + for (var/A in get_changeable_accesses()) var/area = get_access_desc(A) if (A in accesses) area = "[area]" @@ -124,7 +127,8 @@ if (A in accesses) accesses.Remove(A) else - accesses.Add(A) + if(giver && giver.access && (A in get_changeable_accesses())) + accesses.Add(A) if (href_list["action"]) switch(href_list["action"]) if ("id") @@ -178,4 +182,12 @@ else to_chat(usr, "\red Cannot issue pass without issuing ID.") updateUsrDialog() - return \ No newline at end of file + return + +/obj/machinery/computer/guestpass/hop + name = "\improper HoP guest pass terminal" + +/obj/machinery/computer/guestpass/hop/get_changeable_accesses() + . = ..() + if(. && access_change_ids in .) + return get_all_accesses() diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index f916998e26b..fb1ef8c8740 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -99,13 +99,12 @@ one_access = 0 /obj/machinery/porta_turret/proc/setup() - var/obj/item/weapon/gun/energy/E = installation //All energy-based weapons are applicable - if(istext(installation)) E = text2path(installation) - //var/obj/item/ammo_casing/shottype = E.projectile_type + var/obj/item/weapon/gun/energy/E= new installation //All energy-based weapons are applicable + var/obj/item/ammo_casing/shottype = E.ammo_type[1] - projectile = initial(E.projectile_type) + projectile = shottype.projectile_type eprojectile = projectile - shot_sound = initial(E.fire_sound) + shot_sound = shottype.fire_sound eshot_sound = shot_sound weapon_setup(installation) @@ -519,7 +518,7 @@ var/list/turret_icons assess_and_assign(ME.occupant, targets, secondarytargets) for(var/obj/spacepod/SP in view(7,src)) - assess_and_assign(SP.occupant, targets, secondarytargets) + assess_and_assign(SP.pilot, targets, secondarytargets) for(var/obj/vehicle/T in view(7,src)) assess_and_assign(T.buckled_mob, targets, secondarytargets) @@ -561,9 +560,6 @@ var/list/turret_icons if(get_dist(src, L) > 7) //if it's too far away, why bother? return TURRET_NOT_TARGET - if(!check_trajectory(L, src)) //check if we have true line of sight - return TURRET_NOT_TARGET - if(emagged) // If emagged not even the dead get a rest return L.stat ? TURRET_SECONDARY_TARGET : TURRET_PRIORITY_TARGET @@ -670,6 +666,8 @@ var/list/turret_icons return /obj/machinery/porta_turret/proc/shootAt(var/mob/living/target) + if(!raised) //the turret has to be raised in order to fire - makes sense, right? + return //any emagged turrets will shoot extremely fast! This not only is deadly, but drains a lot power! if(!emagged) //if it hasn't been emagged, it has to obey a cooldown rate if(last_fired || !raised) //prevents rapid-fire shooting, unless it's been emagged @@ -684,10 +682,6 @@ var/list/turret_icons if(!istype(T) || !istype(U)) return - if(!raised) //the turret has to be raised in order to fire - makes sense, right? - return - - update_icon() var/obj/item/projectile/A if(emagged || lethal) @@ -698,18 +692,17 @@ var/list/turret_icons if(projectile) A = new projectile(loc) playsound(loc, shot_sound, 75, 1) - A.original = target // Lethal/emagged turrets use twice the power due to higher energy beams // Emagged turrets again use twice as much power due to higher firing rates use_power(reqpower * (2 * (emagged || lethal)) * (2 * emagged)) - //Shooting Code: + A.original = target A.current = T A.yo = U.y - T.y A.xo = U.x - T.x - spawn(1) - A.process() + A.fire() + return A /datum/turret_checks var/enabled diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 5b5a532efdb..a1559c4fb3a 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -54,8 +54,52 @@ if(src.occupant) process_occupant() + + for(var/mob/M as mob in src) // makes sure that simple mobs don't get stuck inside a sleeper when they resist out of occupant's grasp + if(M == occupant) + continue + else + M.forceMove(src.loc) return 1 +/obj/machinery/recharge_station/ex_act(severity) + switch(severity) + if(1.0) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + A.ex_act(severity) + qdel(src) + return + if(2.0) + if (prob(50)) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + A.ex_act(severity) + qdel(src) + return + if(3.0) + if (prob(25)) + for(var/atom/movable/A as mob|obj in src) + A.forceMove(src.loc) + A.ex_act(severity) + qdel(src) + return + +/obj/machinery/recharge_station/blob_act() + if(prob(50)) + var/atom/movable/A = occupant + go_out() + A.blob_act() + qdel(src) + +/obj/machinery/recharge_station/attack_animal(var/mob/living/simple_animal/M)//Stop putting hostile mobs in things guise + if(M.environment_smash) + M.do_attack_animation(src) + visible_message("[M.name] smashes [src] apart!") + go_out() + qdel(src) + return + /obj/machinery/recharge_station/Bumped(var/mob/AM) move_inside(AM) @@ -159,7 +203,8 @@ if(istype(O,/obj/item/weapon/gun/energy/disabler/cyborg)) var/obj/item/weapon/gun/energy/disabler/cyborg/D = O if(D.power_supply.charge < D.power_supply.maxcharge) - D.power_supply.give(D.charge_cost) + var/obj/item/ammo_casing/energy/E = D.ammo_type[D.select] + D.power_supply.give(E.e_cost) D.update_icon() else D.charge_tick = 0 @@ -210,7 +255,7 @@ /obj/machinery/recharge_station/verb/move_inside(var/mob/user = usr) set category = "Object" set src in oview(1) - if(!user) + if(!user || !usr) return if (usr.stat != CONSCIOUS) diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index 15b8b621b0c..5d6aa95b56f 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -621,7 +621,8 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept //#### Sending the signal to all subspace receivers ####// for(var/obj/machinery/telecomms/receiver/R in telecomms_list) - R.receive_signal(signal) + spawn(0) + R.receive_signal(signal) if(do_sleep) sleep(rand(10,25)) diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 9d9481aba04..290e3352ea8 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -387,7 +387,7 @@ var/global/list/obj/machinery/telecomms/telecomms_list = list() src.receive_information(signal, src) // Try sending it! - var/list/try_send = list("/obj/machinery/telecomms/server", "/obj/machinery/telecomms/hub", "/obj/machinery/telecomms/broadcaster", "/obj/machinery/telecomms/bus") + var/list/try_send = list("/obj/machinery/telecomms/server", "/obj/machinery/telecomms/hub", "/obj/machinery/telecomms/broadcaster") var/i = 0 for(var/send in try_send) if(i) diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm index 6dd9954046b..9c1d90ce67a 100644 --- a/code/game/machinery/teleporter.dm +++ b/code/game/machinery/teleporter.dm @@ -319,17 +319,18 @@ /obj/machinery/teleport/hub/Bumped(M as mob|obj) if(z == ZLEVEL_CENTCOMM) to_chat(M, "You can't use this here.") + return if(power_station && power_station.engaged && !panel_open) //--FalseIncarnate //Prevents AI cores from using the teleporter, prints out failure messages for clarity if(istype(M, /mob/living/silicon/ai) || istype(M, /obj/structure/AIcore)) - visible_message("\red The teleporter rejects the AI unit.") + visible_message("The teleporter rejects the AI unit.") if(istype(M, /mob/living/silicon/ai)) var/mob/living/silicon/ai/T = M - var/list/TPError = list("\red Firmware instructions dictate you must remain on your assigned station!", - "\red You cannot interface with this technology and get rejected!", - "\red External firewalls prevent you from utilizing this machine!", - "\red Your AI core's anti-bluespace failsafes trigger and prevent teleportation!") + var/list/TPError = list("Firmware instructions dictate you must remain on your assigned station!", + "You cannot interface with this technology and get rejected!", + "External firewalls prevent you from utilizing this machine!", + "Your AI core's anti-bluespace failsafes trigger and prevent teleportation!") to_chat(T, "[pick(TPError)]") return else @@ -370,6 +371,80 @@ else icon_state = "tele0" +/obj/machinery/teleport/perma + name = "permanent teleporter" + desc = "A teleporter with the target pre-set on the circuit board." + icon_state = "tele0" + var/recalibrating = 0 + use_power = 1 + idle_power_usage = 10 + active_power_usage = 2000 + + var/target + var/tele_delay = 50 + +/obj/machinery/teleport/perma/RefreshParts() + for(var/obj/item/weapon/circuitboard/teleporter_perma/C in component_parts) + target = C.target + var/A = 40 + for(var/obj/item/weapon/stock_parts/matter_bin/M in component_parts) + A -= M.rating * 10 + tele_delay = max(A, 0) + update_icon() + +/obj/machinery/teleport/perma/Bumped(M as mob|obj) + if(stat & (BROKEN|NOPOWER)) + return + if(z == ZLEVEL_CENTCOMM) + to_chat(M, "You can't use this here.") + return + if(target && !recalibrating && !panel_open) + //--FalseIncarnate + //Prevents AI cores from using the teleporter, prints out failure messages for clarity + if(istype(M, /mob/living/silicon/ai) || istype(M, /obj/structure/AIcore)) + visible_message("The teleporter rejects the AI unit.") + if(istype(M, /mob/living/silicon/ai)) + var/mob/living/silicon/ai/T = M + var/list/TPError = list("Firmware instructions dictate you must remain on your assigned station!", + "You cannot interface with this technology and get rejected!", + "External firewalls prevent you from utilizing this machine!", + "Your AI core's anti-bluespace failsafes trigger and prevent teleportation!") + to_chat(T, "[pick(TPError)]") + return + else + do_teleport(M, target) + use_power(5000) + + if(tele_delay) + recalibrating = 1 + update_icon() + spawn(tele_delay) + recalibrating = 0 + update_icon() + //--FalseIncarnate + return + +/obj/machinery/teleport/perma/power_change() + ..() + update_icon() + +/obj/machinery/teleport/perma/update_icon() + if(panel_open) + icon_state = "tele-o" + else if(target && !recalibrating && !(stat & (BROKEN|NOPOWER))) + icon_state = "tele1" + else + icon_state = "tele0" + +/obj/machinery/teleport/perma/attackby(obj/item/W, mob/user, params) + if(default_deconstruction_screwdriver(user, "tele-o", "tele0", W)) + return + + if(exchange_parts(user, W)) + return + + default_deconstruction_crowbar(W) + /obj/machinery/teleport/station name = "station" desc = "The power control station for a bluespace teleporter." @@ -457,6 +532,11 @@ link_console_and_hub() to_chat(user, "You reconnect the station to nearby machinery.") return + if(istype(W, /obj/item/weapon/circuitboard/teleporter_perma)) + var/obj/item/weapon/circuitboard/teleporter_perma/C = W + C.target = teleporter_console.target + to_chat(user, "You copy the targeting information from \the [src] to \the [W]") + return /obj/machinery/teleport/station/attack_ai() src.attack_hand() diff --git a/code/game/machinery/turrets.dm b/code/game/machinery/turrets.dm index b1d92718104..f0b6ce34ef7 100644 --- a/code/game/machinery/turrets.dm +++ b/code/game/machinery/turrets.dm @@ -21,7 +21,7 @@ turretTargets |= Mech else if( istype(O, /obj/spacepod) ) var/obj/spacepod/Pod = O - if( Pod.occupant || Pod.occupant2 ) + if( Pod.pilot ) turretTargets |= Pod else if(istype(O,/mob/living/simple_animal)) turretTargets |= O @@ -139,7 +139,7 @@ return 1 else if( istype(T, /obj/spacepod) ) var/obj/spacepod/SP = T - if( SP.occupant || SP.occupant2 ) + if( SP.pilot ) return 1 else if(istype(T,/mob/living/simple_animal)) var/mob/living/simple_animal/A = T @@ -159,8 +159,8 @@ if(M.occupant) new_targets += M for(var/obj/spacepod/M in protected_area.turretTargets) - if(M.occupant) - new_targets += M + if(M.pilot) + new_targets += M.pilot for(var/mob/living/simple_animal/M in protected_area.turretTargets) if(!M.stat) new_targets += M @@ -227,15 +227,15 @@ if(1) A = new /obj/item/projectile/beam(loc) if(2) - A = new /obj/item/projectile/beam/heavylaser(loc) + A = new /obj/item/projectile/beam/laser/heavylaser(loc) if(3) A = new /obj/item/projectile/beam/pulse(loc) if(4) A = new /obj/item/projectile/magic/change(loc) if(5) - A = new /obj/item/projectile/lasertag/blue(loc) + A = new /obj/item/projectile/beam/lasertag/bluetag(loc) if(6) - A = new /obj/item/projectile/lasertag/red(loc) + A = new /obj/item/projectile/beam/lasertag/redtag(loc) A.original = target use_power(500) else @@ -248,8 +248,7 @@ A.current = T A.yo = U.y - T.y A.xo = U.x - T.x - spawn( 0 ) - A.process() + A.fire() return @@ -488,7 +487,7 @@ return 1 else if(istype(target, /obj/spacepod)) var/obj/spacepod/S = target - if(S.occupant || S.occupant2) + if(S.pilot) return 1 return 0 @@ -522,14 +521,12 @@ continue //Don't shoot at empty mechs. pos_targets += M for(var/obj/spacepod/M in oview(scan_range, src)) - if(M.occupant) - if(faction in M.occupant.faction) + if(M.pilot) + var/mob/P = M.pilot + if(faction in P.faction) continue - if(M.occupant2) - if(faction in M.occupant2.faction) - continue - if(!M.occupant && !M.occupant2) - continue //Don't shoot at empty mechs. + if(!M.pilot) + continue //Don't shoot at empty pods. pos_targets += M if(pos_targets.len) target = pick(pos_targets) diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 29880e519ec..e022e0c6a4b 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -849,7 +849,7 @@ product_ads = "Float like an astronaut, sting like a bullet!;Express your second amendment today!;Guns don't kill people, but you can!;Who needs responsibilities when you have guns?" vend_reply = "Remember the name: Liberation Station!" products = list(/obj/item/weapon/gun/projectile/automatic/pistol/deagle/gold = 2,/obj/item/weapon/gun/projectile/automatic/pistol/deagle/camo = 2, - /obj/item/weapon/gun/projectile/automatic/pistol/m2411 = 2,/obj/item/weapon/gun/projectile/automatic/proto = 2, + /obj/item/weapon/gun/projectile/automatic/pistol/m1911 = 2,/obj/item/weapon/gun/projectile/automatic/proto = 2, /obj/item/weapon/gun/projectile/shotgun/automatic/combat = 2,/obj/item/weapon/gun/projectile/automatic/gyropistol = 1, /obj/item/weapon/gun/projectile/shotgun = 2,/obj/item/weapon/gun/projectile/automatic/ar = 2) premium = list(/obj/item/ammo_box/magazine/smgm9mm = 2,/obj/item/ammo_box/magazine/m50 = 4,/obj/item/ammo_box/magazine/m45 = 2,/obj/item/ammo_box/magazine/m75 = 2) diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm index f79c43068ee..05b3dac0e63 100644 --- a/code/game/mecha/equipment/tools/medical_tools.dm +++ b/code/game/mecha/equipment/tools/medical_tools.dm @@ -384,7 +384,7 @@ /obj/item/mecha_parts/mecha_equipment/tool/syringe_gun name = "Syringe Gun" desc = "Exosuit-mounted chem synthesizer with syringe gun. Reagents inside are held in stasis, so no reactions will occur. (Can be attached to: Medical Exosuits)" - icon = 'icons/obj/gun.dmi' + icon = 'icons/obj/guns/projectile.dmi' icon_state = "syringegun" item_state = "syringegun" lefthand_file = 'icons/mob/inhands/guns_lefthand.dmi' @@ -666,4 +666,4 @@ for(var/reagent in S.processed_reagents) S.reagents.add_reagent(reagent,amount) S.chassis.use_power(energy_drain) - return 1 \ No newline at end of file + return 1 diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index d95cbaff799..ae5595d69e5 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -5,6 +5,10 @@ var/projectile var/fire_sound var/size=0 + var/projectiles_per_shot = 1 + var/variance = 0 + var/randomspread = 0 //use random spread for machineguns, instead of shotgun scatter + var/projectile_delay = 0 /obj/item/mecha_parts/mecha_equipment/weapon/can_attach(var/obj/mecha/combat/M as obj) if(..()) @@ -16,32 +20,51 @@ return 1 return 0 +/obj/item/mecha_parts/mecha_equipment/weapon/proc/get_shot_amount() + return projectiles_per_shot -/obj/item/mecha_parts/mecha_equipment/weapon/energy - name = "General Energy Weapon" - size = 2 - action(target) - if(!action_checks(target)) return - var/turf/curloc = chassis.loc - var/atom/targloc = get_turf(target) - if (!targloc || !istype(targloc, /turf) || !curloc) - return - if (targloc == curloc) - return - set_ready_state(0) - playsound(chassis, fire_sound, 50, 1) +/obj/item/mecha_parts/mecha_equipment/weapon/action(target, params) + if(!action_checks(target)) + return 0 + + var/turf/curloc = get_turf(chassis) + var/turf/targloc = get_turf(target) + if (!targloc || !istype(targloc) || !curloc) + return 0 + if (targloc == curloc) + return 0 + + set_ready_state(0) + for(var/i=1 to get_shot_amount()) var/obj/item/projectile/A = new projectile(curloc) A.firer = chassis.occupant A.original = target A.current = curloc - A.yo = targloc.y - curloc.y - A.xo = targloc.x - curloc.x - chassis.use_power(energy_drain) - A.process() - chassis.log_message("Fired from [src.name], targeting [target].") - do_after_cooldown() - return + var/spread = 0 + if(variance) + if(randomspread) + spread = round((rand() - 0.5) * variance) + else + spread = round((i / projectiles_per_shot - 0.5) * variance) + A.preparePixelProjectile(target, targloc, chassis.occupant, params, spread) + + chassis.use_power(energy_drain) + A.fire() + playsound(chassis, fire_sound, 50, 1) + + sleep(max(0, projectile_delay)) + set_ready_state(0) + log_message("Fired from [name], targeting [target].") + var/turf/T = get_turf(src) + msg_admin_attack("[key_name_admin(chassis.occupant)] fired a [src] in ([T.x], [T.y], [T.z] - JMP)") + log_game("[key_name(chassis.occupant)] fired a [src] in [T.x], [T.y], [T.z]") + do_after_cooldown() + return + +/obj/item/mecha_parts/mecha_equipment/weapon/energy + name = "General Energy Weapon" + size = 2 /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser equip_cooldown = 8 @@ -56,7 +79,7 @@ name = "CH-LC \"Solaris\" Laser Cannon" icon_state = "mecha_laser" energy_drain = 40 - projectile = /obj/item/projectile/beam/heavylaser + projectile = /obj/item/projectile/beam/laser/heavylaser fire_sound = 'sound/weapons/lasercannonfire.ogg' /obj/item/mecha_parts/mecha_equipment/weapon/energy/ion @@ -82,25 +105,25 @@ icon_state = "pulse1_bl" var/life = 20 - Bump(atom/A) - A.bullet_act(src, def_zone) - src.life -= 10 - if(ismob(A)) - var/mob/M = A - if(istype(firer, /mob)) - M.attack_log += "\[[time_stamp()]\] [firer]/[firer.ckey] shot [M]/[M.ckey] with a [src]" - firer.attack_log += "\[[time_stamp()]\] [firer]/[firer.ckey] shot [M]/[M.ckey] with a [src]" - log_attack("[firer] ([firer.ckey]) shot [M] ([M.ckey]) with a [src]") - if(!iscarbon(firer)) - M.LAssailant = null - else - M.LAssailant = firer +/obj/item/projectile/beam/pulse/heavy/Bump(atom/A) + A.bullet_act(src, def_zone) + life -= 10 + if(ismob(A)) + var/mob/M = A + if(istype(firer, /mob)) + M.attack_log += "\[[time_stamp()]\] [firer]/[firer.ckey] shot [M]/[M.ckey] with a [src]" + firer.attack_log += "\[[time_stamp()]\] [firer]/[firer.ckey] shot [M]/[M.ckey] with a [src]" + log_attack("[firer] ([firer.ckey]) shot [M] ([M.ckey]) with a [src]") + if(!iscarbon(firer)) + M.LAssailant = null else - M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [M]/[M.ckey] with a [src]" - log_attack("UNKNOWN shot [M] ([M.ckey]) with a [src]") - if(life <= 0) - qdel(src) - return + M.LAssailant = firer + else + M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [M]/[M.ckey] with a [src]" + log_attack("UNKNOWN shot [M] ([M.ckey]) with a [src]") + if(life <= 0) + qdel(src) + return /obj/item/mecha_parts/mecha_equipment/weapon/energy/taser @@ -119,89 +142,89 @@ equip_cooldown = 150 range = MELEE|RANGED - can_attach(obj/mecha/combat/honker/M as obj) - if(..()) - if(istype(M)) - return 1 +/obj/item/mecha_parts/mecha_equipment/weapon/honker/can_attach(obj/mecha/combat/honker/M as obj) + if(..()) + if(istype(M)) + return 1 + return 0 + +/obj/item/mecha_parts/mecha_equipment/weapon/honker/action(target, params) + if(!chassis) + return 0 + if(energy_drain && chassis.get_charge() < energy_drain) + return 0 + if(!equip_ready) return 0 - action(target) - if(!chassis) - return 0 - if(energy_drain && chassis.get_charge() < energy_drain) - return 0 - if(!equip_ready) - return 0 + playsound(chassis, 'sound/items/AirHorn.ogg', 100, 1) + chassis.occupant_message("HONK") + for(var/mob/living/carbon/M in ohearers(6, chassis)) + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs)) + continue + to_chat(M, "HONK") + M.sleeping = 0 + M.stuttering = 20 + M.ear_deaf = 30 + M.Weaken(3) + if(prob(30)) + M.Stun(10) + M.Paralyse(4) + else + M.Jitter(500) + ///else the mousetraps are useless + if(istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + if(isobj(H.shoes)) + var/thingy = H.shoes + H.unEquip(H.shoes) + walk_away(thingy,chassis,15,2) + spawn(20) + if(thingy) + walk(thingy,0) + for(var/obj/mecha/combat/recitence/R in oview(6, chassis)) + R.occupant_message("\The [R] has protected you from [chassis]'s HONK at the cost of some power.") + R.use_power(R.get_charge() / 4) - playsound(chassis, 'sound/items/AirHorn.ogg', 100, 1) - chassis.occupant_message("HONK") - for(var/mob/living/carbon/M in ohearers(6, chassis)) - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs)) - continue - to_chat(M, "HONK") - M.sleeping = 0 - M.stuttering = 20 - M.ear_deaf = 30 - M.Weaken(3) - if(prob(30)) - M.Stun(10) - M.Paralyse(4) - else - M.Jitter(500) - ///else the mousetraps are useless - if(istype(M, /mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - if(isobj(H.shoes)) - var/thingy = H.shoes - H.unEquip(H.shoes) - walk_away(thingy,chassis,15,2) - spawn(20) - if(thingy) - walk(thingy,0) - for(var/obj/mecha/combat/recitence/R in oview(6, chassis)) - R.occupant_message("\The [R] has protected you from [chassis]'s HONK at the cost of some power.") - R.use_power(R.get_charge() / 4) - - chassis.use_power(energy_drain) - log_message("Honked from [src.name]. HONK!") - var/turf/T = get_turf(src) - msg_admin_attack("[key_name_admin(chassis.occupant)] used a Mecha Honker in ([T.x], [T.y], [T.z] - JMP)") - log_game("[key_name(chassis.occupant)] used a Mecha Honker in [T.x], [T.y], [T.z]") - do_after_cooldown() - return + chassis.use_power(energy_drain) + log_message("Honked from [name]. HONK!") + var/turf/T = get_turf(src) + msg_admin_attack("[key_name_admin(chassis.occupant)] used a Mecha Honker in ([T.x], [T.y], [T.z] - JMP)") + log_game("[key_name(chassis.occupant)] used a Mecha Honker in [T.x], [T.y], [T.z]") + do_after_cooldown() + return /obj/item/mecha_parts/mecha_equipment/weapon/ballistic name = "General Ballisic Weapon" var/projectiles var/projectile_energy_cost size = 2 - action_checks(atom/target) - if(..()) - if(projectiles > 0) - return 1 - return 0 +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/action_checks(atom/target) + if(..()) + if(projectiles > 0) + return 1 + return 0 - get_equip_info() - return "[..()]\[[src.projectiles]\][(src.projectiles < initial(src.projectiles))?" - Rearm":null]" +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/get_equip_info() + return "[..()]\[[projectiles]\][(projectiles < initial(projectiles))?" - Rearm":null]" - proc/rearm() - if(projectiles < initial(projectiles)) - var/projectiles_to_add = initial(projectiles) - projectiles - while(chassis.get_charge() >= projectile_energy_cost && projectiles_to_add) - projectiles++ - projectiles_to_add-- - chassis.use_power(projectile_energy_cost) - send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) - log_message("Rearmed [src.name].") - return +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/proc/rearm() + if(projectiles < initial(projectiles)) + var/projectiles_to_add = initial(projectiles) - projectiles + while(chassis.get_charge() >= projectile_energy_cost && projectiles_to_add) + projectiles++ + projectiles_to_add-- + chassis.use_power(projectile_energy_cost) + send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",get_equip_info()) + log_message("Rearmed [name].") + return - Topic(href, href_list) - ..() - if (href_list["rearm"]) - src.rearm() - return +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/Topic(href, href_list) + ..() + if (href_list["rearm"]) + rearm() + return /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine name = "FNX-66 Carbine" @@ -211,41 +234,6 @@ fire_sound = 'sound/weapons/Gunshot.ogg' projectiles = 24 projectile_energy_cost = 15 - var/projectiles_per_shot = 1 - var/deviation = 0.0 - - action(atom/target) - if(!action_checks(target)) return - var/turf/targloc = get_turf(target) - var/target_x = targloc.x - var/target_y = targloc.y - var/target_z = targloc.z - targloc = null - spawn for(var/i=1 to min(projectiles, projectiles_per_shot)) - if(!chassis) break - var/turf/curloc = get_turf(chassis) - targloc = locate(target_x+GaussRandRound(deviation,1),target_y+GaussRandRound(deviation,1),target_z) - if (!targloc || !curloc) - continue - if (targloc == curloc) - continue - - playsound(chassis, fire_sound, 50, 1) - var/obj/item/projectile/A = new projectile(curloc) - src.projectiles-- - A.original = target - A.current = curloc - A.yo = targloc.y - curloc.y - A.xo = targloc.x - curloc.x - A.process() - sleep(2) - set_ready_state(0) - log_message("Fired from [src.name], targeting [target].") - var/turf/T = get_turf(src) - msg_admin_attack("[key_name_admin(chassis.occupant)] fired a [src] in ([T.x], [T.y], [T.z] - JMP)") - log_game("[key_name(chassis.occupant)] fired a [src] in [T.x], [T.y], [T.z]") - do_after_cooldown() - return /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/carbine/silenced name = "\improper S.H.H. \"Quietus\" Carbine" @@ -270,36 +258,8 @@ fire_sound = 'sound/weapons/Gunshot.ogg' projectiles = 40 projectile_energy_cost = 25 - var/projectiles_per_shot = 4 - var/deviation = 0.7 - - action(atom/target) - if(!action_checks(target)) return - var/turf/curloc = get_turf(chassis) - var/turf/targloc = get_turf(target) - if(!curloc || !targloc) return - var/target_x = targloc.x - var/target_y = targloc.y - var/target_z = targloc.z - targloc = null - for(var/i=1 to min(projectiles, projectiles_per_shot)) - targloc = locate(target_x+GaussRandRound(deviation,1),target_y+GaussRandRound(deviation,1),target_z) - if(!targloc || targloc == curloc) - break - playsound(chassis, fire_sound, 80, 1) - var/obj/item/projectile/A = new projectile(curloc) - src.projectiles-- - A.original = target - A.current = curloc - A.yo = targloc.y - curloc.y - A.xo = targloc.x - curloc.x - set_ready_state(0) - A.process() - log_message("Fired from [src.name], targeting [target].") - do_after_cooldown() - return - - + projectiles_per_shot = 4 + variance = 25 /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg name = "Ultra AC 2" @@ -309,38 +269,9 @@ fire_sound = 'sound/weapons/Gunshot.ogg' projectiles = 300 projectile_energy_cost = 20 - var/projectiles_per_shot = 3 - var/deviation = 0.3 - - action(atom/target) - if(!action_checks(target)) return - var/turf/targloc = get_turf(target) - var/target_x = targloc.x - var/target_y = targloc.y - var/target_z = targloc.z - targloc = null - spawn for(var/i=1 to min(projectiles, projectiles_per_shot)) - if(!chassis) break - var/turf/curloc = get_turf(chassis) - targloc = locate(target_x+GaussRandRound(deviation,1),target_y+GaussRandRound(deviation,1),target_z) - if (!targloc || !curloc) - continue - if (targloc == curloc) - continue - - playsound(chassis, fire_sound, 50, 1) - var/obj/item/projectile/A = new projectile(curloc) - src.projectiles-- - A.original = target - A.current = curloc - A.yo = targloc.y - curloc.y - A.xo = targloc.x - curloc.x - A.process() - sleep(2) - set_ready_state(0) - log_message("Fired from [src.name], targeting [target].") - do_after_cooldown() - return + projectiles_per_shot = 3 + variance = 6 + projectile_delay = 2 /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack name = "SRM-8 Missile Rack" @@ -353,20 +284,21 @@ var/missile_speed = 2 var/missile_range = 30 - action(target) - if(!action_checks(target)) return - set_ready_state(0) - var/obj/item/missile/M = new projectile(chassis.loc) - M.primed = 1 - playsound(chassis, fire_sound, 50, 1) - M.throw_at(target, missile_range, missile_speed, chassis) - projectiles-- - log_message("Fired from [src.name], targeting [target].") - var/turf/T = get_turf(src) - msg_admin_attack("[key_name_admin(chassis.occupant)] fired a [src] in ([T.x], [T.y], [T.z] - JMP)") - log_game("[key_name(chassis.occupant)] fired a [src] in [T.x], [T.y], [T.z]") - do_after_cooldown() +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/action(target, params) + if(!action_checks(target)) return + set_ready_state(0) + var/obj/item/missile/M = new projectile(chassis.loc) + M.primed = 1 + playsound(chassis, fire_sound, 50, 1) + M.throw_at(target, missile_range, missile_speed, chassis) + projectiles-- + log_message("Fired from [name], targeting [target].") + var/turf/T = get_turf(src) + msg_admin_attack("[key_name_admin(chassis.occupant)] fired a [src] in ([T.x], [T.y], [T.z] - JMP)") + log_game("[key_name(chassis.occupant)] fired a [src] in [T.x], [T.y], [T.z]") + do_after_cooldown() + return /obj/item/missile @@ -375,13 +307,13 @@ var/primed = null throwforce = 15 - throw_impact(atom/hit_atom) - if(primed) - explosion(hit_atom, 0, 0, 2, 4, 0) - qdel(src) - else - ..() - return +/obj/item/missile/throw_impact(atom/hit_atom) + if(primed) + explosion(hit_atom, 0, 0, 2, 4, 0) + qdel(src) + else + ..() + return /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang name = "SGL-6 Grenade Launcher" @@ -394,18 +326,19 @@ equip_cooldown = 60 var/det_time = 20 size=1 - action(target) - if(!action_checks(target)) return - set_ready_state(0) - var/obj/item/weapon/grenade/flashbang/F = new projectile(chassis.loc) - playsound(chassis, fire_sound, 50, 1) - F.throw_at(target, missile_range, missile_speed, chassis) - projectiles-- - log_message("Fired from [src.name], targeting [target].") - spawn(det_time) - F.prime() - do_after_cooldown() +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/action(target, params) + if(!action_checks(target)) return + set_ready_state(0) + var/obj/item/weapon/grenade/flashbang/F = new projectile(chassis.loc) + playsound(chassis, fire_sound, 50, 1) + F.throw_at(target, missile_range, missile_speed, chassis) + projectiles-- + log_message("Fired from [name], targeting [target].") + spawn(det_time) + F.prime() + do_after_cooldown() + return /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang//Because I am a heartless bastard -Sieve name = "SOB-3 Grenade Launcher" @@ -417,7 +350,7 @@ size=1 /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang/limited/get_equip_info()//Limited version of the clusterbang launcher that can't reload - return "* [chassis.selected==src?"":""][src.name][chassis.selected==src?"":""]\[[src.projectiles]\]" + return "* [chassis.selected==src?"":""][name][chassis.selected==src?"":""]\[[projectiles]\]" /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang/limited/rearm() return//Extra bit of security @@ -432,22 +365,23 @@ projectile_energy_cost = 100 equip_cooldown = 20 - can_attach(obj/mecha/combat/honker/M as obj) - if(..()) - if(istype(M)) - return 1 - return 0 +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/banana_mortar/can_attach(obj/mecha/combat/honker/M as obj) + if(..()) + if(istype(M)) + return 1 + return 0 - action(target) - if(!action_checks(target)) return - set_ready_state(0) - var/obj/item/weapon/bananapeel/B = new projectile(chassis.loc) - playsound(chassis, fire_sound, 60, 1) - B.throw_at(target, missile_range, missile_speed, chassis) - projectiles-- - log_message("Bananed from [src.name], targeting [target]. HONK!") - do_after_cooldown() +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/banana_mortar/action(target, params) + if(!action_checks(target)) return + set_ready_state(0) + var/obj/item/weapon/bananapeel/B = new projectile(chassis.loc) + playsound(chassis, fire_sound, 60, 1) + B.throw_at(target, missile_range, missile_speed, chassis) + projectiles-- + log_message("Bananed from [name], targeting [target]. HONK!") + do_after_cooldown() + return /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/mousetrap_mortar @@ -460,23 +394,24 @@ projectile_energy_cost = 100 equip_cooldown = 10 - can_attach(obj/mecha/combat/honker/M as obj) - if(..()) - if(istype(M)) - return 1 - return 0 +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/mousetrap_mortar/can_attach(obj/mecha/combat/honker/M as obj) + if(..()) + if(istype(M)) + return 1 + return 0 - action(target) - if(!action_checks(target)) return - set_ready_state(0) - var/obj/item/device/assembly/mousetrap/M = new projectile(chassis.loc) - M.secured = 1 - playsound(chassis, fire_sound, 60, 1) - M.throw_at(target, missile_range, missile_speed, chassis) - projectiles-- - log_message("Launched a mouse-trap from [src.name], targeting [target]. HONK!") - do_after_cooldown() +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/mousetrap_mortar/action(target, params) + if(!action_checks(target)) return + set_ready_state(0) + var/obj/item/device/assembly/mousetrap/M = new projectile(chassis.loc) + M.secured = 1 + playsound(chassis, fire_sound, 60, 1) + M.throw_at(target, missile_range, missile_speed, chassis) + projectiles-- + log_message("Launched a mouse-trap from [name], targeting [target]. HONK!") + do_after_cooldown() + return /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/bolas name = "PCMK-6 Bolas Launcher" @@ -489,23 +424,24 @@ projectile_energy_cost = 50 equip_cooldown = 10 - can_attach(obj/mecha/combat/gygax/M as obj) - if(..()) - if(istype(M)) - return 1 - return 0 +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/bolas/can_attach(obj/mecha/combat/gygax/M as obj) + if(..()) + if(istype(M)) + return 1 + return 0 - action(target) - if(!action_checks(target)) return - set_ready_state(0) - var/obj/item/weapon/legcuffs/bolas/M = new projectile(chassis.loc) - playsound(chassis, fire_sound, 50, 1) - M.thrown_from = src - M.throw_at(target, missile_range, missile_speed) - projectiles-- - log_message("Fired from [src.name], targeting [target].") - do_after_cooldown() +/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/bolas/action(target, params) + if(!action_checks(target)) return + set_ready_state(0) + var/obj/item/weapon/legcuffs/bolas/M = new projectile(chassis.loc) + playsound(chassis, fire_sound, 50, 1) + M.thrown_from = src + M.throw_at(target, missile_range, missile_speed) + projectiles-- + log_message("Fired from [name], targeting [target].") + do_after_cooldown() + return /obj/item/mecha_parts/mecha_equipment/weapon/energy/plasma equip_cooldown = 20 diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index ceeca47f72e..fcfccd1f9b6 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -219,7 +219,7 @@ // return ..() */ -/obj/mecha/proc/click_action(atom/target,mob/user) +/obj/mecha/proc/click_action(atom/target, mob/user, params) if(!src.occupant || src.occupant != user ) return if(user.stat || !user.canmove) return @@ -239,9 +239,9 @@ return if(!target.Adjacent(src)) if(selected && selected.is_ranged()) - selected.action(target) + selected.action(target, params) else if(selected && selected.is_melee()) - selected.action(target) + selected.action(target, params) else if(internal_damage&MECHA_INT_CONTROL_LOST) target = safepick(oview(1,src)) @@ -1991,4 +1991,4 @@ /obj/mecha/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list()) - flick_overlay(image('icons/mob/talk.dmi', bubble_loc, bubble_state,MOB_LAYER+1), bubble_recipients, 30) \ No newline at end of file + flick_overlay(image('icons/mob/talk.dmi', bubble_loc, bubble_state,MOB_LAYER+1), bubble_recipients, 30) diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm index 744edcd7711..d73edde1525 100644 --- a/code/game/objects/effects/effect_system.dm +++ b/code/game/objects/effects/effect_system.dm @@ -916,6 +916,8 @@ steam.start() -- spawns the effect /obj/effect/effect/foam/New(loc, var/ismetal=0) ..(loc) icon_state = "[ismetal ? "m":""]foam" + if(!ismetal && reagents) + color = mix_color_from_reagents(reagents.reagent_list) metal = ismetal playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3) spawn(3 + metal*3) @@ -944,10 +946,13 @@ steam.start() -- spawns the effect // on delete, transfer any reagents to the floor /obj/effect/effect/foam/Destroy() if(!metal && reagents) - for(var/atom/A in oview(0,src)) + reagents.handle_reactions() + for(var/atom/A in oview(1, src)) if(A == src) continue - reagents.reaction(A, 1, 1) + if(reagents.total_volume) + var/fraction = 5 / reagents.total_volume + reagents.reaction(A, TOUCH, fraction) return ..() /obj/effect/effect/foam/process() @@ -969,13 +974,14 @@ steam.start() -- spawns the effect if(F) continue - F = new(T, metal) + F = new /obj/effect/effect/foam(T, metal) F.amount = amount if(!metal) - F.create_reagents(10) - if (reagents) + F.create_reagents(15) + if(reagents) for(var/datum/reagent/R in reagents.reagent_list) - F.reagents.add_reagent(R.id,1) + F.reagents.add_reagent(R.id, min(R.volume, 3), R.data, reagents.chem_temp) + F.color = mix_color_from_reagents(reagents.reagent_list) // foam disolves when heated // except metal foams @@ -993,16 +999,26 @@ steam.start() -- spawns the effect if (istype(AM, /mob/living/carbon)) var/mob/living/carbon/M = AM - M.slip("foam", 5, 2) + if(M.slip("foam", 5, 2)) + if(reagents) + for(var/reagent_id in reagents.reagent_list) + var/amount = M.reagents.get_reagent_amount(reagent_id) + if(amount < 25) + M.reagents.add_reagent(reagent_id, min(round(amount / 2), 15)) + if(reagents.total_volume) + var/fraction = 5 / reagents.total_volume + reagents.reaction(M, TOUCH, fraction) /datum/effect/system/foam_spread var/amount = 5 // the size of the foam spread. var/list/carried_reagents // the IDs of reagents present when the foam was mixed var/metal = 0 // 0=foam, 1=metalfoam, 2=ironfoam + var/temperature = T0C + var/list/banned_reagents = list("smoke_powder", "fluorosurfactant", "stimulants") /datum/effect/system/foam_spread/set_up(amt=5, loca, var/datum/reagents/carry = null, var/metalfoam = 0) - amount = round(sqrt(amt / 3), 1) + amount = min(round(amt/5, 1), 7) if(istype(loca, /turf/)) location = loca else @@ -1010,35 +1026,40 @@ steam.start() -- spawns the effect carried_reagents = list() metal = metalfoam - + temperature = carry.chem_temp // bit of a hack here. Foam carries along any reagent also present in the glass it is mixed // with (defaults to water if none is present). Rather than actually transfer the reagents, // this makes a list of the reagent ids and spawns 1 unit of that reagent when the foam disolves. - if(carry && !metal) for(var/datum/reagent/R in carry.reagent_list) - carried_reagents += R.id + carried_reagents[R.id] = R.volume /datum/effect/system/foam_spread/start() spawn(0) var/obj/effect/effect/foam/F = locate() in location if(F) F.amount += amount + F.amount = min(F.amount, 27) return - F = new(src.location, metal) + F = new /obj/effect/effect/foam(location, metal) F.amount = amount if(!metal) // don't carry other chemicals if a metal foam - F.create_reagents(10) + F.create_reagents(15) if(carried_reagents) for(var/id in carried_reagents) - F.reagents.add_reagent(id,1) + if(banned_reagents.Find("[id]")) + continue + var/datum/reagent/reagent_volume = carried_reagents[id] + F.reagents.add_reagent(id, min(reagent_volume, 3), null, temperature) + F.color = mix_color_from_reagents(F.reagents.reagent_list) else - F.reagents.add_reagent("water", 1) + F.reagents.add_reagent("cleaner", 1) + F.color = mix_color_from_reagents(F.reagents.reagent_list) // wall formed by metal foams // dense and opaque, but easy to break diff --git a/code/game/objects/effects/spawners/lootdrop.dm b/code/game/objects/effects/spawners/lootdrop.dm index a916172118a..d88d5a309d1 100644 --- a/code/game/objects/effects/spawners/lootdrop.dm +++ b/code/game/objects/effects/spawners/lootdrop.dm @@ -118,3 +118,41 @@ /obj/item/weapon/relic = 3, "" = 11 ) + +/obj/effect/spawner/lootdrop/trade_sol_rare + name = "trader rare item spawner" + lootdoubles = 0 + color = "#00FFFF" + + loot = list( + /obj/item/weapon/card/emag_broken = 2, + /obj/item/weapon/defibrillator/compact/loaded = 2, + /obj/item/weapon/gun/energy/laser/retro = 2, + /obj/item/weapon/rcd/combat = 1, + /obj/item/weapon/rcd = 2, + ) + +/obj/effect/spawner/lootdrop/trade_sol_common + name = "trader common item spawner" + lootdoubles = 0 + color = "#00FFFF" + + loot = list( + /obj/item/weapon/tank/anesthetic = 2, + /obj/item/weapon/weldingtool/hugetank = 2, + /obj/item/weapon/pickaxe/diamond = 1, + /obj/item/device/spacepod_equipment/weaponry/mining_laser = 1, + /obj/item/device/paicard = 2, + /obj/item/weapon/gun/projectile/automatic/pistol = 2, + /obj/item/device/megaphone = 2, + /obj/item/weapon/stock_parts/capacitor = 1, + /obj/item/weapon/stock_parts/cell/high = 1, + /obj/item/weapon/stock_parts/manipulator = 1, + /obj/item/weapon/stock_parts/matter_bin = 1, + /obj/item/weapon/stock_parts/micro_laser = 1, + /obj/item/weapon/stock_parts/scanning_module = 1, + /obj/item/weapon/spacecash/c200 = 1, + /obj/item/weapon/airlock_electronics = 1, + /obj/item/weapon/gun/energy/kinetic_accelerator/super = 1, + /obj/item/pizzabox = 3, + ) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 417ad82d46b..2a3fe4a2a03 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -31,7 +31,7 @@ //If this is set, The item will make an action button on the player's HUD when picked up. var/action_button_name //It is also the text which gets displayed on the action button. If not set it defaults to 'Use [name]'. If it's not set, there'll be no button. - var/action_button_is_hands_free = 0 //If 1, bypass the restrained, lying, and stunned checks action buttons normally test for + var/action_button_custom_type = null var/datum/action/item_action/action = null var/list/materials = list() diff --git a/code/game/objects/items/control_wand.dm b/code/game/objects/items/control_wand.dm index 86f6fd5a74d..178f56912c1 100644 --- a/code/game/objects/items/control_wand.dm +++ b/code/game/objects/items/control_wand.dm @@ -31,6 +31,9 @@ /obj/item/weapon/door_remote/afterattack(obj/machinery/door/airlock/D, mob/user) if(!istype(D)) return + if(D.is_special) + to_chat(user, "[src] cannot access this kind of door!") + return if(!(D.arePowerSystemsOn())) to_chat(user, "[D] has no power!") return @@ -99,6 +102,12 @@ icon_state = "gangtool-white" region_access = REGION_GENERAL +/obj/item/weapon/door_remote/centcomm + name = "centcomm door remote" + desc = "High-ranking NT officials only." + icon_state = "gangtool-blue" + region_access = REGION_CENTCOMM + #undef WAND_OPEN #undef WAND_BOLT -#undef WAND_EMERGENCY \ No newline at end of file +#undef WAND_EMERGENCY diff --git a/code/game/objects/items/devices/floor_painter.dm b/code/game/objects/items/devices/floor_painter.dm new file mode 100644 index 00000000000..7fa9759e330 --- /dev/null +++ b/code/game/objects/items/devices/floor_painter.dm @@ -0,0 +1,98 @@ +// Floor painter + +/obj/item/device/floor_painter + name = "floor painter" + icon_state = "floor_painter" + + var/floor_icon + var/floor_state = "floor" + var/floor_dir = SOUTH + + w_class = 1 + item_state = "electronic" + flags = CONDUCT + slot_flags = SLOT_BELT + + var/static/list/allowed_states = list("arrival", "arrivalcorner", "bar", "barber", "blackcorner", "blue", "bluecorner", + "bluefull", "bluered", "blueyellow", "blueyellowfull", "bot", "brown", "browncorner", "browncornerold", "brownold", + "cafeteria", "caution", "cautioncorner", "chapel", "cmo", "dark", "delivery", "escape", "escapecorner", "floor", + "freezerfloor", "green", "greenblue", "greenbluefull", "greencorner", "greenfull", "greenyellow", + "greenyellowfull", "grimy", "loadingarea", "neutral", "neutralcorner", "neutralfull", "orange", "orangecorner", + "orangefull", "purple", "purplecorner", "purplefull", "rampbottom", "ramptop", "red", "redblue", "redbluefull", + "redcorner", "redfull", "redgreen", "redgreenfull", "redyellow", "redyellowfull", "warning", "warningcorner", "warnwhite", + "warnwhitecorner", "white", "whiteblue", "whitebluecorner", "whitebluefull", "whitebot", "whitecorner", "whitedelivery", + "whitegreen", "whitegreencorner", "whitegreenfull", "whitehall", "whitepurple", "whitepurplecorner", "whitepurplefull", + "whitered", "whiteredcorner", "whiteredfull", "whiteyellow", "whiteyellowcorner", "whiteyellowfull", "yellow", + "yellowcorner", "yellowcornersiding", "yellowsiding") + +/obj/item/device/floor_painter/afterattack(var/atom/A, var/mob/user, proximity, params) + if(!proximity) + return + + var/turf/simulated/floor/plasteel/F = A + if(!istype(F)) + to_chat(user, "\The [src] can only be used on station flooring.") + return + + F.icon_state = floor_state + F.icon_regular_floor = floor_state + F.dir = floor_dir + +/obj/item/device/floor_painter/attack_self(var/mob/user) + if(!user) + return 0 + user.set_machine(src) + interact(user) + return 1 + +/obj/item/device/floor_painter/interact(mob/user as mob) + if(!floor_icon) + floor_icon = icon('icons/turf/floors.dmi', floor_state, floor_dir) + user << browse_rsc(floor_icon, "floor.png") + var/dat = {" +
+ <- + + -> +
+ Choose Style +
Style: [floor_state]
+ Choose Direction +
Direction: [dir2text(floor_dir)]
+ "} + + var/datum/browser/popup = new(user, "floor_painter", name, 225, 300) + popup.set_content(dat) + popup.open() + +/obj/item/device/floor_painter/Topic(href, href_list) + if(..()) + return + + if(href_list["choose_state"]) + var/state = input("Please select a style", "[src]") as null|anything in allowed_states + if(state) + floor_state = state + floor_dir = SOUTH // Reset dir, because some icon_states might not have that dir. + if(href_list["choose_dir"]) + var/seldir = input("Please select a direction", "[src]") as null|anything in list("north", "south", "east", "west", "northeast", "northwest", "southeast", "southwest") + if(seldir) + floor_dir = text2dir(seldir) + if(href_list["cycleleft"]) + var/index = allowed_states.Find(floor_state) + index-- + if(index < 1) + index = allowed_states.len + floor_state = allowed_states[index] + floor_dir = SOUTH + if(href_list["cycleright"]) + var/index = allowed_states.Find(floor_state) + index++ + if(index > allowed_states.len) + index = 1 + floor_state = allowed_states[index] + floor_dir = SOUTH + + floor_icon = icon('icons/turf/floors.dmi', floor_state, floor_dir) + if(usr) + attack_self(usr) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 741ecfa7fa2..1f86a35c497 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -422,11 +422,13 @@ var/global/list/default_medbay_channels = list( //#### Sending the signal to all subspace receivers ####// for(var/obj/machinery/telecomms/receiver/R in telecomms_list) - R.receive_signal(signal) + spawn(0) + R.receive_signal(signal) // Allinone can act as receivers. for(var/obj/machinery/telecomms/allinone/R in telecomms_list) - R.receive_signal(signal) + spawn(0) + R.receive_signal(signal) // Receiving code can be located in Telecommunications.dm return signal.data["done"] && position.z in signal.data["level"] @@ -475,7 +477,8 @@ var/global/list/default_medbay_channels = list( signal.frequency = connection.frequency // Quick frequency set for(var/obj/machinery/telecomms/receiver/R in telecomms_list) - R.receive_signal(signal) + spawn(0) + R.receive_signal(signal) sleep(rand(10,25)) // wait a little... @@ -520,7 +523,7 @@ var/global/list/default_medbay_channels = list( // what the range is in which mobs will hear the radio // returns: -1 if can't receive, range otherwise - if (wires.IsIndexCut(WIRE_RECEIVE)) + if (!wires || wires.IsIndexCut(WIRE_RECEIVE)) return -1 if(!listening) return -1 diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm index ef79d5c2a35..9ea2f17378a 100644 --- a/code/game/objects/items/devices/taperecorder.dm +++ b/code/game/objects/items/devices/taperecorder.dm @@ -233,7 +233,6 @@ sleep(300) canprint = 1 - //empty tape recorders /obj/item/device/taperecorder/empty/New() return @@ -260,12 +259,29 @@ to_chat(user, "You pull out all the tape!") ruin() +/obj/item/device/tape/verb/wipe() + set name = "Wipe Tape" + set category = "Object" + + if(usr.stat) + return + if(ruined) + return + + to_chat(usr, "You erase the data from the [src]") + clear() + +/obj/item/device/tape/proc/clear() + used_capacity = 0 + storedinfo.Cut() + timestamp.Cut() /obj/item/device/tape/proc/ruin() overlays += "ribbonoverlay" ruined = 1 + /obj/item/device/tape/proc/fix() overlays -= "ribbonoverlay" ruined = 0 @@ -277,6 +293,12 @@ if(do_after(user, 120, target = src)) to_chat(user, "You wound the tape back in!") fix() + else if(istype(I, /obj/item/weapon/pen)) + var/title = stripped_input(usr,"What do you want to name the tape?", "Tape Renaming", name, MAX_NAME_LEN) + if(!title || !length(title)) + name = initial(name) + return + name = "tape - [title]" //Random colour tapes diff --git a/code/game/objects/items/devices/traitordevices.dm b/code/game/objects/items/devices/traitordevices.dm index 2a1bc41970b..f05b179e62a 100644 --- a/code/game/objects/items/devices/traitordevices.dm +++ b/code/game/objects/items/devices/traitordevices.dm @@ -27,35 +27,34 @@ effective or pretty fucking useless. origin_tech = "magnets=3;combat=3;syndicate=3" var/times_used = 0 //Number of times it's been used. - var/max_uses = 2 + var/max_uses = 5 - -/obj/item/device/batterer/attack_self(mob/living/carbon/user as mob, flag = 0, emp = 0) - if(!user) return +/obj/item/device/batterer/examine(mob/user) + ..(user) if(times_used >= max_uses) - to_chat(user, "\red The mind batterer has been burnt out!") + to_chat(user, "[src] is out of charge.") + if(times_used < max_uses) + to_chat(user, "[src] has [max_uses-times_used] charges left.") + +/obj/item/device/batterer/attack_self(mob/living/carbon/user, flag = 0, emp = 0) + if(!user) + return + if(times_used >= max_uses) + to_chat(user, "The mind batterer has been burnt out!") return - user.attack_log += text("\[[time_stamp()]\] Used [src] to knock down people in the area.") - for(var/mob/living/carbon/human/M in orange(10, user)) - spawn() - if(prob(50)) + for(var/mob/living/carbon/human/M in oview(7, user)) + if(prob(50)) + M.Weaken(rand(4,7)) + add_logs(M, user, "stunned", src) + to_chat(M, "You feel a tremendous, paralyzing wave flood your mind.") + else + to_chat(M, "You feel a sudden, electric jolt travel through your head.") - M.Weaken(rand(10,20)) - if(prob(25)) - M.Stun(rand(5,10)) - to_chat(M, "\red You feel a tremendous, paralyzing wave flood your mind.") - if(!iscarbon(user)) - M.LAssailant = null - else - M.LAssailant = user - else - to_chat(M, "\red You feel a sudden, electric jolt travel through your head.") - - playsound(src.loc, 'sound/misc/interference.ogg', 50, 1) - to_chat(user, "\blue You trigger [src].") - times_used += 1 + playsound(loc, 'sound/misc/interference.ogg', 50, 1) + times_used++ + to_chat(user, "You trigger [src]. It has [max_uses-times_used] charges left.") if(times_used >= max_uses) icon_state = "battererburnt" diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm index 9e4d83592b0..5b4afe8095c 100644 --- a/code/game/objects/items/devices/transfer_valve.dm +++ b/code/game/objects/items/devices/transfer_valve.dm @@ -9,6 +9,7 @@ var/mob/attacher = null var/valve_open = 0 var/toggle = 1 + origin_tech = "materials=1;engineering=1" /obj/item/device/transfer_valve/proc/process_activation(var/obj/item/device/D) @@ -187,7 +188,7 @@ attacher_name = "[key_name_admin(attacher)]" var/mob/mob = get_mob_by_key(src.fingerprintslast) - + bombers += "Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]" message_admins("Bomb valve opened at [A.name] (JMP) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name_admin(mob)]") log_game("Bomb valve opened at [A.name] ([bombturf.x],[bombturf.y],[bombturf.z]) with [attached_device ? attached_device : "no device"], attached by [attacher_name]. Last touched by: [key_name(mob)]") diff --git a/code/game/objects/items/policetape.dm b/code/game/objects/items/policetape.dm index bd222c52dbb..ad46a511641 100644 --- a/code/game/objects/items/policetape.dm +++ b/code/game/objects/items/policetape.dm @@ -147,17 +147,14 @@ var/list/tape_roll_applications = list() tape_roll_applications[F] |= direction return -/obj/item/tape/Bumped(M as mob) - if(src.allowed(M)) - var/turf/T = get_turf(src) - M:loc = T - /obj/item/tape/CanPass(atom/movable/mover, turf/target, height=0, air_group=0) if(!density) return 1 if(air_group || (height==0)) return 1 if ((mover.pass_flags & PASSTABLE || istype(mover, /obj/effect/meteor) || mover.throwing == 1) ) return 1 + else if(ismob(mover) && allowed(mover)) + return 1 else return 0 @@ -166,7 +163,7 @@ var/list/tape_roll_applications = list() /obj/item/tape/attack_hand(mob/user as mob) if (user.a_intent == I_HELP && src.allowed(user)) - user.show_viewers("\blue [user] lifts [src], allowing passage.") + user.visible_message("[user] lifts [src], allowing passage.", "You lift [src], allowing passage.") src.density = 0 spawn(200) src.density = 1 @@ -180,7 +177,7 @@ var/list/tape_roll_applications = list() if(user.a_intent == I_HELP && ((!can_puncture(W) && src.allowed(user)))) to_chat(user, "You can't break the [src] with that!") return - user.show_viewers("\blue [user] breaks the [src]!") + user.visible_message("[user] breaks the [src]!", "You break the [src]!") var/dir[2] var/icon_dir = src.icon_state diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index bfb90de8cac..512baa30703 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -125,13 +125,13 @@ to_chat(usr, "This robot has had its disabler removed!") return 0 - if(T.recharge_time <= 2) + if(T.charge_delay <= 2) to_chat(R, "Maximum cooling achieved for this hardpoint!") to_chat(usr, "There's no room for another cooling unit!") return 0 else - T.recharge_time = max(2 , T.recharge_time - 4) + T.charge_delay = max(2 , T.charge_delay - 4) return 1 @@ -214,4 +214,4 @@ return 0 R.emagged = 1 - return 1 \ No newline at end of file + return 1 diff --git a/code/game/objects/items/shooting_range.dm b/code/game/objects/items/shooting_range.dm index c71f2e14182..fd3f5505f4f 100644 --- a/code/game/objects/items/shooting_range.dm +++ b/code/game/objects/items/shooting_range.dm @@ -114,7 +114,7 @@ bmark.pixel_x-- bmark.pixel_y-- - if(Proj.damage >= 20 || istype(Proj, /obj/item/projectile/practice)) + if(Proj.damage >= 20 || istype(Proj, /obj/item/projectile/beam/practice)) bmark.icon_state = "scorch" bmark.dir = pick(NORTH,SOUTH,EAST,WEST) // random scorch design @@ -178,4 +178,4 @@ b2y1 = pixel_y + pick(1,1,1,1,2,2,3,3,4) b2y2 = pixel_y - pick(1,1,1,1,2,2,3,3,4) - Target.bulletholes.Add(src) \ No newline at end of file + Target.bulletholes.Add(src) diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm index e41457f0c38..efba4f62a77 100644 --- a/code/game/objects/items/stacks/rods.dm +++ b/code/game/objects/items/stacks/rods.dm @@ -80,7 +80,7 @@ return to_chat(usr, "\blue Assembling grille...") - if (!do_after(usr, 10, target = src)) + if (!do_after(usr, 10, target = user)) return var /obj/structure/grille/F = new /obj/structure/grille/ ( usr.loc ) diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 3fe6dc7102f..50dc5c3b467 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -140,7 +140,6 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \ new/datum/stack_recipe("wooden barricade", /obj/structure/barricade/wooden, 5, time = 50, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("bookcase", /obj/structure/bookcase, 5, time = 50, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("rifle stock", /obj/item/weaponcrafting/stock, 10, time = 40), \ - new/datum/stack_recipe("crossbow frame", /obj/item/weapon/crossbowframe, 5, time = 25, one_per_turf = 0, on_floor = 0), \ new/datum/stack_recipe("wooden door", /obj/structure/mineral_door/wood, 10, time = 20, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("coffin", /obj/structure/closet/coffin, 5, time = 15, one_per_turf = 1, on_floor = 1), \ new/datum/stack_recipe("easel", /obj/structure/easel, 3, one_per_turf = 1, on_floor = 1), \ diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 41c2946a0c1..bd799640122 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -130,7 +130,7 @@ return if (R.time) to_chat(usr, "\blue Building [R.title] ...") - if (!do_after(usr, R.time, target = src)) + if (!do_after(usr, R.time, target = usr)) return if (src.amount < R.req_amount*multiplier) return @@ -194,20 +194,24 @@ /obj/item/stack/proc/get_max_amount() return max_amount +/obj/item/stack/proc/split(mob/user, amt) + var/obj/item/stack/F = new type(user, amt) + F.copy_evidences(src) + if(isliving(user)) + add_fingerprint(user) + F.add_fingerprint(user) + use(amt) + return F + /obj/item/stack/attack_hand(mob/user as mob) if (user.get_inactive_hand() == src) - var/obj/item/stack/F = new src.type( user, 1) - F.copy_evidences(src) + var/obj/item/stack/F = split(user, 1) user.put_in_hands(F) - src.add_fingerprint(user) - F.add_fingerprint(user) - use(1) - if (src && usr.machine==src) - spawn(0) src.interact(usr) + if(src && usr.machine == src) + spawn(0) + interact(usr) else ..() - update_icon() - return /obj/item/stack/attackby(obj/item/W as obj, mob/user as mob, params) ..() diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index 25ade73eb38..f2f07174ec5 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -1318,7 +1318,7 @@ obj/item/toy/cards/deck/syndicate/black /obj/item/toy/russian_revolver name = "russian revolver" desc = "for fun and games!" - icon = 'icons/obj/gun.dmi' + icon = 'icons/obj/guns/projectile.dmi' icon_state = "detective_gold" item_state = "gun" lefthand_file = 'icons/mob/inhands/guns_lefthand.dmi' diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index 7bd8f6e1207..5d85ea20e2b 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -74,6 +74,12 @@ RCD src.spark_system.start() return if(3) + mode = 4 + to_chat(user, "Changed mode to 'Windows'") + if(prob(20)) + src.spark_system.start() + return + if(4) mode = 1 to_chat(user, "Changed mode to 'Floor & Walls'") if(prob(20)) @@ -88,7 +94,7 @@ RCD if(!proximity) return if(istype(A,/area/shuttle)||istype(A,/turf/space/transit)) return 0 - if(!(istype(A, /turf) || istype(A, /obj/machinery/door/airlock))) + if(!(istype(A, /turf) || istype(A, /obj/machinery/door/airlock) || istype(A, /obj/structure/grille) || istype(A, /obj/structure/window))) return 0 switch(mode) @@ -97,7 +103,8 @@ RCD if(useResource(1, user)) to_chat(user, "Building Floor...") activate() - A:ChangeTurf(/turf/simulated/floor/plating) + var/turf/AT = A + AT.ChangeTurf(/turf/simulated/floor/plating) return 1 return 0 @@ -108,7 +115,8 @@ RCD if(do_after(user, 20, target = A)) if(!useResource(3, user)) return 0 activate() - A:ChangeTurf(/turf/simulated/wall) + var/turf/AT = A + AT.ChangeTurf(/turf/simulated/wall) return 1 return 0 @@ -136,7 +144,8 @@ RCD if(do_after(user, 40, target = A)) if(!useResource(5, user)) return 0 activate() - A:ChangeTurf(/turf/simulated/floor/plating) + var/turf/AT = A + AT.ChangeTurf(/turf/simulated/floor/plating) return 1 return 0 @@ -147,7 +156,8 @@ RCD if(do_after(user, 50, target = A)) if(!useResource(5, user)) return 0 activate() - A:ChangeTurf(/turf/space) + var/turf/AT = A + AT.ChangeTurf(/turf/space) return 1 return 0 @@ -161,7 +171,78 @@ RCD qdel(A) return 1 return 0 + + if(istype(A, /obj/structure/window)) // You mean the grille of course, do you? + A = locate(/obj/structure/grille) in A.loc + + if(istype(A, /obj/structure/grille)) + if(!checkResource(2, user)) + return 0 + to_chat(user, "Deconstructing window...") + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + if(!do_after(user, 20, target = A)) + return 0 + if(locate(/obj/structure/window/full/shuttle) in A.contents) + return 0 // Let's not give shuttle-griefers an easy time. + if(!useResource(2, user)) + return 0 + activate() + var/turf/T1 = get_turf(A) + qdel(A) + A = null + for(var/obj/structure/window/W in T1.contents) + W.disassembled = 1 + W.density = 0 + qdel(W) + for(var/cdir in cardinal) + var/turf/T2 = get_step(T1, cdir) + if(locate(/obj/structure/window/full/shuttle) in T2.contents) + continue // Shuttle windows? Nah. We don't need extra windows there. + if(!(locate(/obj/structure/grille) in T2.contents)) + continue + for(var/obj/structure/window/W in T2.contents) + if(W.dir == turn(cdir, 180)) + W.disassembled = 1 + W.density = 0 + qdel(W) + var/obj/structure/window/reinforced/W = new(T2) + W.dir = turn(cdir, 180) + return 1 return 0 + if(4) + if(istype(A, /turf/simulated/floor)) + if(locate(/obj/structure/grille) in contents) + return 0 // We already have window + if(!checkResource(2, user)) + return 0 + to_chat(user, "Constructing window...") + playsound(src.loc, 'sound/machines/click.ogg', 50, 1) + if(!do_after(user, 20, target = A)) + return 0 + if(locate(/obj/structure/grille) in A.contents) + return 0 // We already have window + if(!useResource(2, user)) + return 0 + activate() + new /obj/structure/grille(A) + for(var/obj/structure/window/W in contents) + W.disassembled = 1 // Prevent that annoying glass breaking sound + W.density = 0 + qdel(W) + for(var/cdir in cardinal) + var/turf/T = get_step(A, cdir) + if(locate(/obj/structure/grille) in T.contents) + for(var/obj/structure/window/W in T.contents) + if(W.dir == turn(cdir, 180)) + W.disassembled = 1 + W.density = 0 + qdel(W) + else // Build a window! + var/obj/structure/window/reinforced/W = new(A) + W.dir = cdir + var/turf/AT = A + AT.ChangeTurf(/turf/simulated/floor/plating) // Platings go under windows. + return 1 else to_chat(user, "ERROR: RCD in MODE: [mode] attempted use by [user]. Send this text #coderbus or an admin.") return 0 diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index d30cc76b0a7..79c6466235b 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -107,6 +107,8 @@ var/icon/side var/dat var/stamped = 0 + + var/obj/item/weapon/card/id/guest/guest_pass = null // Guest pass attached to the ID /obj/item/weapon/card/id/New() ..() @@ -120,6 +122,16 @@ show(usr) else to_chat(user, "It is too far away.") + if(guest_pass) + to_chat(user, "There is a guest pass attached to this ID card") + if (world.time < guest_pass.expiration_time) + to_chat(user, "It expires at [worldtime2text(guest_pass.expiration_time)].") + else + to_chat(user, "It expired at [worldtime2text(guest_pass.expiration_time)].") + to_chat(user, "It grants access to following areas:") + for (var/A in guest_pass.temp_access) + to_chat(user, "[get_access_desc(A)].") + to_chat(user, "Issuing reason: [guest_pass.reason].") /obj/item/weapon/card/id/proc/show(mob/user as mob) var/datum/asset/assets = get_asset_datum(/datum/asset/simple/paper) @@ -170,7 +182,9 @@
" /obj/item/weapon/card/id/GetAccess() - return access + if(!guest_pass) + return access + return access | guest_pass.GetAccess() /obj/item/weapon/card/id/GetID() return src @@ -204,9 +218,42 @@ if(!stamped) dat+="" stamped = 1 - to_chat(usr, "You stamp the ID card!") + to_chat(user, "You stamp the ID card!") else - to_chat(usr, "This ID has already been stamped!") + to_chat(user, "This ID has already been stamped!") + + else if(istype(W, /obj/item/weapon/card/id/guest)) + if(istype(src, /obj/item/weapon/card/id/guest)) + return + var/obj/item/weapon/card/id/guest/G = W + if(world.time > G.expiration_time) + to_chat(user, "There's no point, the guest pass has expired.") + return + if(guest_pass) + to_chat(user, "There's already a guest pass attached to this ID.") + return + if(G.registered_name != registered_name && G.registered_name != "NOT SPECIFIED") + to_chat(user, "The guest pass cannot be attached to this ID") + return + if(!user.unEquip(G)) + return + G.loc = src + guest_pass = G + +/obj/item/weapon/card/id/verb/remove_guest_pass() + set name = "Remove Guest Pass" + set category = "Object" + set src in range(0) + + if(usr.stat || !usr.canmove || usr.restrained()) + return + + if(guest_pass) + to_chat(usr, "You remove the guest pass from this ID.") + guest_pass.forceMove(get_turf(src)) + guest_pass = null + else + to_chat(usr, "There is no guest pass attached to this ID") /obj/item/weapon/card/id/silver name = "identification card" diff --git a/code/game/objects/items/weapons/chrono_eraser.dm b/code/game/objects/items/weapons/chrono_eraser.dm index e0ac96c4feb..b0a1c45622d 100644 --- a/code/game/objects/items/weapons/chrono_eraser.dm +++ b/code/game/objects/items/weapons/chrono_eraser.dm @@ -41,12 +41,11 @@ icon = 'icons/obj/chronos.dmi' icon_state = "chronogun" item_state = "chronogun" - w_class = 3.0 - projectile_type = "/obj/item/projectile/energy/chrono_beam" - fire_sound = 'sound/weapons/Laser.ogg' - charge_cost = 0 - fire_delay = 50 + w_class = 3 flags = NODROP + ammo_type = list(/obj/item/ammo_casing/energy/chrono_beam) + can_charge = 0 + fire_delay = 50 var/obj/item/weapon/chrono_eraser/TED = null var/obj/effect/chrono_field/field = null var/turf/startpos = null @@ -60,12 +59,13 @@ qdel(src) /obj/item/weapon/gun/energy/chrono_gun/dropped() + ..() qdel(src) /obj/item/weapon/gun/energy/chrono_gun/update_icon() return -/obj/item/weapon/gun/energy/chrono_gun/Fire() +/obj/item/weapon/gun/energy/chrono_gun/process_fire() if(field) field_disconnect(field) ..() @@ -125,18 +125,23 @@ nodamage = 1 var/obj/item/weapon/gun/energy/chrono_gun/gun = null -/obj/item/projectile/energy/chrono_beam/process() +/obj/item/projectile/energy/chrono_beam/fire() gun = firer.get_active_hand() if(istype(gun)) return ..() else return 0 -/obj/item/projectile/energy/chrono_beam/on_hit(var/atom/target) +/obj/item/projectile/energy/chrono_beam/on_hit(atom/target) if(target && gun && isliving(target)) var/obj/effect/chrono_field/F = new(target.loc, target, gun) gun.field_connect(F) +/obj/item/ammo_casing/energy/chrono_beam + name = "eradication beam" + projectile_type = /obj/item/projectile/energy/chrono_beam + icon_state = "chronobolt" + e_cost = 0 /obj/effect/chrono_field name = "eradication field" @@ -256,4 +261,4 @@ #undef CHRONO_BEAM_RANGE -#undef CHRONO_FRAME_COUNT \ No newline at end of file +#undef CHRONO_FRAME_COUNT diff --git a/code/game/objects/items/weapons/cosmetics.dm b/code/game/objects/items/weapons/cosmetics.dm index 3e2448fa8fe..89a8b52b8da 100644 --- a/code/game/objects/items/weapons/cosmetics.dm +++ b/code/game/objects/items/weapons/cosmetics.dm @@ -91,16 +91,16 @@ /obj/item/weapon/razor/attack(mob/living/carbon/M as mob, mob/user as mob) if(ishuman(M)) var/mob/living/carbon/human/H = M - var/obj/item/organ/external/head/C = H.organs_by_name["head"] + var/obj/item/organ/external/head/C = H.get_organ("head") var/datum/robolimb/robohead = all_robolimbs[C.model] if(user.zone_sel.selecting == "mouth") if(!get_location_accessible(H, "mouth")) to_chat(user, "The mask is in the way.") return - if((H.species && H.species.flags & ALL_RPARTS) && robohead.is_monitor) //If the target is of a species that can have prosthetic heads, but the head doesn't support human hair 'wigs'... + if((C.species && C.species.flags & ALL_RPARTS) && robohead.is_monitor) //If the target is of a species that can have prosthetic heads, but the head doesn't support human hair 'wigs'... to_chat(user, "You find yourself disappointed at the appalling lack of facial hair.") return - if(H.f_style == "Shaved") + if(C.f_style == "Shaved") to_chat(user, "Already clean-shaven.") return if(H == user) //shaving yourself @@ -109,7 +109,7 @@ if(do_after(user, 50, target = H)) user.visible_message("[user] shaves his facial hair clean with the [src].", \ "You finish shaving with the [src]. Fast and clean!") - H.f_style = "Shaved" + C.f_style = "Shaved" H.update_fhair() playsound(src.loc, 'sound/items/Welder2.ogg', 20, 1) else @@ -121,17 +121,17 @@ if(user_loc == user.loc && H_loc == H.loc) user.visible_message("[user] shaves off [H]'s facial hair with \the [src].", \ "You shave [H]'s facial hair clean off.") - H.f_style = "Shaved" + C.f_style = "Shaved" H.update_fhair() playsound(src.loc, 'sound/items/Welder2.ogg', 20, 1) if(user.zone_sel.selecting == "head") if(!get_location_accessible(H, "head")) to_chat(user, "The headgear is in the way.") return - if((H.species && H.species.flags & ALL_RPARTS) && robohead.is_monitor) //If the target is of a species that can have prosthetic heads, but the head doesn't support human hair 'wigs'... + if((C.species && C.species.flags & ALL_RPARTS) && robohead.is_monitor) //If the target is of a species that can have prosthetic heads, but the head doesn't support human hair 'wigs'... to_chat(user, "You find yourself disappointed at the appalling lack of hair.") return - if(H.h_style == "Bald" || H.h_style == "Balding Hair" || H.h_style == "Skinhead") + if(C.h_style == "Bald" || C.h_style == "Balding Hair" || C.h_style == "Skinhead") to_chat(user, "There is not enough hair left to shave...") return if(H == user) //shaving yourself @@ -140,7 +140,7 @@ if(do_after(user, 50, target = H)) user.visible_message("[user] shaves his head with the [src].", \ "You finish shaving with the [src].") - H.h_style = "Skinhead" + C.h_style = "Skinhead" H.update_hair() playsound(src.loc, 'sound/items/Welder2.ogg', 40, 1) else @@ -152,7 +152,7 @@ if(user_loc == user.loc && H_loc == H.loc) user.visible_message("[user] shaves [H]'s head bald with \the [src]!", \ "You shave [H]'s head bald.") - H.h_style = "Skinhead" + C.h_style = "Skinhead" H.update_hair() playsound(src.loc, 'sound/items/Welder2.ogg', 40, 1) else diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index 73eda279b3d..2cc37b0ba85 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -368,8 +368,26 @@ update_icon() return if(H.heart_attack) - H.heart_attack = 0 - if(H.stat == 2) + if(!H.get_int_organ(/obj/item/organ/internal/heart) && !H.get_int_organ(/obj/item/organ/internal/brain/slime)) //prevents defibing someone still alive suffering from a heart attack attack if they lack a heart + user.visible_message("[defib] buzzes: Resuscitation failed - Failed to pick up any heart electrical activity.") + playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0) + busy = 0 + update_icon() + return + else + H.heart_attack = 0 + user.visible_message("[defib] pings: Cardiac arrhythmia corrected.") + M.visible_message("[M]'s body convulses a bit.") + playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 50, 1, -1) + playsound(get_turf(src), "bodyfall", 50, 1) + playsound(get_turf(src), 'sound/machines/defib_success.ogg', 50, 0) + defib.deductcharge(revivecost) + busy = 0 + cooldown = 1 + update_icon() + defib.cooldowncheck(user) + return + if(H.stat == DEAD) var/health = H.health M.visible_message("[M]'s body convulses a bit.") playsound(get_turf(src), "bodyfall", 50, 1) @@ -377,7 +395,7 @@ for(var/obj/item/organ/external/O in H.organs) total_brute += O.brute_dam total_burn += O.burn_dam - if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !(NOCLONE in H.mutations)) + if(total_burn <= 180 && total_brute <= 180 && !H.suiciding && !ghost && tplus < tlimit && !(NOCLONE in H.mutations) && (H.get_int_organ(/obj/item/organ/internal/heart) || H.get_int_organ(/obj/item/organ/internal/brain/slime))) tobehealed = min(health + threshold, 0) // It's HILARIOUS without this min statement, let me tell you tobehealed -= 5 //They get 5 of each type of damage healed so excessive combined damage will not immediately kill them after they get revived H.adjustOxyLoss(tobehealed) diff --git a/code/game/objects/items/weapons/dnascrambler.dm b/code/game/objects/items/weapons/dnascrambler.dm index 47bea6ca58d..2765b4a319d 100644 --- a/code/game/objects/items/weapons/dnascrambler.dm +++ b/code/game/objects/items/weapons/dnascrambler.dm @@ -1,16 +1,16 @@ /obj/item/weapon/dnascrambler name = "dna scrambler" desc = "An illegal genetic serum designed to randomize the user's identity." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/obj/hypo.dmi' item_state = "syringe_0" - icon_state = "b10" + icon_state = "lepopen1" var/used = null update_icon() if(used) - icon_state = "b0" + icon_state = "lepopen0" else - icon_state = "b10" + icon_state = "lepopen1" attack(mob/M as mob, mob/user as mob) if(!M || !user) diff --git a/code/game/objects/items/weapons/grenades/chem_grenade.dm b/code/game/objects/items/weapons/grenades/chem_grenade.dm index 149cc03a866..a951f1ade8f 100644 --- a/code/game/objects/items/weapons/grenades/chem_grenade.dm +++ b/code/game/objects/items/weapons/grenades/chem_grenade.dm @@ -458,11 +458,11 @@ New() ..() var/obj/item/weapon/reagent_containers/glass/beaker/B1 = new(src) - var/obj/item/weapon/reagent_containers/glass/beaker/large/B2 = new(src) + var/obj/item/weapon/reagent_containers/glass/beaker/B2 = new(src) B1.reagents.add_reagent("fluorosurfactant", 40) - B2.reagents.add_reagent("water", 40) - B2.reagents.add_reagent("cleaner", 60) + B2.reagents.add_reagent("cleaner", 10) + B2.reagents.add_reagent("water", 40) //when you make pre-designed foam reactions that carry the reagents, always add water last beakers += B1 beakers += B2 diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm new file mode 100644 index 00000000000..b56e103233e --- /dev/null +++ b/code/game/objects/items/weapons/holy_weapons.dm @@ -0,0 +1,456 @@ +/obj/item/weapon/nullrod + name = "null rod" + desc = "A rod of pure obsidian, its very presence disrupts and dampens the powers of Nar-Sie's followers." + icon_state = "nullrod" + item_state = "nullrod" + force = 18 + throw_speed = 3 + throw_range = 4 + throwforce = 10 + w_class = 1 + var/reskinned = FALSE + var/list/fluff_transformations = list() //does it have any special transformations only accessible to it? Should only be subtypes of /obj/item/weapon/nullrod + +/obj/item/weapon/nullrod/suicide_act(mob/user) + user.visible_message("[user] is killing \himself with \the [src.name]! It looks like \he's trying to get closer to god!") + return (BRUTELOSS|FIRELOSS) + +/obj/item/weapon/nullrod/attack(mob/M, mob/living/carbon/user) + ..() + if(M.mind) + if(M.mind.vampire) + if(ishuman(M)) + if(!M.mind.vampire.get_ability(/datum/vampire_passive/full)) + to_chat(M, "The nullrod's power interferes with your own!") + M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) + +/obj/item/weapon/nullrod/attack_self(mob/user) + if(reskinned) + return + if(user.mind && (user.mind.assigned_role == "Chaplain")) + reskin_holy_weapon(user) + +/obj/item/weapon/nullrod/proc/reskin_holy_weapon(mob/M) + var/list/holy_weapons_list = typesof(/obj/item/weapon/nullrod) - typesof(/obj/item/weapon/nullrod/fluff) + if(fluff_transformations.len) + for(var/thing in fluff_transformations) + holy_weapons_list += thing + var/list/display_names = list() + for(var/V in holy_weapons_list) + var/atom/A = V + display_names += initial(A.name) + + var/choice = input(M,"What theme would you like for your holy weapon?","Holy Weapon Theme") as null|anything in display_names + if(!src || !choice || !in_range(M, src) || M.incapacitated() || reskinned) + return + + var/index = display_names.Find(choice) + var/A = holy_weapons_list[index] + + var/obj/item/weapon/nullrod/holy_weapon = new A + + feedback_set_details("chaplain_weapon","[choice]") + + if(holy_weapon) + holy_weapon.reskinned = TRUE + M.unEquip(src) + M.put_in_active_hand(holy_weapon) + qdel(src) + +/obj/item/weapon/nullrod/godhand + icon_state = "disintegrate" + item_state = "disintegrate" + name = "god hand" + desc = "This hand of yours glows with an awesome power!" + flags = ABSTRACT | NODROP + w_class = 5 + hitsound = 'sound/weapons/sear.ogg' + damtype = BURN + attack_verb = list("punched", "cross countered", "pummeled") + +/obj/item/weapon/nullrod/staff + icon_state = "godstaff-red" + item_state = "godstaff-red" + name = "red holy staff" + desc = "It has a mysterious, protective aura." + w_class = 5 + force = 5 + slot_flags = SLOT_BACK + +/obj/item/weapon/nullrod/staff/IsShield() + return 1 + +/obj/item/weapon/nullrod/staff/blue + name = "blue holy staff" + icon_state = "godstaff-blue" + item_state = "godstaff-blue" + +/obj/item/weapon/nullrod/claymore + icon_state = "claymore" + item_state = "claymore" + name = "holy claymore" + desc = "A weapon fit for a crusade!" + w_class = 4 + slot_flags = SLOT_BACK|SLOT_BELT + sharp = 1 + edge = 1 + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/weapon/nullrod/claymore/IsShield() + if(prob(30)) + return 1 + else + return 0 + +/obj/item/weapon/nullrod/claymore/darkblade + icon_state = "cultblade" + item_state = "cultblade" + name = "dark blade" + desc = "Spread the glory of the dark gods!" + slot_flags = SLOT_BELT + hitsound = 'sound/hallucinations/growl1.ogg' + +/obj/item/weapon/nullrod/claymore/chainsaw_sword + icon_state = "chainswordon" + item_state = "chainswordon" + name = "sacred chainsaw sword" + desc = "Suffer not a heretic to live." + slot_flags = SLOT_BELT + attack_verb = list("sawed", "torn", "cut", "chopped", "diced") + hitsound = 'sound/weapons/chainsaw.ogg' + +/obj/item/weapon/nullrod/claymore/glowing + icon_state = "swordon" + item_state = "swordon" + name = "force weapon" + desc = "The blade glows with the power of faith. Or possibly a battery." + slot_flags = SLOT_BELT + +/obj/item/weapon/nullrod/claymore/katana + name = "hanzo steel" + desc = "Capable of cutting clean through a holy claymore." + icon_state = "katana" + item_state = "katana" + slot_flags = SLOT_BELT | SLOT_BACK + +/obj/item/weapon/nullrod/claymore/multiverse + name = "extradimensional blade" + desc = "Once the harbringer of a interdimensional war, now a dormant souvenir. Still sharp though." + icon_state = "multiverse" + item_state = "multiverse" + slot_flags = SLOT_BELT + +/obj/item/weapon/nullrod/claymore/saber + name = "light energy sword" + hitsound = 'sound/weapons/blade1.ogg' + icon_state = "swordblue" + item_state = "swordblue" + desc = "If you strike me down, I shall become more robust than you can possibly imagine." + slot_flags = SLOT_BELT + +/obj/item/weapon/nullrod/claymore/saber/red + name = "dark energy sword" + icon_state = "swordred" + item_state = "swordred" + desc = "Woefully ineffective when used on steep terrain." + +/obj/item/weapon/nullrod/claymore/saber/pirate + name = "nautical energy sword" + icon_state = "cutlass1" + item_state = "cutlass1" + desc = "Convincing HR that your religion involved piracy was no mean feat." + +/obj/item/weapon/nullrod/sord + name = "\improper UNREAL SORD" + desc = "This thing is so unspeakably HOLY you are having a hard time even holding it." + icon_state = "sord" + item_state = "sord" + slot_flags = SLOT_BELT + force = 4.13 + throwforce = 1 + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/weapon/nullrod/scythe + icon_state = "scythe0" + item_state = "scythe0" + name = "reaper scythe" + desc = "Ask not for whom the bell tolls..." + w_class = 4 + armour_penetration = 35 + slot_flags = SLOT_BACK + sharp = 1 + edge = 1 + attack_verb = list("chopped", "sliced", "cut", "reaped") + hitsound = 'sound/weapons/bladeslice.ogg' + +/obj/item/weapon/nullrod/scythe/vibro + icon_state = "hfrequency0" + item_state = "hfrequency1" + name = "high frequency blade" + desc = "Bad references are the DNA of the soul." + attack_verb = list("chopped", "sliced", "cut", "zandatsu'd") + +/obj/item/weapon/nullrod/scythe/talking + icon_state = "talking_sword" + item_state = "talking_sword" + name = "possessed blade" + desc = "When the station falls into chaos, it's nice to have a friend by your side." + attack_verb = list("chopped", "sliced", "cut") + hitsound = 'sound/weapons/bladeslice.ogg' + var/possessed = FALSE + +/obj/item/weapon/nullrod/scythe/talking/attack_self(mob/living/user) + if(possessed) + return + + to_chat(user, "You attempt to wake the spirit of the blade...") + + possessed = TRUE + + var/list/mob/dead/observer/candidates = pollCandidates("Do you want to play as the spirit of [user.real_name]'s blade?", ROLE_PAI, 0, 100) + var/mob/dead/observer/theghost = null + + if(candidates.len) + theghost = pick(candidates) + var/mob/living/simple_animal/shade/S = new(src) + S.real_name = name + S.name = name + S.ckey = theghost.ckey + var/input = stripped_input(S,"What are you named?", ,"", MAX_NAME_LEN) + + if(src && input) + name = input + S.real_name = input + S.name = input + else + to_chat(user, "The blade is dormant. Maybe you can try again later.") + possessed = FALSE + +/obj/item/weapon/nullrod/scythe/talking/Destroy() + for(var/mob/living/simple_animal/shade/S in contents) + to_chat(S, "You were destroyed!") + S.ghostize() + qdel(S) + return ..() + +/obj/item/weapon/nullrod/hammmer + icon_state = "hammeron" + item_state = "hammeron" + name = "relic war hammer" + desc = "This war hammer cost the chaplain fourty thousand space dollars." + slot_flags = SLOT_BELT + w_class = 5 + attack_verb = list("smashed", "bashed", "hammered", "crunched") + +/obj/item/weapon/nullrod/chainsaw + name = "chainsaw hand" + desc = "Good? Bad? You're the guy with the chainsaw hand." + icon_state = "chainsaw1" + item_state = "mounted_chainsaw" + w_class = 5 + flags = NODROP | ABSTRACT + sharp = 1 + edge = 1 + attack_verb = list("sawed", "torn", "cut", "chopped", "diced") + hitsound = 'sound/weapons/chainsaw.ogg' + +/obj/item/weapon/nullrod/clown + icon = 'icons/obj/wizard.dmi' + icon_state = "clownrender" + item_state = "gold_horn" + name = "clown dagger" + desc = "Used for absolutely hilarious sacrifices." + hitsound = 'sound/items/bikehorn.ogg' + sharp = 1 + edge = 1 + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut", "honked") + +/obj/item/weapon/nullrod/whip + name = "holy whip" + desc = "What a terrible night to be on Space Station 13." + icon_state = "chain" + item_state = "chain" + slot_flags = SLOT_BELT + attack_verb = list("whipped", "lashed") + hitsound = 'sound/weapons/slash.ogg' + +/obj/item/weapon/nullrod/whip/afterattack(atom/movable/AM, mob/user, proximity) + if(!proximity) + return + if(istype(AM, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = AM + if(is_shadow(H)) + var/phrase = pick("Die monster! You don't belong in this world!!!", "You steal men's souls and make them your slaves!!!", "Your words are as empty as your soul!!!", "Mankind ill needs a savior such as you!!!") + user.say("[phrase]") + H.adjustBruteLoss(8) //Bonus damage + +/obj/item/weapon/nullrod/fedora + name = "athiest's fedora" + desc = "The brim of the hat is as sharp as your wit. Throwing it at someone would hurt almost as much as disproving the existence of God." + icon_state = "fedora" + item_state = "fedora" + slot_flags = SLOT_HEAD + icon = 'icons/obj/clothing/hats.dmi' + force = 0 + throw_speed = 4 + throw_range = 7 + throwforce = 20 + +/obj/item/weapon/nullrod/armblade + name = "dark blessing" + desc = "Particularly twisted deities grant gifts of dubious value." + icon_state = "arm_blade" + item_state = "arm_blade" + flags = ABSTRACT | NODROP + w_class = 5 + sharp = 1 + edge = 1 + +/obj/item/weapon/nullrod/carp + name = "carp-sie plushie" + desc = "An adorable stuffed toy that resembles the god of all carp. The teeth look pretty sharp. Activate it to recieve the blessing of Carp-Sie." + icon = 'icons/obj/toy.dmi' + icon_state = "carpplushie" + item_state = "carp_plushie" + force = 15 + attack_verb = list("bitten", "eaten", "fin slapped") + hitsound = 'sound/weapons/bite.ogg' + var/used_blessing = FALSE + +/obj/item/weapon/nullrod/carp/attack_self(mob/living/user) + if(used_blessing) + return + if(user.mind && (user.mind.assigned_role != "Chaplain")) + return + to_chat(user, "You are blessed by Carp-Sie. Wild space carp will no longer attack you.") + user.faction |= "carp" + used_blessing = TRUE + +/obj/item/weapon/nullrod/claymore/bostaff //May as well make it a "claymore" and inherit the blocking + name = "monk's staff" + desc = "A long, tall staff made of polished wood. Traditionally used in ancient old-Earth martial arts, now used to harass the clown." + w_class = 4 + force = 15 + slot_flags = SLOT_BACK + sharp = 0 + edge = 0 + hitsound = "swing_hit" + attack_verb = list("smashed", "slammed", "whacked", "thwacked") + icon = 'icons/obj/weapons.dmi' + icon_state = "bostaff0" + item_state = "bostaff0" + +/obj/item/weapon/nullrod/claymore/bostaff/IsShield() + if(prob(40)) + return 1 + else + return 0 + +/obj/item/weapon/nullrod/tribal_knife + icon_state = "crysknife" + item_state = "crysknife" + name = "arrhythmic knife" + w_class = 5 + desc = "They say fear is the true mind killer, but stabbing them in the head works too. Honour compels you to not sheathe it once drawn." + sharp = 1 + edge = 1 + slot_flags = null + flags = HANDSLOW + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + +/obj/item/weapon/nullrod/tribal_knife/New() + ..() + processing_objects.Add(src) + +/obj/item/weapon/nullrod/tribal_knife/Destroy() + processing_objects.Remove(src) + return ..() + +/obj/item/weapon/nullrod/tribal_knife/process() + slowdown = rand(-2, 2) + +/obj/item/weapon/nullrod/pitchfork + icon_state = "pitchfork0" + item_state = "pitchfork0" + name = "unholy pitchfork" + w_class = 3 + desc = "Holding this makes you look absolutely devilish." + attack_verb = list("poked", "impaled", "pierced", "jabbed") + hitsound = 'sound/weapons/bladeslice.ogg' + sharp = 1 + edge = 1 + +/obj/item/weapon/nullrod/rosary + icon_state = "rosary" + item_state = null + name = "prayer beads" + desc = "A set of prayer beads used by many of the more traditional religions in space.
Vampires and other unholy abominations have learned to fear these." + force = 0 + throwforce = 0 + var/praying = 0 + +/obj/item/weapon/nullrod/rosary/New() + ..() + processing_objects.Add(src) + + +/obj/item/weapon/nullrod/rosary/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + if(!istype(M)) + return ..() + + if(!user.mind || user.mind.assigned_role != "Chaplain") + to_chat(user, "You are not close enough with [ticker.Bible_deity_name] to use [src].") + return + + if(praying) + to_chat(user, "You are already using [src].") + + user.visible_message("[user] kneels[M == user ? null : " next to [M]"] and begins to utter a prayer to [ticker.Bible_deity_name].", \ + "You kneel[M == user ? null : " next to [M]"] and begin a prayer to [ticker.Bible_deity_name].") + + praying = 1 + if(do_after(user, 150, target = M)) + if(istype(M, /mob/living/carbon/human)) // This probably should not work on vulps. They're unholy abominations. + var/mob/living/carbon/human/target = M + + if(target.mind) + if(iscultist(target)) + ticker.mode.remove_cultist(target.mind) // This proc will handle message generation. + praying = 0 + return + + if(target.mind.vampire && !target.mind.vampire.get_ability(/datum/vampire_passive/full)) // Getting a full prayer off on a vampire will interrupt their powers for a large duration. + target.mind.vampire.nullified = max(120, target.mind.vampire.nullified + 120) + to_chat(target, "[user]'s prayer to [ticker.Bible_deity_name] has interfered with your power!") + praying = 0 + return + + if(prob(25)) + to_chat(target, "[user]'s prayer to [ticker.Bible_deity_name] has eased your pain!") + target.adjustToxLoss(-5) + target.adjustOxyLoss(-5) + target.adjustBruteLoss(-5) + target.adjustFireLoss(-5) + + praying = 0 + + else + to_chat(user, "Your prayer to [ticker.Bible_deity_name] was interrupted.") + praying = 0 + +/obj/item/weapon/nullrod/rosary/process() + if(istype(loc, /mob/living/carbon/human)) + var/mob/living/carbon/human/holder = loc + + if(src == holder.l_hand || src == holder.r_hand) // Holding this in your hand will + for(var/mob/living/carbon/human/M in range(5)) + if(M.mind.vampire && !M.mind.vampire.get_ability(/datum/vampire_passive/full)) + M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) + if(prob(10)) + to_chat(M, "Being in the presence of [holder]'s [src] is interfering with your powers!") + + + diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index c466c5ba811..67b52da31ec 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -2,7 +2,7 @@ name = "implant" icon = 'icons/obj/implants.dmi' icon_state = "generic" //Shows up as the action button icon - action_button_is_hands_free = 1 + action_button_custom_type = /datum/action/item_action/hands_free origin_tech = "materials=2;biotech=3;programming=2" var/activated = 1 //1 for implant types that can be activated, 0 for ones that are "always on" like loyalty implants diff --git a/code/game/objects/items/weapons/implants/implant_traitor.dm b/code/game/objects/items/weapons/implants/implant_traitor.dm index 547206da29c..78e63ddfae4 100644 --- a/code/game/objects/items/weapons/implants/implant_traitor.dm +++ b/code/game/objects/items/weapons/implants/implant_traitor.dm @@ -56,11 +56,11 @@ ticker.mode.traitors += H.mind H.mind.special_role = "traitor" to_chat(H, "You're now completely loyal to [user.name]! You now must lay down your life to protect them and assist in their goals at any cost.") - var/datum/objective/protect/p = new - p.owner = H.mind - p.target = user:mind - p.explanation_text = "Obey every order from and protect [user:real_name], the [user:mind:assigned_role=="MODE" ? (user:mind:special_role) : (user:mind:assigned_role)]." - H.mind.objectives += p + var/datum/objective/protect/mindslave/MS = new + MS.owner = H.mind + MS.target = user:mind + MS.explanation_text = "Obey every order from and protect [user:real_name], the [user:mind:assigned_role=="MODE" ? (user:mind:special_role) : (user:mind:assigned_role)]." + H.mind.objectives += MS for(var/datum/objective/objective in H.mind.objectives) to_chat(H, "Objective #1: [objective.explanation_text]") @@ -71,10 +71,16 @@ var/datum/mindslaves/slaved = user.mind.som H.mind.som = slaved slaved.serv += H - slaved.add_serv_hud(user.mind,"syndicate")//handles master servent icons - slaved.add_serv_hud(H.mind,"mindslave") + slaved.add_serv_hud(user.mind, "master") //handles master servent icons + slaved.add_serv_hud(H.mind, "mindslave") log_admin("[ckey(user.key)] has mind-slaved [ckey(H.key)].") activated = 1 return 1 - return 0 \ No newline at end of file + return 0 + +/obj/item/weapon/implant/traitor/removed(mob/target) + if(..()) + ticker.mode.remove_traitor_mind(target.mind) + return 1 + return 0 \ No newline at end of file diff --git a/code/game/objects/items/weapons/legcuffs.dm b/code/game/objects/items/weapons/legcuffs.dm index fa485cbf93b..034dfc2ddc2 100644 --- a/code/game/objects/items/weapons/legcuffs.dm +++ b/code/game/objects/items/weapons/legcuffs.dm @@ -19,11 +19,15 @@ desc = "A trap used to catch bears and other legged creatures." var/armed = 0 var/obj/item/weapon/grenade/iedcasing/IED = null + var/obj/item/device/assembly/signaler/sig = null /obj/item/weapon/restraints/legcuffs/beartrap/Destroy() if(IED) qdel(IED) IED = null + if(sig) + qdel(sig) + sig = null return ..() /obj/item/weapon/restraints/legcuffs/beartrap/suicide_act(mob/user) @@ -43,6 +47,9 @@ if(IED) to_chat(user, "This beartrap already has an IED hooked up to it!") return + if(sig) + to_chat(user, "This beartrap already has a signaler hooked up to it!") + return IED = I switch(IED.assembled) if(0,1) //if it's not fueled/hooked up @@ -50,7 +57,7 @@ IED = null return if(2,3) - user.drop_item(src) + user.drop_item() I.forceMove(src) message_admins("[key_name_admin(user)] has rigged a beartrap with an IED.") log_game("[key_name(user)] has rigged a beartrap with an IED.") @@ -60,12 +67,33 @@ to_chat(user, "You shouldn't be reading this message! Contact a coder or someone, something broke!") IED = null return + if(istype(I, /obj/item/device/assembly/signaler)) + if(IED) + to_chat(user, "This beartrap already has an IED hooked up to it!") + return + if(sig) + to_chat(user, "This beartrap already has a signaler hooked up to it!") + return + sig = I + if(sig.secured) + to_chat(user, "The signaler is secured.") + sig = null + return + user.drop_item() + I.forceMove(src) + to_chat(user, "You sneak the [sig] underneath the pressure plate and connect the trigger wire.") + desc = "A trap used to catch bears and other legged creatures. There is a remote signaler hooked up to it." if(istype(I, /obj/item/weapon/screwdriver)) if(IED) IED.forceMove(get_turf(src)) IED = null to_chat(user, "You remove the IED from the [src].") return + if(sig) + sig.forceMove(get_turf(src)) + sig = null + to_chat(user, "You remove the signaler from the [src].") + return ..() /obj/item/weapon/restraints/legcuffs/beartrap/Crossed(AM as mob|obj) @@ -88,6 +116,9 @@ spawn(IED.det_time) IED.prime() + if(sig && isturf(src.loc)) + sig.signal() + if(ishuman(AM)) var/mob/living/carbon/H = AM if(H.lying) @@ -192,4 +223,4 @@ /obj/item/weapon/legcuffs/bolas/Bump() ..() - throw_failed() //allows a mech bolas to be destroyed \ No newline at end of file + throw_failed() //allows a mech bolas to be destroyed diff --git a/code/game/objects/items/weapons/manuals.dm b/code/game/objects/items/weapons/manuals.dm index 3a371b8191e..b580a024b91 100644 --- a/code/game/objects/items/weapons/manuals.dm +++ b/code/game/objects/items/weapons/manuals.dm @@ -1815,18 +1815,6 @@

-

Atmospherics Technician


-
    -
  1. Atmospheric Technicians are permitted to completely repipe the Atmospherics Piping Setup, provided they do not pump harmful gases into anywhere except the Turbine;
  2. -
  3. Atmospheric Technicians are not permitted to create volatile mixes using Plasma and Oxygen, nor are they permitted to create any potentially harmful mixes with Carbon Dioxide and/or Nitrous Oxide. An exception is made when working with the Turbine;
  4. -
  5. Atmospheric Technicians are permitted to cool Plasma and store it for later use in Radiation Collectors. Likewise, they are permitted to cool Nitrogen or Carbon Dioxide and store it for use as coolant for the Supermatter Engine;
  6. -
  7. Atmospheric Technicians are not permitted to take the axe out of its case unless there is an immediate and urgent threat to their life or urgent access to crisis locations is necessary. The axe must be returned to the case afterwards, and the case locked;
  8. -
  9. Atmospheric Technicians are not permitted to tamper with the default values on Air Alarms. They are, however, permitted to create small, acclimatized rooms for species that require special atmospheric conditions (such as Plasmamen and Vox), provided they receive express permission from the Chief Engineer;
  10. -
  11. Atmospheric Technicians must periodically check on the Central Alarms Computer, in periods of, at most, thirty (30) minutes;
  12. -
  13. Atmospheric Technicians must respond promptly to piping and station breaches. Failure to report within fifteen (15) minutes will be considered a breach of Standard Operating Procedure, unless there are no spare Atmospheric Technicians to report, or an Engineer has arrived on scene first. All Hazard Zones must be cordoned off with Engineering Tape, for the sake of everyone else
  14. -
-

-

Shaft Miner


  1. Shaft Miners are not permitted to bring Gibtonite aboard the station;
  2. @@ -2412,7 +2400,104 @@
  3. Demotion of Chief Engineer and reparation of Engine if no threat manifests.


  4. - + + + + + "} + +/obj/item/weapon/book/manual/sop_command + name = "Command Standard Operating Procedures" + desc = "A set of guidelines aiming at the safe conduct of all Command activities." + icon_state = "book4" + author = "Nanotrasen" + title = "Command Standard Operating Procedures" + dat = {" + + + + + + + + +

    Contents

    +
      +
    1. Foreword
    2. +
    3. Captain
    4. +
    5. Head of Personnel
    6. +
    7. NanoTrasen Representative
    8. +
    9. Blueshield Officer
    10. +
    11. AI
    12. +
    +

    + +

    FOREWORD


    + Job SOP should not be a considered a checklist of conditions to fire someone over, and should not be rigidly followed to the letter in detriment of circumstances and context. + As always, SOP can be malleable if the situation so requires, and the decision to punish a crewmember for breaching it ultimately falls onto the relevant Head of Staff, + for Department Members, or Captain, for the Head of Staff.

    + +

    Captain


    +
      +
    1. The Captain is not permitted to perform regular Security Duty. However, they may still assist Security if they are understaffed, or if they see a crime being committed. However, the Captain is not permitted to take items from the Armory under normal circumstances, unless authorized by the Head of Security. In addition, the Captain may not requisition weaponry for themselves from Cargo and/or Science, unless there's an immediate threat to station and/or crew;
    2. +
    3. If a Department lacks a Head of Staff, the Captain should make reasonable efforts to appoint an Acting Head of Staff, if there are available personnel to fill the position;
    4. +
    5. The Captain is to ensure that Space Law is being correctly applied. This should be done in cooperation with the Head of Security;
    6. +
    7. The Captain is not to leave the NSS Cyberiad unless given specific permission by Central Command, or it happens to be the end of the shift. This includes via space or via the Gateway. To do so is to be considered abandoning their posts and is grounds for termination;
    8. +
    9. The Captain must keep the Nuclear Authentication Disk on their person at all times or, failing that, in the possession of the Head of Security or Blueshield;
    10. +
    11. The Captain is to attempt to resolve every issue that arises in Command locally before contacting Central Command;
    12. +
    13. The Captain is not permitted to carry their Antique Laser Gun or Space Armor unless there's an immediate emergency that requires attending to;
    14. +
    15. The Captain, despite being in charge of the Cyberiad, is not independent from NanoTrasen. Any attempts to disregard general company policy are to be considered an instant condition for contract termination;
    16. +
    17. The Captain may only promote personnel to a Acting Head of Staff position if there is no assigned Head of Staff associated with the Department. Said Acting Head of Staff must be a member of the Department they are to lead. See below for more information on Chain of Command;
    18. +
    19. The Captain may not fire any Head of Staff without reasonable justification (ie, incompetency, criminal activity, or otherwise any action that endangers/compromises the station and/or crew). The Captain may not fire any Central Command VIPs (ie, Blueshield, Magistrate, NanoTrasen Representative) without permission from Central Command, unless they are blatantly acting against the well-being and safety of the crew and station.
    20. +

    + +

    Head of Personnel


    +
      +
    1. The Head of Personnel may not transfer any personnel to another Department without authorization from the relevant Head of Staff. If no Head of Staff is available, the Head of Personnel may make a judgement call. This does not apply to Security, which always requires authorization from the Head of Security, or Genetics, which requires both Chief Medical Officer and Research Director approval. If there is no Head of Security active, no transfers are allowed to Security without authorization from the Captain;
    2. +
    3. The Head of Personnel may not give any personnel increased access without authorization from the relevant Head of Staff. This includes the Head of Personnel. In addition, the Head of Personnel may only give Captain-Level access to someone if they are the Acting Captain. This access is to be removed when a proper Captain arrives on the station;
    4. +
    5. The Head of Personnel may not increase any Job Openings unless the relevant Head of Staff approves;
    6. +
    7. The Head of Personnel may not fire any personnel without authorization from the relevant Head of Staff, unless other conditions apply (see Space Law and General Standard Operating Procedure);
    8. +
    9. The Head of Personnel may not promote any personnel to the following Jobs without authorization from Central Command: Barber, Brig Physician, NanoTrasen Representative, Blueshield, Security Pod Pilot, Mechanic and Magistrate; (This is due to them being karma locked. Do not promote people to these positions without approval from the Administrators);
    10. +
    11. The Head of Personnel is free to utilize paperwork at their discretion. However, during major station emergencies, expediency should take precedence over bureaucracy;
    12. +
    13. The Head of Personnel may not leave their office unmanned if there are personnel waiting in line. Failure to respond to personnel with a legitimate request within ten (10) minutes, either via radio or in person, is to be considered a breach of Standard Operating Procedure;
    14. +
    15. Despite nominally being in charge of Supply, the Head of Personnel should allow the Quartermaster to run the Department, unless they prove themselves to be incompetent/dangerous;
    16. +
    17. The Head of Personnel is bound to the same rules regarding ordering Cargo Crates as the Quartermaster and Cargo Technicians. In addition, the Head of Personnel may not order unneeded, non-essential items against the wishes of Cargo;
    18. +
    19. The Head of Personnel is not permitted to perform Security duty. The Head of Personnel is permitted to carry an Energy Gun, for self-defence only.
    20. +

    + +

    NanoTrasen Representative


    +
      +
    1. The NanoTrasen Representative is to ensure that every Department is following Standard Operating Procedure, up to and including the respective Head of Staff. If a Head of Staff is not available for a Department, the NanoTrasen Representative must ensure that the Captain appoints an Acting Head of Staff for said Department;
    2. +
    3. The NanoTrasen Representative must attempt to resolve any breach of Standard Operating Procedure locally before contacting Central Command. This is an imperative: Standard Operating Procedure should always be followed unless there is a very good reason not to;
    4. +
    5. The NanoTrasen Representative must, together with the Magistrate and Head of Security, ensure that Space Law is being followed and correctly applied;
    6. +
    7. The NanoTrasen Representative may not threaten the use of a fax in order to gain leverage over any personnel, up to and including Command. In addition they may not threaten to fire, or have Central Command, fire anyone, unless they actually possess a demotion note;
    8. +
    9. The NanoTrasen Representative is permitted to carry their Stun-Cane, or a Telescopic Baton if the Stun-Cane is lost.
    10. +

    + +

    Blueshield Officer


    +
      +
    1. The Blueshield may not conduct arrests under the same conditions as Security. However, they may apprehend any personnel that trespass on a Head of Staff Office or Command Area, any personnel that steal from those locations, or any personnel that steal from and/or injure any Head of Staff or Central Command VIP. However, all apprehended personnel are to be processed by Security personnel;
    2. +
    3. The Blueshield is to put the lives of Command over those of any other personnel, the Blueshield included. Their continued well-being is the Blueshield's top priority. This includes applying basic first aid and making sure they are revived if killed;
    4. +
    5. The Blueshield is to protect the lives of Command personnel, not follow their orders to a fault. The Blueshield is not to interfere with legal demotions or arrests. To do so is to place themselves under the Special Modifier Aiding and Abetting;
    6. +
    7. The Blueshield is not to apply Lethal Force unless there is a clear and present danger to their life, or to the life of a member of Command, and the assailant cannot be non-lethally detained.
    8. +

    + +

    AI


    + The following are procedures for AI Maintenance:
    +
      +
    1. Only the Captain or Research Director may enter the AI Upload to perform Law Changes (see below), and only the Captain, Research Director or Chief Engineer may enter the AI Core to perform a Carding (see below);
    2. +
    3. No Law Changes are to be performed without approval from the Captain and Research Director. The only Lawsets to be used are those provided by NanoTrasen. Failure to legally perform a Law Change is to be considered Sabotage. Command must be informed prior to the Law Change, and all objections must be taken into consideration. If the number of Command personnel opposing the Law Change is greater than the number of Command personnel in favour, the Law Change is not to be done. If the Law Change is performed, the crew is to be immediately informed of the new Law(s);
    4. +
    5. The AI may not be Carded unless it it clearly malfunctioning or subverted. However, any member of Command may card it if the AI agrees to it, either at the end of the shift, or due to external circumstances (such as massive damage to the AI Satellite);
    6. +
    7. The AI Upload and Minisat Antechamber Turrets are to be kept on Non-Lethal in Code Green and Code Blue. The AI Core Turrets are to be kept on Lethal at all times. If a legal Law Change or Carding is occurring, the Turrets are to be disabled;
    8. +
    9. If the AI Unit is not malfunctioning or subverted, any attempt at performing an illegal Carding or Law Change is to be responded to with non-lethal force. If the illegal attempts persist, and the perpetrator is demonstrably hostile, lethal force from Command/Security is permitted;
    10. +
    11. Freeform Laws are only to be added if absolutely necessary due to external circumstances (such as major station emergencies). Adding unnecessary Freeform Laws is not permitted. Exception is made if the AI Unit and majority of Command agree to the Freeform Law that is proposed;
    12. +
    13. Any use of the "Purge" Module is to be followed by the upload of a NanoTrasen-approved Lawset immediately. AI Units must be bound to a Lawset at all times.
    14. +

    diff --git a/code/game/objects/items/weapons/power_cells.dm b/code/game/objects/items/weapons/power_cells.dm index 62f60a91bc4..a34a8328457 100644 --- a/code/game/objects/items/weapons/power_cells.dm +++ b/code/game/objects/items/weapons/power_cells.dm @@ -128,7 +128,6 @@ materials = list() minor_fault = 1 - /obj/item/weapon/stock_parts/cell/high/slime name = "charged slime core" desc = "A yellow slime core infused with plasma, it crackles with power." @@ -138,6 +137,12 @@ materials = list() self_recharge = 1 // Infused slime cores self-recharge, over time +/obj/item/weapon/stock_parts/cell/pulse //200 pulse shots + name = "pulse rifle power cell" + maxcharge = 40000 + rating = 3 + chargerate = 1500 + /obj/item/weapon/stock_parts/cell/pulse/carbine name = "pulse carbine power cell" maxcharge = 4000 @@ -168,9 +173,3 @@ /obj/item/weapon/stock_parts/cell/emproof/corrupt() return - -/obj/item/weapon/stock_parts/cell/temperaturegun - name = "temperature gun cell" - desc = "A specially designed power cell for heating and cooling projectiles" - icon_state = "icell" - maxcharge = 900 \ No newline at end of file diff --git a/code/game/objects/items/weapons/scissors.dm b/code/game/objects/items/weapons/scissors.dm index 806c6a5b0e5..9f0c824dead 100644 --- a/code/game/objects/items/weapons/scissors.dm +++ b/code/game/objects/items/weapons/scissors.dm @@ -30,21 +30,21 @@ //this is largely copypasted from there. //handle facial hair (if necessary) var/list/species_facial_hair = list() - var/obj/item/organ/external/head/C = H.organs_by_name["head"] + var/obj/item/organ/external/head/C = H.get_organ("head") var/datum/robolimb/robohead = all_robolimbs[C.model] if(H.gender == MALE || H.get_species() == "Vulpkanin") - if(H.species) + if(C.species) for(var/i in facial_hair_styles_list) var/datum/sprite_accessory/facial_hair/tmp_facial = facial_hair_styles_list[i] - if(H.species.name in tmp_facial.species_allowed) //If the species is allowed to have the style, add the style to the list. Or, if the character has a prosthetic head, give them the human hair styles. - if(H.species.flags & ALL_RPARTS) //If the character is of a species that can have full body prosthetics and their head doesn't suport human hair 'wigs', don't add the style to the list. + if(C.species.name in tmp_facial.species_allowed) //If the species is allowed to have the style, add the style to the list. Or, if the character has a prosthetic head, give them the human hair styles. + if(C.species.flags & ALL_RPARTS) //If the character is of a species that can have full body prosthetics and their head doesn't suport human hair 'wigs', don't add the style to the list. if(robohead.is_monitor) to_chat(user, "You are unable to find anything on [H]'s face worth cutting. How disappointing.") return continue //If the head DOES support human hair wigs, make sure they don't get monitor-oriented styles. species_facial_hair += i else - if(H.species.flags & ALL_RPARTS) //If the target is of a species that can have prosthetic heads, and the head supports human hair 'wigs' AND the hair-style is human-suitable, add it to the list. + if(C.species.flags & ALL_RPARTS) //If the target is of a species that can have prosthetic heads, and the head supports human hair 'wigs' AND the hair-style is human-suitable, add it to the list. if(!robohead.is_monitor) if("Human" in tmp_facial.species_allowed) species_facial_hair += i @@ -56,18 +56,18 @@ var/f_new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in species_facial_hair //handle normal hair var/list/species_hair = list() - if(H.species) + if(C.species) for(var/i in hair_styles_list) var/datum/sprite_accessory/hair/tmp_hair = hair_styles_list[i] - if(H.species.name in tmp_hair.species_allowed) //If the species is allowed to have the style, add the style to the list. Or, if the character has a prosthetic head, give them the human facial hair styles. - if(H.species.flags & ALL_RPARTS) //If the character is of a species that can have full body prosthetics and their head doesn't suport human hair 'wigs', don't add the style to the list. + if(C.species.name in tmp_hair.species_allowed) //If the species is allowed to have the style, add the style to the list. Or, if the character has a prosthetic head, give them the human facial hair styles. + if(C.species.flags & ALL_RPARTS) //If the character is of a species that can have full body prosthetics and their head doesn't suport human hair 'wigs', don't add the style to the list. if(robohead.is_monitor) to_chat(user, "You are unable to find anything on [H]'s head worth cutting. How disappointing.") return continue //If the head DOES support human hair wigs, make sure they don't get monitor-oriented styles. species_hair += i else - if(H.species.flags & ALL_RPARTS) //If the target is of a species that can have prosthetic heads, and the head supports human hair 'wigs' AND the hair-style is human-suitable, add it to the list. + if(C.species.flags & ALL_RPARTS) //If the target is of a species that can have prosthetic heads, and the head supports human hair 'wigs' AND the hair-style is human-suitable, add it to the list. if(!robohead.is_monitor) if("Human" in tmp_hair.species_allowed) species_hair += i @@ -84,11 +84,12 @@ user.visible_message("[user] stops cutting [M]'s hair.", "You stop cutting [M]'s hair.") return if(f_new_style) - H.f_style = f_new_style + C.f_style = f_new_style if(h_new_style) - H.h_style = h_new_style + C.h_style = h_new_style H.update_hair() + H.update_fhair() user.visible_message("[user] finishes cutting [M]'s hair!") /obj/item/weapon/scissors/safety //Totally safe, I assure you. diff --git a/code/game/objects/items/weapons/stock_parts.dm b/code/game/objects/items/weapons/stock_parts.dm index f7edba7e1c4..6e0500ffd38 100644 --- a/code/game/objects/items/weapons/stock_parts.dm +++ b/code/game/objects/items/weapons/stock_parts.dm @@ -131,7 +131,7 @@ name = "nano-manipulator" desc = "A tiny little manipulator used in the construction of certain devices." icon_state = "nano_mani" - origin_tech = "materials=3,programming=2" + origin_tech = "materials=3;programming=2" rating = 2 materials = list(MAT_METAL=30) @@ -173,7 +173,7 @@ name = "pico-manipulator" desc = "A tiny little manipulator used in the construction of certain devices." icon_state = "pico_mani" - origin_tech = "materials=5,programming=2" + origin_tech = "materials=5;programming=2" rating = 3 materials = list(MAT_METAL=30) diff --git a/code/game/objects/items/weapons/storage/belt.dm b/code/game/objects/items/weapons/storage/belt.dm index daefa0db457..e8771a6c7c6 100644 --- a/code/game/objects/items/weapons/storage/belt.dm +++ b/code/game/objects/items/weapons/storage/belt.dm @@ -6,8 +6,17 @@ item_state = "utility" slot_flags = SLOT_BELT attack_verb = list("whipped", "lashed", "disciplined") + var/use_item_overlays = 0 // Do we have overlays for items held inside the belt? +/obj/item/weapon/storage/belt/update_icon() + if(use_item_overlays) + overlays.Cut() + for(var/obj/item/I in contents) + overlays += "[I.name]" + + ..() + /obj/item/weapon/storage/belt/proc/can_use() return is_equipped() @@ -35,6 +44,7 @@ desc = "Can hold various tools." icon_state = "utilitybelt" item_state = "utility" + use_item_overlays = 1 can_hold = list( "/obj/item/weapon/crowbar", "/obj/item/weapon/screwdriver", @@ -81,6 +91,7 @@ desc = "Can hold various medical equipment." icon_state = "medicalbelt" item_state = "medical" + use_item_overlays = 1 can_hold = list( "/obj/item/device/healthanalyzer", "/obj/item/weapon/dnainjector", @@ -120,6 +131,7 @@ desc = "Can hold various botanical supplies." icon_state = "botanybelt" item_state = "botany" + use_item_overlays = 1 can_hold = list( "/obj/item/device/analyzer/plant_analyzer", "/obj/item/weapon/minihoe", @@ -127,8 +139,8 @@ "/obj/item/weapon/reagent_containers/glass/fertilizer", "/obj/item/weapon/reagent_containers/glass/bottle", "/obj/item/weapon/plantspray", - "/obj/item/weapon/reagent_containers/syringe", - "/obj/item/weapon/reagent_containers/glass/beaker", +// "/obj/item/weapon/reagent_containers/syringe", +// "/obj/item/weapon/reagent_containers/glass/beaker", "/obj/item/weapon/lighter/zippo", "/obj/item/weapon/storage/fancy/cigarettes", "obj/item/weapon/rollingpaperpack", @@ -148,6 +160,7 @@ item_state = "security"//Could likely use a better one. storage_slots = 5 max_w_class = 3 + use_item_overlays = 1 can_hold = list( "/obj/item/weapon/grenade/flashbang", "/obj/item/weapon/grenade/chem_grenade/teargas", @@ -185,6 +198,7 @@ icon_state = "soulstonebelt" item_state = "soulstonebelt" storage_slots = 6 + use_item_overlays = 1 can_hold = list( "/obj/item/device/soulstone" ) @@ -230,6 +244,7 @@ item_state = "janibelt" storage_slots = 6 max_w_class = 4 // Set to this so the light replacer can fit. + use_item_overlays = 1 can_hold = list( "/obj/item/weapon/grenade/chem_grenade/cleaner", "/obj/item/device/lightreplacer", @@ -300,6 +315,21 @@ new /obj/item/ammo_casing/shotgun/beanbag(src) new /obj/item/ammo_casing/shotgun/beanbag(src) +/obj/item/weapon/storage/belt/bandolier/update_icon() + ..() + icon_state = "[initial(icon_state)]_[contents.len]" + +/obj/item/weapon/storage/belt/bandolier/attackby(obj/item/W, mob/user) + var/amount = contents.len + . = ..() + if(amount != contents.len) + update_icon() + +/obj/item/weapon/storage/belt/lazabandolierrus/remove_from_storage(obj/item/W as obj, atom/new_location) + ..() + update_icon() + + /obj/item/weapon/storage/belt/holster name = "shoulder holster" desc = "A holster to conceal a carried handgun. WARNING: Badasses only." @@ -318,6 +348,7 @@ icon_state = "soulstonebelt" item_state = "soulstonebelt" storage_slots = 6 + use_item_overlays = 1 can_hold = list( "/obj/item/weapon/gun/magic/wand" ) diff --git a/code/game/objects/items/weapons/table_rack_parts.dm b/code/game/objects/items/weapons/table_rack_parts.dm index 61c58ce9aa5..4f5db94d4af 100644 --- a/code/game/objects/items/weapons/table_rack_parts.dm +++ b/code/game/objects/items/weapons/table_rack_parts.dm @@ -15,6 +15,11 @@ materials = list(MAT_METAL=4000) flags = CONDUCT attack_verb = list("slammed", "bashed", "battered", "bludgeoned", "thrashed", "whacked") + var/upgradable = 1 + var/result = /obj/structure/table + var/parts = list( + /obj/item/stack/sheet/metal, + /obj/item/stack/sheet/metal) /obj/item/weapon/table_parts/reinforced name = "reinforced table parts" @@ -23,18 +28,33 @@ icon_state = "reinf_tableparts" materials = list(MAT_METAL=8000) flags = CONDUCT + upgradable = 0 + result = /obj/structure/table/reinforced + parts = list( + /obj/item/stack/sheet/metal, + /obj/item/stack/rods) /obj/item/weapon/table_parts/wood name = "wooden table parts" desc = "Keep away from fire." icon_state = "wood_tableparts" flags = null + upgradable = 0 + result = /obj/structure/table/woodentable + parts = list( + /obj/item/stack/sheet/wood, + /obj/item/stack/sheet/wood) /obj/item/weapon/table_parts/glass name = "glass table parts" desc = "fragile!" icon_state = "glass_tableparts" flags = null + upgradable = 0 + result = /obj/structure/glasstable_frame + parts = list( + /obj/item/stack/sheet/metal, + /obj/item/stack/sheet/metal) /obj/item/weapon/rack_parts name = "rack parts" @@ -49,71 +69,27 @@ */ /obj/item/weapon/table_parts/attackby(obj/item/weapon/W as obj, mob/user as mob, params) ..() - if (istype(W, /obj/item/weapon/wrench)) - new /obj/item/stack/sheet/metal( user.loc ) - new /obj/item/stack/sheet/metal( user.loc ) - //SN src = null + if(istype(W, /obj/item/weapon/wrench)) + for(var/p in parts) + new p(user.loc) qdel(src) - if (istype(W, /obj/item/stack/rods)) - if (W:amount >= 4) - new /obj/item/weapon/table_parts/reinforced( user.loc ) - to_chat(user, "\blue You reinforce the [name].") - W:use(4) + else if(upgradable && istype(W, /obj/item/stack/rods)) + var/obj/item/stack/rods/R = W + if(R.amount >= 4) + new /obj/item/weapon/table_parts/reinforced(user.loc) + to_chat(user, "You reinforce the [name].") + R.use(4) qdel(src) - else if (W:amount < 4) - to_chat(user, "\red You need at least four rods to do this.") + else + to_chat(user, "You need at least four rods to do this.") /obj/item/weapon/table_parts/attack_self(mob/user as mob) - new /obj/structure/table( user.loc ) + for(var/obj/structure/table/T in user.loc) + to_chat(user, "You can't build tables on top of tables!") + return + new result(user.loc) user.drop_item() qdel(src) - return - - -/* - * Reinforced Table Parts - */ -/obj/item/weapon/table_parts/reinforced/attackby(obj/item/weapon/W as obj, mob/user as mob, params) - if (istype(W, /obj/item/weapon/wrench)) - new /obj/item/stack/sheet/metal( user.loc ) - new /obj/item/stack/rods( user.loc ) - qdel(src) - -/obj/item/weapon/table_parts/reinforced/attack_self(mob/user as mob) - new /obj/structure/table/reinforced( user.loc ) - user.drop_item() - qdel(src) - return - -/* - * Wooden Table Parts - */ -/obj/item/weapon/table_parts/wood/attackby(obj/item/weapon/W as obj, mob/user as mob, params) - if (istype(W, /obj/item/weapon/wrench)) - new /obj/item/stack/sheet/wood(get_turf(src)) - new /obj/item/stack/sheet/wood(get_turf(src)) - qdel(src) - -/obj/item/weapon/table_parts/wood/attack_self(mob/user as mob) - new /obj/structure/table/woodentable( user.loc ) - user.drop_item() - qdel(src) - return - -/* - * Glass Table Parts - */ -/obj/item/weapon/table_parts/glass/attackby(obj/item/weapon/W as obj, mob/user as mob, params) - if (istype(W, /obj/item/weapon/wrench)) - new /obj/item/stack/sheet/metal( user.loc ) - new /obj/item/stack/sheet/metal( user.loc ) - qdel(src) - -/obj/item/weapon/table_parts/glass/attack_self(mob/user as mob) - new /obj/structure/glasstable_frame( user.loc ) - user.drop_item() - qdel(src) - return /* * Rack Parts @@ -121,14 +97,11 @@ /obj/item/weapon/rack_parts/attackby(obj/item/weapon/W as obj, mob/user as mob, params) ..() if (istype(W, /obj/item/weapon/wrench)) - new /obj/item/stack/sheet/metal( user.loc ) + new /obj/item/stack/sheet/metal(user.loc) qdel(src) - return - return /obj/item/weapon/rack_parts/attack_self(mob/user as mob) - var/obj/structure/rack/R = new /obj/structure/rack( user.loc ) + var/obj/structure/rack/R = new /obj/structure/rack(user.loc) R.add_fingerprint(user) user.drop_item() - qdel(src) - return \ No newline at end of file + qdel(src) \ No newline at end of file diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 3ab237084e6..29bcb4f8fe2 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -222,6 +222,10 @@ icon_state = "dualsaber0" /obj/item/weapon/twohanded/dualsaber/attack(target as mob, mob/living/user as mob) + if(HULK in user.mutations) + to_chat(user, "You grip the blade too hard and accidentally close it!") + unwield() + return ..() if((CLUMSY in user.mutations) && (wielded) &&prob(40)) to_chat(user, "\red You twirl around a bit before losing your balance and impaling yourself on the [src].") @@ -259,7 +263,10 @@ if(wielded) return 1 -/obj/item/weapon/twohanded/dualsaber/wield() +/obj/item/weapon/twohanded/dualsaber/wield(mob/living/carbon/M) //Specific wield () hulk checks due to reflection chance for balance issues and switches hitsounds. + if(HULK in M.mutations) + to_chat(M, "You lack the grace to wield this!") + return ..() hitsound = 'sound/weapons/blade1.ogg' diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm index e20a3af837b..8ff2f931159 100644 --- a/code/game/objects/items/weapons/weaponry.dm +++ b/code/game/objects/items/weapons/weaponry.dm @@ -15,75 +15,6 @@ to_chat(viewers(user), "[user] is hitting \himself with the [src.name]! It looks like \he's trying to ban \himself from life.") return (BRUTELOSS|FIRELOSS|TOXLOSS|OXYLOSS) -/obj/item/weapon/nullrod - name = "null rod" - desc = "A rod of pure obsidian, its very presence disrupts and dampens the powers of paranormal phenomenae." - icon_state = "nullrod" - item_state = "nullrod" - slot_flags = SLOT_BELT - force = 15 - throw_speed = 1 - throw_range = 4 - throwforce = 10 - w_class = 1 - var/transformed = 0 - var/transform_into = /obj/item/weapon/nullrod/sword - var/transform_via = list(/obj/item/clothing/suit/armor/riot/knight/templar, /obj/item/clothing/suit/chaplain_hoodie/fluff/chronx) - - suicide_act(mob/user) - to_chat(viewers(user), "[user] is impaling \himself with the [src.name]! It looks like \he's trying to commit suicide.") - return (BRUTELOSS|FIRELOSS) - -/obj/item/weapon/nullrod/attack(mob/M as mob, mob/living/user as mob) //Paste from old-code to decult with a null rod. - - M.attack_log += text("\[[time_stamp()]\] Has been attacked with [src.name] by [user.name] ([user.ckey])") - user.attack_log += text("\[[time_stamp()]\] Used the [src.name] to attack [M.name] ([M.ckey])") - - if(!iscarbon(user)) - M.LAssailant = null - else - M.LAssailant = user - - msg_admin_attack("[key_name_admin(user)] attacked [key_name_admin(M)] with [src.name] (INTENT: [uppertext(user.a_intent)])") - - if ((CLUMSY in user.mutations) && prob(50)) - to_chat(user, "\red The rod slips out of your hand and hits your head.") - user.take_organ_damage(10) - user.Paralyse(20) - return - - if(M.mind) - if(M.mind.vampire) - if(ishuman(M)) - if(!M.mind.vampire.get_ability(/datum/vampire_passive/full)) - to_chat(M, "The nullrod's power interferes with your own!") - M.mind.vampire.nullified = max(5, M.mind.vampire.nullified + 2) - ..() - -/obj/item/weapon/nullrod/afterattack(var/obj/item/I as obj, mob/user as mob, proximity) - if(!proximity) - return - for(var/T in transform_via) - if(istype(I, T)) //Only the Chaplain's holy armor is capable fo performing this feat. - if(!transformed) // can't turn a sword into a sword. - var/obj/item/S = new transform_into() - to_chat(user, "You sheath the [src] into the [I]'s scabbard, transforming it into \a [S].") - user.unEquip(src) - qdel(src) - user.put_in_hands(S) - break - -/obj/item/weapon/nullrod/sword - name = "holy sword" - desc = "A sword imbued with holy power, its very presence disrupts and dampens the powers of paranormal phenomenae." - icon_state = "claymore" - item_state = "claymore" - hitsound = 'sound/weapons/bladeslice.ogg' - w_class = 3 //transforming it is not without its downsides. - sharp = 1 - edge = 1 - transformed = 1 - /obj/item/weapon/sord name = "\improper SORD" desc = "This thing is so unspeakably shitty you are having a hard time even holding it." diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index a6b19ebbea5..42a2541f0bf 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -320,7 +320,7 @@ return step_towards(O, src.loc) if(user != O) - user.show_viewers("[user] stuffs [O] into [src]!") + user.visible_message("[user] stuffs [O] into [src]!", "You stuff [O] into [src]!") src.add_fingerprint(user) /obj/structure/closet/attack_ai(mob/user) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm index fc7563e6b3a..fe1e33d0999 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm @@ -58,6 +58,7 @@ return if(src.allowed(user)) src.locked = !src.locked + playsound(src.loc, 'sound/machines/click.ogg', 15, 1, -3) for(var/mob/O in viewers(user, 3)) if((O.client && !( O.blinded ))) to_chat(O, "The locker has been [locked ? null : "un"]locked by [user].") @@ -172,4 +173,4 @@ if(istype(src.loc, /obj/structure/bigDelivery)) //Do this to prevent contents from being opened into nullspace (read: bluespace) var/obj/structure/bigDelivery/BD = src.loc BD.attack_hand(usr) - open() \ No newline at end of file + open() diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 4a2ced79339..1a24f932091 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -115,7 +115,7 @@ new /obj/item/weapon/melee/baton/loaded(src) new /obj/item/weapon/storage/belt/security/sec(src) new /obj/item/taperoll/police(src) - new /obj/item/weapon/gun/energy/hos(src) + new /obj/item/weapon/gun/energy/gun/hos(src) new /obj/item/weapon/door_remote/head_of_security(src) @@ -152,7 +152,7 @@ new /obj/item/weapon/storage/box/flashbangs(src) new /obj/item/weapon/reagent_containers/spray/pepper(src) new /obj/item/weapon/melee/baton/loaded(src) - new /obj/item/weapon/gun/energy/advtaser(src) + new /obj/item/weapon/gun/energy/gun/advtaser(src) new /obj/item/weapon/storage/belt/security/sec(src) new /obj/item/weapon/storage/box/holobadge(src) diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 699f5ac85aa..d0e8d4c9c85 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -17,6 +17,7 @@ if(!AC) AC = new(src, user) AC.name = "SalonPro Nano-Mirror™" + AC.flags = APPEARANCE_ALL_BODY ui_users[user] = AC AC.ui_interact(user) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 17a4233ffa9..bdf94263c8e 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -208,7 +208,7 @@ if(!G.confirm()) return 0 G.affecting.forceMove(get_turf(src)) - G.affecting.Weaken(5) + G.affecting.Weaken(2) G.affecting.visible_message("[G.assailant] pushes [G.affecting] onto [src].", \ "[G.assailant] pushes [G.affecting] onto [src].") add_logs(G.affecting, G.assailant, "pushed onto a table") @@ -448,8 +448,9 @@ /obj/structure/table/glass/destroy(dirty) if(dirty) new /obj/item/weapon/shard(loc) + new /obj/item/weapon/shard(loc) else - new /obj/item/stack/sheet/glass(loc) + new /obj/item/stack/sheet/glass(loc, 2) ..() /obj/structure/table/glass/tablepush(obj/item/I, mob/user) diff --git a/code/game/response_team.dm b/code/game/response_team.dm index 14bf44ff7b5..d9b8cfcc375 100644 --- a/code/game/response_team.dm +++ b/code/game/response_team.dm @@ -148,6 +148,7 @@ var/send_emergency_team /client/proc/create_response_team(obj/spawn_location) var/mob/living/carbon/human/M = new(null) + var/obj/item/organ/external/head/head_organ = M.get_organ("head") response_team_members |= M var/new_gender = alert(usr, "Please select your gender.", "Character Generation", "Male", "Female") @@ -173,18 +174,18 @@ var/send_emergency_team if(prob(5)) facial_hair_style = pick(facial_hair_styles_list) - M.r_facial = hex2num(copytext(hair_c, 2, 4)) - M.g_facial = hex2num(copytext(hair_c, 4, 6)) - M.b_facial = hex2num(copytext(hair_c, 6, 8)) - M.r_hair = hex2num(copytext(hair_c, 2, 4)) - M.g_hair = hex2num(copytext(hair_c, 4, 6)) - M.b_hair = hex2num(copytext(hair_c, 6, 8)) + head_organ.r_facial = hex2num(copytext(hair_c, 2, 4)) + head_organ.g_facial = hex2num(copytext(hair_c, 4, 6)) + head_organ.b_facial = hex2num(copytext(hair_c, 6, 8)) + head_organ.r_hair = hex2num(copytext(hair_c, 2, 4)) + head_organ.g_hair = hex2num(copytext(hair_c, 4, 6)) + head_organ.b_hair = hex2num(copytext(hair_c, 6, 8)) M.r_eyes = hex2num(copytext(eye_c, 2, 4)) M.g_eyes = hex2num(copytext(eye_c, 4, 6)) M.b_eyes = hex2num(copytext(eye_c, 6, 8)) M.s_tone = skin_tone - M.h_style = hair_style - M.f_style = facial_hair_style + head_organ.h_style = hair_style + head_organ.f_style = facial_hair_style M.real_name = "[pick("Corporal", "Sergeant", "Staff Sergeant", "Sergeant First Class", "Master Sergeant", "Sergeant Major")] [pick(last_names)]" M.name = M.real_name @@ -381,7 +382,7 @@ var/send_emergency_team M.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(M), slot_shoes) M.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/black(M), slot_gloves) M.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest/ert/security(M), slot_wear_suit) - M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/advtaser(M), slot_s_store) + M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/gun/advtaser(M), slot_s_store) M.equip_to_slot_or_del(new /obj/item/clothing/glasses/hud/security/sunglasses(M), slot_glasses) M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/ert/security(M), slot_in_backpack) @@ -458,7 +459,7 @@ var/send_emergency_team M.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(M), slot_shoes) M.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/black(M), slot_gloves) M.equip_to_slot_or_del(new /obj/item/clothing/suit/space/rig/ert/security(M), slot_wear_suit) - M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/advtaser(M), slot_s_store) + M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/gun/advtaser(M), slot_s_store) M.equip_to_slot_or_del(new /obj/item/clothing/glasses/hud/security/sunglasses(M), slot_glasses) M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/ert/security(M), slot_in_backpack) @@ -531,7 +532,7 @@ var/send_emergency_team M.equip_to_slot_or_del(new /obj/item/weapon/rcd_ammo/large(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/weapon/rcd_ammo/large(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/weapon/rcd_ammo/large(M), slot_in_backpack) - M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle/pistol(M), slot_in_backpack) + M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse/pistol(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/device/t_scanner/extended_range(M), slot_l_store) M.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(M), slot_r_store) @@ -552,7 +553,7 @@ var/send_emergency_team M.equip_to_slot_or_del(new /obj/item/weapon/storage/box/flashbangs(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/ionrifle/carbine(M), slot_in_backpack) - M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle/carbine(M), slot_r_hand) + M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse/carbine(M), slot_r_hand) if("Medic") M.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat/swat(M), slot_shoes) @@ -565,7 +566,7 @@ var/send_emergency_team M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/rig/ert/medical(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/sechailer/swat(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/surgery(M), slot_in_backpack) - M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle/pistol(M), slot_in_backpack) + M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse/pistol(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/hypospray/combat/nanites(src), slot_l_store) M.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(M), slot_r_store) @@ -584,7 +585,7 @@ var/send_emergency_team M.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/sechailer/swat(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/weapon/restraints/handcuffs(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/weapon/storage/lockbox/loyalty(M), slot_in_backpack) - M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle/pistol(M), slot_in_backpack) + M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse/pistol(M), slot_in_backpack) M.equip_to_slot_or_del(new /obj/item/weapon/pinpointer(M), slot_l_store) M.equip_to_slot_or_del(new /obj/item/weapon/melee/classic_baton/telescopic(M), slot_r_store) @@ -609,4 +610,4 @@ var/send_emergency_team new /obj/item/device/radio/centcom( src ) new /obj/item/weapon/reagent_containers/food/pill/salicylic( src ) new /obj/item/weapon/reagent_containers/food/pill/patch/synthflesh( src ) - return \ No newline at end of file + return diff --git a/code/game/sound.dm b/code/game/sound.dm index cecf12c657d..1890a0966e7 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -9,8 +9,9 @@ var/list/jackboot_sound = list('sound/effects/jackboot1.ogg','sound/effects/jack var/list/swing_hit_sound = list('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg') var/list/hiss_sound = list('sound/voice/hiss1.ogg','sound/voice/hiss2.ogg','sound/voice/hiss3.ogg','sound/voice/hiss4.ogg') var/list/page_sound = list('sound/effects/pageturn1.ogg', 'sound/effects/pageturn2.ogg','sound/effects/pageturn3.ogg') -//var/list/gun_sound = list('sound/weapons/Gunshot.ogg', 'sound/weapons/Gunshot2.ogg','sound/weapons/Gunshot3.ogg','sound/weapons/Gunshot4.ogg') +var/list/gun_sound = list('sound/weapons/Gunshot.ogg', 'sound/weapons/Gunshot2.ogg','sound/weapons/Gunshot3.ogg','sound/weapons/Gunshot4.ogg') var/list/computer_ambience = list('sound/goonstation/machines/ambicomp1.ogg', 'sound/goonstation/machines/ambicomp2.ogg', 'sound/goonstation/machines/ambicomp3.ogg') +var/list/ricochet = list('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg','sound/weapons/effects/ric3.ogg','sound/weapons/effects/ric4.ogg','sound/weapons/effects/ric5.ogg') /proc/playsound(var/atom/source, soundin, vol as num, vary, extrarange as num, falloff, var/is_global, var/pitch) @@ -107,17 +108,32 @@ var/const/FALLOFF_SOUNDS = 0.5 /proc/get_sfx(soundin) if(istext(soundin)) switch(soundin) - if ("shatter") soundin = pick(shatter_sound) - if ("explosion") soundin = pick(explosion_sound) - if ("sparks") soundin = pick(spark_sound) - if ("rustle") soundin = pick(rustle_sound) - if ("bodyfall") soundin = pick(bodyfall_sound) - if ("punch") soundin = pick(punch_sound) - if ("clownstep") soundin = pick(clown_sound) - if ("jackboot") soundin = pick(jackboot_sound) - if ("swing_hit") soundin = pick(swing_hit_sound) - if ("hiss") soundin = pick(hiss_sound) - if ("pageturn") soundin = pick(page_sound) - //if ("gunshot") soundin = pick(gun_sound) - if("computer_ambience") soundin = pick(computer_ambience) + if ("shatter") + soundin = pick(shatter_sound) + if ("explosion") + soundin = pick(explosion_sound) + if ("sparks") + soundin = pick(spark_sound) + if ("rustle") + soundin = pick(rustle_sound) + if ("bodyfall") + soundin = pick(bodyfall_sound) + if ("punch") + soundin = pick(punch_sound) + if ("clownstep") + soundin = pick(clown_sound) + if ("jackboot") + soundin = pick(jackboot_sound) + if ("swing_hit") + soundin = pick(swing_hit_sound) + if ("hiss") + soundin = pick(hiss_sound) + if ("pageturn") + soundin = pick(page_sound) + if ("gunshot") + soundin = pick(gun_sound) + if("computer_ambience") + soundin = pick(computer_ambience) + if("ricochet") + soundin = pick(ricochet) return soundin diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 8f1dded0a6e..7f4ac1704d9 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -66,8 +66,9 @@ smooth_icon(src) if(!damage) - overlays -= damage_overlays[damage_overlay] - damage_overlay = 0 + if(damage_overlay) + overlays -= damage_overlays[damage_overlay] + damage_overlay = 0 return var/overlay = round(damage / damage_cap * damage_overlays.len) + 1 @@ -76,12 +77,11 @@ if(damage_overlay && overlay == damage_overlay) //No need to update. return - overlays -= damage_overlays[damage_overlay] + if(damage_overlay) + overlays -= damage_overlays[damage_overlay] overlays += damage_overlays[overlay] damage_overlay = overlay - return - /turf/simulated/wall/proc/generate_overlays() var/alpha_inc = 256 / damage_overlays.len diff --git a/code/game/verbs/suicide.dm b/code/game/verbs/suicide.dm index 5d91c835ea0..857fcadb48a 100644 --- a/code/game/verbs/suicide.dm +++ b/code/game/verbs/suicide.dm @@ -3,7 +3,7 @@ /mob/living/carbon/human/proc/do_suicide(damagetype, byitem) var/threshold = (config.health_threshold_crit + config.health_threshold_dead) / 2 var/dmgamt = maxHealth - threshold - + var/damage_mod = 1 switch(damagetype) //Sorry about the magic numbers. //brute = 1, burn = 2, tox = 4, oxy = 8 @@ -163,7 +163,7 @@ var/turf/T = get_turf_or_move(card.loc) for (var/mob/M in viewers(T)) M.show_message("\blue [src] flashes a message across its screen, \"Wiping core files. Please acquire a new personality to continue using pAI device functions.\"", 3, "\blue [src] bleeps electronically.", 2) - death(0) + death(0, 1) else to_chat(src, "Aborting suicide attempt.") diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 6e4f58c5ab2..7e5edf7c8bb 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -142,6 +142,11 @@ var/global/nologevent = 0 if(istype(M, /mob/dead/observer)) body += "Re-incarnate | " + if(ispAI(M)) + body += "Is a pAI " + else + body += "Make pAI | " + // DNA2 - Admin Hax if(M.dna && iscarbon(M)) body += "

    " @@ -945,7 +950,7 @@ var/gamma_ship_location = 1 // 0 = station , 1 = space //returns 1 to let the dragdrop code know we are trapping this event //returns 0 if we don't plan to trap the event -/datum/admins/proc/cmd_ghost_drag(var/mob/dead/observer/frommob, var/mob/living/tomob) +/datum/admins/proc/cmd_ghost_drag(var/mob/dead/observer/frommob, var/tothing) if(!istype(frommob)) return //extra sanity check to make sure only observers are shoved into things @@ -957,26 +962,49 @@ var/gamma_ship_location = 1 // 0 = station , 1 = space if (!frommob.ckey) return 0 - var/question = "" - if (tomob.ckey) - question = "This mob already has a user ([tomob.key]) in control of it! " - question += "Are you sure you want to place [frommob.name]([frommob.key]) in control of [tomob.name]?" + if(istype(tothing, /obj/item)) + var/mob/living/toitem = tothing + + var/ask = alert("Are you sure you want to allow [frommob.name]([frommob.key]) to possess [toitem.name]?", "Place ghost in control of item?", "Yes", "No") + if (ask != "Yes") + return 1 + + if(!frommob || !toitem) //make sure the mobs don't go away while we waited for a response + return 1 + + var/mob/living/simple_animal/possessed_object/tomob = new(toitem) + + message_admins("[key_name_admin(usr)] has put [frommob.ckey] in control of [tomob.name].") + log_admin("[key_name(usr)] stuffed [frommob.ckey] into [tomob.name].") + feedback_add_details("admin_verb","CGD") + + tomob.ckey = frommob.ckey + qdel(frommob) + + + if(isliving(tothing)) + var/mob/living/tomob = tothing + + var/question = "" + if (tomob.ckey) + question = "This mob already has a user ([tomob.key]) in control of it! " + question += "Are you sure you want to place [frommob.name]([frommob.key]) in control of [tomob.name]?" + + var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No") + if (ask != "Yes") + return 1 + + if(!frommob || !tomob) //make sure the mobs don't go away while we waited for a response + return 1 + + if(tomob.client) //no need to ghostize if there is no client + tomob.ghostize(0) + + message_admins("[key_name_admin(usr)] has put [frommob.ckey] in control of [tomob.name].") + log_admin("[key_name(usr)] stuffed [frommob.ckey] into [tomob.name].") + feedback_add_details("admin_verb","CGD") + + tomob.ckey = frommob.ckey + qdel(frommob) - var/ask = alert(question, "Place ghost in control of mob?", "Yes", "No") - if (ask != "Yes") return 1 - - if(!frommob || !tomob) //make sure the mobs don't go away while we waited for a response - return 1 - - if(tomob.client) //no need to ghostize if there is no client - tomob.ghostize(0) - - message_admins("[key_name_admin(usr)] has put [frommob.ckey] in control of [tomob.name].") - log_admin("[key_name(usr)] stuffed [frommob.ckey] into [tomob.name].") - feedback_add_details("admin_verb","CGD") - - tomob.ckey = frommob.ckey - qdel(frommob) - - return 1 diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 577f8be3856..ef5d4bf3de3 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -125,6 +125,7 @@ var/list/admin_verbs_server = list( /datum/admins/proc/toggleAI, /client/proc/cmd_admin_delete, /*delete an instance/object/mob/etc*/ /client/proc/cmd_debug_del_all, + /client/proc/cmd_debug_del_sing, /datum/admins/proc/toggle_aliens, /client/proc/delbook, /client/proc/view_flagged_books, @@ -141,6 +142,7 @@ var/list/admin_verbs_debug = list( /client/proc/cmd_debug_mob_lists, /client/proc/cmd_admin_delete, /client/proc/cmd_debug_del_all, + /client/proc/cmd_debug_del_sing, /client/proc/reload_admins, /client/proc/restart_controller, /client/proc/enable_debug_verbs, @@ -945,15 +947,15 @@ var/list/admin_verbs_snpc = list( verbs += admin_verbs_snpc verbs -= /client/proc/show_snpc_verbs - to_chat(src, "SNPC verbs on.") - -/client/proc/hide_snpc_verbs() - set name = "Hide SNPC Verbs" - set category = "Admin" - - if(!holder) - return - - verbs -= admin_verbs_snpc - verbs += /client/proc/show_snpc_verbs - to_chat(src, "SNPC verbs off.") + to_chat(src, "SNPC verbs on.") + +/client/proc/hide_snpc_verbs() + set name = "Hide SNPC Verbs" + set category = "Admin" + + if(!holder) + return + + verbs -= admin_verbs_snpc + verbs += /client/proc/show_snpc_verbs + to_chat(src, "SNPC verbs off.") diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 7fb6806b5c0..dc7cc24d6b7 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1142,6 +1142,28 @@ message_admins("\blue [key_name_admin(usr)] attempting to corgize [key_name_admin(H)]", 1) H.corgize() + else if(href_list["makePAI"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["makePAI"]) + if(!istype(H)) + to_chat(usr, "This can only be used on instances of type /mob/living/carbon/human") + return + + var/painame = "Default" + var/name = "" + if(alert(usr, "Do you want to set their name or let them choose their own name?", "Name Choice", "Set Name", "Let them choose") == "Set Name") + name = sanitize(copytext(input(usr, "Enter a name for the new pAI. Default name is [painame].", "pAI Name", painame),1,MAX_NAME_LEN)) + else + name = sanitize(copytext(input(H, "An admin wants to make you into a pAI. Choose a name. Default is [painame].", "pAI Name", painame),1,MAX_NAME_LEN)) + + if(!name) + name = painame + + log_admin("[key_name(usr)] attempting to pAIze [key_name(H)]") + message_admins("\blue [key_name_admin(usr)] attempting to pAIze [key_name_admin(H)]", 1) + H.paize(name) + else if(href_list["forcespeech"]) if(!check_rights(R_SERVER|R_EVENT)) return @@ -2461,7 +2483,7 @@ for(var/obj/item/W in world) if(istype(W, /obj/item/clothing) || istype(W, /obj/item/weapon/card/id) || istype(W, /obj/item/weapon/disk) || istype(W, /obj/item/weapon/tank)) continue - W.icon = 'icons/obj/gun.dmi' + W.icon = 'icons/obj/guns/projectile.dmi' W.icon_state = "revolver" W.item_state = "gun" message_admins("[key_name_admin(usr)] made every item look like a gun") diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 4793edd37c8..e02ac49b821 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -359,6 +359,27 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that message_admins("[key_name_admin(src)] has deleted all instances of [hsbitem].", 0) feedback_add_details("admin_verb","DELA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! +/client/proc/cmd_debug_del_sing() + set category = "Debug" + set name = "Del Singulo / Tesla" + + if(!check_rights(R_DEBUG)) + return + + //This gets a confirmation check because it's way easier to accidentally hit this and delete things than it is with del-all + var/confirm = alert("This will delete ALL Singularities and Tesla orbs except for any that are on away mission z-levels or the centcomm z-level. Are you sure you want to delete them?", "Confirm Panic Button", "Yes", "No") + if(confirm != "Yes") + return + + for(var/I in singularities) + var/obj/singularity/S = I + if(S.z == ZLEVEL_CENTCOMM || S.z >= MAX_Z) + continue + qdel(S) + log_admin("[key_name(src)] has deleted all Singularities and Tesla orbs.") + message_admins("[key_name_admin(src)] has deleted all Singularities and Tesla orbs.", 0) + feedback_add_details("admin_verb","DELS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + /client/proc/cmd_debug_make_powernets() set category = "Debug" set name = "Make Powernets" @@ -669,7 +690,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that M.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(M), slot_wear_suit) M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/thunderdome(M), slot_head) - M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle/destroyer(M), slot_r_hand) + M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse/destroyer(M), slot_r_hand) M.equip_to_slot_or_del(new /obj/item/weapon/kitchen/knife(M), slot_l_hand) M.equip_to_slot_or_del(new /obj/item/weapon/grenade/smokebomb(M), slot_r_store) @@ -860,7 +881,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that M.equip_or_collect(pda, slot_r_store) M.equip_or_collect(new /obj/item/clothing/glasses/sunglasses(M), slot_l_store) - M.equip_or_collect(new /obj/item/weapon/gun/energy/pulse_rifle/pistol(M), slot_belt) + M.equip_or_collect(new /obj/item/weapon/gun/energy/pulse/pistol(M), slot_belt) var/obj/item/weapon/card/id/centcom/W = new(M) W.name = "[M.real_name]'s ID Card (Nanotrasen Navy Officer)" @@ -883,7 +904,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that M.equip_or_collect(pda, slot_r_store) M.equip_or_collect(new /obj/item/clothing/glasses/sunglasses(M), slot_l_store) - M.equip_or_collect(new /obj/item/weapon/gun/energy/pulse_rifle/pistol(M), slot_belt) + M.equip_or_collect(new /obj/item/weapon/gun/energy/pulse/pistol(M), slot_belt) var/obj/item/weapon/card/id/centcom/W = new(M) W.name = "[M.real_name]'s ID Card (Nanotrasen Navy Captain)" @@ -946,7 +967,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/cyber(M), slot_glasses) M.equip_to_slot_or_del(new /obj/item/clothing/mask/cigarette/cigar/cohiba(M), slot_wear_mask) M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/deathsquad/beret(M), slot_head) - M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle/pistol/m1911(M), slot_belt) + M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse/pistol/m1911(M), slot_belt) M.equip_to_slot_or_del(new /obj/item/weapon/storage/box/matches(M), slot_r_store) M.equip_to_slot_or_del(new /obj/item/weapon/twohanded/dualsaber/red(M), slot_l_store) @@ -975,7 +996,7 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that M.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/deathsquad/beret(M), slot_head) M.equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/cyber(M), slot_glasses) M.equip_to_slot_or_del(new /obj/item/clothing/mask/cigarette/cigar/cohiba(M), slot_wear_mask) - M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle/pistol/m1911(M), slot_belt) + M.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse/pistol/m1911(M), slot_belt) M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(M), slot_back) M.equip_to_slot_or_del(new /obj/item/weapon/storage/box/matches(M), slot_r_store) M.equip_or_collect(new /obj/item/weapon/melee/classic_baton/telescopic(M), slot_l_store) @@ -1212,4 +1233,4 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that assets.register() // Clear the user's cache so they get resent. - usr.client.cache = list() \ No newline at end of file + usr.client.cache = list() diff --git a/code/modules/admin/verbs/honksquad.dm b/code/modules/admin/verbs/honksquad.dm index 75fc6af84d9..dd37a828302 100644 --- a/code/modules/admin/verbs/honksquad.dm +++ b/code/modules/admin/verbs/honksquad.dm @@ -121,7 +121,7 @@ var/global/sent_honksquad = 0 if(prob(50)) equip_to_slot_or_del(new /obj/item/weapon/gun/energy/clown(src), slot_in_backpack) else - equip_to_slot_or_del(new /obj/item/weapon/gun/grenadelauncher/piecannon(src), slot_in_backpack) + equip_to_slot_or_del(new /obj/item/weapon/gun/throw/piecannon(src), slot_in_backpack) src.mutations.Add(CLUMSY) @@ -134,4 +134,4 @@ var/global/sent_honksquad = 0 W.registered_name = real_name equip_to_slot_or_del(W, slot_wear_id) - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/admin/verbs/one_click_antag.dm b/code/modules/admin/verbs/one_click_antag.dm index e09953a81d6..46972243a06 100644 --- a/code/modules/admin/verbs/one_click_antag.dm +++ b/code/modules/admin/verbs/one_click_antag.dm @@ -498,6 +498,7 @@ client/proc/one_click_antag() /datum/admins/proc/create_vox_raider(obj/spawn_location, leader_chosen = 0) var/mob/living/carbon/human/new_vox = new(spawn_location.loc, "Vox") + var/obj/item/organ/external/head/head_organ = new_vox.get_organ("head") var/sounds = rand(2,8) var/i = 0 @@ -516,8 +517,8 @@ client/proc/one_click_antag() new_vox.add_language("Vox-pidgin") new_vox.add_language("Galactic Common") new_vox.add_language("Tradeband") - new_vox.h_style = "Short Vox Quills" - new_vox.f_style = "Shaved" + head_organ.h_style = "Short Vox Quills" + head_organ.f_style = "Shaved" for(var/obj/item/organ/external/limb in new_vox.organs) limb.status &= ~(ORGAN_DESTROYED | ORGAN_ROBOT) diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm index 61c7b4f5790..4eeab674a88 100644 --- a/code/modules/admin/verbs/onlyone.dm +++ b/code/modules/admin/verbs/onlyone.dm @@ -3,7 +3,7 @@ alert("The game hasn't started yet!") return - var/list/incompatible_species = list("Plasmaman") + var/list/incompatible_species = list("Plasmaman", "Vox") for(var/mob/living/carbon/human/H in player_list) if(H.stat == DEAD || !(H.client)) continue diff --git a/code/modules/admin/verbs/onlyoneteam.dm b/code/modules/admin/verbs/onlyoneteam.dm index 6d5c11e3a4b..5072b43383e 100644 --- a/code/modules/admin/verbs/onlyoneteam.dm +++ b/code/modules/admin/verbs/onlyoneteam.dm @@ -3,7 +3,8 @@ alert("The game hasn't started yet!") return - var/list/incompatible_species = list("Plasmaman") + var/list/incompatible_species = list("Plasmaman", "Vox") + var/team_toggle = 0 for(var/mob/living/carbon/human/H in player_list) if(H.stat == DEAD || !(H.client)) continue @@ -27,7 +28,7 @@ H.equip_to_slot_or_del(new /obj/item/weapon/beach_ball/dodgeball(H), slot_r_hand) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/white(H), slot_shoes) - if(prob(50)) + if(!team_toggle) team_alpha += H H.equip_to_slot_or_del(new /obj/item/clothing/under/color/red/dodgeball(H), slot_w_uniform) @@ -53,6 +54,7 @@ W.registered_name = H.real_name H.equip_to_slot_or_del(W, slot_wear_id) + team_toggle = !team_toggle H.species.equip(H) H.regenerate_icons() diff --git a/code/modules/admin/verbs/striketeam.dm b/code/modules/admin/verbs/striketeam.dm index a5b98bc888c..142bb8203cd 100644 --- a/code/modules/admin/verbs/striketeam.dm +++ b/code/modules/admin/verbs/striketeam.dm @@ -154,7 +154,7 @@ var/global/sent_strike_team = 0 equip_to_slot_or_del(new /obj/item/weapon/tank/emergency_oxygen/double/full(src), slot_s_store) equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/revolver/mateba(src), slot_belt) - equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse_rifle(src), slot_r_hand) + equip_to_slot_or_del(new /obj/item/weapon/gun/energy/pulse(src), slot_r_hand) var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(src)//Here you go Deuryn @@ -170,4 +170,4 @@ var/global/sent_strike_team = 0 W.registered_name = real_name equip_to_slot_or_del(W, slot_wear_id) - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/admin/verbs/striketeam_syndicate.dm b/code/modules/admin/verbs/striketeam_syndicate.dm index 6131962b881..054b5469d9b 100644 --- a/code/modules/admin/verbs/striketeam_syndicate.dm +++ b/code/modules/admin/verbs/striketeam_syndicate.dm @@ -144,7 +144,7 @@ var/global/sent_syndicate_strike_team = 0 equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal(src), slot_glasses) equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/security(src), slot_back) - equip_to_slot_or_del(new /obj/item/ammo_box/magazine/m762, slot_in_backpack) + equip_to_slot_or_del(new /obj/item/ammo_box/magazine/mm556x45) equip_to_slot_or_del(new /obj/item/ammo_box/magazine/m45(src), slot_in_backpack) equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/hypospray/combat/nanites(src), slot_in_backpack) @@ -160,7 +160,7 @@ var/global/sent_syndicate_strike_team = 0 equip_to_slot_or_del(new /obj/item/weapon/melee/energy/sword/saber(src), slot_l_store) equip_to_slot_or_del(new /obj/item/weapon/grenade/empgrenade(src), slot_r_store) equip_to_slot_or_del(new /obj/item/weapon/tank/emergency_oxygen/double/full(src), slot_s_store) - equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/automatic/pistol/m2411(src), slot_belt) + equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/automatic/pistol/m1911(src), slot_belt) equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/automatic/l6_saw(src), slot_r_hand) @@ -173,4 +173,4 @@ var/global/sent_syndicate_strike_team = 0 W.registered_name = real_name equip_to_slot_or_del(W, slot_wear_id) - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/admin/verbs/vox_raiders.dm b/code/modules/admin/verbs/vox_raiders.dm index c5e370f06f7..b2cc9336bf5 100644 --- a/code/modules/admin/verbs/vox_raiders.dm +++ b/code/modules/admin/verbs/vox_raiders.dm @@ -18,7 +18,7 @@ var/global/vox_tick = 1 equip_to_slot_or_del(new /obj/item/clothing/glasses/thermal/monocle(src), slot_glasses) // REPLACE WITH CODED VOX ALTERNATIVE. equip_to_slot_or_del(new /obj/item/device/chameleon(src), slot_l_store) - var/obj/item/weapon/gun/launcher/spikethrower/W = new(src) + var/obj/item/weapon/gun/projectile/automatic/spikethrower/W = new(src) equip_to_slot_or_del(W, slot_r_hand) @@ -77,4 +77,4 @@ var/global/vox_tick = 1 vox_tick++ if (vox_tick > 4) vox_tick = 1 - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm index 3bf0775473c..3171755b34c 100644 --- a/code/modules/assembly/bomb.dm +++ b/code/modules/assembly/bomb.dm @@ -10,6 +10,7 @@ var/status = 0 //0 - not readied //1 - bomb finished with welder var/obj/item/device/assembly_holder/bombassembly = null //The first part of the bomb is an assembly holder, holding an igniter+some device var/obj/item/weapon/tank/bombtank = null //the second part of the bomb is a plasma tank + origin_tech = "materials=1;engineering=1" /obj/item/device/onetankbomb/examine(mob/user) ..(user) diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 844e66cd68c..6797ba8f340 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -43,7 +43,8 @@ timer_end() if((!secured)||(cooldown > 0)) return 0 pulse(0) - loc.visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") + if(loc) + loc.visible_message("\icon[src] *beep* *beep*", "*beep* *beep*") cooldown = 2 spawn(10) process_cooldown() diff --git a/code/modules/awaymissions/mission_code/stationCollision.dm b/code/modules/awaymissions/mission_code/stationCollision.dm index 0adf55229e0..682e2137d2a 100644 --- a/code/modules/awaymissions/mission_code/stationCollision.dm +++ b/code/modules/awaymissions/mission_code/stationCollision.dm @@ -61,10 +61,8 @@ */ //Captain's retro laser - Fires practice laser shots instead. obj/item/weapon/gun/energy/laser/retro/sc_retro - name ="retro laser" - icon_state = "retro" desc = "An older model of the basic lasergun, no longer used by Nanotrasen's security or military forces." -// projectile_type = "/obj/item/projectile/practice" + ammo_type = list(/obj/item/ammo_casing/energy/laser/practice) clumsy_check = 0 //No sense in having a harmless gun blow up in the clowns face //Syndicate sub-machine guns. @@ -196,4 +194,4 @@ var/sc_safecode5 = "[rand(0,9)]" return /obj/singularity/narsie/sc_Narsie/ex_act() - return \ No newline at end of file + return diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 9575002bc88..756e5c6b156 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -315,6 +315,11 @@ send_resources() + if(prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates. -CP + if(establish_db_connection()) + winset(src, "rpane.changelog", "background-color=#f4aa94;font-style=bold") + to_chat(src, "Changelog has changed since your last visit.") + if(!void) void = new() diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 009599f00de..ae9620c7217 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -83,7 +83,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts var/last_id //game-preferences -// var/lastchangelog = "" //Saved changlog filesize to detect if there was a change + var/lastchangelog = "" //Saved changlog filesize to detect if there was a change var/ooccolor = "#b82e00" var/be_special = list() //Special role selection var/UI_style = "Midnight" @@ -1985,3 +1985,1894 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts /datum/preferences/proc/close_load_dialog(mob/user) user << browse(null, "window=saves") +======= +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:33 + +var/list/preferences_datums = list() + +var/global/list/special_role_times = list( //minimum age (in days) for accounts to play these roles + ROLE_PAI = 0, + ROLE_POSIBRAIN = 0, + ROLE_GUARDIAN = 0, + ROLE_TRAITOR = 7, + ROLE_CHANGELING = 14, + ROLE_SHADOWLING = 14, + ROLE_WIZARD = 14, + ROLE_REV = 14, + ROLE_VAMPIRE = 14, + ROLE_BLOB = 14, + ROLE_REVENANT = 14, + ROLE_OPERATIVE = 21, + ROLE_CULTIST = 21, + ROLE_RAIDER = 21, + ROLE_ALIEN = 21, + ROLE_DEMON = 21, + ROLE_SENTIENT = 21, +// ROLE_GANG = 21, + ROLE_BORER = 21, + ROLE_NINJA = 21, + ROLE_MUTINEER = 21, + ROLE_MALF = 30, + ROLE_ABDUCTOR = 30, +) + +/proc/player_old_enough_antag(client/C, role) + if(available_in_days_antag(C, role) == 0) + return 1 //Available in 0 days = available right now = player is old enough to play. + return 0 + +/proc/available_in_days_antag(client/C, role) + if(!C) + return 0 + if(!role) + return 0 + if(!config.use_age_restriction_for_antags) + return 0 + if(!isnum(C.player_age)) + return 0 //This is only a number if the db connection is established, otherwise it is text: "Requires database", meaning these restrictions cannot be enforced + var/minimal_player_age_antag = special_role_times[num2text(role)] + if(!isnum(minimal_player_age_antag)) + return 0 + + return max(0, minimal_player_age_antag - C.player_age) + +/proc/check_client_age(client/C, var/days) // If days isn't provided, returns the age of the client. If it is provided, it returns the days until the player_age is equal to or greater than the days variable + if(!days) + return C.player_age + else + return max(0, days - C.player_age) + return 0 + +//used for alternate_option +#define GET_RANDOM_JOB 0 +#define BE_CIVILIAN 1 +#define RETURN_TO_LOBBY 2 + +#define MAX_SAVE_SLOTS 20 // Save slots for regular players +#define MAX_SAVE_SLOTS_MEMBER 20 // Save slots for BYOND members + +#define TAB_CHAR 0 +#define TAB_GAME 1 + +/datum/preferences + //doohickeys for savefiles +// var/path + var/default_slot = 1 //Holder so it doesn't default to slot 1, rather the last one used +// var/savefile_version = 0 + var/max_save_slots = MAX_SAVE_SLOTS + + //non-preference stuff + var/warns = 0 + var/muted = 0 + var/last_ip + var/last_id + + //game-preferences + var/lastchangelog = "" //Saved changelog filesize to detect if there was a change + var/ooccolor = "#b82e00" + var/be_special = list() //Special role selection + var/UI_style = "Midnight" + var/nanoui_fancy = TRUE + var/toggles = TOGGLES_DEFAULT + var/sound = SOUND_DEFAULT + var/show_ghostitem_attack = TRUE + var/UI_style_color = "#ffffff" + var/UI_style_alpha = 255 + + + //character preferences + var/real_name //our character's name + var/be_random_name = 0 //whether we are a random name every round + var/gender = MALE //gender of character (well duh) + var/age = 30 //age of character + var/spawnpoint = "Arrivals Shuttle" //where this character will spawn (0-2). + var/b_type = "A+" //blood type (not-chooseable) + var/underwear = "Nude" //underwear type + var/undershirt = "Nude" //undershirt type + var/socks = "Nude" //socks type + var/backbag = 2 //backpack type + var/ha_style = "None" //Head accessory style + var/r_headacc = 0 //Head accessory colour + var/g_headacc = 0 //Head accessory colour + var/b_headacc = 0 //Head accessory colour + var/m_style = "None" //Marking style + var/r_markings = 0 //Marking colour + var/g_markings = 0 //Marking colour + var/b_markings = 0 //Marking colour + var/h_style = "Bald" //Hair type + var/r_hair = 0 //Hair color + var/g_hair = 0 //Hair color + var/b_hair = 0 //Hair color + var/f_style = "Shaved" //Face hair type + var/r_facial = 0 //Face hair color + var/g_facial = 0 //Face hair color + var/b_facial = 0 //Face hair color + var/s_tone = 0 //Skin tone + var/r_skin = 0 //Skin color + var/g_skin = 0 //Skin color + var/b_skin = 0 //Skin color + var/r_eyes = 0 //Eye color + var/g_eyes = 0 //Eye color + var/b_eyes = 0 //Eye color + var/species = "Human" + var/language = "None" //Secondary language + + var/body_accessory = null + + var/speciesprefs = 0//I hate having to do this, I really do (Using this for oldvox code, making names universal I guess + + //Mob preview + var/icon/preview_icon = null + var/icon/preview_icon_front = null + var/icon/preview_icon_side = null + + //Jobs, uses bitflags + var/job_support_high = 0 + var/job_support_med = 0 + var/job_support_low = 0 + + var/job_medsci_high = 0 + var/job_medsci_med = 0 + var/job_medsci_low = 0 + + var/job_engsec_high = 0 + var/job_engsec_med = 0 + var/job_engsec_low = 0 + + var/job_karma_high = 0 + var/job_karma_med = 0 + var/job_karma_low = 0 + + //Keeps track of preferrence for not getting any wanted jobs + var/alternate_option = 0 + + // maps each organ to either null(intact), "cyborg" or "amputated" + // will probably not be able to do this for head and torso ;) + var/list/organ_data = list() + var/list/rlimb_data = list() + + var/list/player_alt_titles = new() // the default name of a job like "Medical Doctor" +// var/accent = "en-us" +// var/voice = "m1" +// var/pitch = 50 +// var/talkspeed = 175 + var/flavor_text = "" + var/med_record = "" + var/sec_record = "" + var/gen_record = "" + var/disabilities = 0 + + var/nanotrasen_relation = "Neutral" + + // 0 = character settings, 1 = game preferences + var/current_tab = TAB_CHAR + + // OOC Metadata: + var/metadata = "" + var/slot_name = "" + + // Whether or not to use randomized character slots + var/randomslot = 0 + + // jukebox volume + var/volume = 100 + + // BYOND membership + var/unlock_content = 0 + +/datum/preferences/New(client/C) + b_type = pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+") + if(istype(C)) + if(!IsGuestKey(C.key)) + unlock_content = C.IsByondMember() + if(unlock_content) + max_save_slots = MAX_SAVE_SLOTS_MEMBER + var/loaded_preferences_successfully = load_preferences(C) + if(loaded_preferences_successfully) + if(load_character(C)) + return + //we couldn't load character data so just randomize the character appearance + name + random_character() //let's create a random character then - rather than a fat, bald and naked man. + real_name = random_name(gender) + if(!loaded_preferences_successfully) + save_preferences(C) + save_character(C) //let's save this new random character so it doesn't keep generating new ones. + +/datum/preferences/proc/color_square(r, g, b) + return "___" + +// Hello I am a proc full of snowflake species checks how are you +/datum/preferences/proc/ShowChoices(mob/user) + if(!user || !user.client) + return + update_preview_icon() + user << browse_rsc(preview_icon_front, "previewicon.png") + user << browse_rsc(preview_icon_side, "previewicon2.png") + + var/dat = "" + dat += "
    " + dat += "Character Settings" + dat += "Game Preferences" + dat += "
    " + dat += "
    " + + switch(current_tab) + if(TAB_CHAR) // Character Settings + dat += "
    " + dat += "
    " + dat += "Name: " + dat += "[real_name]" + dat += "(Randomize)" + dat += "(Always Randomize)
    " + dat += "
    " + dat += "
    " + dat += "Slot [slot_name] - " + dat += "Load slot - " + dat += "Save slot - " + dat += "Reload slot" + dat += "
    " + dat += "
    " + dat += "
    " + dat += "

    Identity

    " + if(appearance_isbanned(user)) + dat += "You are banned from using custom names and appearances. \ + You can continue to adjust your characters, but you will be randomised once you join the game.\ +
    " + dat += "Gender: [gender == MALE ? "Male" : "Female"]
    " + dat += "Age: [age]
    " + dat += "Body: (®)
    " + dat += "Species: [species]
    " + if(species == "Vox") + dat += "N2 Tank: [speciesprefs ? "Large N2 Tank" : "Specialized N2 Tank"]
    " + dat += "Secondary Language: [language]
    " + dat += "Blood Type: [b_type]
    " + if(species in list("Human", "Drask")) + dat += "Skin Tone: [-s_tone + 35]/220
    " + dat += "Disabilities: \[Set\]
    " + dat += "Nanotrasen Relation: [nanotrasen_relation]
    " + dat += "Set Flavor Text
    " + if(lentext(flavor_text) <= 40) + if(!lentext(flavor_text)) dat += "\[...\]
    " + else dat += "[flavor_text]
    " + else dat += "[TextPreview(flavor_text)]...
    " + + dat += "

    Hair & Accessories

    " + + if(species in list("Unathi", "Vulpkanin", "Tajaran", "Machine")) //Species that have head accessories. + var/headaccessoryname = "Head Accessory: " + if(species == "Unathi") + headaccessoryname = "Horns: " + dat += "[headaccessoryname]" + dat += "[ha_style] " + dat += "Color [color_square(r_headacc, g_headacc, b_headacc)]
    " + + if(species in list("Unathi", "Vulpkanin", "Tajaran", "Machine")) //Species that have body markings. + dat += "Body Markings: " + dat += "[m_style]" + dat += "Color [color_square(r_markings, g_markings, b_markings)]
    " + + dat += "Hair: " + dat += "[h_style]" + dat += "Color [color_square(r_hair, g_hair, b_hair)]
    " + + dat += "Facial Hair: " + dat += "[f_style ? "[f_style]" : "Shaved"]" + dat += "Color [color_square(r_facial, g_facial, b_facial)]
    " + + if(species != "Machine") + dat += "Eyes: " + dat += "Color [color_square(r_eyes, g_eyes, b_eyes)]
    " + + if((species in list("Unathi", "Tajaran", "Skrell", "Slime People", "Vulpkanin", "Machine")) || body_accessory_by_species[species] || check_rights(R_ADMIN, 0, user)) //admins can always fuck with this, because they are admins + dat += "Body Color: " + dat += "Color [color_square(r_skin, g_skin, b_skin)]
    " + + if(body_accessory_by_species[species] || check_rights(R_ADMIN, 0, user)) + dat += "Body Accessory: " + dat += "[body_accessory ? "[body_accessory]" : "None"]
    " + + dat += "
    " + dat += "

    Occupation Choices

    " + dat += "Set Occupation Preferences
    " + if(jobban_isbanned(user, "Records")) + dat += "You are banned from using character records.
    " + else + dat += "Character Records
    " + + dat += "

    Limbs

    " + dat += "Limbs and Parts: Adjust
    " + if(species != "Slime People" && species != "Machine") + dat += "Internal Organs: Adjust
    " + + //display limbs below + var/ind = 0 + for(var/name in organ_data) + var/status = organ_data[name] + var/organ_name = null + switch(name) + if("chest") organ_name = "torso" + if("groin") organ_name = "lower body" + if("head") organ_name = "head" + if("l_arm") organ_name = "left arm" + if("r_arm") organ_name = "right arm" + if("l_leg") organ_name = "left leg" + if("r_leg") organ_name = "right leg" + if("l_foot") organ_name = "left foot" + if("r_foot") organ_name = "right foot" + if("l_hand") organ_name = "left hand" + if("r_hand") organ_name = "right hand" + if("heart") organ_name = "heart" + if("eyes") organ_name = "eyes" + + if(status in list("cyborg", "amputated", "mechanical", "assisted")) + ++ind + if(ind > 1) dat += ", " + + switch(status) + if("cyborg") + var/datum/robolimb/R + if(rlimb_data[name] && all_robolimbs[rlimb_data[name]]) + R = all_robolimbs[rlimb_data[name]] + else + R = basic_robolimb + dat += "\t[R.company] [organ_name] prosthesis" + if("amputated") dat += "\tAmputated [organ_name]" + if("mechanical") dat += "\tMechanical [organ_name]" + if("assisted") + switch(organ_name) + if("heart") dat += "\tPacemaker-assisted [organ_name]" + if("voicebox") dat += "\tSurgically altered [organ_name]" + if("eyes") dat += "\tRetinal overlayed [organ_name]" + else dat += "\tMechanically assisted [organ_name]" + if(!ind) dat += "\[...\]
    " + else dat += "
    " + + dat += "

    Clothing

    " + dat += "Underwear: [underwear]
    " + dat += "Undershirt: [undershirt]
    " + dat += "Socks: [socks]
    " + dat += "Backpack Type: [backbaglist[backbag]]
    " + + dat += "
    " + + if(TAB_GAME) // General Preferences + dat += "
    " + dat += "

    General Settings

    " + dat += "Fancy NanoUI: [(nanoui_fancy) ? "Yes" : "No"]
    " + dat += "Ghost-Item Attack Animation: [(show_ghostitem_attack) ? "Yes" : "No"]
    " + dat += "Custom UI settings:
    " + dat += " - UI Style: [UI_style]
    " + dat += " - Color: [UI_style_color]
    __

    " + dat += " - Alpha (transparency): [UI_style_alpha]
    " + dat += "
    " + dat += "Play admin midis: [(sound & SOUND_MIDI) ? "Yes" : "No"]
    " + dat += "Play lobby music: [(sound & SOUND_LOBBY) ? "Yes" : "No"]
    " + if(user.client.holder) + dat += "Adminhelp sound: " + dat += "[(sound & SOUND_ADMINHELP)?"On":"Off"]
    " + + if(check_rights(R_ADMIN,0)) + dat += "OOC:     Change
    " + if(config.allow_Metadata) + dat += "OOC notes: Edit
    " + if(unlock_content) + dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]
    " + + dat += "Randomized character slot: [randomslot ? "Yes" : "No"]
    " + dat += "Ghost ears: [(toggles & CHAT_GHOSTEARS) ? "Nearest Creatures" : "All Speech"]
    " + dat += "Ghost sight: [(toggles & CHAT_GHOSTSIGHT) ? "Nearest Creatures" : "All Emotes"]
    " + dat += "Ghost radio: [(toggles & CHAT_GHOSTRADIO) ? "Nearest Speakers" : "All Chatter"]
    " + + dat += "
    " + dat += "

    Special Role Settings

    " + if(jobban_isbanned(user, "Syndicate")) + dat += "You are banned from special roles." + be_special = list() + else + for(var/i in special_roles) + if(jobban_isbanned(user, i)) + dat += "Be [capitalize(i)]: \[BANNED]
    " + else if(!player_old_enough_antag(user.client,i)) + var/available_in_days_antag = available_in_days_antag(user.client,i) + dat += "Be [capitalize(i)]: \[IN [(available_in_days_antag)] DAYS]
    " + else + dat += "Be [capitalize(i)]: [(i in src.be_special) ? "Yes" : "No"]
    " + dat += "
    " + + dat += "
    " + if(!IsGuestKey(user.key)) + dat += "Undo - " + dat += "Save Setup - " + + dat += "Reset Setup" + dat += "
    " + + var/datum/browser/popup = new(user, "preferences", "
    Character Setup
    ", 820, 640) + popup.set_content(dat) + popup.open(0) + +/datum/preferences/proc/SetChoices(mob/user, limit = 12, list/splitJobs = list("Civilian","Research Director","AI","Bartender"), width = 760, height = 790) + if(!job_master) + return + + //limit - The amount of jobs allowed per column. Defaults to 17 to make it look nice. + //splitJobs - Allows you split the table by job. You can make different tables for each department by including their heads. Defaults to CE to make it look nice. + //width - Screen' width. Defaults to 550 to make it look nice. + //height - Screen's height. Defaults to 500 to make it look nice. + + + var/HTML = "" + HTML += "
    " + HTML += "Choose occupation chances
    Unavailable occupations are crossed out.

    " + HTML += "
    \[Done\]

    " // Easier to press up here. + HTML += "
    Left-click to raise an occupation preference, right-click to lower it.
    " + HTML += "" + HTML += "
    " // Table within a table for alignment, also allows you to easily add more colomns. + HTML += "" + var/index = -1 + + //The job before the current job. I only use this to get the previous jobs color when I'm filling in blank rows. + var/datum/job/lastJob + if (!job_master) return + for(var/datum/job/job in job_master.occupations) + + index += 1 + if((index >= limit) || (job.title in splitJobs)) + if((index < limit) && (lastJob != null)) + //If the cells were broken up by a job in the splitJob list then it will fill in the rest of the cells with + //the last job's selection color. Creating a rather nice effect. + for(var/i = 0, i < (limit - index), i += 1) + HTML += "" + HTML += "
      
    " + index = 0 + + HTML += "" + continue + if(jobban_isbanned(user, rank)) + HTML += "[rank]" + continue + if(!job.player_old_enough(user.client)) + var/available_in_days = job.available_in_days(user.client) + HTML += "[rank]" + continue + if((job_support_low & CIVILIAN) && (rank != "Civilian")) + HTML += "[rank]" + continue + if((rank in command_positions) || (rank == "AI"))//Bold head jobs + HTML += "[rank]" + else + HTML += "[rank]" + + HTML += "" + HTML += "" + continue +/* + if(GetJobDepartment(job, 1) & job.flag) + HTML += " \[High]" + else if(GetJobDepartment(job, 2) & job.flag) + HTML += " \[Medium]" + else if(GetJobDepartment(job, 3) & job.flag) + HTML += " \[Low]" + else + HTML += " \[NEVER]" + */ + HTML += "[prefLevelLabel]" + + if(job.alt_titles) + HTML += "
    \[[GetPlayerAltTitle(job)]\]" + + + HTML += "" + + for(var/i = 1, i < (limit - index), i += 1) // Finish the column so it is even + HTML += "" + + HTML += "
    " + var/rank = job.title + lastJob = job + if(!is_job_whitelisted(user, rank)) + HTML += "[rank] \[KARMA]
    \[BANNED]
    \[IN [(available_in_days)] DAYS]
    " + + var/prefLevelLabel = "ERROR" + var/prefLevelColor = "pink" + var/prefUpperLevel = -1 // level to assign on left click + var/prefLowerLevel = -1 // level to assign on right click + + if(GetJobDepartment(job, 1) & job.flag) + prefLevelLabel = "High" + prefLevelColor = "slateblue" + prefUpperLevel = 4 + prefLowerLevel = 2 + else if(GetJobDepartment(job, 2) & job.flag) + prefLevelLabel = "Medium" + prefLevelColor = "green" + prefUpperLevel = 1 + prefLowerLevel = 3 + else if(GetJobDepartment(job, 3) & job.flag) + prefLevelLabel = "Low" + prefLevelColor = "orange" + prefUpperLevel = 2 + prefLowerLevel = 4 + else + prefLevelLabel = "NEVER" + prefLevelColor = "red" + prefUpperLevel = 3 + prefLowerLevel = 1 + + + HTML += "" + +// HTML += "" + + if(rank == "Civilian")//Civilian is special + if(job_support_low & CIVILIAN) + HTML += " \[Yes]" + else + HTML += " \[No]" + if(job.alt_titles) + HTML += "
    \[[GetPlayerAltTitle(job)]\]
      
    " + + HTML += "
    " + + switch(alternate_option) + if(GET_RANDOM_JOB) + HTML += "

    Get random job if preferences unavailable

    " + if(BE_CIVILIAN) + HTML += "

    Be a civilian if preferences unavailable

    " + if(RETURN_TO_LOBBY) + HTML += "

    Return to lobby if preferences unavailable

    " + + HTML += "
    \[Reset\]
    " + HTML += "
    " + + user << browse(null, "window=preferences") +// user << browse(HTML, "window=mob_occupation;size=[width]x[height]") + var/datum/browser/popup = new(user, "mob_occupation", "
    Occupation Preferences
    ", width, height) + popup.set_window_options("can_close=0") + popup.set_content(HTML) + popup.open(0) + return + +/datum/preferences/proc/SetJobPreferenceLevel(var/datum/job/job, var/level) + if (!job) + return 0 + + if (level == 1) // to high + // remove any other job(s) set to high + job_support_med |= job_support_high + job_engsec_med |= job_engsec_high + job_medsci_med |= job_medsci_high + job_karma_med |= job_karma_high + job_support_high = 0 + job_engsec_high = 0 + job_medsci_high = 0 + job_karma_high = 0 + + if (job.department_flag == SUPPORT) + job_support_low &= ~job.flag + job_support_med &= ~job.flag + job_support_high &= ~job.flag + + switch(level) + if (1) + job_support_high |= job.flag + if (2) + job_support_med |= job.flag + if (3) + job_support_low |= job.flag + + return 1 + else if (job.department_flag == ENGSEC) + job_engsec_low &= ~job.flag + job_engsec_med &= ~job.flag + job_engsec_high &= ~job.flag + + switch(level) + if (1) + job_engsec_high |= job.flag + if (2) + job_engsec_med |= job.flag + if (3) + job_engsec_low |= job.flag + + return 1 + else if (job.department_flag == MEDSCI) + job_medsci_low &= ~job.flag + job_medsci_med &= ~job.flag + job_medsci_high &= ~job.flag + + switch(level) + if (1) + job_medsci_high |= job.flag + if (2) + job_medsci_med |= job.flag + if (3) + job_medsci_low |= job.flag + + return 1 + else if (job.department_flag == KARMA) + job_karma_low &= ~job.flag + job_karma_med &= ~job.flag + job_karma_high &= ~job.flag + + switch(level) + if (1) + job_karma_high |= job.flag + if (2) + job_karma_med |= job.flag + if (3) + job_karma_low |= job.flag + + return 1 + + return 0 + +/datum/preferences/proc/UpdateJobPreference(mob/user, role, desiredLvl) + var/datum/job/job = job_master.GetJob(role) + + if(!job) + user << browse(null, "window=mob_occupation") + ShowChoices(user) + return + + if (!isnum(desiredLvl)) + to_chat(user, "\red UpdateJobPreference - desired level was not a number. Please notify coders!") + ShowChoices(user) + return + + if(role == "Civilian") + if(job_support_low & job.flag) + job_support_low &= ~job.flag + else + job_support_low |= job.flag + SetChoices(user) + return 1 + + SetJobPreferenceLevel(job, desiredLvl) + SetChoices(user) + + return 1 + +/datum/preferences/proc/ShowDisabilityState(mob/user,flag,label) + if(flag==DISABILITY_FLAG_FAT && species!=("Human" || "Tajaran" || "Grey")) + return "
  5. [species] cannot be fat.
  6. " + return "
  7. [label]: [disabilities & flag ? "Yes" : "No"]
  8. " + +/datum/preferences/proc/SetDisabilities(mob/user) + var/HTML = "" + + // AUTOFIXED BY fix_string_idiocy.py + // C:\Users\Rob\Documents\Projects\vgstation13\code\modules\client\preferences.dm:474: HTML += "
    " + HTML += {"
    + Choose disabilities
      "} + // END AUTOFIX + HTML += ShowDisabilityState(user,DISABILITY_FLAG_NEARSIGHTED,"Needs Glasses") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_FAT,"Obese") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_EPILEPTIC,"Seizures") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_DEAF,"Deaf") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_BLIND,"Blind") + HTML += ShowDisabilityState(user,DISABILITY_FLAG_MUTE,"Mute") + + + // AUTOFIXED BY fix_string_idiocy.py + // C:\Users\Rob\Documents\Projects\vgstation13\code\modules\client\preferences.dm:481: HTML += "
    " + HTML += {" + \[Done\] + \[Reset\] +
    "} + // END AUTOFIX + user << browse(null, "window=preferences") + user << browse(HTML, "window=disabil;size=350x300") + return + +/datum/preferences/proc/SetRecords(mob/user) + var/HTML = "" + HTML += "
    " + HTML += "Set Character Records
    " + + HTML += "Medical Records
    " + + if(lentext(med_record) <= 40) + HTML += "[med_record]" + else + HTML += "[copytext(med_record, 1, 37)]..." + + HTML += "

    Employment Records
    " + + if(lentext(gen_record) <= 40) + HTML += "[gen_record]" + else + HTML += "[copytext(gen_record, 1, 37)]..." + + HTML += "

    Security Records
    " + + if(lentext(sec_record) <= 40) + HTML += "[sec_record]
    " + else + HTML += "[copytext(sec_record, 1, 37)]...
    " + + HTML += "
    " + HTML += "\[Done\]" + HTML += "
    " + + user << browse(null, "window=preferences") + user << browse(HTML, "window=records;size=350x300") + return + +/datum/preferences/proc/GetPlayerAltTitle(datum/job/job) + return player_alt_titles.Find(job.title) > 0 \ + ? player_alt_titles[job.title] \ + : job.title + +/datum/preferences/proc/SetPlayerAltTitle(datum/job/job, new_title) + // remove existing entry + if(player_alt_titles.Find(job.title)) + player_alt_titles -= job.title + // add one if it's not default + if(job.title != new_title) + player_alt_titles[job.title] = new_title + +/datum/preferences/proc/SetJob(mob/user, role) + var/datum/job/job = job_master.GetJob(role) + if(!job) + user << browse(null, "window=mob_occupation") + ShowChoices(user) + return + + if(role == "Civilian") + if(job_support_low & job.flag) + job_support_low &= ~job.flag + else + job_support_low |= job.flag + SetChoices(user) + return 1 + + if(GetJobDepartment(job, 1) & job.flag) + SetJobDepartment(job, 1) + else if(GetJobDepartment(job, 2) & job.flag) + SetJobDepartment(job, 2) + else if(GetJobDepartment(job, 3) & job.flag) + SetJobDepartment(job, 3) + else//job = Never + SetJobDepartment(job, 4) + + SetChoices(user) + return 1 + +/datum/preferences/proc/ResetJobs() + job_support_high = 0 + job_support_med = 0 + job_support_low = 0 + + job_medsci_high = 0 + job_medsci_med = 0 + job_medsci_low = 0 + + job_engsec_high = 0 + job_engsec_med = 0 + job_engsec_low = 0 + + job_karma_high = 0 + job_karma_med = 0 + job_karma_low = 0 + + +/datum/preferences/proc/GetJobDepartment(var/datum/job/job, var/level) + if(!job || !level) return 0 + switch(job.department_flag) + if(SUPPORT) + switch(level) + if(1) + return job_support_high + if(2) + return job_support_med + if(3) + return job_support_low + if(MEDSCI) + switch(level) + if(1) + return job_medsci_high + if(2) + return job_medsci_med + if(3) + return job_medsci_low + if(ENGSEC) + switch(level) + if(1) + return job_engsec_high + if(2) + return job_engsec_med + if(3) + return job_engsec_low + if(KARMA) + switch(level) + if(1) + return job_karma_high + if(2) + return job_karma_med + if(3) + return job_karma_low + return 0 + +/datum/preferences/proc/SetJobDepartment(var/datum/job/job, var/level) + if(!job || !level) return 0 + switch(level) + if(1)//Only one of these should ever be active at once so clear them all here + job_support_high = 0 + job_medsci_high = 0 + job_engsec_high = 0 + job_karma_high = 0 + return 1 + if(2)//Set current highs to med, then reset them + job_support_med |= job_support_high + job_medsci_med |= job_medsci_high + job_engsec_med |= job_engsec_high + job_karma_med |= job_karma_high + job_support_high = 0 + job_medsci_high = 0 + job_engsec_high = 0 + job_karma_high = 0 + + switch(job.department_flag) + if(SUPPORT) + switch(level) + if(2) + job_support_high = job.flag + job_support_med &= ~job.flag + if(3) + job_support_med |= job.flag + job_support_low &= ~job.flag + else + job_support_low |= job.flag + if(MEDSCI) + switch(level) + if(2) + job_medsci_high = job.flag + job_medsci_med &= ~job.flag + if(3) + job_medsci_med |= job.flag + job_medsci_low &= ~job.flag + else + job_medsci_low |= job.flag + if(ENGSEC) + switch(level) + if(2) + job_engsec_high = job.flag + job_engsec_med &= ~job.flag + if(3) + job_engsec_med |= job.flag + job_engsec_low &= ~job.flag + else + job_engsec_low |= job.flag + if(KARMA) + switch(level) + if(2) + job_karma_high = job.flag + job_karma_med &= ~job.flag + if(3) + job_karma_med |= job.flag + job_karma_low &= ~job.flag + else + job_karma_low |= job.flag + return 1 + +/datum/preferences/proc/process_link(mob/user, list/href_list) + if(!user) return + + if(href_list["preference"] == "job") + switch(href_list["task"]) + if("close") + user << browse(null, "window=mob_occupation") + ShowChoices(user) + if("reset") + ResetJobs() + SetChoices(user) + if("random") + if(alternate_option == GET_RANDOM_JOB || alternate_option == BE_CIVILIAN) + alternate_option += 1 + else if(alternate_option == RETURN_TO_LOBBY) + alternate_option = 0 + else + return 0 + SetChoices(user) + if ("alt_title") + var/datum/job/job = locate(href_list["job"]) + if (job) + var/choices = list(job.title) + job.alt_titles + var/choice = input("Pick a title for [job.title].", "Character Generation", GetPlayerAltTitle(job)) as anything in choices | null + if(choice) + SetPlayerAltTitle(job, choice) + SetChoices(user) + if("input") + SetJob(user, href_list["text"]) + if("setJobLevel") + UpdateJobPreference(user, href_list["text"], text2num(href_list["level"])) + else + SetChoices(user) + return 1 + else if(href_list["preference"] == "disabilities") + + switch(href_list["task"]) + if("close") + user << browse(null, "window=disabil") + ShowChoices(user) + if("reset") + disabilities=0 + SetDisabilities(user) + if("input") + var/dflag=text2num(href_list["disability"]) + if(dflag >= 0) + if(!(dflag==DISABILITY_FLAG_FAT && species!=("Human" || "Tajaran" || "Grey"))) + disabilities ^= text2num(href_list["disability"]) //MAGIC + SetDisabilities(user) + else + SetDisabilities(user) + return 1 + + else if(href_list["preference"] == "records") + if(text2num(href_list["record"]) >= 1) + SetRecords(user) + return + else + user << browse(null, "window=records") + if(href_list["task"] == "med_record") + var/medmsg = input(usr,"Set your medical notes here.","Medical Records",html_decode(med_record)) as message + + if(medmsg != null) + medmsg = copytext(medmsg, 1, MAX_PAPER_MESSAGE_LEN) + medmsg = html_encode(medmsg) + + med_record = medmsg + SetRecords(user) + + if(href_list["task"] == "sec_record") + var/secmsg = input(usr,"Set your security notes here.","Security Records",html_decode(sec_record)) as message + + if(secmsg != null) + secmsg = copytext(secmsg, 1, MAX_PAPER_MESSAGE_LEN) + secmsg = html_encode(secmsg) + + sec_record = secmsg + SetRecords(user) + if(href_list["task"] == "gen_record") + var/genmsg = input(usr,"Set your employment notes here.","Employment Records",html_decode(gen_record)) as message + + if(genmsg != null) + genmsg = copytext(genmsg, 1, MAX_PAPER_MESSAGE_LEN) + genmsg = html_encode(genmsg) + + gen_record = genmsg + SetRecords(user) + + switch(href_list["task"]) + if("random") + switch(href_list["preference"]) + if("name") + real_name = random_name(gender,species) + if("age") + age = rand(AGE_MIN, AGE_MAX) + if("hair") + if(species == "Human" || species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Machine" || species == "Wryn" || species == "Vulpkanin") + r_hair = rand(0,255) + g_hair = rand(0,255) + b_hair = rand(0,255) + if("h_style") + h_style = random_hair_style(gender, species) + if("facial") + r_facial = rand(0,255) + g_facial = rand(0,255) + b_facial = rand(0,255) + if("f_style") + f_style = random_facial_hair_style(gender, species) + if("underwear") + underwear = random_underwear(gender) + ShowChoices(user) + if("undershirt") + undershirt = random_undershirt(gender) + ShowChoices(user) + if("socks") + socks = random_socks(gender) + ShowChoices(user) + if("eyes") + r_eyes = rand(0,255) + g_eyes = rand(0,255) + b_eyes = rand(0,255) + if("s_tone") + if(species in list("Human", "Drask")) + s_tone = random_skin_tone() + if("s_color") + if(species in list("Unathi", "Tajaran", "Skrell", "Slime People", "Wyrn", "Vulpkanin", "Machine")) + r_skin = rand(0,255) + g_skin = rand(0,255) + b_skin = rand(0,255) + if("bag") + backbag = rand(1,4) + /*if("skin_style") + h_style = random_skin_style(gender)*/ + if("all") + random_character() + if("input") + switch(href_list["preference"]) + if("name") + var/raw_name = input(user, "Choose your character's name:", "Character Preference") as text|null + if (!isnull(raw_name)) // Check to ensure that the user entered text (rather than cancel.) + var/new_name = reject_bad_name(raw_name) + if(new_name) + real_name = new_name + else + to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .") + + if("age") + var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null + if(new_age) + age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) + if("species") + + var/list/new_species = list("Human", "Tajaran", "Skrell", "Unathi", "Diona", "Vulpkanin") + var/prev_species = species +// var/whitelisted = 0 + + if(config.usealienwhitelist) //If we're using the whitelist, make sure to check it! + for(var/S in whitelisted_species) + if(is_alien_whitelisted(user,S)) + new_species += S +// whitelisted = 1 +// if(!whitelisted) +// alert(user, "You cannot change your species as you need to be whitelisted. If you wish to be whitelisted contact an admin in-game, on the forums, or on IRC.") + else //Not using the whitelist? Aliens for everyone! + new_species += whitelisted_species + + species = input("Please select a species", "Character Generation", null) in new_species + + if(prev_species != species) + //grab one of the valid hair styles for the newly chosen species + var/list/valid_hairstyles = list() + for(var/hairstyle in hair_styles_list) + var/datum/sprite_accessory/S = hair_styles_list[hairstyle] + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + if(!(species in S.species_allowed)) + continue + + valid_hairstyles[hairstyle] = hair_styles_list[hairstyle] + + if(valid_hairstyles.len) + h_style = pick(valid_hairstyles) + else + //this shouldn't happen + h_style = hair_styles_list["Bald"] + + //grab one of the valid facial hair styles for the newly chosen species + var/list/valid_facialhairstyles = list() + for(var/facialhairstyle in facial_hair_styles_list) + var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + if(!(species in S.species_allowed)) + continue + + valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] + + if(valid_facialhairstyles.len) + f_style = pick(valid_facialhairstyles) + else + //this shouldn't happen + f_style = facial_hair_styles_list["Shaved"] + + // Don't wear another species' underwear! + var/datum/sprite_accessory/S = underwear_list[underwear] + if(!(species in S.species_allowed)) + underwear = random_underwear(gender, species) + + S = undershirt_list[undershirt] + if(!(species in S.species_allowed)) + undershirt = random_undershirt(gender, species) + + S = socks_list[socks] + if(!(species in S.species_allowed)) + socks = random_socks(gender, species) + + //reset hair colour and skin colour + r_hair = 0//hex2num(copytext(new_hair, 2, 4)) + g_hair = 0//hex2num(copytext(new_hair, 4, 6)) + b_hair = 0//hex2num(copytext(new_hair, 6, 8)) + + s_tone = 0 + + ha_style = "None" // No Vulp ears on Unathi + m_style = "None" // No Unathi markings on Tajara + + body_accessory = null //no vulptail on humans damnit + + //Reset prosthetics. + organ_data = list() + rlimb_data = list() + if("speciesprefs")//oldvox code + speciesprefs = !speciesprefs + + if("language") +// var/languages_available + var/list/new_languages = list("None") +/* + if(config.usealienwhitelist) + for(var/L in all_languages) + var/datum/language/lang = all_languages[L] + if((!(lang.flags & RESTRICTED)) && (is_alien_whitelisted(user, L)||(!( lang.flags & WHITELISTED )))) + new_languages += lang + languages_available = 1 + + if(!(languages_available)) + alert(user, "There are not currently any available secondary languages.") + else +*/ + for(var/L in all_languages) + var/datum/language/lang = all_languages[L] + if(!(lang.flags & RESTRICTED)) + new_languages += lang.name + + language = input("Please select a secondary language", "Character Generation", null) in new_languages + + if("metadata") + var/new_metadata = input(user, "Enter any information you'd like others to see, such as Roleplay-preferences:", "Game Preference" , metadata) as message|null + if(new_metadata) + metadata = sanitize(copytext(new_metadata,1,MAX_MESSAGE_LEN)) + + if("b_type") + var/new_b_type = input(user, "Choose your character's blood-type:", "Character Preference") as null|anything in list( "A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-" ) + if(new_b_type) + b_type = new_b_type + + if("hair") + if(species == "Human" || species == "Unathi" || species == "Tajaran" || species == "Skrell" || species == "Machine" || species == "Vulpkanin") + var/input = "Choose your character's hair colour:" + var/new_hair = input(user, input, "Character Preference", rgb(r_hair, g_hair, b_hair)) as color|null + if(new_hair) + r_hair = hex2num(copytext(new_hair, 2, 4)) + g_hair = hex2num(copytext(new_hair, 4, 6)) + b_hair = hex2num(copytext(new_hair, 6, 8)) + + if("h_style") + var/list/valid_hairstyles = list() + for(var/hairstyle in hair_styles_list) + var/datum/sprite_accessory/S = hair_styles_list[hairstyle] + if(species == "Machine") //Species that can use prosthetic heads. + var/obj/item/organ/external/head/H = new() + if(S.name == "Bald") + valid_hairstyles[hairstyle] = S + if(!rlimb_data["head"]) //Handle situations where the head is default. + H.model = "Morpheus Cyberkinetics" + else + H.model = rlimb_data["head"] + var/datum/robolimb/robohead = all_robolimbs[H.model] + if(species in S.species_allowed) + if(robohead.is_monitor && (robohead.company in S.models_allowed)) //If the Machine character has the default Morpheus screen head or another screen head + //and said head is in the hair style's allowed models list... + valid_hairstyles[hairstyle] = S //Allow them to select the hairstyle. + continue + else + if(robohead.is_monitor) //Monitors (incl. the default morpheus head) cannot have wigs (human hairstyles). + continue + else if(!robohead.is_monitor && ("Human" in S.species_allowed)) + valid_hairstyles[hairstyle] = S + continue + else + if(!(species in S.species_allowed)) + continue + + valid_hairstyles[hairstyle] = S + + var/new_h_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in valid_hairstyles + if(new_h_style) + h_style = new_h_style + + if("headaccessory") + if(species in list("Unathi", "Vulpkanin", "Tajaran", "Machine")) //Species with head accessories. + var/input = "Choose the colour of your your character's head accessory:" + var/new_head_accessory = input(user, input, "Character Preference", rgb(r_headacc, g_headacc, b_headacc)) as color|null + if(new_head_accessory) + r_headacc = hex2num(copytext(new_head_accessory, 2, 4)) + g_headacc = hex2num(copytext(new_head_accessory, 4, 6)) + b_headacc = hex2num(copytext(new_head_accessory, 6, 8)) + + if("ha_style") + if(species in list("Unathi", "Vulpkanin", "Tajaran", "Machine")) //Species with head accessories. + var/list/valid_head_accessory_styles = list() + for(var/head_accessory_style in head_accessory_styles_list) + var/datum/sprite_accessory/H = head_accessory_styles_list[head_accessory_style] + if(!(species in H.species_allowed)) + continue + + valid_head_accessory_styles[head_accessory_style] = head_accessory_styles_list[head_accessory_style] + + var/new_head_accessory_style = input(user, "Choose the style of your character's head accessory:", "Character Preference") as null|anything in valid_head_accessory_styles + if(new_head_accessory_style) + ha_style = new_head_accessory_style + + if("markings") + if(species in list("Unathi", "Vulpkanin", "Tajaran", "Machine")) //Species with markings. + var/input = "Choose the colour of your your character's markings:" + var/new_markings = input(user, input, "Character Preference", rgb(r_markings, g_markings, b_markings)) as color|null + if(new_markings) + r_markings = hex2num(copytext(new_markings, 2, 4)) + g_markings = hex2num(copytext(new_markings, 4, 6)) + b_markings = hex2num(copytext(new_markings, 6, 8)) + + if("m_style") + if(species in list("Unathi", "Vulpkanin", "Tajaran", "Machine")) //Species with markings. + var/list/valid_markings = list() + for(var/markingstyle in marking_styles_list) + var/datum/sprite_accessory/M = marking_styles_list[markingstyle] + if(!(species in M.species_allowed)) + continue + + if(species == "Machine") //Species that can use prosthetic heads. + var/obj/item/organ/external/head/H = new() + if(!rlimb_data["head"]) //Handle situations where the head is default. + H.model = "Morpheus Cyberkinetics" + else + H.model = rlimb_data["head"] + var/datum/robolimb/robohead = all_robolimbs[H.model] + if(robohead.is_monitor && M.name != "None") //If the character can have prosthetic heads and they have the default Morpheus head (or another monitor-head), no optic markings. + continue + else if(!robohead.is_monitor && M.name != "None") //Otherwise, if they DON'T have the default head and the head's not a monitor but the head's not in the style's list of allowed models, skip. + if(!(robohead.company in M.models_allowed)) + continue + + valid_markings[markingstyle] = marking_styles_list[markingstyle] + + var/new_marking_style = input(user, "Choose the style of your character's markings:", "Character Preference", m_style) as null|anything in valid_markings + if(new_marking_style) + m_style = new_marking_style + + if("body_accessory") + var/list/possible_body_accessories = list() + if(check_rights(R_ADMIN, 1, user)) + possible_body_accessories = body_accessory_by_name.Copy() + else + for(var/B in body_accessory_by_name) + var/datum/body_accessory/accessory = body_accessory_by_name[B] + if(!istype(accessory)) + possible_body_accessories += "None" //the only null entry should be the "None" option + continue + if(species in accessory.allowed_species) + possible_body_accessories += B + + var/new_body_accessory = input(user, "Choose your body accessory:", "Character Preference") as null|anything in possible_body_accessories + if(new_body_accessory) + body_accessory = (new_body_accessory == "None") ? null : new_body_accessory + + if("facial") + var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference", rgb(r_facial, g_facial, b_facial)) as color|null + if(new_facial) + r_facial = hex2num(copytext(new_facial, 2, 4)) + g_facial = hex2num(copytext(new_facial, 4, 6)) + b_facial = hex2num(copytext(new_facial, 6, 8)) + + if("f_style") + var/list/valid_facialhairstyles = list() + for(var/facialhairstyle in facial_hair_styles_list) + var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] + if(S.name == "Shaved") + valid_facialhairstyles[facialhairstyle] = S + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + if(species == "Machine") //Species that can use prosthetic heads. + var/obj/item/organ/external/head/H = new() + if(!rlimb_data["head"]) //Handle situations where the head is default. + H.model = "Morpheus Cyberkinetics" + else + H.model = rlimb_data["head"] + var/datum/robolimb/robohead = all_robolimbs[H.model] + if(species in S.species_allowed) + if(robohead.is_monitor) //If the Machine character has the default Morpheus screen head or another screen head and they're allowed to have the style, let them have it. + valid_facialhairstyles[facialhairstyle] = S + continue + else + if(robohead.is_monitor) //Monitors (incl. the default morpheus head) cannot have wigs (human facial hairstyles). + continue + else if(!robohead.is_monitor && ("Human" in S.species_allowed)) + valid_facialhairstyles[facialhairstyle] = S + continue + else + if(!(species in S.species_allowed)) + continue + + valid_facialhairstyles[facialhairstyle] = facial_hair_styles_list[facialhairstyle] + + var/new_f_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in valid_facialhairstyles + if(new_f_style) + f_style = new_f_style + + if("underwear") + var/list/underwear_options + if(gender == MALE) + underwear_options = underwear_m + else + underwear_options = underwear_f + + var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in underwear_options + if(new_underwear) + underwear = new_underwear + ShowChoices(user) + + if("undershirt") + var/new_undershirt + if(gender == MALE) + new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_m + else + new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in undershirt_f + if(new_undershirt) + undershirt = new_undershirt + ShowChoices(user) + + if("socks") + var/list/valid_sockstyles = list() + for(var/sockstyle in socks_list) + var/datum/sprite_accessory/S = socks_list[sockstyle] + if(gender == MALE && S.gender == FEMALE) + continue + if(gender == FEMALE && S.gender == MALE) + continue + if(!(species in S.species_allowed)) + continue + valid_sockstyles[sockstyle] = socks_list[sockstyle] + var/new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in valid_sockstyles + ShowChoices(user) + if(new_socks) + socks = new_socks + + if("eyes") + var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference", rgb(r_eyes, g_eyes, b_eyes)) as color|null + if(new_eyes) + r_eyes = hex2num(copytext(new_eyes, 2, 4)) + g_eyes = hex2num(copytext(new_eyes, 4, 6)) + b_eyes = hex2num(copytext(new_eyes, 6, 8)) + + if("s_tone") + if(species != "Human" && species != "Drask") + return + var/new_s_tone = input(user, "Choose your character's skin-tone:\n(Light 1 - 220 Dark)", "Character Preference") as num|null + if(new_s_tone) + s_tone = 35 - max(min( round(new_s_tone), 220),1) + + if("skin") + if((species in list("Unathi", "Tajaran", "Skrell", "Slime People", "Vulpkanin", "Machine")) || body_accessory_by_species[species] || check_rights(R_ADMIN, 0, user)) + var/new_skin = input(user, "Choose your character's skin colour: ", "Character Preference", rgb(r_skin, g_skin, b_skin)) as color|null + if(new_skin) + r_skin = hex2num(copytext(new_skin, 2, 4)) + g_skin = hex2num(copytext(new_skin, 4, 6)) + b_skin = hex2num(copytext(new_skin, 6, 8)) + + + if("ooccolor") + var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference", ooccolor) as color|null + if(new_ooccolor) + ooccolor = new_ooccolor + + if("bag") + var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in backbaglist + if(new_backbag) + backbag = backbaglist.Find(new_backbag) + + if("nt_relation") + var/new_relation = input(user, "Choose your relation to NT. Note that this represents what others can find out about your character by researching your background, not what your character actually thinks.", "Character Preference") as null|anything in list("Loyal", "Supportive", "Neutral", "Skeptical", "Opposed") + if(new_relation) + nanotrasen_relation = new_relation + + if("flavor_text") + var/msg = input(usr,"Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!","Flavor Text",html_decode(flavor_text)) as message + + if(msg != null) + msg = copytext(msg, 1, MAX_MESSAGE_LEN) + msg = html_encode(msg) + + flavor_text = msg + + if("limbs") + var/valid_limbs = list("Left Leg", "Right Leg", "Left Arm", "Right Arm", "Left Foot", "Right Foot", "Left Hand", "Right Hand") + if(species == "Machine") + valid_limbs = list("Torso", "Lower Body", "Head", "Left Leg", "Right Leg", "Left Arm", "Right Arm", "Left Foot", "Right Foot", "Left Hand", "Right Hand") + var/limb_name = input(user, "Which limb do you want to change?") as null|anything in valid_limbs + if(!limb_name) return + + var/limb = null + var/second_limb = null // if you try to change the arm, the hand should also change + var/third_limb = null // if you try to unchange the hand, the arm should also change + var/valid_limb_states = list("Normal", "Amputated", "Prosthesis") + var/no_amputate = 0 + + switch(limb_name) + if("Torso") + limb = "chest" + second_limb = "groin" + no_amputate = 1 + if("Lower Body") + limb = "groin" + no_amputate = 1 + if("Head") + limb = "head" + no_amputate = 1 + if("Left Leg") + limb = "l_leg" + second_limb = "l_foot" + if("Right Leg") + limb = "r_leg" + second_limb = "r_foot" + if("Left Arm") + limb = "l_arm" + second_limb = "l_hand" + if("Right Arm") + limb = "r_arm" + second_limb = "r_hand" + if("Left Foot") + limb = "l_foot" + if(species != "Machine") + third_limb = "l_leg" + if("Right Foot") + limb = "r_foot" + if(species != "Machine") + third_limb = "r_leg" + if("Left Hand") + limb = "l_hand" + if(species != "Machine") + third_limb = "l_arm" + if("Right Hand") + limb = "r_hand" + if(species != "Machine") + third_limb = "r_arm" + + var/new_state = input(user, "What state do you wish the limb to be in?") as null|anything in valid_limb_states + if(!new_state) return + + switch(new_state) + if("Normal") + if(limb == "head") + m_style = "None" + h_style = random_hair_style(gender, species) + f_style = facial_hair_styles_list["Shaved"] + organ_data[limb] = null + rlimb_data[limb] = null + if(third_limb) + organ_data[third_limb] = null + rlimb_data[third_limb] = null + if("Amputated") + if(!no_amputate) + organ_data[limb] = "amputated" + rlimb_data[limb] = null + if(second_limb) + organ_data[second_limb] = "amputated" + rlimb_data[second_limb] = null + if("Prosthesis") + var/choice + var/subchoice + var/datum/robolimb/R = new() + var/in_model + var/robolimb_companies = list() + for(var/limb_type in typesof(/datum/robolimb)) //This loop populates a list of companies that offer the limb the user selected previously as one of their cybernetic products. + R = new limb_type() + if(!R.unavailable_at_chargen && (limb in R.parts) && R.has_subtypes) //Ensures users can only choose companies that offer the parts they want, that singular models get added to the list as well companies that offer more than one model, and... + robolimb_companies[R.company] = R //List only main brands that have the parts we're looking for. + R = new() //Re-initialize R. + + choice = input(user, "Which manufacturer do you wish to use for this limb?") as null|anything in robolimb_companies //Choose from a list of companies that offer the part the user wants. + if(!choice) + return + R.company = choice + R = all_robolimbs[R.company] + if(R.has_subtypes == 1) //If the company the user selected provides more than just one base model, lets handle it. + var/list/robolimb_models = list() + for(var/limb_type in typesof(R)) //Handling the different models of parts that manufacturers can provide. + var/datum/robolimb/L = new limb_type() + if(limb in L.parts) //Make sure that only models that provide the parts the user needs populate the list. + robolimb_models[L.company] = L + if(robolimb_models.len == 1) //If there's only one model available in the list, autoselect it to avoid having to bother the user with a dialog that provides only one option. + subchoice = L.company //If there ends up being more than one model populating the list, subchoice will be overwritten later anyway, so this isn't a problem. + if(second_limb in L.parts) //If the child limb of the limb the user selected is also present in the model's parts list, state it's been found so the second limb can be set later. + in_model = 1 + if(robolimb_models.len > 1) //If there's more than one model in the list that can provide the part the user wants, let them choose. + subchoice = input(user, "Which model of [choice] [limb_name] do you wish to use?") as null|anything in robolimb_models + if(subchoice) + choice = subchoice + if(limb == "head") + ha_style = "None" + h_style = hair_styles_list["Bald"] + f_style = facial_hair_styles_list["Shaved"] + m_style = "None" + rlimb_data[limb] = choice + organ_data[limb] = "cyborg" + if(second_limb) + if(subchoice) + if(in_model) + rlimb_data[second_limb] = choice + organ_data[second_limb] = "cyborg" + else + rlimb_data[second_limb] = choice + organ_data[second_limb] = "cyborg" + + if("organs") + var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes") + if(!organ_name) return + + var/organ = null + switch(organ_name) + if("Heart") + organ = "heart" + if("Eyes") + organ = "eyes" + + var/new_state = input(user, "What state do you wish the organ to be in?") as null|anything in list("Normal","Assisted","Mechanical") + if(!new_state) return + + switch(new_state) + if("Normal") + organ_data[organ] = null + if("Assisted") + organ_data[organ] = "assisted" + if("Mechanical") + organ_data[organ] = "mechanical" + +/* + if("skin_style") + var/skin_style_name = input(user, "Select a new skin style") as null|anything in list("default1", "default2", "default3") + if(!skin_style_name) return +*/ + +/* if("spawnpoint") + var/list/spawnkeys = list() + for(var/S in spawntypes) + spawnkeys += S + var/choice = input(user, "Where would you like to spawn when latejoining?") as null|anything in spawnkeys + if(!choice || !spawntypes[choice]) + spawnpoint = "Arrivals Shuttle" + return + spawnpoint = choice */ + + else + switch(href_list["preference"]) + if("publicity") + if(unlock_content) + toggles ^= MEMBER_PUBLIC + + if("gender") + if(gender == MALE) + gender = FEMALE + else + gender = MALE + underwear = random_underwear(gender) + + if("hear_adminhelps") + sound ^= SOUND_ADMINHELP + + if("ui") + switch(UI_style) + if("Midnight") + UI_style = "Plasmafire" + if("Plasmafire") + UI_style = "Retro" + if("Retro") + UI_style = "Slimecore" + if("Slimecore") + UI_style = "Operative" + if("Operative") + UI_style = "White" + else + UI_style = "Midnight" + + if(ishuman(usr)) //mid-round preference changes, for aesthetics + var/mob/living/carbon/human/H = usr + H.remake_hud() + + if("nanoui") + nanoui_fancy = !nanoui_fancy + + if("ghost_att_anim") + show_ghostitem_attack = !show_ghostitem_attack + + if("UIcolor") + var/UI_style_color_new = input(user, "Choose your UI color, dark colors are not recommended!", UI_style_color) as color|null + if(!UI_style_color_new) return + UI_style_color = UI_style_color_new + + if(ishuman(usr)) //mid-round preference changes, for aesthetics + var/mob/living/carbon/human/H = usr + H.remake_hud() + + if("UIalpha") + var/UI_style_alpha_new = input(user, "Select a new alpha(transparence) parameter for UI, between 50 and 255", UI_style_alpha) as num + if(!UI_style_alpha_new | !(UI_style_alpha_new <= 255 && UI_style_alpha_new >= 50)) return + UI_style_alpha = UI_style_alpha_new + + if(ishuman(usr)) //mid-round preference changes, for aesthetics + var/mob/living/carbon/human/H = usr + H.remake_hud() + + if("be_special") + var/r = href_list["role"] + if(!(r in special_roles)) + var/cleaned_r = sql_sanitize_text(r) + if(r != cleaned_r) // up to no good + message_admins("[user] attempted an href exploit! (This could have possibly lead to a \"Bobby Tables\" exploit, so they're probably up to no good). String: [r] ID: [last_id] IP: [last_ip]") + to_chat(user, "Stop right there, criminal scum") + else + be_special ^= r + + if("name") + be_random_name = !be_random_name + + if("randomslot") + randomslot = !randomslot + + if("hear_midis") + sound ^= SOUND_MIDI + + if("lobby_music") + sound ^= SOUND_LOBBY + if(sound & SOUND_LOBBY) + to_chat(user, sound(ticker.login_music, repeat = 0, wait = 0, volume = 85, channel = 1)) + else + to_chat(user, sound(null, repeat = 0, wait = 0, volume = 85, channel = 1)) + + if("ghost_ears") + toggles ^= CHAT_GHOSTEARS + + if("ghost_sight") + toggles ^= CHAT_GHOSTSIGHT + + if("ghost_radio") + toggles ^= CHAT_GHOSTRADIO + + if("ghost_radio") + toggles ^= CHAT_GHOSTRADIO + + if("save") + save_preferences(user) + save_character(user) + + if("reload") + load_preferences(user) + load_character(user) + + if("open_load_dialog") + if(!IsGuestKey(user.key)) + open_load_dialog(user) + return 1 + + if("close_load_dialog") + close_load_dialog(user) + + if("changeslot") + if(!load_character(user,text2num(href_list["num"]))) + random_character() + real_name = random_name(gender) + save_character(user) + close_load_dialog(user) + + if("tab") + if (href_list["tab"]) + current_tab = text2num(href_list["tab"]) + + ShowChoices(user) + return 1 + +/datum/preferences/proc/copy_to(mob/living/carbon/human/character) + var/datum/species/S = all_species[species] + character.change_species(species) // Yell at me if this causes everything to melt + if(be_random_name) + real_name = random_name(gender,species) + + if(config.humans_need_surnames) + var/firstspace = findtext(real_name, " ") + var/name_length = length(real_name) + if(!firstspace) //we need a surname + real_name += " [pick(last_names)]" + else if(firstspace == name_length) + real_name += "[pick(last_names)]" + + character.add_language(language) + + character.real_name = real_name + character.dna.real_name = real_name + character.name = character.real_name + + character.flavor_text = flavor_text + if(character.ckey && !jobban_isbanned(character, "Records")) + character.med_record = med_record + character.sec_record = sec_record + character.gen_record = gen_record + + character.change_gender(gender) + character.age = age + character.b_type = b_type + + character.r_eyes = r_eyes + character.g_eyes = g_eyes + character.b_eyes = b_eyes + + //Head-specific + var/obj/item/organ/external/head/H = character.get_organ("head") + H.r_hair = r_hair + H.g_hair = g_hair + H.b_hair = b_hair + + H.r_facial = r_facial + H.g_facial = g_facial + H.b_facial = b_facial + + H.h_style = h_style + H.f_style = f_style + //End of head-specific. + + character.r_skin = r_skin + character.g_skin = g_skin + character.b_skin = b_skin + + character.s_tone = s_tone + + // Destroy/cyborgize organs + for(var/name in organ_data) + + var/status = organ_data[name] + var/obj/item/organ/external/O = character.organs_by_name[name] + if(O) + if(status == "amputated") + character.organs_by_name[O.limb_name] = null + character.organs -= O + if(O.children) // This might need to become recursive. + for(var/obj/item/organ/external/child in O.children) + character.organs_by_name[child.limb_name] = null + character.organs -= child + + else if(status == "cyborg") + if(rlimb_data[name]) + O.robotize(rlimb_data[name]) + else + O.robotize() + else + var/obj/item/organ/internal/I = character.get_int_organ_tag(name) + if(I) + if(status == "assisted") + I.mechassist() + else if(status == "mechanical") + I.robotize() + + character.dna.b_type = b_type + if(disabilities & DISABILITY_FLAG_FAT && character.species.flags & CAN_BE_FAT) + character.dna.SetSEState(FATBLOCK,1,1) + character.mutations += FAT + character.mutations += OBESITY + character.overeatduration = 600 + + if(disabilities & DISABILITY_FLAG_NEARSIGHTED) + character.dna.SetSEState(GLASSESBLOCK,1,1) + character.disabilities|=NEARSIGHTED + + if(disabilities & DISABILITY_FLAG_EPILEPTIC) + character.dna.SetSEState(EPILEPSYBLOCK,1,1) + character.disabilities|=EPILEPSY + + if(disabilities & DISABILITY_FLAG_DEAF) + character.dna.SetSEState(DEAFBLOCK,1,1) + character.sdisabilities|=DEAF + + if(disabilities & DISABILITY_FLAG_BLIND) + character.dna.SetSEState(BLINDBLOCK,1,1) + character.sdisabilities|=BLIND + + if(disabilities & DISABILITY_FLAG_MUTE) + character.dna.SetSEState(MUTEBLOCK,1,1) + character.sdisabilities |= MUTE + + S.handle_dna(character) + + if(character.dna.dirtySE) + character.dna.UpdateSE() + domutcheck(character) + + // Wheelchair necessary? + var/obj/item/organ/external/l_foot = character.get_organ("l_foot") + var/obj/item/organ/external/r_foot = character.get_organ("r_foot") + if((!l_foot || l_foot.status & ORGAN_DESTROYED) && (!r_foot || r_foot.status & ORGAN_DESTROYED)) + var/obj/structure/stool/bed/chair/wheelchair/W = new /obj/structure/stool/bed/chair/wheelchair (character.loc) + character.buckled = W + character.update_canmove() + W.dir = character.dir + W.buckled_mob = character + W.add_fingerprint(character) + + character.underwear = underwear + character.undershirt = undershirt + character.socks = socks + + if(character.species.bodyflags & HAS_HEAD_ACCESSORY) + H.r_headacc = r_headacc + H.g_headacc = g_headacc + H.b_headacc = b_headacc + H.ha_style = ha_style + if(character.species.bodyflags & HAS_MARKINGS) + character.r_markings = r_markings + character.g_markings = g_markings + character.b_markings = b_markings + character.m_style = m_style + + if(body_accessory) + character.body_accessory = body_accessory_by_name["[body_accessory]"] + + if(backbag > 4 || backbag < 1) + backbag = 1 //Same as above + character.backbag = backbag + + //Debugging report to track down a bug, which randomly assigned the plural gender to people. + if(character.gender in list(PLURAL, NEUTER)) + if(isliving(src)) //Ghosts get neuter by default + message_admins("[key_name_admin(character)] has spawned with their gender as plural or neuter. Please notify coders.") + character.change_gender(MALE) + + character.dna.ready_dna(character, flatten_SE = 0) + character.sync_organ_dna(assimilate=1) + character.UpdateAppearance() + + // Do the initial caching of the player's body icons. + character.force_update_limbs() + character.update_eyes() + character.regenerate_icons() + +/datum/preferences/proc/open_load_dialog(mob/user) + + var/DBQuery/query = dbcon.NewQuery("SELECT slot,real_name FROM [format_table_name("characters")] WHERE ckey='[user.ckey]' ORDER BY slot") + + var/dat = "" + dat += "
    " + dat += "Select a character slot to load
    " + var/name + + for(var/i=1, i<=max_save_slots, i++) + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during character slot loading. Error : \[[err]\]\n") + message_admins("SQL ERROR during character slot loading. Error : \[[err]\]\n") + return + while(query.NextRow()) + if(i==text2num(query.item[1])) + name = query.item[2] + if(!name) name = "Character[i]" + if(i==default_slot) + name = "[name]" + dat += "[name]
    " + name = null + + dat += "
    " + dat += "Close
    " + dat += "
    " +// user << browse(dat, "window=saves;size=300x390") + var/datum/browser/popup = new(user, "saves", "
    Character Saves
    ", 300, 390) + popup.set_content(dat) + popup.open(0) + +/datum/preferences/proc/close_load_dialog(mob/user) + user << browse(null, "window=saves") diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm index 43dc470c784..6de5dcc3b51 100644 --- a/code/modules/client/preference/preferences_mysql.dm +++ b/code/modules/client/preference/preferences_mysql.dm @@ -12,7 +12,8 @@ randomslot, volume, nanoui_fancy, - show_ghostitem_attack + show_ghostitem_attack, + lastchangelog FROM [format_table_name("player")] WHERE ckey='[C.ckey]'"} ) @@ -38,10 +39,10 @@ volume = text2num(query.item[10]) nanoui_fancy = text2num(query.item[11]) show_ghostitem_attack = text2num(query.item[12]) + lastchangelog = query.item[13] //Sanitize ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) -// lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) UI_style = sanitize_inlist(UI_style, list("White", "Midnight"), initial(UI_style)) default_slot = sanitize_integer(default_slot, 1, max_save_slots, initial(default_slot)) toggles = sanitize_integer(toggles, 0, 65535, initial(toggles)) @@ -52,6 +53,7 @@ volume = sanitize_integer(volume, 0, 100, initial(volume)) nanoui_fancy = sanitize_integer(nanoui_fancy, 0, 1, initial(nanoui_fancy)) show_ghostitem_attack = sanitize_integer(show_ghostitem_attack, 0, 1, initial(show_ghostitem_attack)) + lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) return 1 /datum/preferences/proc/save_preferences(client/C) @@ -75,7 +77,8 @@ randomslot='[randomslot]', volume='[volume]', nanoui_fancy='[nanoui_fancy]', - show_ghostitem_attack='[show_ghostitem_attack]' + show_ghostitem_attack='[show_ghostitem_attack]', + lastchangelog='[lastchangelog]' WHERE ckey='[C.ckey]'"} ) @@ -456,4 +459,16 @@ load_character(C) return 0 load_character(C,pick(saves)) - return 1*/ \ No newline at end of file + return 1*/ + +/datum/preferences/proc/SetChangelog(client/C,hash) + lastchangelog=hash + winset(C, "rpane.changelog", "background-color=none;font-style=") + var/DBQuery/query = dbcon.NewQuery("UPDATE [format_table_name("player")] SET lastchangelog='[lastchangelog]' WHERE ckey='[C.ckey]'") + if(!query.Execute()) + var/err = query.ErrorMsg() + log_game("SQL ERROR during lastchangelog updating. Error : \[[err]\]\n") + message_admins("SQL ERROR during lastchangelog updating. Error : \[[err]\]\n") + to_chat(C, "Couldn't update your last seen changelog, please try again later.") + return + return 1 diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 04f0f3ed42d..8d6595b73ff 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -25,6 +25,7 @@ var/active_sound = null var/toggle_cooldown = null var/cooldown = 0 + var/species_disguise = null //BS12: Species-restricted clothing check. /obj/item/clothing/mob_can_equip(M as mob, slot) diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm index 1654198d9c9..6e4623fa9be 100644 --- a/code/modules/clothing/glasses/glasses.dm +++ b/code/modules/clothing/glasses/glasses.dm @@ -218,10 +218,7 @@ desc = "Somehow these seem even more out-of-date than normal sunglasses." action_button_name = "Noir Mode" var/noir_mode = 0 - color_view = list(0.3, 0.3, 0.3, 0,\ - 0.3, 0.3, 0.3, 0,\ - 0.3, 0.3, 0.3, 0,\ - 0.0, 0.0, 0.0, 1,) //greyscale + color_view = MATRIX_GREYSCALE /obj/item/clothing/glasses/sunglasses/noir/attack_self() if(is_equipped()) diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm index db163ad3e59..a50e56382a1 100644 --- a/code/modules/clothing/gloves/color.dm +++ b/code/modules/clothing/gloves/color.dm @@ -6,8 +6,32 @@ siemens_coefficient = 0 permeability_coefficient = 0.05 item_color="yellow" - power - var/next_shock = 0 + +/obj/item/clothing/gloves/color/yellow/power + description_antag = "These are a pair of power gloves, and can be used to fire bolts of electricity while standing over powered power cables." + var/old_mclick_override + var/datum/middleClickOverride/power_gloves/mclick_override = new /datum/middleClickOverride/power_gloves + +/obj/item/clothing/gloves/color/yellow/power/equipped(mob/user, slot) + if(!ishuman(user)) + return + var/mob/living/carbon/human/H = user + if(slot == slot_gloves) + if(H.middleClickOverride) + old_mclick_override = H.middleClickOverride + H.middleClickOverride = mclick_override + to_chat(H, "You feel electricity begin to build up in [src].") + +/obj/item/clothing/gloves/color/yellow/power/dropped(mob/user, slot) + if(!ishuman(user)) + return + var/mob/living/carbon/human/H = user + if(H.get_item_by_slot(slot_gloves) == src && H.middleClickOverride == mclick_override) + if(old_mclick_override) + H.middleClickOverride = old_mclick_override + old_mclick_override = null + else + H.middleClickOverride = null /obj/item/clothing/gloves/color/yellow/fake desc = "These gloves will protect the wearer from electric shock. They don't feel like rubber..." @@ -167,4 +191,4 @@ min_cold_protection_temperature = GLOVES_MIN_TEMP_PROTECT heat_protection = HANDS max_heat_protection_temperature = GLOVES_MAX_TEMP_PROTECT - strip_delay = 60 \ No newline at end of file + strip_delay = 60 diff --git a/code/modules/clothing/head/misc_special.dm b/code/modules/clothing/head/misc_special.dm index 071c6032722..0fbb39e6f1b 100644 --- a/code/modules/clothing/head/misc_special.dm +++ b/code/modules/clothing/head/misc_special.dm @@ -176,9 +176,11 @@ /obj/item/clothing/head/kitty/update_icon(var/mob/living/carbon/human/user) if(!istype(user)) return + var/obj/item/organ/external/head/head_organ = user.get_organ("head") + mob = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "kitty") // mob2 = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "kitty2") - Commented out because it seemingly does nothing. - mob.Blend(rgb(user.r_hair, user.g_hair, user.b_hair), ICON_ADD) + mob.Blend(rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair), ICON_ADD) // mob2.Blend(rgb(user.r_hair, user.g_hair, user.b_hair), ICON_ADD) - Commented out because it seemingly does nothing. var/icon/earbit = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "kittyinner") @@ -201,8 +203,9 @@ /obj/item/clothing/head/kitty/mouse/update_icon(var/mob/living/carbon/human/user) if(!istype(user)) return + var/obj/item/organ/external/head/head_organ = user.get_organ("head") mob = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "mousey") - mob.Blend(rgb(user.r_hair, user.g_hair, user.b_hair), ICON_ADD) + mob.Blend(rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair), ICON_ADD) var/icon/earbit = new/icon("icon" = 'icons/mob/head.dmi', "icon_state" = "mouseyinner") mob.Blend(earbit, ICON_OVERLAY) @@ -216,6 +219,7 @@ item_state = "cardborg_h" flags = HEADCOVERSEYES | HEADCOVERSMOUTH flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE + species_disguise = "High-tech robot" /obj/item/clothing/head/cardborg/equipped(mob/living/user, slot) ..() diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm index 364c4d808ac..1b7ea8fc4c9 100644 --- a/code/modules/clothing/shoes/colour.dm +++ b/code/modules/clothing/shoes/colour.dm @@ -95,13 +95,12 @@ src.icon_state = "orange" return -/obj/item/clothing/shoes/orange/attackby(H as obj, loc, params) +/obj/item/clothing/shoes/orange/attackby(obj/H, loc, params) ..() - if ((istype(H, /obj/item/weapon/restraints/handcuffs) && !( src.chained ))) - //H = null + if (istype(H, /obj/item/weapon/restraints/handcuffs) && !chained && !(H.flags & NODROP)) if (src.icon_state != "orange") return qdel(H) src.chained = 1 src.slowdown = 15 src.icon_state = "orange1" - return \ No newline at end of file + return diff --git a/code/modules/clothing/spacesuits/ert.dm b/code/modules/clothing/spacesuits/ert.dm index 4015f107e51..91824a9856e 100644 --- a/code/modules/clothing/spacesuits/ert.dm +++ b/code/modules/clothing/spacesuits/ert.dm @@ -34,8 +34,8 @@ armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 100, rad = 60) allowed = list(/obj/item/device/flashlight, /obj/item/weapon/tank, /obj/item/device/t_scanner, /obj/item/weapon/rcd, /obj/item/weapon/crowbar, \ /obj/item/weapon/screwdriver, /obj/item/weapon/weldingtool, /obj/item/weapon/wirecutters, /obj/item/weapon/wrench, /obj/item/device/multitool, \ - /obj/item/device/radio, /obj/item/device/analyzer, /obj/item/weapon/gun/energy/laser, /obj/item/weapon/gun/energy/pulse_rifle, \ - /obj/item/weapon/gun/energy/advtaser, /obj/item/weapon/melee/baton, /obj/item/weapon/gun/energy/gun) + /obj/item/device/radio, /obj/item/device/analyzer, /obj/item/weapon/gun/energy/laser, /obj/item/weapon/gun/energy/pulse, \ + /obj/item/weapon/gun/energy/gun/advtaser, /obj/item/weapon/melee/baton, /obj/item/weapon/gun/energy/gun) strip_delay = 130 //Commander @@ -121,4 +121,4 @@ /obj/item/clothing/suit/space/rig/ert/paranormal/New() ..() - new /obj/item/weapon/nullrod(src) \ No newline at end of file + new /obj/item/weapon/nullrod(src) diff --git a/code/modules/clothing/spacesuits/rig/modules/combat.dm b/code/modules/clothing/spacesuits/rig/modules/combat.dm index 2473fd24eb8..16ddf2bdd69 100644 --- a/code/modules/clothing/spacesuits/rig/modules/combat.dm +++ b/code/modules/clothing/spacesuits/rig/modules/combat.dm @@ -119,7 +119,7 @@ gun.attack_self(holder.wearer) return 1 - gun.Fire(target,holder.wearer) + gun.process_fire(target,holder.wearer) return 1 /obj/item/rig_module/mounted/egun @@ -168,7 +168,7 @@ active_power_cost = 10 passive_power_cost = 0 - gun_type = /obj/item/weapon/gun/energy/crossbow/ninja + gun_type = /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow/ninja /obj/item/rig_module/mounted/energy_blade/process() diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm index 6f699e3a9ae..abdfaf7648e 100644 --- a/code/modules/clothing/suits/armor.dm +++ b/code/modules/clothing/suits/armor.dm @@ -135,13 +135,13 @@ icon_state = "armor_reflec" item_state = "armor_reflec" blood_overlay_type = "armor" - var/hit_reflect_chance = 40 armor = list(melee = 10, bullet = 10, laser = 80, energy = 50, bomb = 0, bio = 0, rad = 0) + var/hit_reflect_chance = 40 /obj/item/clothing/suit/armor/laserproof/IsReflect(var/def_zone) if(!(def_zone in list("chest", "groin"))) //If not shot where ablative is covering you, you don't get the reflection bonus! - hit_reflect_chance = 0 - if (prob(hit_reflect_chance)) + return 0 + if(prob(hit_reflect_chance)) return 1 /obj/item/clothing/suit/armor/vest/det_suit @@ -265,7 +265,7 @@ desc = "God wills it!" icon_state = "knight_templar" item_state = "knight_templar" - allowed = list(/obj/item/weapon/gun/energy,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/weapon/gun/projectile,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs,/obj/item/device/flashlight/seclite,/obj/item/weapon/melee/classic_baton/telescopic,/obj/item/weapon/nullrod/sword) + allowed = list(/obj/item/weapon/gun/energy,/obj/item/weapon/reagent_containers/spray/pepper,/obj/item/weapon/gun/projectile,/obj/item/ammo_box,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs,/obj/item/device/flashlight/seclite,/obj/item/weapon/melee/classic_baton/telescopic,/obj/item/weapon/nullrod/claymore) //Non-hardsuit ERT armor. /obj/item/clothing/suit/armor/vest/ert diff --git a/code/modules/clothing/suits/miscellaneous.dm b/code/modules/clothing/suits/miscellaneous.dm index 5abc5e86cbf..7985eb06b57 100644 --- a/code/modules/clothing/suits/miscellaneous.dm +++ b/code/modules/clothing/suits/miscellaneous.dm @@ -206,6 +206,7 @@ item_state = "cardborg" body_parts_covered = UPPER_TORSO|LOWER_TORSO flags_inv = HIDEJUMPSUIT + species_disguise = "High-tech robot" /obj/item/clothing/suit/cardborg/equipped(mob/living/user, slot) ..() diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm index 5dc5cf02699..8b1d33d6ddb 100644 --- a/code/modules/clothing/under/accessories/accessory.dm +++ b/code/modules/clothing/under/accessories/accessory.dm @@ -10,6 +10,7 @@ var/slot = "decor" var/obj/item/clothing/under/has_suit = null //the suit the tie may be attached to var/image/inv_overlay = null //overlay used when attached to clothing. + action_button_custom_type = /datum/action/item_action/accessory /obj/item/clothing/accessory/New() ..() diff --git a/code/modules/clothing/under/miscellaneous.dm b/code/modules/clothing/under/miscellaneous.dm index 0e2392ceff1..9533d7c4aae 100644 --- a/code/modules/clothing/under/miscellaneous.dm +++ b/code/modules/clothing/under/miscellaneous.dm @@ -256,7 +256,7 @@ /obj/item/clothing/under/suit_jacket/charcoal name = "charcoal suit" - desc = "A charcoal suit and red tie. Very professional." + desc = "A charcoal suit and blue tie. Very professional." icon_state = "charcoal_suit" item_state = "charcoal_suit" item_color = "charcoal_suit" diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index c578c452bbc..bbdb526c70a 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -44,7 +44,7 @@ /obj/item/robot_parts/r_leg = 1, /obj/item/stack/sheet/metal = 5, /obj/item/stack/cable_coil = 5, - /obj/item/weapon/gun/energy/advtaser = 1, + /obj/item/weapon/gun/energy/gun/advtaser = 1, /obj/item/weapon/stock_parts/cell = 1, /obj/item/device/assembly/prox_sensor = 1, /obj/item/robot_parts/r_arm = 1) @@ -200,4 +200,22 @@ time = 15 reqs = list(/obj/item/stack/sheet/wood = 1, /obj/item/stack/cable_coil = 5) - tools = list(/obj/item/weapon/kitchen/knife) // Gotta carve the wood into handles \ No newline at end of file + tools = list(/obj/item/weapon/kitchen/knife) // Gotta carve the wood into handles + +/datum/table_recipe/makeshift_bolt + name = "Makeshift Bolt" + result = /obj/item/weapon/arrow/rod + time = 15 + reqs = list(/obj/item/stack/rods = 1) + tools = list(/obj/item/weapon/weldingtool) + +/datum/table_recipe/crossbow + name = "Powered Crossbow" + result = /obj/item/weapon/gun/throw/crossbow + time = 300 + reqs = list(/obj/item/stack/rods = 3, + /obj/item/stack/cable_coil = 10, + /obj/item/stack/sheet/mineral/plastic = 3, + /obj/item/stack/sheet/wood = 5) + tools = list(/obj/item/weapon/weldingtool, + /obj/item/weapon/screwdriver) diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm index c89d08b8d1b..ab8670b3b05 100644 --- a/code/modules/customitems/item_defines.dm +++ b/code/modules/customitems/item_defines.dm @@ -67,8 +67,23 @@ target.update_markings() playsound(src.loc, 'sound/items/Welder2.ogg', 20, 1) - icon_state = "tatgun_used" used = 1 + update_icon() + +/obj/item/device/fluff/tattoo_gun/update_icon() + ..() + + overlays.Cut() + + if(!used) + var/image/ink = image(src.icon, src, "ink_overlay") + ink.icon += rgb(tattoo_r, tattoo_g, tattoo_b, 190) + overlays += ink + +/obj/item/device/fluff/tattoo_gun/New() + ..() + update_icon() + /obj/item/weapon/claymore/fluff // MrBarrelrolll: Maximus Greenwood name = "Greenwood's Blade" @@ -293,6 +308,16 @@ src.item_state = "[item_color]" usr.update_inv_w_uniform() +/obj/item/clothing/under/fluff/honourable // MrBarrelrolll: Maximus Greenwood + name = "Viridi Protegat" + desc = "A set of chainmail adorned with a hide mantle. \"Greenwood\" is engraved into the right breast." + icon = 'icons/obj/clothing/uniforms.dmi' + icon_state = "roman" + item_state = "maximus_armor" + item_color = "maximus_armor" + displays_id = 0 + strip_delay = 100 + //////////// Masks //////////// //////////// Shoes //////////// @@ -340,9 +365,9 @@ flags_inv = HIDEFACE /obj/item/weapon/nullrod/fluff/chronx //chronx100: Hughe O'Splash - transform_into = /obj/item/weapon/nullrod/sword/fluff/chronx + fluff_transformations = list(/obj/item/weapon/nullrod/fluff/chronx/scythe) -/obj/item/weapon/nullrod/sword/fluff/chronx +/obj/item/weapon/nullrod/fluff/chronx/scythe name = "Soul Collector" desc = "An ancient scythe used by the worshipers of Cthulhu. Tales say it is used to prepare souls for Cthulhu's great devouring. Someone carved their name into the handle: Hughe O'Splash" icon = 'icons/obj/custom_items.dmi' @@ -422,24 +447,34 @@ icon_state = "chaps" item_color = "combat_pants" -/obj/item/clothing/suit/jacket/fluff/windbreaker // DaveTheHeadcrab: Elliot Campbell +/obj/item/clothing/suit/jacket/fluff/elliot_windbreaker // DaveTheHeadcrab: Elliot Campbell name = "nylon windbreaker" desc = "A cheap nylon windbreaker, according to the tag it was manufactured in New Chiba, Earth.
    The color reminds you of a television tuned to a dead channel." icon = 'icons/obj/custom_items.dmi' - icon_state = "elliot_windbreaker" - item_state = "elliot_windbreaker" + icon_state = "elliot_windbreaker_open" + item_state = "elliot_windbreaker_open" adjust_flavour = "unzip" + suit_adjusted = 1 -/obj/item/clothing/ears/earring/fluff/industrial_piercing - name = "industrial piercing and stud earring" - desc = "A set of ear piercings containing an industrial rod and a small stud. They appear to be made out of some form of non-magnetic metal." - icon = 'icons/obj/custom_items.dmi' - icon_state = "elliot_earring" - -/obj/item/device/fluff/tattoo_gun/cybernetic_tat - desc = "A cheap plastic tattoo application pen.
    This one seems to have light blue ink." +/obj/item/device/fluff/tattoo_gun/elliot_cybernetic_tat + desc = "A cheap plastic tattoo application pen.
    This one seems heavily used." tattoo_name = "circuitry tattoo" tattoo_icon = "Elliot Circuit Tattoo" - tattoo_r = 100 - tattoo_g = 150 - tattoo_b = 255 \ No newline at end of file + tattoo_r = 48 + tattoo_g = 138 + tattoo_b = 176 + +/obj/item/device/fluff/tattoo_gun/elliot_cybernetic_tat/attack_self(mob/user as mob) + if(!used) + var/ink_color = input("Please select an ink color.", "Tattoo Ink Color", rgb(tattoo_r, tattoo_g, tattoo_b)) as color|null + if(ink_color && !(user.incapacitated() || used) ) + tattoo_r = hex2num(copytext(ink_color, 2, 4)) + tattoo_g = hex2num(copytext(ink_color, 4, 6)) + tattoo_b = hex2num(copytext(ink_color, 6, 8)) + + to_chat(user, "You change the color setting on the [src].") + + update_icon() + + else + to_chat(user, "The [src] is out of ink!") \ No newline at end of file diff --git a/code/modules/detective_work/scanner.dm b/code/modules/detective_work/scanner.dm index 59466282384..e959df37989 100644 --- a/code/modules/detective_work/scanner.dm +++ b/code/modules/detective_work/scanner.dm @@ -5,7 +5,8 @@ /obj/item/device/detective_scanner name = "forensic scanner" desc = "Used to remotely scan objects and biomass for DNA and fingerprints. Can print a report of the findings." - icon_state = "forensic1" + icon = 'icons/goonstation/objects/objects.dmi' + icon_state = "detscanner" w_class = 3.0 item_state = "electronic" flags = CONDUCT | NOBLUDGEON @@ -15,9 +16,56 @@ var/list/log = list() /obj/item/device/detective_scanner/attack_self(var/mob/user) + var/search = input(user, "Enter name, fingerprint or blood DNA.", "Find record", "") + + if (!search || user.stat || user.incapacitated()) + return + + search = lowertext(search) + + var/name + var/fingerprint + var/dna + + // I really, really wish I didn't have to split this into two seperate loops. But the datacore is awful. + + for (var/record in data_core.general) + var/datum/data/record/S = record + if(search == lowertext(S.fields["fingerprint"]) || search == lowertext(S.fields["name"])) + name = S.fields["name"] + fingerprint = S.fields["fingerprint"] + continue + + for (var/record in data_core.medical) + var/datum/data/record/M = record + if (search == lowertext(M.fields["b_dna"]) || name == M.fields["name"]) + dna = M.fields["b_dna"] + + if(!fingerprint) // We have searched by DNA, and do not have the relevant information from the security records. + name = M.fields["name"] + for (var/gen_record in data_core.general) + var/datum/data/record/S = gen_record + if(name == S.fields["name"]) + fingerprint = S.fields["fingerprint"] + continue + continue + + if(name && fingerprint && dna) + to_chat(user, "Match found in station records: [name]
    \ + Fingerprint: [fingerprint]
    \ + Blood DNA: [dna]") + return + + to_chat(user, "No match found in station records.") + + +/obj/item/device/detective_scanner/verb/print_scanner_report() + set name = "Print Scanner Report" + set category = "Object" + if(log.len && !scanning) scanning = 1 - to_chat(user, "Printing report, please wait...") + to_chat(usr, "Printing report, please wait...") playsound(loc, "sound/goonstation/machines/printer_thermal.ogg", 50, 1) spawn(100) @@ -38,7 +86,8 @@ log = list() scanning = 0 else - to_chat(user, "The scanner has no logs or is in use.") + to_chat(usr, "The scanner has no logs or is in use.") + /obj/item/device/detective_scanner/attack(mob/living/M as mob, mob/user as mob) return diff --git a/code/modules/events/event_container.dm b/code/modules/events/event_container.dm index 304abd3cd13..5955d60cbec 100644 --- a/code/modules/events/event_container.dm +++ b/code/modules/events/event_container.dm @@ -184,6 +184,7 @@ var/list/event_last_fired = list() new /datum/event_meta(EVENT_LEVEL_MAJOR, "Meteor Wave", /datum/event/meteor_wave, 0, list(ASSIGNMENT_ENGINEER = 3), 1), new /datum/event_meta(EVENT_LEVEL_MAJOR, "Abductor Visit", /datum/event/abductor, 80, is_one_shot = 1), new /datum/event_meta/alien(EVENT_LEVEL_MAJOR, "Alien Infestation", /datum/event/alien_infestation, 0, list(ASSIGNMENT_SECURITY = 30), 1), + new /datum/event_meta(EVENT_LEVEL_MAJOR, "Traders", /datum/event/traders, 0, is_one_shot = 1), ) diff --git a/code/modules/events/traders.dm b/code/modules/events/traders.dm new file mode 100644 index 00000000000..e4c7d95fb89 --- /dev/null +++ b/code/modules/events/traders.dm @@ -0,0 +1,87 @@ +var/global/list/unused_trade_stations = list("sol") + +// Traders event. +// Heavily copy-pasted from "heist" gamemode. + +/datum/event/traders + var/success_spawn = 0 + var/station = null + var/spawn_count = 3 + var/list/trader_objectives = list() + +/datum/event/traders/setup() + if(unused_trade_stations.len) + station = pick_n_take(unused_trade_stations) + +/datum/event/traders/start() + if(!station) // If there are no unused stations, just no. + return + var/list/spawnlocs = list() + for(var/obj/effect/landmark/landmark in landmarks_list) + if(landmark.name == "traderstart_[station]") + spawnlocs += get_turf(landmark) + if(!spawnlocs.len) + return + + trader_objectives = forge_trader_objectives() + + spawn() + var/list/candidates = pollCandidates("Do you want to play as a trader?", ROLE_TRADER, 1) + var/index = 1 + while(spawn_count > 0 && candidates.len > 0) + if(index > spawnlocs.len) + index = 1 + + var/turf/picked_loc = spawnlocs[index] + index++ + var/mob/C = pick_n_take(candidates) + if(C) + respawnable_list -= C.client + var/mob/living/carbon/human/M = create_trader(picked_loc) + M.ckey = C.ckey + M.mind.objectives += trader_objectives + greet_trader(M) + success_spawn = 1 + if(!success_spawn) + unused_trade_stations += station // Return the station to the list of usable stations. + +/datum/event/traders/proc/create_trader(var/turf/picked_loc) + var/mob/living/carbon/human/M + switch(station) + if("sol") + M = new /mob/living/carbon/human(picked_loc) + M.equip_to_slot_or_del(new /obj/item/device/radio/headset(M), slot_l_ear) + M.equip_to_slot_or_del(new /obj/item/clothing/under/rank/cargotech(M), slot_w_uniform) + M.equip_to_slot_or_del(new /obj/item/clothing/shoes/black(M), slot_shoes) + M.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/industrial(M), slot_back) + var/obj/item/weapon/card/id/supply/W = new(M) + W.name = "[M.real_name]'s ID Card (Sol Trader)" + W.assignment = "Sol Trader" + W.registered_name = M.real_name + W.access = list(access_trade_sol, access_maint_tunnels, access_external_airlocks) + M.equip_to_slot_or_del(W, slot_wear_id) + return M + +/datum/event/traders/proc/greet_trader(var/mob/living/carbon/human/M) + to_chat(M, "You are a trader!") + to_chat(M, "You are currently docked at [get_area(M)].") + to_chat(M, "You are about to trade with NSS Cyberiad.") + to_chat(M, "Negotiate an agreement, and request docking.") + spawn(25) + show_objectives(M.mind) + +/datum/event/traders/proc/forge_trader_objectives() + var/i = 1 + var/max_objectives = pick(2, 2, 2, 2, 3, 3, 3, 4) + var/list/objs = list() + var/list/goals = list("stockparts") + while(i<= max_objectives) + var/goal = pick(goals) + var/datum/objective/trade/O + if(goal == "stockparts") + O = new /datum/objective/trade/stock(station) + O.choose_target() + objs += O + + i++ + return objs diff --git a/code/modules/examine/descriptions/weapons.dm b/code/modules/examine/descriptions/weapons.dm index 90929d31e08..264e0e99dfe 100644 --- a/code/modules/examine/descriptions/weapons.dm +++ b/code/modules/examine/descriptions/weapons.dm @@ -26,7 +26,7 @@ then click where you want to fire. Most energy weapons can fire through windows harmlessly. To switch between stun and lethal, click the weapon \ in your hand. To recharge this weapon, use a weapon recharger." -/obj/item/weapon/gun/energy/advtaser +/obj/item/weapon/gun/energy/gun/advtaser description_info = "This is an energy weapon. To fire the weapon, have your gun mode set to 'fire', \ then click where you want to fire. To recharge this weapon, use a weapon recharger. \ To switch between insta-stun and disabler beams, click the weapon in your hand. This weapon can only fire through glass if it is set to disabler beams." @@ -55,11 +55,6 @@ then click where you want to fire. After firing, you will need to pump the gun, by clicking on the gun in your hand. To reload, load more shotgun \ shells into the gun." -/obj/item/weapon/gun/projectile/heavysniper - description_info = "This is a ballistic weapon. To fire the weapon, have your gun mode set to 'fire', \ - then click where you want to fire. The gun's chamber can be opened or closed by using it in your hand. To reload, open the chamber, add a new bullet \ - then close it. To use the scope, use the appropriate verb in the object tab." - //******* //*Melee* //******* diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index c4088d9a53f..45ef929967a 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -695,7 +695,7 @@ var/list/non_fakeattack_weapons = list(/obj/item/weapon/gun/projectile, /obj/ite halitem.layer = 50 switch(rand(1,6)) if(1) //revolver - halitem.icon = 'icons/obj/gun.dmi' + halitem.icon = 'icons/obj/guns/projectile.dmi' halitem.icon_state = "revolver" halitem.name = "Revolver" if(2) //c4 @@ -780,4 +780,4 @@ var/list/non_fakeattack_weapons = list(/obj/item/weapon/gun/projectile, /obj/ite if(client) client.images += halbody spawn(rand(50,80)) //Only seen for a brief moment. if(client) client.images -= halbody - halbody = null \ No newline at end of file + halbody = null diff --git a/code/modules/food/recipes_candy.dm b/code/modules/food/recipes_candy.dm index 794fcb649e2..8067820786f 100644 --- a/code/modules/food/recipes_candy.dm +++ b/code/modules/food/recipes_candy.dm @@ -25,8 +25,37 @@ items = list() result = /obj/item/weapon/reagent_containers/food/snacks/chocolatebar +/datum/recipe/candy/fudge_peanut + reagents = list("sugar" = 5, "milk" = 5) + items = list(/obj/item/weapon/reagent_containers/food/snacks/chocolatebar) + fruit = list("peanuts" = 3) + result = /obj/item/weapon/reagent_containers/food/snacks/candy/fudge/peanut + +/datum/recipe/candy/fudge_cherry + reagents = list("sugar" = 5, "milk" = 5) + items = list(/obj/item/weapon/reagent_containers/food/snacks/chocolatebar) + fruit = list("cherries" = 3) + result = /obj/item/weapon/reagent_containers/food/snacks/candy/fudge/cherry + +/datum/recipe/candy/fudge_cookies_n_cream + reagents = list("sugar" = 5, "milk" = 5, "cream" = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, + /obj/item/weapon/reagent_containers/food/snacks/cookie, + ) + result = /obj/item/weapon/reagent_containers/food/snacks/candy/fudge/cookies_n_cream + +/datum/recipe/candy/fudge_turtle + reagents = list("sugar" = 5, "milk" = 5) + items = list( + /obj/item/weapon/reagent_containers/food/snacks/chocolatebar, + /obj/item/weapon/reagent_containers/food/snacks/candy/caramel, + ) + fruit = list("peanuts" = 1) + result = /obj/item/weapon/reagent_containers/food/snacks/candy/fudge/turtle + /datum/recipe/candy/fudge - reagents = list("sugar" = 5, "cream" = 5) + reagents = list("sugar" = 5, "milk" = 5) items = list(/obj/item/weapon/reagent_containers/food/snacks/chocolatebar) result = /obj/item/weapon/reagent_containers/food/snacks/candy/fudge diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm index 150528d4c66..553251a2ee8 100644 --- a/code/modules/hydroponics/beekeeping/beebox.dm +++ b/code/modules/hydroponics/beekeeping/beebox.dm @@ -82,7 +82,7 @@ honey_frames += HF for(var/i in 1 to get_max_bees()) - var/mob/living/simple_animal/hostile/poison/bees/B = new(src) + var/mob/living/simple_animal/hostile/poison/bees/worker/B = new(src) bees += B B.beehome = src B.assign_reagent(R) diff --git a/code/modules/hydroponics/seed.dm b/code/modules/hydroponics/seed.dm index 7f7addca012..57ad87ecbbe 100644 --- a/code/modules/hydroponics/seed.dm +++ b/code/modules/hydroponics/seed.dm @@ -9,6 +9,7 @@ var/seed_name // Plant name for seed packet. var/seed_noun = "seeds" // Descriptor for packet. var/display_name // Prettier name. + var/base_name // Unchanging name for use with modified versions var/roundstart // If set, seed will not display variety number. var/mysterious // Only used for the random seed packets. var/can_self_harvest = 0 // Mostly used for living mobs. @@ -23,12 +24,13 @@ var/splat_type = /obj/effect/decal/cleanable/fruit_smudge // Graffiti decal. var/preset_product var/final_form = 1 + var/last_diverge_type = -1 // Used to check if we need to change our name prefix when we are mutated/modified/enhanced var/modular_icon = 0 // Dictates if the product uses a modular sprite. 0 = preset, 1 = modular var/preset_icon = "undef" // Name of the iconstate in icon/obj/harvest.dmi to use for preset sprite // Make sure to set this to the correct icon if not using a modular sprite /datum/seed/New() - + base_name = seed_name set_trait(TRAIT_IMMUTABLE, 0) // If set, plant will never mutate. If -1, plant is highly mutable. set_trait(TRAIT_HARVEST_REPEAT, 0) // If 1, this plant will fruit repeatedly. set_trait(TRAIT_PRODUCES_POWER, 0) // Can be used to make a battery. @@ -797,16 +799,8 @@ new_seed.modular_icon = modular_icon new_seed.preset_icon = preset_icon - switch(modified) - if(0) //Mutant (default) - new_seed.seed_name = "mutant [seed_name]" - new_seed.display_name = "mutant [seed_name]" - if(1) //Modified - new_seed.seed_name = "modified [seed_name]" - new_seed.display_name = "modified [seed_name]" - if(2) //Enhanced - new_seed.seed_name = "enhanced [seed_name]" - new_seed.display_name = "enhanced [seed_name]" + new_seed.base_name = base_name + new_seed.update_name_prefixes(modified) new_seed.seed_noun = seed_noun new_seed.traits = traits.Copy() @@ -818,3 +812,20 @@ growth_stages = plant_controller.plant_sprites[get_trait(TRAIT_PLANT_ICON)] else growth_stages = 0 + +/datum/seed/proc/update_name_prefixes(var/modified = 0) + if(last_diverge_type == modified) + //We already match the new prefix, so we're not going to bother + return + //Since we don't match, set the last_diverge type to the modified value, then handle the new prefix + last_diverge_type = modified + switch(modified) + if(0) //Mutant (default) + seed_name = "mutant [base_name]" + display_name = "mutant [base_name]" + if(1) //Modified + seed_name = "modified [base_name]" + display_name = "modified [base_name]" + if(2) //Enhanced + seed_name = "enhanced [base_name]" + display_name = "enhanced [base_name]" \ No newline at end of file diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm index d7ce6d9f49a..a028fa66727 100644 --- a/code/modules/hydroponics/seed_datums.dm +++ b/code/modules/hydroponics/seed_datums.dm @@ -40,7 +40,7 @@ seed_name = "ghost pepper" display_name = "ghost pepper plants" mutants = null - chems = list("capsaicin" = list(8,2), "condensedcapsaicin" = list(4,4), "ghostchilijuice" = list(4,4), "plantmatter" = list(1,50)) + chems = list("capsaicin" = list(8,2), "condensedcapsaicin" = list(4,4), "plantmatter" = list(1,50)) kitchen_tag = "ghostchili" preset_icon = "ghostchilipepper" @@ -899,6 +899,7 @@ seed_name = "peanut" display_name = "peanut vines" chems = list("plantmatter" = list(1,10)) + kitchen_tag = "peanuts" preset_icon = "peanuts" /datum/seed/peanuts/New() diff --git a/code/modules/hydroponics/trays/tray.dm b/code/modules/hydroponics/trays/tray.dm index 1f48cf69adf..74a8d7824dc 100644 --- a/code/modules/hydroponics/trays/tray.dm +++ b/code/modules/hydroponics/trays/tray.dm @@ -260,12 +260,16 @@ if(prob(20+mutation_mod)) //Low chance of stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return if(2) //Tier 2 if(prob(60+mutation_mod)) //Higher chance of stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return if(3) //Tier 3 @@ -275,11 +279,15 @@ else //No mutant species, mutate stats instead if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return else //Failed to shift, mutate stats instead if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return if(4) //Tier 4 @@ -289,19 +297,27 @@ else //No mutant species, mutate stats instead if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) if(prob(20+mutation_mod)) //Low chance for second stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return else //Failed to shift, mutate stats instead if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) if(prob(20+mutation_mod)) //Low chance for second stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return //Floral Somatoray Tiers @@ -309,12 +325,16 @@ if(prob(80+mutation_mod)) //EVEN Higher chance of stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() seed.mutate(1,get_turf(src)) return if("F2") //Yield Tier if(prob(40+mutation_mod)) //Medium chance of Yield stat mutation if(!isnull(plant_controller.seeds[seed.name])) seed = seed.diverge() + else + seed.update_name_prefixes() if(seed.get_trait(TRAIT_IMMUTABLE) <= 0 && seed.get_trait(TRAIT_YIELD) != -1) //Check if the plant can be mutated and has a yield to mutate seed.set_trait(TRAIT_YIELD, (seed.get_trait(TRAIT_YIELD) + rand(-2, 2))) //Randomly adjust yield if(seed.get_trait(TRAIT_YIELD) < 0) //If yield would drop below 0 after adjustment, set to 0 to allow further attempts diff --git a/code/modules/hydroponics/trays/tray_reagents.dm b/code/modules/hydroponics/trays/tray_reagents.dm index a2f308f9e33..8f7e4f5e836 100644 --- a/code/modules/hydroponics/trays/tray_reagents.dm +++ b/code/modules/hydroponics/trays/tray_reagents.dm @@ -180,12 +180,16 @@ if(production_stat_value && seed.get_trait(TRAIT_PRODUCTION) > 2) if(!isnull(plant_controller.seeds[seed.name])) //This is so we don't affect plants in other trays unintentionally seed = seed.diverge(2) //ENHANCE! + else + seed.update_name_prefixes(2) var/new_production = seed.get_trait(TRAIT_PRODUCTION) + (reagent_total * production_stat_value) seed.set_trait(TRAIT_PRODUCTION, max(2, new_production)) //can't drop below 2 with this method //Potency if(potency_stat_value) if(!isnull(plant_controller.seeds[seed.name])) //This is so we don't affect plants in other trays unintentionally seed = seed.diverge(2) //ENHANCE! + else + seed.update_name_prefixes(2) var/new_potency = seed.get_trait(TRAIT_POTENCY) + (reagent_total * potency_stat_value) seed.set_trait(TRAIT_POTENCY, max(0, min(100, new_potency))) //can't go above 100 or below 0 with this method diff --git a/code/modules/mining/abandonedcrates.dm b/code/modules/mining/abandonedcrates.dm index 9102af9e0ab..3e9580ef14b 100644 --- a/code/modules/mining/abandonedcrates.dm +++ b/code/modules/mining/abandonedcrates.dm @@ -179,6 +179,7 @@ if(locked) if(istype(W, /obj/item/weapon/card/emag)) boom(user) + return 1 if(istype(W, /obj/item/device/multitool)) to_chat(user, "DECA-CODE LOCK REPORT:") if(attempts == 1) @@ -186,30 +187,24 @@ else to_chat(user, "* Anti-Tamper Bomb will activate after [src.attempts] failed access attempts.") if(lastattempt != null) - var/guess = lastattempt var/bulls = 0 var/cows = 0 var/list/banned = list() - for(var/i; i <= length(lastattempt); i++) - var/list/a = strip_first(guess) - if(a[1] in banned) + for(var/i in 1 to codelen) + var/list/a = copytext(lastattempt, i, i + 1) + if(a in banned) continue - if(findtext(a[2], a[1])) - if(findtext(code, a[1], i, i+1)) + var/g = findtext(code, a) + if(g) + banned += a + if(g == i) ++bulls - banned += a[1] - else - var/g = findtext(code, a[1]) - if(g) - if(g == i) - ++bulls - else - ++cows - guess = a[2] + else + ++cows to_chat(user, "Last code attempt had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions.") - else ..() - else ..() + return 1 + return ..() /obj/structure/closet/crate/secure/loot/togglelock(mob/user) if(locked) diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm index 140cdc8b85b..ee84c1a5864 100644 --- a/code/modules/mining/equipment_locker.dm +++ b/code/modules/mining/equipment_locker.dm @@ -897,7 +897,7 @@ /obj/item/weapon/lazarus_injector name = "lazarus injector" desc = "An injector with a cocktail of nanomachines and chemicals, this device can seemingly raise animals from the dead, making them become friendly to the user. Unfortunately, the process is useless on higher forms of life and incredibly costly, so these were hidden in storage until an executive thought they'd be great motivation for some of their employees." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/obj/hypo.dmi' icon_state = "lazarus_hypo" item_state = "hypo" throwforce = 0 @@ -916,6 +916,7 @@ if(M.stat == DEAD) M.faction = list("neutral") M.revive() + M.can_collar = 1 if(istype(target, /mob/living/simple_animal/hostile)) var/mob/living/simple_animal/hostile/H = M if(malfunctioning) diff --git a/code/modules/mining/security_recipes.dm b/code/modules/mining/security_recipes.dm index f08addbf4a0..9cbdeadc154 100644 --- a/code/modules/mining/security_recipes.dm +++ b/code/modules/mining/security_recipes.dm @@ -99,7 +99,7 @@ /datum/manufacture/taser name = "Advanced Taser" - item = /obj/item/weapon/gun/energy/advtaser + item = /obj/item/weapon/gun/energy/gun/advtaser cost1 = /obj/item/weapon/ore/iron cname1 = "Iron" amount1 = 15 diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index 77afb5e2665..7061b653f81 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -192,7 +192,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp return 0 /mob/dead/observer/can_use_hands() return 0 -/mob/dead/observer/is_active() return 0 /mob/dead/observer/Stat() ..() @@ -518,7 +517,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp //this is called when a ghost is drag clicked to something. /mob/dead/observer/MouseDrop(atom/over) if(!usr || !over) return - if (isobserver(usr) && usr.client && usr.client.holder && isliving(over)) + if (isobserver(usr) && usr.client && usr.client.holder) if (usr.client.holder.cmd_ghost_drag(src,over)) return 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 afae056b99f..9311ab0592f 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/alien_powers.dm @@ -123,8 +123,8 @@ Doesn't work on other aliens/AI.*/ A.firer = src A.yo = U.y - T.y A.xo = U.x - T.x - spawn(1) - A.process() + A.fire() + A.newtonian_move(get_dir(U, T)) return /mob/living/carbon/alien/humanoid/proc/resin() // -- TLE @@ -185,4 +185,4 @@ Doesn't work on other aliens/AI.*/ adjustPlasma(-amount) return 1 - return 0 \ No newline at end of file + return 0 diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm index 6ad6a672b43..ec0791d9e09 100644 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ b/code/modules/mob/living/carbon/brain/MMI.dm @@ -44,14 +44,15 @@ user.drop_item() B.forceMove(src) held_brain = B - if(istype(O,/obj/item/organ/internal/brain/xeno)) // I'm not sure how well this will work now, since I don't think you can actually get xeno brains + if(istype(O,/obj/item/organ/internal/brain/xeno)) // kept the type check, as it still does other weird stuff name = "Man-Machine Interface: Alien - [brainmob.real_name]" icon = 'icons/mob/alien.dmi' icon_state = "AlienMMI" alien = 1 else name = "Man-Machine Interface: [brainmob.real_name]" - icon_state = "mmi_full" + icon = B.mmi_icon + icon_state = "[B.mmi_icon_state]" alien = 0 feedback_inc("cyborg_mmis_filled",1) diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/carbon/brain/brain_item.dm index e10b3d257d3..92c04ca0066 100644 --- a/code/modules/mob/living/carbon/brain/brain_item.dm +++ b/code/modules/mob/living/carbon/brain/brain_item.dm @@ -15,6 +15,8 @@ parent_organ = "head" slot = "brain" vital = 1 + var/mmi_icon = 'icons/obj/assemblies.dmi' + var/mmi_icon_state = "mmi_full" /obj/item/organ/internal/brain/surgeryize() if(!owner) @@ -27,6 +29,8 @@ desc = "We barely understand the brains of terrestial animals. Who knows what we may find in the brain of such an advanced species?" icon_state = "brain-x" origin_tech = "biotech=7" + mmi_icon = 'icons/mob/alien.dmi' + mmi_icon_state = "AlienMMI" /obj/item/organ/internal/brain/New() ..() @@ -107,6 +111,7 @@ desc = "A complex, organic knot of jelly and crystalline particles." icon = 'icons/mob/slimes.dmi' icon_state = "green slime extract" + mmi_icon_state = "slime_mmi" // parent_organ = "chest" Hello I am from the ministry of rubber forehead aliens how are you /obj/item/organ/brain/slime/take_damage(var/amount, var/silent = 1) diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/carbon/brain/life.dm index 857546732d7..63eb38e607f 100644 --- a/code/modules/mob/living/carbon/brain/life.dm +++ b/code/modules/mob/living/carbon/brain/life.dm @@ -32,22 +32,6 @@ adjustToxLoss(3) updatehealth() -/mob/living/carbon/brain/handle_environment(datum/gas_mixture/environment) - if(!environment) - return - var/environment_heat_capacity = environment.heat_capacity() - if(istype(get_turf(src), /turf/space)) - var/turf/heat_turf = get_turf(src) - environment_heat_capacity = heat_turf.heat_capacity - - if((environment.temperature > (T0C + 50)) || (environment.temperature < (T0C + 10))) - var/transfer_coefficient = 1 - - handle_temperature_damage(HEAD, environment.temperature, environment_heat_capacity*transfer_coefficient) - - if(stat == DEAD) - bodytemperature += 0.1*(environment.temperature - bodytemperature)*environment_heat_capacity/(environment_heat_capacity + 270000) - /mob/living/carbon/brain/proc/handle_temperature_damage(body_part, exposed_temperature, exposed_intensity) if(status_flags & GODMODE) return @@ -94,3 +78,6 @@ see_in_dark = 2 see_invisible = SEE_INVISIBLE_LIVING handle_hud_icons_health() + +/mob/living/carbon/brain/breathe() + return diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 5a641a81689..9aed3244949 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -517,57 +517,39 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, /mob/living/carbon/throw_item(atom/target) throw_mode_off() - if(stat || !target) + if(!target || !isturf(loc)) return - if(target.type == /obj/screen) + if(istype(target, /obj/screen)) return - var/atom/movable/item = get_active_hand() + var/atom/movable/thrown_thing + var/obj/item/I = src.get_active_hand() - if(!item || (item.flags & NODROP)) + if(!I || (I.flags & NODROP)) return - if (istype(item, /obj/item/weapon/grab)) - var/obj/item/weapon/grab/G = item - item = G.get_mob_if_throwable() //throw the person instead of the grab - if(ismob(item)) + if(istype(I, /obj/item/weapon/grab)) + var/obj/item/weapon/grab/G = I + var/mob/throwable_mob = G.get_mob_if_throwable() //throw the person instead of the grab + qdel(G) //We delete the grab. + if(throwable_mob) + thrown_thing = throwable_mob var/turf/start_T = get_turf(loc) //Get the start and target tile for the descriptors var/turf/end_T = get_turf(target) if(start_T && end_T) - var/mob/M = item var/start_T_descriptor = "tile at [start_T.x], [start_T.y], [start_T.z] in area [get_area(start_T)]" var/end_T_descriptor = "tile at [end_T.x], [end_T.y], [end_T.z] in area [get_area(end_T)]" - M.attack_log += text("\[[time_stamp()]\] Has been thrown by [key_name(src)] from [start_T_descriptor] with the target [end_T_descriptor]") - attack_log += text("\[[time_stamp()]\] Has thrown [key_name(M)] from [start_T_descriptor] with the target [end_T_descriptor]") - msg_admin_attack("[key_name_admin(src)] has thrown [key_name_admin(M)] from [start_T_descriptor] with the target [end_T_descriptor]") + add_logs(throwable_mob, src, "thrown", addition="from [start_T_descriptor] with the target [end_T_descriptor]") - if(!iscarbon(src)) - M.LAssailant = null - else - M.LAssailant = src - - if(!item) - return //Grab processing has a chance of returning null - if(!ismob(item)) //Honk mobs don't have a dropped() proc honk - unEquip(item) - update_icons() - - if (istype(src, /mob/living/carbon)) //Check if a carbon mob is throwing. Modify/remove this line as required. - item.loc = loc - if(client) - client.screen -= item - if(istype(item, /obj/item)) - item:dropped(src) // let it know it's been dropped - - //actually throw it! - if (item) - item.layer = initial(item.layer) - visible_message("\red [src] has thrown [item].") + else if(!(I.flags & ABSTRACT)) //can't throw abstract items + thrown_thing = I + unEquip(I) + if(thrown_thing) + visible_message("[src] has thrown [thrown_thing].") newtonian_move(get_dir(target, src)) - - item.throw_at(target, item.throw_range, item.throw_speed, src) + thrown_thing.throw_at(target, thrown_thing.throw_range, thrown_thing.throw_speed, src) /* /mob/living/carbon/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) ..() @@ -863,6 +845,12 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, //called when we get cuffed/uncuffed /mob/living/carbon/proc/update_handcuffed() if(handcuffed) + //we don't want problems with nodrop shit if there ever is more than one nodrop twohanded + var/obj/item/I = get_active_hand() + if(istype(I, /obj/item/weapon/twohanded)) + var/obj/item/weapon/twohanded/TH = I //FML + if(TH.wielded) + TH.unwield() drop_r_hand() drop_l_hand() stop_pulling() diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index 8264db804fd..52488051f50 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -18,16 +18,17 @@ return 1 /mob/living/carbon/human/proc/change_gender(var/gender, var/update_dna = 1) + var/obj/item/organ/external/head/H = organs_by_name["head"] if(src.gender == gender) return src.gender = gender - var/datum/sprite_accessory/hair/current_hair = hair_styles_list[h_style] + var/datum/sprite_accessory/hair/current_hair = hair_styles_list[H.h_style] if(current_hair.gender != NEUTER && current_hair.gender != src.gender) reset_head_hair() - var/datum/sprite_accessory/hair/current_fhair = facial_hair_styles_list[f_style] + var/datum/sprite_accessory/hair/current_fhair = facial_hair_styles_list[H.f_style] if(current_fhair.gender != NEUTER && current_fhair.gender != src.gender) reset_facial_hair() @@ -38,59 +39,137 @@ return 1 /mob/living/carbon/human/proc/change_hair(var/hair_style) + var/obj/item/organ/external/head/H = get_organ("head") if(!hair_style) return - if(h_style == hair_style) + if(H.h_style == hair_style) return if(!(hair_style in hair_styles_list)) return - h_style = hair_style + H.h_style = hair_style update_hair() return 1 /mob/living/carbon/human/proc/change_facial_hair(var/facial_hair_style) + var/obj/item/organ/external/head/H = get_organ("head") if(!facial_hair_style) return - if(f_style == facial_hair_style) + if(H.f_style == facial_hair_style) return if(!(facial_hair_style in facial_hair_styles_list)) return - f_style = facial_hair_style + H.f_style = facial_hair_style update_fhair() return 1 +/mob/living/carbon/human/proc/change_head_accessory(var/head_accessory_style) + var/obj/item/organ/external/head/H = get_organ("head") + if(!head_accessory_style) + return + + if(H.ha_style == head_accessory_style) + return + + if(!(head_accessory_style in head_accessory_styles_list)) + return + + H.ha_style = head_accessory_style + + update_head_accessory() + return 1 + +/mob/living/carbon/human/proc/change_markings(var/marking_style) + if(!marking_style) + return + + if(src.m_style == marking_style) + return + + if(!(marking_style in marking_styles_list)) + return + + src.m_style = marking_style + + update_markings() + return 1 + +/mob/living/carbon/human/proc/change_body_accessory(var/body_accessory_style) + var/found + if(!body_accessory_style) + return + + if(src.body_accessory) + if(src.body_accessory.name == body_accessory_style) + return + + for(var/B in body_accessory_by_name) + if(B == body_accessory_style) + src.body_accessory = body_accessory_by_name[body_accessory_style] + found = 1 + + if(!found) + return + + update_tail_layer() + return 1 + /mob/living/carbon/human/proc/reset_hair() reset_head_hair() reset_facial_hair() + reset_head_accessory() + if(m_style && m_style != "None") //Resets the markings if they were head markings. + var/datum/sprite_accessory/marking_style = marking_styles_list[m_style] + if(marking_style && marking_style.marking_location == "head") + reset_markings() /mob/living/carbon/human/proc/reset_head_hair() + var/obj/item/organ/external/head/H = get_organ("head") var/list/valid_hairstyles = generate_valid_hairstyles() - if(valid_hairstyles.len) - h_style = pick(valid_hairstyles) + H.h_style = pick(valid_hairstyles) else //this shouldn't happen - h_style = "Bald" + H.h_style = "Bald" update_hair() /mob/living/carbon/human/proc/reset_facial_hair() + var/obj/item/organ/external/head/H = get_organ("head") var/list/valid_facial_hairstyles = generate_valid_facial_hairstyles() if(valid_facial_hairstyles.len) - f_style = pick(valid_facial_hairstyles) + H.f_style = pick(valid_facial_hairstyles) else //this shouldn't happen - f_style = "Shaved" + H.f_style = "Shaved" update_fhair() +/mob/living/carbon/human/proc/reset_markings() + var/list/valid_markings = generate_valid_markings() + if(valid_markings.len) + m_style = pick(valid_markings) + else + //this shouldn't happen + m_style = "None" + update_markings() + +/mob/living/carbon/human/proc/reset_head_accessory() + var/obj/item/organ/external/head/H = get_organ("head") + var/list/valid_head_accessories = generate_valid_head_accessories() + if(valid_head_accessories.len) + H.ha_style = pick(valid_head_accessories) + else + //this shouldn't happen + H.ha_style = "None" + update_head_accessory() + /mob/living/carbon/human/proc/change_eye_color(var/red, var/green, var/blue) if(red == r_eyes && green == g_eyes && blue == b_eyes) return @@ -104,27 +183,53 @@ return 1 /mob/living/carbon/human/proc/change_hair_color(var/red, var/green, var/blue) - if(red == r_eyes && green == g_eyes && blue == b_eyes) + var/obj/item/organ/external/head/H = get_organ("head") + if(red == H.r_hair && green == H.g_hair && blue == H.b_hair) return - r_hair = red - g_hair = green - b_hair = blue + H.r_hair = red + H.g_hair = green + H.b_hair = blue update_hair() return 1 /mob/living/carbon/human/proc/change_facial_hair_color(var/red, var/green, var/blue) - if(red == r_facial && green == g_facial && blue == b_facial) + var/obj/item/organ/external/head/H = get_organ("head") + if(red == H.r_facial && green == H.g_facial && blue == H.b_facial) return - r_facial = red - g_facial = green - b_facial = blue + H.r_facial = red + H.g_facial = green + H.b_facial = blue update_fhair() return 1 +/mob/living/carbon/human/proc/change_head_accessory_color(var/red, var/green, var/blue) + var/obj/item/organ/external/head/H = get_organ("head") + if(red == H.r_headacc && green == H.g_headacc && blue == H.b_headacc) + return + + H.r_headacc = red + H.g_headacc = green + H.b_headacc = blue + + update_head_accessory() + return 1 + +/mob/living/carbon/human/proc/change_marking_color(var/red, var/green, var/blue) + if(red == r_markings && green == g_markings && blue == b_markings) + return + + r_markings = red + g_markings = green + b_markings = blue + + update_markings() + return 1 + + /mob/living/carbon/human/proc/change_skin_color(var/red, var/green, var/blue) if(red == r_skin && green == g_skin && blue == b_skin || !(species.bodyflags & HAS_SKIN_COLOR)) return @@ -170,6 +275,7 @@ /mob/living/carbon/human/proc/generate_valid_hairstyles() var/list/valid_hairstyles = new() + var/obj/item/organ/external/head/H = get_organ("head") for(var/hairstyle in hair_styles_list) var/datum/sprite_accessory/S = hair_styles_list[hairstyle] @@ -177,12 +283,11 @@ continue if(gender == FEMALE && S.gender == MALE) continue - if(species.flags & ALL_RPARTS) //If the user is a species who can have a robotic head... - var/obj/item/organ/external/head/H = organs_by_name["head"] + if(H.species.flags & ALL_RPARTS) //If the user is a species who can have a robotic head... var/datum/robolimb/robohead = all_robolimbs[H.model] if(!H) return - if(species.name in S.species_allowed) //If this is a hairstyle native to the user's species... + if(H.species.name in S.species_allowed) //If this is a hairstyle native to the user's species... if(robohead.is_monitor && (robohead.company in S.models_allowed)) //Check to see if they have a head with an ipc-style screen and that the head's company is in the screen style's allowed models list. valid_hairstyles += hairstyle //Give them their hairstyles if they do. continue @@ -195,8 +300,8 @@ if("Human" in S.species_allowed) //If the user has a robotic head and the hairstyle can fit humans, let them use it as a wig for their humanoid robot head. valid_hairstyles += hairstyle continue - else - if(!(species.name in S.species_allowed)) //If the user is not a species who can have robotic heads, use the default handling. + else //If the user is not a species who can have robotic heads, use the default handling. + if(!(H.species.name in S.species_allowed)) //If the user's head is not of a species the hair style allows, skip it. Otherwise, add it to the list. continue valid_hairstyles += hairstyle @@ -204,6 +309,7 @@ /mob/living/carbon/human/proc/generate_valid_facial_hairstyles() var/list/valid_facial_hairstyles = new() + var/obj/item/organ/external/head/H = get_organ("head") for(var/facialhairstyle in facial_hair_styles_list) var/datum/sprite_accessory/S = facial_hair_styles_list[facialhairstyle] @@ -211,12 +317,11 @@ continue if(gender == FEMALE && S.gender == MALE) continue - if(species.flags & ALL_RPARTS) //If the user is a species who can have a robotic head... - var/obj/item/organ/external/head/H = organs_by_name["head"] + if(H.species.flags & ALL_RPARTS) //If the user is a species who can have a robotic head... var/datum/robolimb/robohead = all_robolimbs[H.model] if(!H) continue // No head, no hair - if(species.name in S.species_allowed) //If this is a facial hair style native to the user's species... + if(H.species.name in S.species_allowed) //If this is a facial hair style native to the user's species... if(robohead.is_monitor && (robohead.company in S.models_allowed)) //Check to see if they have a head with an ipc-style screen and that the head's company is in the screen style's allowed models list. valid_facial_hairstyles += facialhairstyle //Give them their facial hair styles if they do. continue @@ -231,8 +336,52 @@ valid_facial_hairstyles += facialhairstyle continue else //If the user is not a species who can have robotic heads, use the default handling. - if(!(species.name in S.species_allowed)) + if(!(H.species.name in S.species_allowed)) //If the user's head is not of a species the facial hair style allows, skip it. Otherwise, add it to the list. continue valid_facial_hairstyles += facialhairstyle return valid_facial_hairstyles + +/mob/living/carbon/human/proc/generate_valid_head_accessories() + var/list/valid_head_accessories = new() + var/obj/item/organ/external/head/H = get_organ("head") + for(var/head_accessory in head_accessory_styles_list) + var/datum/sprite_accessory/S = head_accessory_styles_list[head_accessory] + + if(!(H.species.name in S.species_allowed)) //If the user's head is not of a species the head accessory style allows, skip it. Otherwise, add it to the list. + continue + valid_head_accessories += head_accessory + + return valid_head_accessories + +/mob/living/carbon/human/proc/generate_valid_markings() + var/list/valid_markings = new() + var/obj/item/organ/external/head/H = get_organ("head") + for(var/marking in marking_styles_list) + var/datum/sprite_accessory/S = marking_styles_list[marking] + + if(!(species.name in S.species_allowed)) //If the user's head is not of a species the marking style allows, skip it. Otherwise, add it to the list. + continue + if(H.species.flags & ALL_RPARTS) //If the user is a species that can have a robotic head... + var/datum/robolimb/robohead = all_robolimbs[H.model] + if(!(S.models_allowed && (robohead.company in S.models_allowed))) //Make sure they don't get markings incompatible with their head. + continue + valid_markings += marking + + return valid_markings + +/mob/living/carbon/human/proc/generate_valid_body_accessories() + var/list/valid_body_accessories = new() + for(var/B in body_accessory_by_name) + var/datum/body_accessory/A = body_accessory_by_name[B] + if(check_rights(R_ADMIN, 1, src)) + valid_body_accessories = body_accessory_by_name.Copy() + else + if(!istype(A)) + valid_body_accessories += "None" //The only null entry should be the "None" option. + continue + if(!(species.name in A.allowed_species)) //If the user is not of a species the body accessory style allows, skip it. Otherwise, add it to the list. + continue + valid_body_accessories += B + + return valid_body_accessories diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm index aa31c912841..fce12362d73 100644 --- a/code/modules/mob/living/carbon/human/death.dm +++ b/code/modules/mob/living/carbon/human/death.dm @@ -145,12 +145,13 @@ return ..(gibbed) /mob/living/carbon/human/proc/makeSkeleton() + var/obj/item/organ/external/head/H = get_organ("head") if(SKELETON in src.mutations) return - if(f_style) - f_style = "Shaved" - if(h_style) - h_style = "Bald" + if(H.f_style) + H.f_style = "Shaved" + if(H.h_style) + H.h_style = "Bald" update_fhair(0) update_hair(0) @@ -162,12 +163,13 @@ return /mob/living/carbon/human/proc/ChangeToHusk() + var/obj/item/organ/external/head/H = organs_by_name["head"] if(HUSK in mutations) return - if(f_style) - f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE - if(h_style) - h_style = "Bald" + if(H.f_style) + H.f_style = "Shaved" //we only change the icon_state of the hair datum, so it doesn't mess up their UI/UE + if(H.h_style) + H.h_style = "Bald" update_fhair(0) update_hair(0) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 1bb9ec062a9..a57764ed47a 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -28,8 +28,8 @@ act = lowertext(act) switch(act) //Cooldown-inducing emotes - if("ping", "pings", "buzz", "buzzes", "beep", "beeps", "yes", "no") - if (species.name == "Machine") //Only Machines can beep, ping, and buzz + if("ping", "pings", "buzz", "buzzes", "beep", "beeps", "yes", "no", "buzz2") + if (species.name == "Machine") //Only Machines can beep, ping, and buzz, yes, no, and make a silly sad trombone noise. on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm else //Everyone else fails, skip the emote attempt return @@ -86,6 +86,11 @@ playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) m_type = 2 + if("buzz2") + message = "[src] emits an irritated buzzing sound." + playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) + m_type = 2 + if("buzz", "buzzes") var/M = null if(param) @@ -307,18 +312,32 @@ if (M == src) M = null - if (M) - if(src.lying || src.weakened) + if(M) + if(lying || weakened) message = "[src] flops and flails around on the floor." else message = "[src] flips in [M]'s general direction." - src.SpinAnimation(5,1) + SpinAnimation(5,1) else - if(src.lying || src.weakened) + if(lying || weakened) message = "[src] flops and flails around on the floor." else - message = "[src] does a flip!" - src.SpinAnimation(5,1) + var/obj/item/weapon/grab/G + if(istype(get_active_hand(), /obj/item/weapon/grab)) + G = get_active_hand() + if(G && G.affecting) + if(buckled || G.affecting.buckled) + return + var/turf/oldloc = loc + var/turf/newloc = G.affecting.loc + if(isturf(oldloc) && isturf(newloc)) + SpinAnimation(5,1) + forceMove(newloc) + G.affecting.forceMove(oldloc) + message = "[src] flips over [G.affecting]!" + else + message = "[src] does a flip!" + SpinAnimation(5,1) if ("aflap", "aflaps") if (!src.restrained()) diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 714e9c45146..539d88f11cb 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -56,17 +56,22 @@ var/list/nospecies = list("Abductor", "Shadowling", "Neara", "Monkey", "Stok", "Farwa", "Wolpin") //species that won't show their race no matter what - if (skipjumpsuit && skipface || (species.name in nospecies)) //either obscured or on the nospecies list - msg += "!\n" //omit the species when examining - else if (species.name == "Slime People") //snowflakey because Slime People are defined as a plural + var/displayed_species = get_species() + for(var/obj/item/clothing/C in src) //Disguise checks + if (C == src.head || C == src.wear_suit || C == src.wear_mask || C == src.w_uniform || C == src.belt || C == src.back) + if(C.species_disguise) + displayed_species = C.species_disguise + if (skipjumpsuit && skipface || (displayed_species in nospecies)) //either obscured or on the nospecies list + msg += "!\n" //omit the species when examining + else if (displayed_species == "Slime People") //snowflakey because Slime People are defined as a plural msg += ", a slime person!\n" - else if (species.name == "Unathi") //DAMN YOU, VOWELS + else if (displayed_species == "Unathi") //DAMN YOU, VOWELS msg += ", a unathi!\n" else - msg += ", \a [lowertext(species.name)]!\n" + msg += ", \a [lowertext(displayed_species)]!\n" //uniform - if(w_uniform && !skipjumpsuit) + if(w_uniform && !skipjumpsuit && !(w_uniform.flags & ABSTRACT)) //Ties var/tie_msg if(istype(w_uniform,/obj/item/clothing/under)) @@ -80,14 +85,14 @@ msg += "[t_He] [t_is] wearing \icon[w_uniform] \a [w_uniform][tie_msg].\n" //head - if(head) + if(head && !(head.flags & ABSTRACT)) if(head.blood_DNA) msg += "[t_He] [t_is] wearing \icon[head] [head.gender==PLURAL?"some":"a"] [head.blood_color != "#030303" ? "blood-stained":"oil-stained"] [head.name] on [t_his] head!\n" else msg += "[t_He] [t_is] wearing \icon[head] \a [head] on [t_his] head.\n" //suit/armour - if(wear_suit) + if(wear_suit && !(wear_suit.flags & ABSTRACT)) if(wear_suit.blood_DNA) msg += "[t_He] [t_is] wearing \icon[wear_suit] [wear_suit.gender==PLURAL?"some":"a"] [wear_suit.blood_color != "#030303" ? "blood-stained":"oil-stained"] [wear_suit.name]!\n" else @@ -101,7 +106,7 @@ msg += "[t_He] [t_is] carrying \icon[s_store] \a [s_store] on [t_his] [wear_suit.name].\n" //back - if(back) + if(back && !(back.flags & ABSTRACT)) if(back.blood_DNA) msg += "[t_He] [t_has] \icon[back] [back.gender==PLURAL?"some":"a"] [back.blood_color != "#030303" ? "blood-stained":"oil-stained"] [back] on [t_his] back.\n" else @@ -122,7 +127,7 @@ msg += "[t_He] [t_is] holding \icon[r_hand] \a [r_hand] in [t_his] right hand.\n" //gloves - if(gloves && !skipgloves) + if(gloves && !skipgloves && !(gloves.flags & ABSTRACT)) if(gloves.blood_DNA) msg += "[t_He] [t_has] \icon[gloves] [gloves.gender==PLURAL?"some":"a"] [gloves.blood_color != "#030303" ? "blood-stained":"oil-stained"] [gloves.name] on [t_his] hands!\n" else @@ -147,7 +152,7 @@ msg += "[t_He] [t_has] \icon[belt] \a [belt] about [t_his] waist.\n" //shoes - if(shoes && !skipshoes) + if(shoes && !skipshoes && !(shoes.flags & ABSTRACT)) if(shoes.blood_DNA) msg += "[t_He] [t_is] wearing \icon[shoes] [shoes.gender==PLURAL?"some":"a"] [shoes.blood_color != "#030303" ? "blood-stained":"oil-stained"] [shoes.name] on [t_his] feet!\n" else @@ -157,14 +162,14 @@ //mask - if(wear_mask && !skipmask) + if(wear_mask && !skipmask && !(wear_mask.flags & ABSTRACT)) if(wear_mask.blood_DNA) msg += "[t_He] [t_has] \icon[wear_mask] [wear_mask.gender==PLURAL?"some":"a"] [wear_mask.blood_color != "#030303" ? "blood-stained":"oil-stained"] [wear_mask.name] on [t_his] face!\n" else msg += "[t_He] [t_has] \icon[wear_mask] \a [wear_mask] on [t_his] face.\n" //eyes - if(glasses && !skipeyes) + if(glasses && !skipeyes && !(glasses.flags & ABSTRACT)) if(glasses.blood_DNA) msg += "[t_He] [t_has] \icon[glasses] [glasses.gender==PLURAL?"some":"a"] [glasses.blood_color != "#030303" ? "blood-stained":"oil-stained"] [glasses] covering [t_his] eyes!\n" else diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 3e5cb90f380..cb067591904 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -74,38 +74,30 @@ status_flags = GODMODE|CANPUSH /mob/living/carbon/human/skrell/New(var/new_loc) - h_style = "Skrell Male Tentacles" ..(new_loc, "Skrell") /mob/living/carbon/human/tajaran/New(var/new_loc) - ha_style = "Tajaran Ears" ..(new_loc, "Tajaran") /mob/living/carbon/human/vulpkanin/New(var/new_loc) - h_style = "Bald" ..(new_loc, "Vulpkanin") /mob/living/carbon/human/unathi/New(var/new_loc) - h_style = "Unathi Horns" ..(new_loc, "Unathi") /mob/living/carbon/human/vox/New(var/new_loc) - h_style = "Short Vox Quills" ..(new_loc, "Vox") /mob/living/carbon/human/voxarmalis/New(var/new_loc) - h_style = "Bald" ..(new_loc, "Vox Armalis") /mob/living/carbon/human/skeleton/New(var/new_loc) - h_style = "Bald" ..(new_loc, "Skeleton") /mob/living/carbon/human/kidan/New(var/new_loc) ..(new_loc, "Kidan") /mob/living/carbon/human/plasma/New(var/new_loc) - h_style = "Bald" ..(new_loc, "Plasmaman") /mob/living/carbon/human/slime/New(var/new_loc) @@ -121,31 +113,24 @@ ..(new_loc, "Human") /mob/living/carbon/human/diona/New(var/new_loc) - h_style = "Bald" ..(new_loc, "Diona") /mob/living/carbon/human/machine/New(var/new_loc) - h_style = "blue IPC screen" ..(new_loc, "Machine") /mob/living/carbon/human/shadow/New(var/new_loc) - h_style = "Bald" ..(new_loc, "Shadow") /mob/living/carbon/human/golem/New(var/new_loc) - h_style = "Bald" ..(new_loc, "Golem") /mob/living/carbon/human/wryn/New(var/new_loc) - h_style = "Antennae" ..(new_loc, "Wryn") /mob/living/carbon/human/nucleation/New(var/new_loc) - h_style = "Nucleation Crystals" ..(new_loc, "Nucleation") /mob/living/carbon/human/drask/New(var/new_loc) - h_style = "Bald" ..(new_loc, "Drask") /mob/living/carbon/human/monkey/New(var/new_loc) @@ -1270,6 +1255,54 @@ else germ_level += n +/mob/living/carbon/human/proc/check_and_regenerate_organs(var/mob/living/carbon/human/H) //Regenerates missing limbs/organs. + var/list/types_of_int_organs = list() //This will hold all the types of organs in the mob before rejuvenation. + for(var/obj/item/organ/internal/I in H.internal_organs) + types_of_int_organs |= I.type //Compiling the list of organ types. It is possible for organs to be missing from this list if they are absent from the mob. + + //Removing stumps. + for(var/obj/item/organ/organ in H.contents) + if(istype(organ, /obj/item/organ/external/stump)) //Get rid of all stumps. + qdel(organ) + H.contents -= organ //Making sure the list entry is removed. + for(var/obj/item/organ/organ in H.organs) + if(istype(organ, /obj/item/organ/external/stump)) + qdel(organ) + H.organs -= organ //Making sure the list entry is removed. + for(var/organ_name in H.organs_by_name) + var/obj/item/organ/organ = H.organs_by_name[organ_name] + if(istype(organ, /obj/item/organ/external/stump) || !organ) //The !organ check is to account for mechanical limb (prostheses) losses, since those are handled in a way that leaves indexed but null list entries instead of stumps. + qdel(organ) + H.organs_by_name -= organ_name //Making sure the list entry is removed. + + //Replacing lost limbs with the species default. + var/mob/living/carbon/human/temp_holder + for(var/limb_type in H.species.has_limbs) + if(!(limb_type in H.organs_by_name)) + var/list/organ_data = H.species.has_limbs[limb_type] + var/limb_path = organ_data["path"] + var/obj/item/organ/external/O = new limb_path(temp_holder) + if(H.get_limb_by_name(O.name)) //Check to see if the user already has an limb with the same name as the 'missing limb'. If they do, skip regrowth. + continue //In an example, this will prevent duplication of the mob's right arm if the mob is a Human and they have a Diona right arm, since, + //while the limb with the name 'right_arm' the mob has may not be listed in their species' bodyparts definition, it is still viable and has the appropriate limb name. + else + O = new limb_path(H) //Create the limb on the player. + O.owner = H + H.organs |= H.organs_by_name[O.limb_name] + + //Replacing lost organs with the species default. + temp_holder = new /mob/living/carbon/human() + for(var/index in H.species.has_organ) + var/organ = H.species.has_organ[index] + if(!(organ in types_of_int_organs)) //If the mob is missing this particular organ... + var/obj/item/organ/internal/I = new organ(temp_holder) //Create the organ inside our holder so we can check it before implantation. + if(H.get_organ_slot(I.slot)) //Check to see if the user already has an organ in the slot the 'missing organ' belongs to. If they do, skip implantation. + continue //In an example, this will prevent duplication of the mob's eyes if the mob is a Human and they have Nucleation eyes, since, + //while the organ in the eyes slot may not be listed in the mob's species' organs definition, it is still viable and fits in the appropriate organ slot. + else + I = new organ(H) //Create the organ inside the player. + I.insert(H) + /mob/living/carbon/human/revive() if(species && !(species.flags & NO_BLOOD)) @@ -1277,9 +1310,18 @@ vessel.add_reagent(blood_reagent, max_blood-vessel.total_volume) fixblood() - // Fix up all organs. - // This will ignore any prosthetics in the prefs currently. - species.create_organs(src) + //Fix up all organs and replace lost ones. + restore_all_organs() //Rejuvenate and reset all existing organs. + check_and_regenerate_organs(src) //Regenerate limbs and organs only if they're really missing. + surgeries.Cut() //End all surgeries. + update_revive() + + if(species.name != "Skeleton" && (SKELETON in mutations)) + mutations.Remove(SKELETON) + if(NOCLONE in mutations) + mutations.Remove(NOCLONE) + if(HUSK in mutations) + mutations.Remove(HUSK) if(!client || !key) //Don't boot out anyone already in the mob. for (var/obj/item/organ/internal/brain/H in world) @@ -1505,6 +1547,15 @@ species.create_organs(src) + //Handle default hair/head accessories for created mobs. + var/obj/item/organ/external/head/H = get_organ("head") + if(species.default_hair) + H.h_style = species.default_hair + if(species.default_fhair) + H.f_style = species.default_fhair + if(species.default_headacc) + H.ha_style = species.default_headacc + if(!dna) dna = new /datum/dna(null) dna.species = species.name @@ -1601,9 +1652,8 @@ return if(species.flags & ALL_RPARTS) //If they can have a fully cybernetic body... - var/obj/item/organ/external/head/H = organs_by_name["head"] - var/datum/robolimb/robohead = all_robolimbs[H.model] - if(!H) + var/datum/robolimb/robohead = all_robolimbs[head_organ.model] + if(!head_organ) return if(!robohead.is_monitor) //If they've got a prosthetic head and it isn't a monitor, they've no screen to adjust. Instead, let them change the colour of their optics! var/optic_colour = input(src, "Select optic colour", rgb(r_markings, g_markings, b_markings)) as color|null @@ -1620,15 +1670,15 @@ var/list/hair = list() for(var/i in hair_styles_list) var/datum/sprite_accessory/hair/tmp_hair = hair_styles_list[i] - if((species.name in tmp_hair.species_allowed) && (robohead.company in tmp_hair.models_allowed)) //Populate the list of available monitor styles only with styles that the monitor-head is allowed to use. + if((head_organ.species.name in tmp_hair.species_allowed) && (robohead.company in tmp_hair.models_allowed)) //Populate the list of available monitor styles only with styles that the monitor-head is allowed to use. hair += i - var/new_style = input(src, "Select a monitor display", "Monitor Display", h_style) as null|anything in hair + var/new_style = input(src, "Select a monitor display", "Monitor Display", head_organ.h_style) as null|anything in hair if(incapacitated()) to_chat(src, "You were interrupted while changing your monitor display.") return if(new_style) - h_style = new_style + head_organ.h_style = new_style update_hair() @@ -1930,3 +1980,23 @@ if(U.accessories) for(var/obj/item/clothing/accessory/A in U.accessories) . |= A.GetAccess() + +/mob/living/carbon/human/is_mechanical() + return ..() || (species.flags & ALL_RPARTS) != 0 + +/mob/living/carbon/human/can_use_guns(var/obj/item/weapon/gun/G) + . = ..() + + if(G.trigger_guard == TRIGGER_GUARD_NORMAL) + if(HULK in mutations) + to_chat(src, "Your meaty finger is much too large for the trigger guard!") + return 0 + if(species.flags & NOGUNS) + to_chat(src, "Your fingers don't fit in the trigger guard!") + return 0 + + if(martial_art && martial_art.name == "The Sleeping Carp") //great dishonor to famiry + to_chat(src, "Use of ranged weaponry would bring dishonor to the clan.") + return 0 + + return . diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 835f741be3d..3a935e5e449 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -27,7 +27,7 @@ emp_act P.current = curloc P.yo = new_y - curloc.y P.xo = new_x - curloc.x - P.Angle = ""//round(Get_Angle(P,P.original)) + P.Angle = null return -1 // complete projectile permutation @@ -46,7 +46,10 @@ emp_act if((P.embed && prob(20 + max(P.damage - armor, -10)))) var/obj/item/weapon/shard/shrapnel/SP = new() (SP.name) = "[P.name] shrapnel" - (SP.desc) = "[SP.desc] It looks like it was fired from [P.shot_from]." + if(P.ammo_casing && P.ammo_casing.caliber) + (SP.desc) = "[SP.desc] It looks like it is a [P.ammo_casing.caliber] caliber round." + else + (SP.desc) = "[SP.desc] The round's caliber is unidentifiable." (SP.loc) = organ organ.embed(SP) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index e2ebed386b3..6f106f5e125 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -9,24 +9,6 @@ var/global/default_martial_art = new/datum/martial_art var/b_markings = 0 var/m_style = "None" - //Hair colour and style - var/r_hair = 0 - var/g_hair = 0 - var/b_hair = 0 - var/h_style = "Bald" - - //Head accessory colour and style - var/r_headacc = 0 - var/g_headacc = 0 - var/b_headacc = 0 - var/ha_style = "None" - - //Facial hair colour and style - var/r_facial = 0 - var/g_facial = 0 - var/b_facial = 0 - var/f_style = "Shaved" - //Eye colour var/r_eyes = 0 var/g_eyes = 0 diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index d44bfbbb27f..5d79e3f6237 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -39,6 +39,10 @@ if(back) tally += back.slowdown + if(l_hand && (l_hand.flags & HANDSLOW)) + tally += l_hand.slowdown + if(r_hand && (r_hand.flags & HANDSLOW)) + tally += r_hand.slowdown if(FAT in src.mutations) tally += 1.5 diff --git a/code/modules/mob/living/carbon/human/interactive/functions.dm b/code/modules/mob/living/carbon/human/interactive/functions.dm index 0a220accc98..b0806e66241 100644 --- a/code/modules/mob/living/carbon/human/interactive/functions.dm +++ b/code/modules/mob/living/carbon/human/interactive/functions.dm @@ -693,7 +693,7 @@ best = R if(istype(R, /obj/item/weapon/gun)) var/obj/item/weapon/gun/G = R - if(G.can_fire()) + if(G.can_shoot()) best = R break // gun with ammo? screw the rest if(best && best != main_hand) @@ -727,22 +727,23 @@ if(main_hand.force != 0) if(istype(main_hand,/obj/item/weapon/gun)) var/obj/item/weapon/gun/G = main_hand - if(G.special_check(src)) + if(G.can_trigger_gun(src)) var/shouldFire = 1 if(istype(main_hand, /obj/item/weapon/gun/energy)) var/obj/item/weapon/gun/energy/P = main_hand var/stunning = 0 - if(ispath(text2path(P.projectile_type), /obj/item/projectile/energy/electrode)) - stunning = 1 + for(var/A in P.ammo_type) + if(ispath(A,/obj/item/ammo_casing/energy/electrode)) + stunning = 1 var/mob/stunCheck = TARGET if(stunning && stunCheck.stunned) shouldFire = 0 if(shouldFire) - if(!G.process_chambered()) - G.click_empty(src) + if(!G.can_shoot()) + G.shoot_with_empty_chamber(src) npcDrop(G, 1) else - G.Fire(TARGET, src) + G.process_fire(TARGET, src) else if(get_dist(src,TARGET) > 6) if(!walk2derpless(TARGET)) @@ -871,4 +872,4 @@ else A.stamp(S) custom_emote(2, "[pick("gibbers","drools","slobbers","claps wildly","spits")] as they stamp \the [A] with \a [S]!") - return \ No newline at end of file + return diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 7162933349d..840b500de01 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -148,6 +148,9 @@ if(prob(braindam)) message = uppertext(message) verb = "yells loudly" + + if(locate(/obj/item/organ/internal/cyberimp/brain/clown_voice) in internal_organs) + message = "[message]" returns[1] = message returns[2] = verb diff --git a/code/modules/mob/living/carbon/human/species/abductor.dm b/code/modules/mob/living/carbon/human/species/abductor.dm index 1c641b27af0..bb1f3dd2067 100644 --- a/code/modules/mob/living/carbon/human/species/abductor.dm +++ b/code/modules/mob/living/carbon/human/species/abductor.dm @@ -24,4 +24,6 @@ H.gender = NEUTER if(H.mind) H.mind.abductor = new /datum/abductor - return ..() \ No newline at end of file + H.languages.Cut() //Under no condition should you be able to speak any language + H.add_language("Abductor Mindlink") //other than over the abductor's own mindlink + return ..() diff --git a/code/modules/mob/living/carbon/human/species/apollo.dm b/code/modules/mob/living/carbon/human/species/apollo.dm index a7735a00db9..5642eedbcbe 100644 --- a/code/modules/mob/living/carbon/human/species/apollo.dm +++ b/code/modules/mob/living/carbon/human/species/apollo.dm @@ -45,6 +45,8 @@ base_color = "#704300" flesh_color = "#704300" blood_color = "#FFFF99" + //Default styles for created mobs. + default_hair = "Antennae" /datum/species/wryn/handle_death(var/mob/living/carbon/human/H) @@ -54,6 +56,7 @@ to_chat(C, "It feels like part of you has died.") /datum/species/wryn/handle_attack_hand(var/mob/living/carbon/human/H, var/mob/living/carbon/human/M) + var/obj/item/organ/external/head/head_organ = H.get_organ("head") if(M.a_intent == I_HARM) if(H.handcuffed) if(!H.get_int_organ(/obj/item/organ/internal/wryn/hivenode)) return @@ -71,7 +74,7 @@ to_chat(M, "You hear a loud crunch as you mercilessly pull off [H]'s antennae.") to_chat(H, "You hear a loud crunch as your antennae is ripped off your head by [M].") to_chat(H, "It's so quiet...") - H.h_style = "Bald" + head_organ.h_style = "Bald" H.update_hair() M.attack_log += text("\[[time_stamp()]\] removed antennae [H.name] ([H.ckey])") @@ -87,7 +90,7 @@ blurb = "A sub-race of unforunates who have been exposed to too much supermatter radiation. As a result, \ supermatter crystal clusters have begun to grow across their bodies. Research to find a cure for this ailment \ has been slow, and so this is a common fate for veteran engineers. The supermatter crystals produce oxygen, \ - negating the need for the individual to breath. Their massive change in biology, however, renders most medicines \ + negating the need for the individual to breathe. Their massive change in biology, however, renders most medicines \ obselete. Ionizing radiation seems to cause resonance in some of their crystals, which seems to encourage regeneration \ and produces a calming effect on the individual. Nucleations are highly stigmatized, and are treated much in the same \ way as lepers were back on Earth." @@ -97,6 +100,9 @@ flags = IS_WHITELISTED | NO_BREATHE | NO_BLOOD | NO_PAIN | HAS_LIPS | NO_SCAN dietflags = DIET_OMNI //still human at their core, so they maintain their eating habits and diet + //Default styles for created mobs. + default_hair = "Nucleation Crystals" + reagent_tag = PROCESS_ORG has_organ = list( "heart" = /obj/item/organ/internal/heart, diff --git a/code/modules/mob/living/carbon/human/species/drask.dm b/code/modules/mob/living/carbon/human/species/drask.dm index 87f2c287dbe..59789f533f6 100644 --- a/code/modules/mob/living/carbon/human/species/drask.dm +++ b/code/modules/mob/living/carbon/human/species/drask.dm @@ -52,6 +52,7 @@ reagent_tag = PROCESS_ORG base_color = "#a3d4eb" blood_color = "#a3d4eb" + butt_sprite = "drask" has_organ = list( "heart" = /obj/item/organ/internal/heart/drask, diff --git a/code/modules/mob/living/carbon/human/species/plasmaman.dm b/code/modules/mob/living/carbon/human/species/plasmaman.dm index d85da69017b..003e1969d33 100644 --- a/code/modules/mob/living/carbon/human/species/plasmaman.dm +++ b/code/modules/mob/living/carbon/human/species/plasmaman.dm @@ -12,6 +12,8 @@ //default_mutations=list(SKELETON) // This screws things up + butt_sprite = "plasma" + breath_type = "plasma" heat_level_1 = 350 // Heat damage level 1 above this point. @@ -64,7 +66,7 @@ if("Warden","Security Officer","Security Pod Pilot") suit=/obj/item/clothing/suit/space/eva/plasmaman/security/ helm=/obj/item/clothing/head/helmet/space/eva/plasmaman/security/ - H.equip_or_collect(new /obj/item/weapon/gun/energy/advtaser(H), slot_in_backpack) + H.equip_or_collect(new /obj/item/weapon/gun/energy/gun/advtaser(H), slot_in_backpack) if("Magistrate") suit=/obj/item/clothing/suit/space/eva/plasmaman/magistrate helm=/obj/item/clothing/head/helmet/space/eva/plasmaman/magistrate diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index 03091a7e50f..f6a1e5e2088 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -16,6 +16,7 @@ var/eyes = "eyes_s" // Icon for eyes. var/blurb = "A completely nondescript species." // A brief lore summary for use in the chargen screen. + var/butt_sprite = "human" var/primitive_form // Lesser form, if any (ie. monkey for humans) var/greater_form // Greater form, if any, ie. human for monkeys. @@ -118,6 +119,11 @@ var/male_scream_sound = 'sound/goonstation/voice/male_scream.ogg' var/female_scream_sound = 'sound/goonstation/voice/female_scream.ogg' + //Default hair/headacc style vars. + var/default_hair = "Bald" //Default hair style for newly created humans unless otherwise set. + var/default_fhair = "Shaved" //Default facial hair style for newly created humans unless otherwise set. + var/default_headacc = "None" //Default head accessory style for newly created humans unless otherwise set. + // Determines the organs that the species spawns with and var/list/has_organ = list( // which required-organ checks are conducted. "heart" = /obj/item/organ/internal/heart, @@ -158,7 +164,6 @@ /datum/species/proc/create_organs(var/mob/living/carbon/human/H) //Handles creation of mob organs. - for(var/obj/item/organ/internal/iorgan in H.internal_organs) if(iorgan in H.internal_organs) qdel(iorgan) diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index bccd2a1ffdf..65d100dc420 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -55,6 +55,9 @@ flesh_color = "#34AF10" reagent_tag = PROCESS_ORG base_color = "#066000" + //Default styles for created mobs. + default_hair = "Unathi Horns" + butt_sprite = "unathi" allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/simple_animal/lizard, /mob/living/simple_animal/chick, /mob/living/simple_animal/chicken, /mob/living/simple_animal/crab, /mob/living/simple_animal/butterfly, /mob/living/simple_animal/parrot, /mob/living/simple_animal/tribble) @@ -109,6 +112,9 @@ reagent_tag = PROCESS_ORG flesh_color = "#AFA59E" base_color = "#333333" + //Default styles for created mobs. + default_headacc = "Tajaran Ears" + butt_sprite = "tajaran" allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/simple_animal/chick, /mob/living/simple_animal/butterfly, /mob/living/simple_animal/parrot, /mob/living/simple_animal/tribble) @@ -153,6 +159,7 @@ reagent_tag = PROCESS_ORG flesh_color = "#966464" base_color = "#B43214" + butt_sprite = "vulp" allowed_consumed_mobs = list(/mob/living/simple_animal/mouse, /mob/living/simple_animal/lizard, /mob/living/simple_animal/chick, /mob/living/simple_animal/chicken, /mob/living/simple_animal/crab, /mob/living/simple_animal/butterfly, /mob/living/simple_animal/parrot, /mob/living/simple_animal/tribble) @@ -189,7 +196,20 @@ dietflags = DIET_HERB flesh_color = "#8CD7A3" blood_color = "#1D2CBF" + //Default styles for created mobs. + default_hair = "Skrell Male Tentacles" reagent_tag = PROCESS_ORG + butt_sprite = "skrell" + + has_organ = list( + "heart" = /obj/item/organ/internal/heart, + "lungs" = /obj/item/organ/internal/lungs, + "liver" = /obj/item/organ/internal/liver/skrell, + "kidneys" = /obj/item/organ/internal/kidneys, + "brain" = /obj/item/organ/internal/brain, + "appendix" = /obj/item/organ/internal/appendix, + "eyes" = /obj/item/organ/internal/eyes, + ) suicide_messages = list( "is attempting to bite their tongue off!", @@ -251,12 +271,26 @@ blood_color = "#2299FC" flesh_color = "#808D11" + //Default styles for created mobs. + default_hair = "Short Vox Quills" + butt_sprite = "vox" reagent_tag = PROCESS_ORG scream_verb = "shrieks" male_scream_sound = 'sound/voice/shriek1.ogg' female_scream_sound = 'sound/voice/shriek1.ogg' + has_organ = list( + "heart" = /obj/item/organ/internal/heart, + "lungs" = /obj/item/organ/internal/lungs, + "liver" = /obj/item/organ/internal/liver, + "kidneys" = /obj/item/organ/internal/kidneys, + "brain" = /obj/item/organ/internal/brain, + "appendix" = /obj/item/organ/internal/appendix, + "eyes" = /obj/item/organ/internal/eyes, + "stack" = /obj/item/organ/internal/stack/vox //Not the same as the cortical stack implant Vox Raiders spawn with. The cortical stack implant is used + ) //for determining the success of the heist game-mode's 'leave nobody behind' objective, while this is just an organ. + suicide_messages = list( "is attempting to bite their tongue off!", "is jamming their claws into their eye sockets!", @@ -347,8 +381,8 @@ "kidneys" = /obj/item/organ/internal/kidneys, "brain" = /obj/item/organ/internal/brain, "eyes" = /obj/item/organ/internal/eyes, - "stack" = /obj/item/organ/internal/stack/vox - ) + "stack" = /obj/item/organ/internal/stack/vox //Not the same as the cortical stack implant Vox Raiders spawn with. The cortical stack implant is used + ) //for determining the success of the heist game-mode's 'leave nobody behind' objective, while this is just an organ. suicide_messages = list( "is attempting to bite their tongue off!", @@ -376,6 +410,7 @@ dietflags = DIET_HERB blood_color = "#FB9800" reagent_tag = PROCESS_ORG + butt_sprite = "kidan" allowed_consumed_mobs = list(/mob/living/simple_animal/diona) @@ -408,6 +443,7 @@ reagent_tag = PROCESS_ORG exotic_blood = "water" //ventcrawler = 1 //ventcrawling commented out + butt_sprite = "slime" has_organ = list( "brain" = /obj/item/organ/internal/brain/slime @@ -578,6 +614,7 @@ unarmed_type = /datum/unarmed_attack/punch darksight = 5 // BOOSTED from 2 eyes = "grey_eyes_s" + butt_sprite = "grey" brute_mod = 1.25 //greys are fragile @@ -642,6 +679,7 @@ body_temperature = T0C + 15 //make the plant people have a bit lower body temperature, why not blood_color = "#004400" flesh_color = "#907E4A" + butt_sprite = "diona" reagent_tag = PROCESS_ORG @@ -656,17 +694,17 @@ vision_organ = /obj/item/organ/internal/diona_receptor has_limbs = list( - "chest" = list("path" = /obj/item/organ/external/diona/chest), - "groin" = list("path" = /obj/item/organ/external/diona/groin), - "head" = list("path" = /obj/item/organ/external/diona/head), - "l_arm" = list("path" = /obj/item/organ/external/diona/arm), - "r_arm" = list("path" = /obj/item/organ/external/diona/arm/right), - "l_leg" = list("path" = /obj/item/organ/external/diona/leg), - "r_leg" = list("path" = /obj/item/organ/external/diona/leg/right), - "l_hand" = list("path" = /obj/item/organ/external/diona/hand), - "r_hand" = list("path" = /obj/item/organ/external/diona/hand/right), - "l_foot" = list("path" = /obj/item/organ/external/diona/foot), - "r_foot" = list("path" = /obj/item/organ/external/diona/foot/right) + "chest" = list("path" = /obj/item/organ/external/chest/diona), + "groin" = list("path" = /obj/item/organ/external/groin/diona), + "head" = list("path" = /obj/item/organ/external/head/diona), + "l_arm" = list("path" = /obj/item/organ/external/arm/diona), + "r_arm" = list("path" = /obj/item/organ/external/arm/right/diona), + "l_leg" = list("path" = /obj/item/organ/external/leg/diona), + "r_leg" = list("path" = /obj/item/organ/external/leg/right/diona), + "l_hand" = list("path" = /obj/item/organ/external/hand/diona), + "r_hand" = list("path" = /obj/item/organ/external/hand/right/diona), + "l_foot" = list("path" = /obj/item/organ/external/foot/diona), + "r_foot" = list("path" = /obj/item/organ/external/foot/right/diona) ) suicide_messages = list( @@ -751,11 +789,14 @@ dietflags = 0 //IPCs can't eat, so no diet blood_color = "#1F181F" flesh_color = "#AAAAAA" + //Default styles for created mobs. + default_hair = "Blue IPC Screen" virus_immune = 1 can_revive_by_healing = 1 reagent_tag = PROCESS_SYN male_scream_sound = 'sound/goonstation/voice/robot_scream.ogg' female_scream_sound = 'sound/goonstation/voice/robot_scream.ogg' + butt_sprite = "machine" has_organ = list( "brain" = /obj/item/organ/internal/brain/mmi_holder/posibrain, @@ -791,6 +832,10 @@ ) /datum/species/machine/handle_death(var/mob/living/carbon/human/H) - H.h_style = "" + var/obj/item/organ/external/head/head_organ = H.get_organ("head") + head_organ.h_style = "Bald" + head_organ.f_style = "Shaved" spawn(100) - if(H) H.update_hair() + if(H) + H.update_hair() + H.update_fhair() \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 85fff9e6ead..45bc15b1d51 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -393,13 +393,13 @@ var/global/list/damage_icon_parts = list() //base icons var/icon/head_accessory_standing = new /icon('icons/mob/body_accessory.dmi',"accessory_none_s") - if(ha_style && (src.species.bodyflags & HAS_HEAD_ACCESSORY)) - var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[ha_style] + if(head_organ.ha_style && (head_organ.species.bodyflags & HAS_HEAD_ACCESSORY)) + var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[head_organ.ha_style] if(head_accessory_style && head_accessory_style.species_allowed) - if(src.species.name in head_accessory_style.species_allowed) + if(head_organ.species.name in head_accessory_style.species_allowed) var/icon/head_accessory_s = new/icon("icon" = head_accessory_style.icon, "icon_state" = "[head_accessory_style.icon_state]_s") if(head_accessory_style.do_colouration) - head_accessory_s.Blend(rgb(r_headacc, g_headacc, b_headacc), ICON_ADD) + head_accessory_s.Blend(rgb(head_organ.r_headacc, head_organ.g_headacc, head_organ.b_headacc), ICON_ADD) head_accessory_standing = head_accessory_s //head_accessory_standing.Blend(head_accessory_s, ICON_OVERLAY) //Having it this way preserves animations. Useful for animated antennae. else @@ -429,17 +429,17 @@ var/global/list/damage_icon_parts = list() var/icon/hair_standing = new /icon('icons/mob/human_face.dmi',"bald_s") //var/icon/debrained_s = new /icon("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s") - if(h_style && !(head && (head.flags & BLOCKHEADHAIR) && !(isSynthetic()))) - var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] + if(head_organ.h_style && !(head && (head.flags & BLOCKHEADHAIR) && !(isSynthetic()))) + var/datum/sprite_accessory/hair_style = hair_styles_list[head_organ.h_style] //if(!src.get_int_organ(/obj/item/organ/internal/brain) && src.get_species() != "Machine" )//make it obvious we have NO BRAIN // hair_standing.Blend(debrained_s, ICON_OVERLAY) if(hair_style && hair_style.species_allowed) - if((src.species.name in hair_style.species_allowed) || (src.species.flags & ALL_RPARTS)) + if((head_organ.species.name in hair_style.species_allowed) || (head_organ.species.flags & ALL_RPARTS)) //If the head's species is in the list of allowed species for the hairstyle, or the head's species is one flagged to have bodies comprised wholly of cybernetics... var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") - if(src.get_species() == "Slime People") // I am el worstos + if(head_organ.species.name == "Slime People") // I am el worstos hair_s.Blend(rgb(r_skin, g_skin, b_skin, 160), ICON_AND) else if(hair_style.do_colouration) - hair_s.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD) + hair_s.Blend(rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair), ICON_ADD) hair_standing = hair_s //hair_standing.Blend(hair_s, ICON_OVERLAY) //Having it this way preserves animations. Useful for IPC screens. @@ -470,15 +470,15 @@ var/global/list/damage_icon_parts = list() //base icons var/icon/face_standing = new /icon('icons/mob/human_face.dmi',"bald_s") - if(f_style) - var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style] + if(head_organ.f_style) + var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[head_organ.f_style] if(facial_hair_style && facial_hair_style.species_allowed) - if((src.species.name in facial_hair_style.species_allowed) || (src.species.flags & ALL_RPARTS)) + if((head_organ.species.name in facial_hair_style.species_allowed) || (head_organ.species.flags & ALL_RPARTS)) //If the head's species is in the list of allowed species for the hairstyle, or the head's species is one flagged to have bodies comprised wholly of cybernetics... var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") - if(src.get_species() == "Slime People") // I am el worstos + if(head_organ.species.name == "Slime People") // I am el worstos facial_s.Blend(rgb(r_skin, g_skin, b_skin, 160), ICON_AND) else if(facial_hair_style.do_colouration) - facial_s.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD) + facial_s.Blend(rgb(head_organ.r_facial, head_organ.g_facial, head_organ.b_facial), ICON_ADD) face_standing.Blend(facial_s, ICON_OVERLAY) else //warning("Invalid f_style for [species.name]: [f_style]") @@ -574,6 +574,8 @@ var/global/list/damage_icon_parts = list() UpdateDamageIcon() update_icons() update_fire() + force_update_limbs() + update_tail_layer(0) /* --------------------------------------- */ //vvvvvv UPDATE_INV PROCS vvvvvv @@ -1265,22 +1267,23 @@ var/global/list/damage_icon_parts = list() //gender no longer matters for the mouth, although there should probably be seperate base head icons. // var/g = "m" // if (gender == FEMALE) g = "f" - + var/obj/item/organ/external/head/H = get_organ("head") //base icons var/icon/face_lying = new /icon('icons/mob/human_face.dmi',"bald_l") - if(f_style) - var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[f_style] + + if(H.f_style) + var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style] if(facial_hair_style) var/icon/facial_l = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_l") - facial_l.Blend(rgb(r_facial, g_facial, b_facial), ICON_ADD) + facial_l.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD) face_lying.Blend(facial_l, ICON_OVERLAY) - if(h_style) - var/datum/sprite_accessory/hair_style = hair_styles_list[h_style] + if(H.h_style) + var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style] if(hair_style) var/icon/hair_l = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_l") - hair_l.Blend(rgb(r_hair, g_hair, b_hair), ICON_ADD) + hair_l.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD) face_lying.Blend(hair_l, ICON_OVERLAY) //Eyes diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 7b3f74ef65f..c26508b1374 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -465,4 +465,4 @@ else healths.icon_state = "health6" else - healths.icon_state = "health7" \ No newline at end of file + healths.icon_state = "health7" diff --git a/code/modules/mob/living/carbon/superheroes.dm b/code/modules/mob/living/carbon/superheroes.dm index 08f5089a200..1ad57bd787d 100644 --- a/code/modules/mob/living/carbon/superheroes.dm +++ b/code/modules/mob/living/carbon/superheroes.dm @@ -148,6 +148,7 @@ /obj/effect/proc_holder/spell/targeted/recruit/cast(list/targets) for(var/mob/living/carbon/human/target in targets) + var/obj/item/organ/external/head/head_organ = target.get_organ("head") if(ticker.mode.greyshirts.len >= 3) to_chat(usr, "You have already recruited the maximum number of henchmen.") if(!in_range(usr, target)) @@ -210,8 +211,8 @@ to_chat(target, "You may not harm other Greyshirt or [usr]. However, you do not need to obey other Greyshirts.") ticker.mode.greyshirts += target.mind target.set_species("Human") - target.h_style = "Bald" - target.f_style = "Shaved" + head_organ.h_style = "Bald" + head_organ.f_style = "Shaved" target.s_tone = 35 target.r_eyes = 1 target.b_eyes = 1 diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm index c3c64c1c696..85526945b54 100644 --- a/code/modules/mob/living/life.dm +++ b/code/modules/mob/living/life.dm @@ -59,6 +59,8 @@ if(get_nations_mode()) process_nations() + ..() + /mob/living/proc/handle_breathing() return @@ -251,19 +253,17 @@ /mob/living/proc/give_action_button(var/obj/item/I, recursive = 0) if(I.action_button_name) if(!I.action) - if(istype(I, /obj/item/organ/internal)) - I.action = new/datum/action/item_action/organ_action - else if(I.action_button_is_hands_free) - I.action = new/datum/action/item_action/hands_free + if(I.action_button_custom_type) + I.action = new I.action_button_custom_type else - I.action = new/datum/action/item_action + I.action = new /datum/action/item_action I.action.name = I.action_button_name I.action.target = I I.action.Grant(src) if(recursive) for(var/obj/item/T in I) - give_action_button(I, recursive - 1) + give_action_button(T, recursive - 1) /mob/living/update_action_buttons() if(!hud_used) return diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 12473f1d9e8..f3c48bce39a 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -320,7 +320,6 @@ /mob/living/proc/revive() rejuvenate() - buckled = initial(src.buckled) if(iscarbon(src)) var/mob/living/carbon/C = src @@ -348,6 +347,8 @@ timeofdeath = 0 /mob/living/proc/rejuvenate() + var/mob/living/carbon/human/human_mob = null //Get this declared for use later. + // shut down various types of badness setToxLoss(0) setOxyLoss(0) @@ -366,6 +367,7 @@ drowsyness = 0 radiation = 0 druggy = 0 + hallucination = 0 nutrition = 400 bodytemperature = 310 sdisabilities = 0 @@ -380,7 +382,13 @@ fire_stacks = 0 on_fire = 0 suiciding = 0 - buckled = initial(src.buckled) + if(buckled) //Unbuckle the mob and clear the alerts. + buckled.buckled_mob = null + buckled = null + anchored = initial(src.anchored) + update_canmove() + clear_alert("buckled") + post_buckle_mob(src) if(iscarbon(src)) var/mob/living/carbon/C = src @@ -392,12 +400,13 @@ // restore all of the human's blood and reset their shock stage if(ishuman(src)) - var/mob/living/carbon/human/human_mob = src + human_mob = src human_mob.restore_blood() human_mob.shock_stage = 0 human_mob.decaylevel = 0 restore_all_organs() + surgeries.Cut() //End all surgeries. if(stat == DEAD) dead_mob_list -= src living_mob_list += src @@ -406,6 +415,9 @@ stat = CONSCIOUS update_fire() regenerate_icons() + if(human_mob) + human_mob.update_eyes() + human_mob.update_dna() return /mob/living/proc/UpdateDamageIcon() @@ -843,3 +855,9 @@ tally += 10 return tally + +/mob/living/proc/can_use_guns(var/obj/item/weapon/gun/G) + if (G.trigger_guard != TRIGGER_GUARD_ALLOW_ALL && !IsAdvancedToolUser()) + to_chat(src, "You don't have the dexterity to do this!") + return 0 + return 1 diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 4d994436489..cc50408148e 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -47,10 +47,6 @@ proj_sharp = 0 proj_edge = 0 - if(istype(P, /obj/item/projectile/beam/lightning)) //Stupid snowflake lightning gun. - if(P.damage >= 200) - src.dust() - if(!P.nodamage) apply_damage(P.damage, P.damage_type, def_zone, armor) return P.on_hit(src, armor, def_zone) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 272834e0328..812d2e8df58 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -307,7 +307,7 @@ var/list/ai_verbs_default = list( //if(icon_state == initial(icon_state)) var/icontype = "" if (custom_sprite == 1) icontype = ("Custom")//automagically selects custom sprite if one is available - else icontype = input("Select an icon!", "AI", null, null) in list("Monochrome", "Blue", "Clown", "Inverted", "Text", "Smiley", "Angry", "Dorf", "Matrix", "Bliss", "Firewall", "Green", "Red", "Static", "Triumvirate", "Triumvirate Static", "Red October", "Sparkles", "ANIMA", "President") + else icontype = input("Select an icon!", "AI", null, null) in list("Monochrome", "Blue", "Clown", "Inverted", "Text", "Smiley", "Angry", "Dorf", "Matrix", "Bliss", "Firewall", "Green", "Red", "Static", "Triumvirate", "Triumvirate Static", "Red October", "Sparkles", "ANIMA", "President", "NT") switch(icontype) if("Custom") icon_state = "[src.ckey]-ai" if("Clown") icon_state = "ai-clown2" @@ -329,6 +329,7 @@ var/list/ai_verbs_default = list( if("Sparkles") icon_state = "ai-sparkles" if("ANIMA") icon_state = "ai-anima" if("President") icon_state = "ai-president" + if("NT") icon_state = "ai-nt" else icon_state = "ai" //else // to_chat(usr, "You can only change your display once!") @@ -813,7 +814,8 @@ var/list/ai_verbs_default = list( var/icon_list[] = list( "default", "floating face", - "xeno queen" + "xeno queen", + "eldritch" ) input = input("Please select a hologram:") as null|anything in icon_list if(input) @@ -825,6 +827,8 @@ var/list/ai_verbs_default = list( holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo2")) if("xeno queen") holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo3")) + if("eldritch") + holo_icon = getHologramIcon(icon('icons/mob/AI.dmi',"holo4")) return /mob/living/silicon/ai/proc/corereturn() diff --git a/code/modules/mob/living/silicon/ai/freelook/chunk.dm b/code/modules/mob/living/silicon/ai/freelook/chunk.dm index e4b7f983b9d..71d80df9e02 100644 --- a/code/modules/mob/living/silicon/ai/freelook/chunk.dm +++ b/code/modules/mob/living/silicon/ai/freelook/chunk.dm @@ -142,7 +142,7 @@ if(c.can_use()) cameras += c - for(var/turf/t in block(locate(x, y, z), locate(min(x + CHUNK_SIZE - 1, world.maxx), min(y + CHUNK_SIZE - 1, world.maxy), z))) + for(var/turf/t in block(locate(max(x, 1), max(y, 1), max(z, 1)), locate(min(x + CHUNK_SIZE - 1, world.maxx), min(y + CHUNK_SIZE - 1, world.maxy), z))) turfs[t] = t for(var/camera in cameras) diff --git a/code/modules/mob/living/silicon/emote.dm b/code/modules/mob/living/silicon/emote.dm index c70979c5947..233df91eb55 100644 --- a/code/modules/mob/living/silicon/emote.dm +++ b/code/modules/mob/living/silicon/emote.dm @@ -13,7 +13,7 @@ //Cooldown-inducing emotes if("scream", "screams") on_CD = handle_emote_CD(50) //longer cooldown - if("ping","pings","buzz","buzzs","buzzes","beep","beeps","yes","no") + if("ping","pings","buzz","buzzs","buzzes","beep","beeps","yes","no", "buzz2") //halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT. on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm //Everything else, including typos of the above emotes @@ -115,7 +115,13 @@ playsound(src.loc, 'sound/goonstation/voice/robot_scream.ogg', 80, 0) m_type = 2 + if("buzz2") + message = "[src] emits an irritated buzzing sound." + playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) + m_type = 2 + + if("help") - to_chat(src, "yes, no, beep, ping, buzz") + to_chat(src, "yes, no, beep, ping, buzz, scream, buzz2") ..(act, m_type, message) \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/death.dm b/code/modules/mob/living/silicon/pai/death.dm index f9d75773ff9..0f938ab31b0 100644 --- a/code/modules/mob/living/silicon/pai/death.dm +++ b/code/modules/mob/living/silicon/pai/death.dm @@ -1,15 +1,16 @@ -/mob/living/silicon/pai/death(gibbed) - if(stat == DEAD) return - if(canmove || resting) - var/turf/T = get_turf_or_move(loc) - for (var/mob/M in viewers(T)) - M.show_message("\red [src] emits a dull beep before it loses power and collapses.", 3, "\red You hear a dull beep followed by the sound of glass crunching.", 2) - name = "pAI debris" - desc = "The unfortunate remains of some poor personal AI device." - icon_state = "[chassis]_dead" - else - card.overlays.Cut() - card.overlays += "pai-off" +/mob/living/silicon/pai/death(gibbed, cleanWipe) + if(stat == DEAD) + return + + if(!cleanWipe) + force_fold_out() + + var/turf/T = get_turf_or_move(loc) + for (var/mob/M in viewers(T)) + M.show_message("[src] emits a dull beep before it loses power and collapses.", 3, "You hear a dull beep followed by the sound of glass crunching.", 2) + name = "pAI debris" + desc = "The unfortunate remains of some poor personal AI device." + icon_state = "[chassis]_dead" stat = DEAD canmove = 0 sight |= SEE_TURFS|SEE_MOBS|SEE_OBJS @@ -24,5 +25,5 @@ if(mind) qdel(mind) living_mob_list -= src ghostize() - if(icon_state != "[chassis]_dead") + if(icon_state != "[chassis]_dead" || cleanWipe) qdel(src) diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index 4e1373e979b..635efadcaba 100644 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -340,35 +340,37 @@ if(stat || sleeping || paralysis || weakened) return - if(src.loc != card) - to_chat(src, "\red You are already in your mobile form!") + if(loc != card) + to_chat(src, "You are already in your mobile form!") return if(world.time <= last_special) - to_chat(src, "\red You must wait before folding your chassis out again!") + to_chat(src, "You must wait before folding your chassis out again!") return last_special = world.time + 200 //I'm not sure how much of this is necessary, but I would rather avoid issues. - if(istype(card.loc,/mob)) + force_fold_out() + + visible_message("[src] folds outwards, expanding into a mobile form.", "You fold outwards, expanding into a mobile form.") + +/mob/living/silicon/pai/proc/force_fold_out() + if(istype(card.loc, /mob)) var/mob/holder = card.loc holder.unEquip(card) - else if(istype(card.loc,/obj/item/device/pda)) + else if(istype(card.loc, /obj/item/device/pda)) var/obj/item/device/pda/holder = card.loc holder.pai = null - - src.client.perspective = EYE_PERSPECTIVE - src.client.eye = src - src.forceMove(get_turf(card)) + if(client) + client.perspective = EYE_PERSPECTIVE + client.eye = src + forceMove(get_turf(card)) card.forceMove(src) card.screen_loc = null - var/turf/T = get_turf(src) - if(istype(T)) T.visible_message("[src] folds outwards, expanding into a mobile form.") - /mob/living/silicon/pai/verb/fold_up() set category = "pAI Commands" set name = "Collapse Chassis" @@ -376,12 +378,12 @@ if(stat || sleeping || paralysis || weakened) return - if(src.loc == card) - to_chat(src, "\red You are already in your card form!") + if(loc == card) + to_chat(src, "You are already in your card form!") return if(world.time <= last_special) - to_chat(src, "\red You must wait before returning to your card form!") + to_chat(src, "You must wait before returning to your card form!") return close_up() @@ -474,16 +476,15 @@ last_special = world.time + 200 resting = 0 - if(src.loc == card) + if(loc == card) return - var/turf/T = get_turf(src) - if(istype(T)) T.visible_message("[src] neatly folds inwards, compacting down to a rectangular card.") + visible_message("[src] neatly folds inwards, compacting down to a rectangular card.", "You neatly fold inwards, compacting down to a rectangular card.") - src.stop_pulling() - if(src.client) - src.client.perspective = EYE_PERSPECTIVE - src.client.eye = card + stop_pulling() + if(client) + client.perspective = EYE_PERSPECTIVE + client.eye = card // If we are being held, handle removing our holder from their inv. var/obj/item/weapon/holder/H = loc @@ -492,13 +493,13 @@ if(istype(M)) M.unEquip(H) H.loc = get_turf(src) - src.loc = get_turf(H) + loc = get_turf(H) // Move us into the card and move the card to the ground //This seems redundant but not including the forced loc setting messes the behavior up. - src.loc = card + loc = card card.loc = get_turf(card) - src.forceMove(card) + forceMove(card) card.forceMove(card.loc) icon_state = "[chassis]" diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index 97b15ecda1a..9b2f5d1c7c1 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -246,4 +246,4 @@ if(!module) hands.icon_state = "nomod" else - hands.icon_state = lowertext(module.module_type) \ No newline at end of file + hands.icon_state = lowertext(module.module_type) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index cba9fb4c1e1..81c781b51ff 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -298,6 +298,7 @@ var/list/robot_verbs_default = list( module_sprites["Bro"] = "Brobot" module_sprites["Rich"] = "maximillion" module_sprites["Default"] = "Service2" + module_sprites["Standard"] = "robotServ" if("Miner") module = new /obj/item/weapon/robot_module/miner(src) @@ -307,6 +308,7 @@ var/list/robot_verbs_default = list( module_sprites["Basic"] = "Miner_old" module_sprites["Advanced Droid"] = "droid-miner" module_sprites["Treadhead"] = "Miner" + module_sprites["Standard"] = "robotMine" if("Medical") module = new /obj/item/weapon/robot_module/medical(src) @@ -317,6 +319,7 @@ var/list/robot_verbs_default = list( module_sprites["Standard"] = "surgeon" module_sprites["Advanced Droid"] = "droid-medical" module_sprites["Needles"] = "medicalrobot" + module_sprites["Standard"] = "robotMedi" status_flags &= ~CANPUSH if("Security") @@ -326,6 +329,7 @@ var/list/robot_verbs_default = list( module_sprites["Red Knight"] = "Security" module_sprites["Black Knight"] = "securityrobot" module_sprites["Bloodhound"] = "bloodhound" + module_sprites["Standard"] = "robotSecy" status_flags &= ~CANPUSH if("Engineering") @@ -336,6 +340,7 @@ var/list/robot_verbs_default = list( module_sprites["Basic"] = "Engineering" module_sprites["Antique"] = "engineerrobot" module_sprites["Landmate"] = "landmate" + module_sprites["Standard"] = "robotEngi" magpulse = 1 if("Janitor") @@ -344,6 +349,7 @@ var/list/robot_verbs_default = list( module_sprites["Basic"] = "JanBot2" module_sprites["Mopbot"] = "janitorrobot" module_sprites["Mop Gear Rex"] = "mopgearrex" + module_sprites["Standard"] = "robotJani" if("Combat") module = new /obj/item/weapon/robot_module/combat(src) diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 12030e52773..7fb1ba0a8aa 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -337,7 +337,7 @@ src.modules += new /obj/item/device/flash/cyborg(src) src.modules += new /obj/item/borg/sight/thermal(src) src.modules += new /obj/item/weapon/melee/energy/sword/cyborg(src) - src.modules += new /obj/item/weapon/gun/energy/pulse_rifle/cyborg(src) + src.modules += new /obj/item/weapon/gun/energy/pulse/cyborg(src) src.modules += new /obj/item/weapon/tank/jetpack/carbondioxide(src) src.modules += new /obj/item/weapon/crowbar(src) src.emag = null diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 5d88814440b..e6fc318335b 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -355,4 +355,7 @@ /mob/living/silicon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/noise) if(affect_silicon) - return ..() \ No newline at end of file + return ..() + +/mob/living/silicon/is_mechanical() + return 1 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index 633413cfc86..700b47da3f3 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -1010,4 +1010,7 @@ Pass a positive integer as an argument to override a bot's default speed. if(260 to 300) throw_alert("temp", /obj/screen/alert/cold/robot, 1) else - throw_alert("temp", /obj/screen/alert/cold/robot, 2) \ No newline at end of file + throw_alert("temp", /obj/screen/alert/cold/robot, 2) + +/mob/living/simple_animal/bot/is_mechanical() + return 1 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm index 2c2ca652d10..27bfe821502 100644 --- a/code/modules/mob/living/simple_animal/bot/construction.dm +++ b/code/modules/mob/living/simple_animal/bot/construction.dm @@ -158,7 +158,7 @@ return newname = "redtag ED-209 assembly" if("") - if(!istype(W, /obj/item/weapon/gun/energy/advtaser)) + if(!istype(W, /obj/item/weapon/gun/energy/gun/advtaser)) return newname = "taser ED-209 assembly" else diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm index 12dd032ba49..34888dd3488 100644 --- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm +++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm @@ -365,7 +365,7 @@ Auto Patrol[]"}, new /obj/item/device/assembly/prox_sensor(Tsec) if(!lasercolor) - var/obj/item/weapon/gun/energy/advtaser/G = new /obj/item/weapon/gun/energy/advtaser(Tsec) + var/obj/item/weapon/gun/energy/gun/advtaser/G = new /obj/item/weapon/gun/energy/gun/advtaser(Tsec) G.power_supply.charge = 0 G.update_icon() else if(lasercolor == "b") @@ -403,7 +403,7 @@ Auto Patrol[]"}, shoot_sound = 'sound/weapons/laser.ogg' if(emagged == 2) if(lasercolor) - projectile = /obj/item/projectile/lasertag + projectile = /obj/item/projectile/beam/lasertag else projectile = /obj/item/projectile/beam else @@ -411,9 +411,9 @@ Auto Patrol[]"}, shoot_sound = 'sound/weapons/Taser.ogg' projectile = /obj/item/projectile/energy/electrode else if(lasercolor == "b") - projectile = /obj/item/projectile/lasertag/blue + projectile = /obj/item/projectile/beam/lasertag/bluetag else if(lasercolor == "r") - projectile = /obj/item/projectile/lasertag/red + projectile = /obj/item/projectile/beam/lasertag/redtag /mob/living/simple_animal/bot/ed209/proc/shootAt(mob/target) if(lastfired && world.time - lastfired < shot_delay) @@ -438,8 +438,7 @@ Auto Patrol[]"}, A.current = U A.yo = U.y - T.y A.xo = U.x - T.x - spawn(0) - A.process() + A.fire() /mob/living/simple_animal/bot/ed209/attack_alien(mob/living/carbon/alien/user) ..() @@ -491,10 +490,10 @@ Auto Patrol[]"}, if(!disabled) var/lasertag_check = 0 if((lasercolor == "b")) - if(istype(Proj, /obj/item/projectile/lasertag/red)) + if(istype(Proj, /obj/item/projectile/beam/lasertag/redtag)) lasertag_check++ else if((lasercolor == "r")) - if(istype(Proj, /obj/item/projectile/lasertag/blue)) + if(istype(Proj, /obj/item/projectile/beam/lasertag/bluetag)) lasertag_check++ if(lasertag_check) icon_state = "[lasercolor]ed2090" diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm index 3534bbf55b2..80bcbc679f0 100644 --- a/code/modules/mob/living/simple_animal/bot/medbot.dm +++ b/code/modules/mob/living/simple_animal/bot/medbot.dm @@ -492,7 +492,7 @@ if(reagent_id == "internal_beaker") if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume) var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1) - reagent_glass.reagents.reaction(patient, 2, fraction) + reagent_glass.reagents.reaction(patient, INGEST, fraction) reagent_glass.reagents.trans_to(patient, injection_amount) //Inject from beaker instead. else patient.reagents.add_reagent(reagent_id,injection_amount) diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm index 6c630ec0117..c894b014a87 100644 --- a/code/modules/mob/living/simple_animal/constructs.dm +++ b/code/modules/mob/living/simple_animal/constructs.dm @@ -20,6 +20,7 @@ flying = 1 universal_speak = 1 var/list/construct_spells = list() + loot = list(/obj/item/weapon/reagent_containers/food/snacks/ectoplasm) /mob/living/simple_animal/construct/New() ..() @@ -31,7 +32,6 @@ /mob/living/simple_animal/construct/death() ..() - new /obj/item/weapon/reagent_containers/food/snacks/ectoplasm (src.loc) for(var/mob/M in viewers(src, null)) if((M.client && !( M.blinded ))) M.show_message("\red [src] collapses in a shattered heap. ") diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm index c824351a7c8..e8ba27fa07d 100644 --- a/code/modules/mob/living/simple_animal/friendly/corgi.dm +++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm @@ -603,6 +603,7 @@ var/emagged = 0 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) minbodytemp = 0 + loot = list(/obj/effect/decal/cleanable/blood/gibs/robot) /mob/living/simple_animal/pet/corgi/Ian/borgi/emag_act(user as mob) if(!emagged) @@ -631,8 +632,7 @@ A.current = T A.yo = U.y - T.y A.xo = U.x - T.x - spawn( 0 ) - A.process() + A.fire() return /mob/living/simple_animal/pet/corgi/Ian/borgi/Life() @@ -651,10 +651,9 @@ /mob/living/simple_animal/pet/corgi/Ian/borgi/death() ..() visible_message("[src] blows apart!") - new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread s.set_up(3, 1, src) s.start() respawnable_list += src qdel(src) - return \ No newline at end of file + return diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm index 54b0d10608a..c24b0b6a844 100644 --- a/code/modules/mob/living/simple_animal/hostile/bees.dm +++ b/code/modules/mob/living/simple_animal/hostile/bees.dm @@ -140,13 +140,15 @@ /mob/living/simple_animal/hostile/poison/bees/worker/Destroy() if(beehome) - beehome.bees.Remove(src) + if(beehome.bees) + beehome.bees.Remove(src) beehome = null ..() /mob/living/simple_animal/hostile/poison/bees/worker/death(gibbed) if(beehome) - beehome.bees.Remove(src) + if(beehome.bees) + beehome.bees.Remove(src) beehome = null ..() @@ -159,8 +161,8 @@ /mob/living/simple_animal/hostile/poison/bees/worker/Found(atom/A) if(istype(A, /obj/machinery/portable_atmospherics/hydroponics)) var/obj/machinery/portable_atmospherics/hydroponics/Hydro = A - if(Hydro.seed && !Hydro.dead && !Hydro.recent_bee_visit) - wanted_objects |= /obj/machinery/portable_atmospherics/hydroponics //so we only hunt them while they're alive/seeded/not visisted + if(Hydro.seed && !Hydro.dead && !Hydro.recent_bee_visit && !Hydro.closed_system) + wanted_objects |= /obj/machinery/portable_atmospherics/hydroponics //so we only hunt them while they're alive/seeded/not visisted and uncovered return 1 ..() @@ -186,7 +188,7 @@ ..() /mob/living/simple_animal/hostile/poison/bees/worker/proc/pollinate(obj/machinery/portable_atmospherics/hydroponics/Hydro) - if(!istype(Hydro) || !Hydro.seed || Hydro.dead || Hydro.recent_bee_visit) + if(!istype(Hydro) || !Hydro.seed || Hydro.dead || Hydro.recent_bee_visit || Hydro.closed_system) target = null return @@ -205,11 +207,15 @@ if(prob(BEE_POLLINATE_YIELD_CHANCE)) //Yield mod is HELLA powerful, but quite rare if(!isnull(plant_controller.seeds[Hydro.seed.name])) Hydro.seed = Hydro.seed.diverge() + else + Hydro.seed.update_name_prefixes() var/seed_yield = Hydro.seed.get_trait(TRAIT_YIELD) Hydro.seed.set_trait(TRAIT_YIELD, seed_yield + 1, 10, 0) if(prob(BEE_POLLINATE_POTENTCY_CHANCE)) if(!isnull(plant_controller.seeds[Hydro.seed.name])) Hydro.seed = Hydro.seed.diverge() + else + Hydro.seed.update_name_prefixes() var/seed_potency = Hydro.seed.get_trait(TRAIT_POTENCY) Hydro.seed.set_trait(TRAIT_POTENCY, seed_potency + 1, 200, 0) diff --git a/code/modules/mob/living/simple_animal/hostile/hivebot.dm b/code/modules/mob/living/simple_animal/hostile/hivebot.dm index 4412dc77829..94cf8dae65c 100644 --- a/code/modules/mob/living/simple_animal/hostile/hivebot.dm +++ b/code/modules/mob/living/simple_animal/hostile/hivebot.dm @@ -23,6 +23,7 @@ minbodytemp = 0 speak_emote = list("states") gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE + loot = list(/obj/effect/decal/cleanable/blood/gibs/robot) /mob/living/simple_animal/hostile/hivebot/range name = "Hivebot" @@ -47,7 +48,6 @@ /mob/living/simple_animal/hostile/hivebot/death() ..() visible_message("[src] blows apart!") - new /obj/effect/decal/cleanable/blood/gibs/robot(src.loc) var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread s.set_up(3, 1, src) s.start() diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index b1627d17af0..ef048b351fd 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -118,8 +118,8 @@ return 1 if(istype(the_target, /obj/spacepod)) var/obj/spacepod/S = the_target - if(S.occupant || S.occupant2)//Just so we don't attack empty mechs - if(CanAttack(S.occupant) || CanAttack(S.occupant2)) + if(S.pilot) //Just so we don't attack empty pods + if(CanAttack(S.pilot)) return 1 if(isliving(the_target)) var/mob/living/L = the_target @@ -262,7 +262,8 @@ var/obj/item/projectile/A = new projectiletype(src.loc) playsound(user, projectilesound, 100, 1) - if(!A) return + if(!A) + return A.current = target A.firer = src @@ -272,7 +273,7 @@ newtonian_move(get_dir(target, user)) A.original = target spawn( 0 ) - A.process() + A.fire() return /mob/living/simple_animal/hostile/proc/DestroySurroundings() @@ -299,7 +300,7 @@ return /mob/living/simple_animal/hostile/proc/FindHidden() - if(istype(target.loc, /obj/structure/closet) || istype(target.loc, /obj/machinery/disposal) || istype(target.loc, /obj/machinery/sleeper)) + if(istype(target.loc, /obj/structure/closet) || istype(target.loc, /obj/machinery/disposal) || istype(target.loc, /obj/machinery/sleeper) || istype(target.loc, /obj/machinery/bodyscanner) || istype(target.loc, /obj/machinery/recharge_station)) var/atom/A = target.loc Goto(A,move_to_delay,minimum_distance) if(A.Adjacent(src)) diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm index 5a9f4a433af..6d2efd88010 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm @@ -73,6 +73,8 @@ aggro_vision_range = 9 idle_vision_range = 2 turns_per_move = 5 + loot = list(/obj/item/weapon/ore/diamond{layer = 4.1}, + /obj/item/weapon/ore/diamond{layer = 4.1}) /obj/item/projectile/temp/basilisk name = "freezing blast" @@ -100,14 +102,6 @@ if(3.0) adjustBruteLoss(110) -/mob/living/simple_animal/hostile/asteroid/basilisk/death() - if(stat != DEAD) - var/counter - for(counter=0, counter<2, counter++) - var/obj/item/weapon/ore/diamond/D = new /obj/item/weapon/ore/diamond(src.loc) - D.layer = 4.1 - ..() - /mob/living/simple_animal/hostile/asteroid/goldgrub name = "goldgrub" desc = "A worm that grows fat from eating everything in its sight. Seems to enjoy precious metals and other shiny things, hence the name." @@ -239,6 +233,7 @@ retreat_distance = 3 minimum_distance = 3 pass_flags = PASSTABLE + loot = list(/obj/item/organ/internal/hivelord_core) /mob/living/simple_animal/hostile/asteroid/hivelord/OpenFire(var/the_target) var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A = new /mob/living/simple_animal/hostile/asteroid/hivelordbrood(src.loc) @@ -250,11 +245,6 @@ /mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget() OpenFire() -/mob/living/simple_animal/hostile/asteroid/hivelord/death() - if(stat != DEAD) - new /obj/item/organ/internal/hivelord_core(src.loc) - ..() - /obj/item/organ/internal/hivelord_core name = "hivelord remains" desc = "All that remains of a hivelord, it seems to be what allows it to break pieces of itself off without being hurt... its healing properties will soon become inert if not used quickly. Try not to think about what you're eating." @@ -370,6 +360,7 @@ idle_vision_range = 5 anchored = 1 //Stays anchored until death as to be unpullable var/pre_attack = 0 + loot = list(/obj/item/asteroid/goliath_hide{layer = 4.1}) /mob/living/simple_animal/hostile/asteroid/goliath/process_ai() ..() @@ -386,13 +377,6 @@ anchored = 1 ..() -/mob/living/simple_animal/hostile/asteroid/goliath/death() - anchored = 0 - if(stat != DEAD) - var/obj/item/asteroid/goliath_hide/G = new /obj/item/asteroid/goliath_hide(src.loc) - G.layer = 4.1 - ..() - /mob/living/simple_animal/hostile/asteroid/goliath/OpenFire() var/tturf = get_turf(target) if(get_dist(src, target) <= 7)//Screen range check, so you can't get tentacle'd offscreen diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm index fbbc0d0a5e3..89835092ffd 100644 --- a/code/modules/mob/living/simple_animal/hostile/pirate.dm +++ b/code/modules/mob/living/simple_animal/hostile/pirate.dm @@ -22,9 +22,8 @@ atmos_requirements = list("min_oxy" = 5, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 1, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) unsuitable_atmos_damage = 15 speak_emote = list("yarrs") - var/corpse = /obj/effect/landmark/mobcorpse/pirate - var/weapon1 = /obj/item/weapon/melee/energy/sword/pirate - + loot = list(/obj/effect/landmark/mobcorpse/pirate, + /obj/item/weapon/melee/energy/sword/pirate) faction = list("pirate") /mob/living/simple_animal/hostile/pirate/ranged @@ -38,16 +37,12 @@ retreat_distance = 5 minimum_distance = 5 projectiletype = /obj/item/projectile/beam - corpse = /obj/effect/landmark/mobcorpse/pirate/ranged - weapon1 = /obj/item/weapon/gun/energy/laser + loot = list(/obj/effect/landmark/mobcorpse/pirate/ranged, + /obj/item/weapon/gun/energy/laser) /mob/living/simple_animal/hostile/pirate/death() ..() - if(corpse) - new corpse (src.loc) - if(weapon1) - new weapon1 (src.loc) ghostize() qdel(src) return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm index 5ee52bec825..71d088a425c 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/drone.dm @@ -150,8 +150,8 @@ walk(src,0) /mob/living/simple_animal/hostile/retaliate/malf_drone/death() - src.visible_message("\blue \icon[src] [src] suddenly breaks apart.") ..() + visible_message("\blue \icon[src] [src] suddenly breaks apart.") qdel(src) /mob/living/simple_animal/hostile/retaliate/malf_drone/Destroy() //Seriously, what the actual hell. diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm index cd34c8a6491..2e3718cd800 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/retaliate.dm @@ -14,7 +14,7 @@ return A else if(istype(A, /obj/spacepod)) var/obj/spacepod/M = A - if(M.occupant || M.occupant2) + if(M.pilot) return A /mob/living/simple_animal/hostile/retaliate/ListTargets() @@ -47,9 +47,9 @@ enemies |= M.occupant else if(istype(A, /obj/spacepod)) var/obj/spacepod/M = A - if(M.occupant || M.occupant2) + if(M.pilot) enemies |= M - enemies |= M.occupant + enemies |= M.pilot for(var/mob/living/simple_animal/hostile/retaliate/H in around) var/retaliate_faction_check = 0 diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm index 44de372550f..210ff43ebda 100644 --- a/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm +++ b/code/modules/mob/living/simple_animal/hostile/retaliate/undead.dm @@ -45,6 +45,7 @@ minbodytemp = 0 faction = list("undead") // did I mention ghost + loot = list(/obj/item/weapon/reagent_containers/food/snacks/ectoplasm) /mob/living/simple_animal/hostile/retaliate/ghost/Process_Spacemove(var/check_drift = 0) return 1 @@ -61,7 +62,7 @@ invisibility = pick(0,60,60,invisibility) ..() /mob/living/simple_animal/hostile/retaliate/ghost/death() - new /obj/item/weapon/reagent_containers/food/snacks/ectoplasm(loc) + ..() qdel(src) return @@ -90,9 +91,10 @@ minbodytemp = 0 faction = list("undead") + loot = list(/obj/effect/decal/remains/human) /mob/living/simple_animal/hostile/retaliate/skeleton/death() - new /obj/effect/decal/remains/human(loc) + ..() qdel(src) return @@ -121,8 +123,9 @@ minbodytemp = 0 faction = list("undead") + loot = list(/obj/effect/decal/cleanable/blood/gibs) /mob/living/simple_animal/hostile/retaliate/zombie/death() - new /obj/effect/decal/cleanable/blood/gibs(loc) + ..() qdel(src) return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm index 35cdbb14dfb..148eeeef9a7 100644 --- a/code/modules/mob/living/simple_animal/hostile/russian.dm +++ b/code/modules/mob/living/simple_animal/hostile/russian.dm @@ -19,35 +19,30 @@ attacktext = "punches" attack_sound = 'sound/weapons/punch1.ogg' a_intent = I_HARM - var/corpse = /obj/effect/landmark/mobcorpse/russian - var/weapon1 = /obj/item/weapon/kitchen/knife unsuitable_atmos_damage = 15 faction = list("russian") status_flags = CANPUSH + loot = list(/obj/effect/landmark/mobcorpse/russian, + /obj/item/weapon/kitchen/knife) /mob/living/simple_animal/hostile/russian/ranged icon_state = "russianranged" icon_living = "russianranged" - corpse = /obj/effect/landmark/mobcorpse/russian/ranged - weapon1 = /obj/item/weapon/gun/projectile/revolver/mateba ranged = 1 retreat_distance = 5 minimum_distance = 5 projectiletype = /obj/item/projectile/bullet projectilesound = 'sound/weapons/Gunshot.ogg' casingtype = /obj/item/ammo_casing/a357 + loot = list(/obj/effect/landmark/mobcorpse/russian/ranged, /obj/item/weapon/gun/projectile/revolver/mateba) -/mob/living/simple_animal/hostile/russian/ranged/New() - if(prob(50) && ispath(weapon1,/obj/item/weapon/gun/projectile/revolver/mateba)) //to preserve varedits - weapon1 = /obj/item/weapon/gun/projectile/shotgun/boltaction - casingtype = /obj/item/ammo_casing/a762 +/mob/living/simple_animal/hostile/russian/ranged/mosin + loot = list(/obj/effect/landmark/mobcorpse/russian/ranged, + /obj/item/weapon/gun/projectile/shotgun/boltaction) + casingtype = /obj/item/ammo_casing/a762 /mob/living/simple_animal/hostile/russian/death() ..() - if(corpse) - new corpse (src.loc) - if(weapon1) - new weapon1 (src.loc) qdel(src) return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm index 0ce0cc71a86..5546547046d 100644 --- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm +++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm @@ -19,22 +19,14 @@ attacktext = "punches" attack_sound = 'sound/weapons/punch1.ogg' a_intent = I_HARM - var/corpse = /obj/effect/landmark/mobcorpse/syndicatesoldier - var/weapon1 - var/weapon2 unsuitable_atmos_damage = 15 faction = list("syndicate") check_friendly_fire = 1 status_flags = CANPUSH + loot = list(/obj/effect/landmark/mobcorpse/syndicatesoldier) /mob/living/simple_animal/hostile/syndicate/death() ..() - if(corpse) - new corpse (src.loc) - if(weapon1) - new weapon1 (src.loc) - if(weapon2) - new weapon2 (src.loc) qdel(src) return @@ -45,11 +37,10 @@ melee_damage_upper = 25 icon_state = "syndicatemelee" icon_living = "syndicatemelee" - weapon1 = /obj/item/weapon/melee/energy/sword/saber/red - weapon2 = /obj/item/weapon/shield/energy attacktext = "slashes" attack_sound = 'sound/weapons/bladeslice.ogg' status_flags = 0 + loot = list(/obj/effect/landmark/mobcorpse/syndicatesoldier, /obj/item/weapon/melee/energy/sword/saber/red, /obj/item/weapon/shield/energy) /mob/living/simple_animal/hostile/syndicate/melee/attackby(var/obj/item/O as obj, var/mob/user as mob, params) if(O.force) @@ -83,8 +74,8 @@ icon_state = "syndicatemeleespace" icon_living = "syndicatemeleespace" name = "Syndicate Commando" - corpse = /obj/effect/landmark/mobcorpse/syndicatecommando speed = 1 + loot = list(/obj/effect/landmark/mobcorpse/syndicatecommando, /obj/item/weapon/melee/energy/sword/saber/red, /obj/item/weapon/shield/energy) /mob/living/simple_animal/hostile/syndicate/melee/space/Process_Spacemove(var/movement_dir = 0) return @@ -99,8 +90,7 @@ casingtype = /obj/item/ammo_casing/c45 projectilesound = 'sound/weapons/Gunshot_smg.ogg' projectiletype = /obj/item/projectile/bullet/midbullet2 - - weapon1 = /obj/item/weapon/gun/projectile/automatic/c20r + loot = list(/obj/effect/landmark/mobcorpse/syndicatesoldier, /obj/item/weapon/gun/projectile/automatic/c20r) /mob/living/simple_animal/hostile/syndicate/ranged/space icon_state = "syndicaterangedpsace" @@ -108,8 +98,9 @@ name = "Syndicate Commando" 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) minbodytemp = 0 - corpse = /obj/effect/landmark/mobcorpse/syndicatecommando speed = 1 + loot = list(/obj/effect/landmark/mobcorpse/syndicatecommando, /obj/item/weapon/gun/projectile/automatic/c20r) + /mob/living/simple_animal/hostile/syndicate/ranged/space/Process_Spacemove(var/movement_dir = 0) return diff --git a/code/modules/mob/living/simple_animal/hostile/tree.dm b/code/modules/mob/living/simple_animal/hostile/tree.dm index bd39b681978..b47312b15df 100644 --- a/code/modules/mob/living/simple_animal/hostile/tree.dm +++ b/code/modules/mob/living/simple_animal/hostile/tree.dm @@ -28,6 +28,7 @@ minbodytemp = 0 faction = list("hostile", "winter") + loot = list(/obj/item/stack/sheet/wood) gold_core_spawnable = CHEM_MOB_SPAWN_HOSTILE /mob/living/simple_animal/hostile/tree/FindTarget() @@ -46,5 +47,4 @@ /mob/living/simple_animal/hostile/tree/death() ..() visible_message("\red [src] is hacked into pieces!") - new /obj/item/stack/sheet/wood(loc) qdel(src) \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm b/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm index 5710005846c..12ede5955ea 100644 --- a/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/winter_mobs.dm @@ -20,15 +20,12 @@ melee_damage_lower = 3 melee_damage_upper = 7 - var/weapon1 - /mob/living/simple_animal/hostile/winter/snowman name = "snowman" desc = "A very angry snowman. Doesn't look like it wants to play around..." icon_state = "snowman" icon_living = "snowman" icon_dead = "snowman-dead" - weapon1 = /obj/item/weapon/melee/candy_sword bodytemperature = 73.0 //it's made of snow and hatred, so it's pretty cold. maxbodytemp = 280.15 //at roughly 7 C, these will start melting (dying) from the warmth. Mind over matter or something. @@ -37,10 +34,10 @@ /mob/living/simple_animal/hostile/winter/snowman/death() - if(weapon1 && prob(50)) //50% chance to drop weapon on death, if it has one to drop - new weapon1(get_turf(src)) + if(prob(50)) //50% chance to drop weapon on death, if it has one to drop + loot = list(/obj/item/weapon/melee/candy_sword) if(prob(20)) //chance to become a stationary snowman structure instead of a corpse - new /obj/structure/snowman(get_turf(src)) + loot.Add(/obj/structure/snowman) visible_message("The [src.name] shimmers as its animating magic fades away!") ..() //this is just to make sure it gets properly killed before we qdel it qdel(src) @@ -52,7 +49,6 @@ retreat_distance = 5 minimum_distance = 5 projectiletype = /obj/item/projectile/snowball - weapon1 = null /mob/living/simple_animal/hostile/winter/reindeer name = "reindeer" diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm index aa924444a3a..6e528516e3e 100644 --- a/code/modules/mob/living/simple_animal/parrot.dm +++ b/code/modules/mob/living/simple_animal/parrot.dm @@ -36,7 +36,11 @@ small = 1 can_collar = 1 - speak = list("Hi","Hello!","Cracker?","BAWWWWK george mellons griffing me") + var/list/clean_speak = list( + "Hi", + "Hello!", + "Cracker?", + "BAWWWWK george mellons griffing me") speak_emote = list("squawks","says","yells") emote_hear = list("squawks","bawks") emote_see = list("flutters its wings") @@ -95,6 +99,7 @@ /obj/item/device/radio/headset/headset_sci, \ /obj/item/device/radio/headset/headset_cargo) ears = new headset(src) + update_speak() parrot_sleep_dur = parrot_sleep_max //In case someone decides to change the max without changing the duration var @@ -153,14 +158,12 @@ if("ears") if(ears) if(available_channels.len) - src.say("[pick(available_channels)]BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") + say("[pick(available_channels)]BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") else - src.say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") - ears.loc = src.loc + say("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!") + ears.forceMove(loc) ears = null - for(var/possible_phrase in speak) - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = copytext(possible_phrase,3,length(possible_phrase)) + update_speak() else to_chat(usr, "\red There is nothing to remove from its [remove_from].") return @@ -187,11 +190,11 @@ var/obj/item/device/radio/headset/headset_to_add = item_to_add usr.drop_item() - headset_to_add.loc = src - src.ears = headset_to_add + headset_to_add.forceMove(src) + ears = headset_to_add to_chat(usr, "You fit the headset onto [src].") - clearlist(available_channels) + available_channels.Cut() for(var/ch in headset_to_add.channels) switch(ch) if("Engineering") @@ -211,6 +214,7 @@ if(headset_to_add.translate_binary) available_channels.Add(":b") + update_speak() show_inv(usr) else ..() @@ -279,7 +283,19 @@ if(pulledby && stat == CONSCIOUS) icon_state = "parrot_fly" -/mob/living/simple_animal/parrot/process_ai() +/mob/living/simple_animal/parrot/proc/update_speak() + speak.Cut() + + if(available_channels.len && ears) + for(var/possible_phrase in clean_speak) + //50/50 chance to not use the radio at all + speak += "[prob(50) ? pick(available_channels) : ""][possible_phrase]" + + else //If we have no headset or channels to use, dont try to use any! + for(var/possible_phrase in clean_speak) + speak += possible_phrase + +/mob/living/simple_animal/parrot/handle_automated_movement() if(pulledby) parrot_state = PARROT_WANDER return @@ -294,11 +310,11 @@ Every once in a while, the parrot picks one of the lines from the buffer and replaces an element of the 'speech' list. Then it clears the buffer to make sure they dont magically remember something from hours ago. */ if(speech_buffer.len && prob(10)) - if(speak.len) - speak.Remove(pick(speak)) + if(clean_speak.len) + clean_speak -= pick(clean_speak) - speak.Add(pick(speech_buffer)) - clearlist(speech_buffer) + clean_speak += pick(speech_buffer) + speech_buffer.Cut() //-----SLEEPING @@ -321,30 +337,7 @@ parrot_sleep_dur = parrot_sleep_max //Cycle through message modes for the headset - if(speak.len) - var/list/newspeak = list() - - if(available_channels.len && src.ears) - for(var/possible_phrase in speak) - - //50/50 chance to not use the radio at all - var/useradio = 0 - if(prob(50)) - useradio = 1 - - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = "[useradio?pick(available_channels):""][copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix - else - possible_phrase = "[useradio?pick(available_channels):""][possible_phrase]" - - newspeak.Add(possible_phrase) - - else //If we have no headset or channels to use, dont try to use any! - for(var/possible_phrase in speak) - if(copytext(possible_phrase,1,3) in department_radio_keys) - possible_phrase = "[copytext(possible_phrase,3,length(possible_phrase)+1)]" //crop out the channel prefix - newspeak.Add(possible_phrase) - speak = newspeak + update_speak() //Search for item to steal parrot_interest = search_for_item() @@ -686,7 +679,14 @@ /mob/living/simple_animal/parrot/Poly name = "Poly" desc = "Poly the Parrot. An expert on quantum cracker theory." - speak = list("Poly wanna cracker!", ":eCheck the singlo, you chucklefucks!",":eCheck the tesla, you shits!",":eSTOP HOT-WIRING THE ENGINE, FUCKING CHRIST!",":eWire the solars, you lazy bums!",":eWHO TOOK THE DAMN HARDSUITS?",":eOH GOD ITS FREE CALL THE SHUTTLE") + clean_speak = list( + "Poly wanna cracker!", + "Check the singlo, you chucklefucks!", + "Check the tesla, you shits!", + "STOP HOT-WIRING THE ENGINE, FUCKING CHRIST!", + "Wire the solars, you lazy bums!", + "WHO TOOK THE DAMN HARDSUITS?", + "OH GOD ITS FREE CALL THE SHUTTLE") gold_core_spawnable = CHEM_MOB_SPAWN_INVALID /mob/living/simple_animal/parrot/Poly/New() @@ -700,15 +700,15 @@ used_radios += ears /mob/living/simple_animal/parrot/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null) - if(prob(50)) + if(speaker != src && prob(50)) parrot_hear(html_decode(message)) ..() /mob/living/simple_animal/parrot/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/mob/speaker = null, var/hard_to_hear = 0, var/atom/follow_target) - if(prob(50)) - parrot_hear("[pick(available_channels)][html_decode(message)]") + if(speaker != src && prob(50)) + parrot_hear(html_decode(message)) ..() diff --git a/code/modules/mob/living/simple_animal/posessed_object.dm b/code/modules/mob/living/simple_animal/posessed_object.dm new file mode 100644 index 00000000000..0029bbec7fd --- /dev/null +++ b/code/modules/mob/living/simple_animal/posessed_object.dm @@ -0,0 +1,154 @@ +/mob/living/simple_animal/possessed_object + name = "possessed doodad" + var/spirit_name = "mysterious force" // What we call ourselves in attack messages. + health = 50 + maxHealth = 50 + + pass_flags = PASSTABLE // Floating past tables is pretty damn spooky. + status_flags = null // No canpush to prevent grabs ... + density = 0 // ... But a density of 0 means we won't be blocking anyone's way. + healable = 0 // Animated with SPACE NECROMANCY, mere mortal medicines cannot heal such an object. + wander = 0 // These things probably ought to never be AI controlled, but in the event they are probably shouldn't wander. + + universal_speak = 1 // Tell the humans spooky things about the afterlife + speak_emote = list("mumbles", "moans", "whispers", "laments", "screeches") + + allow_spin = 0 // No spinning. Spinning breaks our floating animation and broken floating animations make ghosts SUPER ANGRY. + no_spin_thrown = 1 + + var/obj/item/possessed_item + + +/mob/living/simple_animal/possessed_object/examine() + possessed_item.examine() + if(health > (maxHealth / 30)) + to_chat(usr, "[src] appears to be floating without any support!") + else + to_chat(usr, "[src] appears to be having trouble staying afloat!") + + +/mob/living/simple_animal/possessed_object/do_attack_animation(atom/A) + ..() + animate_ghostly_presence(src, -1, 20, 1) // Restart the floating animation after the attack animation, as it will be cancelled. + + +/mob/living/simple_animal/possessed_object/start_pulling(var/atom/movable/AM) // Silly motherfuckers think they can pull things. + to_chat(src, "You are unable to pull [AM]!") + + +/mob/living/simple_animal/possessed_object/ghost() // Ghosting will return the object to normal, and will not disqualify the ghoster from various mid-round antag positions. + var/response = alert(src, "End your possession of this object? (It will not stop you from respawning later)","Are you sure you want to ghost?","Ghost","Stay in body") + if(response != "Ghost") + return + resting = 1 + var/mob/dead/observer/ghost = ghostize(1) + ghost.timeofdeath = world.time + death(0) // Turn back into a regular object. + + +/mob/living/simple_animal/possessed_object/death(gibbed) + ..() + + if(gibbed) // Leave no trace. + var/mob/dead/observer/ghost = ghostize(1) + ghost.timeofdeath = world.time + qdel(src) + return + + possessed_item.forceMove(loc) // Put the normal item back once the EVIL SPIRIT has been vanquished from it. + qdel(src) + + +/mob/living/simple_animal/possessed_object/Life() + ..() + + if(!possessed_item) // If we're a donut and someone's eaten us, for instance. + death(1) + + if(possessed_item.loc != src) + forceMove(possessed_item.loc) + possessed_item.forceMove(src) + + if(l_hand) // Incase object interactions put things directly into our hands. (Like cameras, or gun magizines) + drop_l_hand() + if(r_hand) + drop_r_hand() + +/mob/living/simple_animal/possessed_object/New(var/atom/loc as obj) + ..() + + if (!istype(loc, /obj/item)) // Some silly motherfucker spawned us directly via the game panel. + message_admins("Posessed object improperly spawned, deleting.") // So silly admins with debug off will see the message too and not spam these things. + log_debug("[src] spawned manually, no object to assign attributes to.") + qdel() + + var/turf/possessed_loc = get_turf(loc) + if(!istype(possessed_loc)) // Will this ever happen? Who goddamn knows. + message_admins("Posessed object could not find turf, deleting.") // So silly admins with debug off will see the message too and not spam these things. + log_debug("[src] attempted to find a turf to spawn on, and could not.") + qdel() + + possessed_item = loc + forceMove(possessed_loc) + possessed_item.forceMove(src) // We'll keep the actual item inside of us until we die. + + zone_sel = new /obj/screen/zone_sel(src) // Create a new zone selection item so the human attacks have something to reference. + + name = possessed_item.name // Take on all the attributes of the item we've possessed. + real_name = name + desc = possessed_item.desc + icon = possessed_item.icon + icon_living = possessed_item.icon_state + icon_state = possessed_item.icon_state + dir = possessed_item.dir + color = possessed_item.color + overlays = possessed_item.overlays + opacity = possessed_item.opacity + + visible_message("[src] rises into the air and begins to float!") // Inform those around us that shit's gettin' spooky. + animate_ghostly_presence(src, -1, 20, 1) + + +/mob/living/simple_animal/possessed_object/get_active_hand() // So that our attacks count as attacking with the item we've possessed. + return possessed_item + + +/mob/living/simple_animal/possessed_object/IsAdvancedToolUser() // So we can shoot guns (Mostly ourselves), among other things. + return 1 + + +/mob/living/simple_animal/possessed_object/get_access() // If we've possessed an ID card we've got access to lots of fun things! + if(istype(possessed_item, /obj/item/weapon/card/id)) + var/obj/item/weapon/card/id/possessed_id = possessed_item + . = possessed_id.access + + +/mob/living/simple_animal/possessed_object/ClickOn(var/atom/A, var/params) + if(client.click_intercept) + client.click_intercept.InterceptClickOn(src, params, A) + return + + if(!istype(loc, /turf)) // If we're inside a card machine or something similar then you're stuck. + return + + name = spirit_name + + if(A == src) // If we're clicking ourself we should not attack ourself. + possessed_item.attack_self(src) + else + ..() + + if(possessed_item.loc != src) // If we've, say, placed the possessed item on the table move onto the table ourselves instead and put it back inside of us. + forceMove(possessed_item.loc) + possessed_item.forceMove(src) + + name = possessed_item.name // Update our status + real_name = name + desc = possessed_item.desc + icon = possessed_item.icon + icon_living = possessed_item.icon_state + icon_state = possessed_item.icon_state + dir = possessed_item.dir + color = possessed_item.color + overlays = possessed_item.overlays + opacity = possessed_item.opacity \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm index 0e01aa51894..9aff96b1fcf 100644 --- a/code/modules/mob/living/simple_animal/shade.dm +++ b/code/modules/mob/living/simple_animal/shade.dm @@ -24,11 +24,11 @@ status_flags = 0 faction = list("cult") status_flags = CANPUSH + loot = list(/obj/item/weapon/reagent_containers/food/snacks/ectoplasm) death() ..() - new /obj/item/weapon/reagent_containers/food/snacks/ectoplasm (src.loc) for(var/mob/M in viewers(src, null)) if((M.client && !( M.blinded ))) M.show_message("\red [src] lets out a contented sigh as their form unwinds. ") diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index bb84eccc66b..9eee62d810a 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -71,6 +71,7 @@ var/master_commander = null //holding var for determining who own/controls a sentient simple animal (for sentience potions). var/sentience_type = SENTIENCE_ORGANIC // Sentience type, for slime potions + var/list/loot = list() //list of things spawned at mob's loc when it dies /mob/living/simple_animal/New() @@ -467,6 +468,9 @@ stat(null, "Health: [round((health / maxHealth) * 100)]%") /mob/living/simple_animal/death(gibbed) + if(loot.len) + for(var/i in loot) + new i(loc) health = 0 icon_state = icon_dead stat = DEAD @@ -532,7 +536,7 @@ return 0 if (istype(the_target,/obj/spacepod)) var/obj/spacepod/S = the_target - if (S.occupant || S.occupant2) + if (S.pilot) return 0 return 1 @@ -668,7 +672,7 @@ if(!can_collar || collar) return var/obj/item/clothing/accessory/petcollar/C = usr.get_active_hand() - if(!C) + if(!istype(C)) usr.visible_message("[usr] rubs [src]'s neck.","You rub [src]'s neck for a moment.") return usr.drop_item() diff --git a/code/modules/mob/living/simple_animal/vox.dm b/code/modules/mob/living/simple_animal/vox.dm index 3b34ddaf143..1a46e46e4e4 100644 --- a/code/modules/mob/living/simple_animal/vox.dm +++ b/code/modules/mob/living/simple_animal/vox.dm @@ -65,15 +65,26 @@ if ((O.client && !( O.blinded ))) to_chat(O, "\red [src] launches a razor-sharp quill at [target]!") - var/obj/item/weapon/arrow/quill/Q = new(loc) + var/obj/item/weapon/quill/Q = new(loc) Q.fingerprintslast = src.ckey Q.throw_at(target,10,30) + quills-- spawn(100) to_chat(src, "\red You feel a fresh quill slide into place.") quills++ +/obj/item/weapon/quill + name = "vox quill" + desc = "A wickedly barbed quill from some bizarre animal." + icon_state = "quill" + item_state = "quill" + throwforce = 5 + w_class = 3.0 + sharp = 1 + edge = 0 + /mob/living/simple_animal/vox/armalis/verb/message_mob() set category = "Alien" set name = "Commune with creature" @@ -155,4 +166,4 @@ desc = "A series of metallic lenses and chains." icon = 'icons/obj/clothing/hats.dmi' icon_state = "amp" - item_state = "amp" \ No newline at end of file + item_state = "amp" diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 5e715255999..8c33a17e829 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -904,13 +904,8 @@ var/list/slot_equipment_priority = list( \ /mob/proc/can_use_hands() return -/mob/proc/is_active() - return (0 >= usr.stat) - /mob/proc/is_mechanical() - if(mind && (mind.assigned_role == "Cyborg" || mind.assigned_role == "AI")) - return 1 - return istype(src, /mob/living/silicon) || get_species() == "Machine" + return mind && (mind.assigned_role == "Cyborg" || mind.assigned_role == "AI") /mob/proc/is_ready() return client && !!mind @@ -937,19 +932,9 @@ var/list/slot_equipment_priority = list( \ /mob/proc/get_gender() return gender -/mob/proc/see(message) - if(!is_active()) - return 0 - to_chat(src, message) - return 1 - /mob/proc/is_muzzled() return 0 -/mob/proc/show_viewers(message) - for(var/mob/M in viewers()) - M.see(message) - /mob/Stat() ..() diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 98437a53ffd..fee4897f375 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -93,13 +93,15 @@ hud.screen_loc = ui_rhand else hud.screen_loc = ui_lhand - + assailant.client.screen += hud /obj/item/weapon/grab/process() - if(!confirm()) return //If the confirm fails, the grab is about to be deleted. That means it shouldn't continue processing. + if(!confirm()) + return //If the confirm fails, the grab is about to be deleted. That means it shouldn't continue processing. if(assailant.client) - if(!hud) return //this somehow can runtime under the right circumstances + if(!hud) + return //this somehow can runtime under the right circumstances assailant.client.screen -= hud assailant.client.screen += hud @@ -136,12 +138,8 @@ hud.icon_state = "!reinforce" if(state >= GRAB_AGGRESSIVE) - var/h = affecting.hand - affecting.hand = 0 - affecting.drop_item() - affecting.hand = 1 - affecting.drop_item() - affecting.hand = h + affecting.drop_r_hand() + affecting.drop_l_hand() //var/announce = 0 @@ -440,7 +438,13 @@ affecting.pixel_y = 0 //used to be an animate, not quick enough for del'ing affecting.layer = initial(affecting.layer) affecting.grabbed_by -= src + affecting = null + if(assailant) + if(assailant.client) + assailant.client.screen -= hud + assailant = null qdel(hud) + hud = null return ..() diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index f9023a97dd3..8d57d115ebe 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -304,26 +304,38 @@ ///Called by client/Move() ///Checks to see if you are being grabbed and if so attemps to break it /client/proc/Process_Grab() - if(locate(/obj/item/weapon/grab, locate(/obj/item/weapon/grab, mob.grabbed_by.len))) + if(mob.grabbed_by.len) var/list/grabbing = list() + if(istype(mob.l_hand, /obj/item/weapon/grab)) var/obj/item/weapon/grab/G = mob.l_hand grabbing += G.affecting + if(istype(mob.r_hand, /obj/item/weapon/grab)) var/obj/item/weapon/grab/G = mob.r_hand grabbing += G.affecting - for(var/obj/item/weapon/grab/G in mob.grabbed_by) - if((G.state == 1)&&(!grabbing.Find(G.assailant))) qdel(G) - if(G.state == 2) - move_delay = world.time + 10 - if(!prob(25)) return 1 - mob.visible_message("\red [mob] has broken free of [G.assailant]'s grip!") - qdel(G) - if(G.state == 3) - move_delay = world.time + 10 - if(!prob(5)) return 1 - mob.visible_message("\red [mob] has broken free of [G.assailant]'s headlock!") - qdel(G) + + for(var/X in mob.grabbed_by) + var/obj/item/weapon/grab/G = X + switch(G.state) + + if(GRAB_PASSIVE) + if(!grabbing.Find(G.assailant)) //moving always breaks a passive grab unless we are also grabbing our grabber. + qdel(G) + + if(GRAB_AGGRESSIVE) + move_delay = world.time + 10 + if(!prob(25)) + return 1 + mob.visible_message("[mob] has broken free of [G.assailant]'s grip!") + qdel(G) + + if(GRAB_NECK) + move_delay = world.time + 10 + if(!prob(5)) + return 1 + mob.visible_message("[mob] has broken free of [G.assailant]'s headlock!") + qdel(G) return 0 diff --git a/code/modules/mob/new_player/login.dm b/code/modules/mob/new_player/login.dm index f6e2441e876..f7cff248519 100644 --- a/code/modules/mob/new_player/login.dm +++ b/code/modules/mob/new_player/login.dm @@ -44,4 +44,3 @@ tally++ if(tally > config.player_overflow_cap) src << link(config.overflow_server_url) - diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm index ffb6f6c13b8..f961055ca56 100644 --- a/code/modules/mob/new_player/new_player.dm +++ b/code/modules/mob/new_player/new_player.dm @@ -88,13 +88,17 @@ stat("Time To Start:", "DELAYED") if(ticker.current_state == GAME_STATE_PREGAME) - stat("Players: [totalPlayers]", "Players Ready: [totalPlayersReady]") + stat("Players:", "[totalPlayers]") + if(client.holder) + stat("Players Ready:", "[totalPlayersReady]") totalPlayers = 0 totalPlayersReady = 0 for(var/mob/new_player/player in player_list) - stat("[player.key]", (player.ready)?("(Playing)"):(null)) + if(client.holder) + stat("[player.key]", (player.ready)?("(Playing)"):(null)) totalPlayers++ - if(player.ready)totalPlayersReady++ + if(player.ready) + totalPlayersReady++ /mob/new_player/Topic(href, href_list[]) if(!client) return 0 @@ -442,14 +446,14 @@ chosen_species = all_species[client.prefs.species] if(!(chosen_species && (is_species_whitelisted(chosen_species) || has_admin_rights()))) // Have to recheck admin due to no usr at roundstart. Latejoins are fine though. - log_to_dd("[src] had species [client.prefs.species], though they weren't supposed to. Setting to Human.") + log_debug("[src] had species [client.prefs.species], though they weren't supposed to. Setting to Human.") client.prefs.species = "Human" var/datum/language/chosen_language if(client.prefs.language) chosen_language = all_languages[client.prefs.language] - if(!((chosen_language || client.prefs.language == "None") && (is_alien_whitelisted(src, client.prefs.language) || !config.usealienwhitelist || !(chosen_language.flags & WHITELISTED)))) - log_to_dd("[src] had language [client.prefs.language], though they weren't supposed to. Setting to None.") + if((chosen_language == null && client.prefs.language != "None") || (chosen_language && chosen_language.flags & RESTRICTED)) + log_debug("[src] had language [client.prefs.language], though they weren't supposed to. Setting to None.") client.prefs.language = "None" /mob/new_player/proc/ViewManifest() diff --git a/code/modules/mob/new_player/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories.dm index e0fbfcdf91b..93797b5bb17 100644 --- a/code/modules/mob/new_player/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories.dm @@ -886,12 +886,12 @@ species_allowed = list("Vox") vox_quills_fluff - name = "Fluffy Quills" + name = "Fluffy Vox Quills" icon_state = "vox_afro" species_allowed = list("Vox") vox_quills_mohawk - name = "Quill Mohawk" + name = "Vox Quill Mohawk" icon_state = "vox_mohawk" species_allowed = list("Vox") @@ -910,6 +910,11 @@ icon_state = "vox_nights" species_allowed = list("Vox") + vox_razor + name = "Vox Razorback" + icon_state = "vox_razor" + species_allowed = list("Vox") + // Apollo-specific //Wryn antennae @@ -1893,22 +1898,22 @@ icon_state = "markings_tiger" /datum/sprite_accessory/body_markings/tigerhead - name = "Tiger Body + Head" + name = "Tiger Body and Head" species_allowed = list("Unathi", "Tajaran", "Vulpkanin") icon_state = "markings_tigerhead" /datum/sprite_accessory/body_markings/tigerheadface_taj - name = "Tajaran Tiger Body + Head + Face" + name = "Tajaran Tiger Body, Head and Face" species_allowed = list("Tajaran") icon_state = "markings_tigerheadface_taj" /datum/sprite_accessory/body_markings/tigerheadface_vulp - name = "Vulpkanin Tiger Body + Head + Face" + name = "Vulpkanin Tiger Body, Head and Face" species_allowed = list("Vulpkanin") icon_state = "markings_tigerheadface_vulp" /datum/sprite_accessory/body_markings/tigerheadface_una - name = "Unathi Tiger Body + Head + Face" + name = "Unathi Tiger Body, Head and Face" species_allowed = list("Unathi") icon_state = "markings_tigerheadface_una" diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index e5b12ed022b..e3e8d4620be 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -40,7 +40,7 @@ usr.emote(message) /mob/proc/say_dead(var/message) - if(!src.client.holder) + if(!(client && client.holder)) if(!config.dsay_allowed) to_chat(src, "Deadchat is globally muted.") return diff --git a/code/modules/mob/spirit/spirit.dm b/code/modules/mob/spirit/spirit.dm index a9b10f8224f..a8667567d03 100644 --- a/code/modules/mob/spirit/spirit.dm +++ b/code/modules/mob/spirit/spirit.dm @@ -25,7 +25,7 @@ mob/spirit var/follow_target = null -mob/spirit/is_active() +mob/spirit/proc/is_active() if (client && client.inactivity <= 10 * 60 * 10) return TRUE return FALSE diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm index ac3dd8af716..ea70bbe88ac 100644 --- a/code/modules/mob/transform_procs.dm +++ b/code/modules/mob/transform_procs.dm @@ -319,6 +319,35 @@ qdel(src) + +/mob/living/carbon/human/proc/paize(var/name) + if(notransform) + return + for(var/obj/item/W in src) + unEquip(W) + regenerate_icons() + notransform = 1 + canmove = 0 + icon = null + invisibility = 101 + for(var/t in organs) //this really should not be necessary + qdel(t) + + var/obj/item/device/paicard/card = new(loc) + var/mob/living/silicon/pai/pai = new(card) + pai.key = key + card.setPersonality(pai) + + pai.name = name + pai.real_name = name + card.name = name + + to_chat(pai, "You have become a pAI! Your name is [pai.name].") + pai.update_pipe_vision() + spawn(0)//To prevent the proc from returning null. + qdel(src) + return + /mob/proc/safe_respawn(var/MP) if(!MP) return 0 diff --git a/code/modules/nano/modules/human_appearance.dm b/code/modules/nano/modules/human_appearance.dm index 606dcade9c9..583b68b3dc6 100644 --- a/code/modules/nano/modules/human_appearance.dm +++ b/code/modules/nano/modules/human_appearance.dm @@ -2,9 +2,13 @@ name = "Appearance Editor" var/flags = APPEARANCE_ALL_HAIR var/mob/living/carbon/human/owner = null + var/obj/item/organ/external/head/head_organ = null var/list/valid_species = list() var/list/valid_hairstyles = list() var/list/valid_facial_hairstyles = list() + var/list/valid_head_accessories = list() + var/list/valid_marking_styles = list() + var/list/valid_body_accessories = list() var/check_whitelist var/list/whitelist @@ -13,6 +17,7 @@ /datum/nano_module/appearance_changer/New(var/location, var/mob/living/carbon/human/H, var/check_species_whitelist = 1, var/list/species_whitelist = list(), var/list/species_blacklist = list()) ..() owner = H + head_organ = owner.get_organ("head") src.check_whitelist = check_species_whitelist src.whitelist = species_whitelist src.blacklist = species_blacklist @@ -54,7 +59,7 @@ return 1 if(href_list["hair_color"]) if(can_change(APPEARANCE_HAIR_COLOR)) - var/new_hair = input("Please select hair color.", "Hair Color", rgb(owner.r_hair, owner.g_hair, owner.b_hair)) as color|null + var/new_hair = input("Please select hair color.", "Hair Color", rgb(head_organ.r_hair, head_organ.g_hair, head_organ.b_hair)) as color|null if(new_hair && can_still_topic(state)) var/r_hair = hex2num(copytext(new_hair, 2, 4)) var/g_hair = hex2num(copytext(new_hair, 4, 6)) @@ -69,7 +74,7 @@ return 1 if(href_list["facial_hair_color"]) if(can_change(APPEARANCE_FACIAL_HAIR_COLOR)) - var/new_facial = input("Please select facial hair color.", "Facial Hair Color", rgb(owner.r_facial, owner.g_facial, owner.b_facial)) as color|null + var/new_facial = input("Please select facial hair color.", "Facial Hair Color", rgb(head_organ.r_facial, head_organ.g_facial, head_organ.b_facial)) as color|null if(new_facial && can_still_topic(state)) var/r_facial = hex2num(copytext(new_facial, 2, 4)) var/g_facial = hex2num(copytext(new_facial, 4, 6)) @@ -87,6 +92,41 @@ if(owner.change_eye_color(r_eyes, g_eyes, b_eyes)) update_dna() return 1 + if(href_list["head_accessory"]) + if(can_change_head_accessory() && (href_list["head_accessory"] in valid_head_accessories)) + if(owner.change_head_accessory(href_list["head_accessory"])) + update_dna() + return 1 + if(href_list["head_accessory_color"]) + if(can_change_head_accessory()) + var/new_head_accessory = input("Please select head accessory color.", "Head Accessory Color", rgb(head_organ.r_headacc, head_organ.g_headacc, head_organ.b_headacc)) as color|null + if(new_head_accessory && can_still_topic(state)) + var/r_headacc = hex2num(copytext(new_head_accessory, 2, 4)) + var/g_headacc = hex2num(copytext(new_head_accessory, 4, 6)) + var/b_headacc = hex2num(copytext(new_head_accessory, 6, 8)) + if(owner.change_head_accessory_color(r_headacc, g_headacc, b_headacc)) + update_dna() + return 1 + if(href_list["marking"]) + if(can_change_markings() && (href_list["marking"] in valid_marking_styles)) + if(owner.change_markings(href_list["marking"])) + update_dna() + return 1 + if(href_list["marking_color"]) + if(can_change_markings()) + var/new_markings = input("Please select marking color.", "Marking Color", rgb(owner.r_markings, owner.g_markings, owner.b_markings)) as color|null + if(new_markings && can_still_topic(state)) + var/r_markings = hex2num(copytext(new_markings, 2, 4)) + var/g_markings = hex2num(copytext(new_markings, 4, 6)) + var/b_markings = hex2num(copytext(new_markings, 6, 8)) + if(owner.change_marking_color(r_markings, g_markings, b_markings)) + update_dna() + return 1 + if(href_list["body_accessory"]) + if(can_change_body_accessory() && (href_list["body_accessory"] in valid_body_accessories)) + if(owner.change_body_accessory(href_list["body_accessory"])) + update_dna() + return 1 return 0 @@ -107,13 +147,21 @@ data["change_skin_tone"] = can_change_skin_tone() data["change_skin_color"] = can_change_skin_color() data["change_eye_color"] = can_change(APPEARANCE_EYE_COLOR) + data["change_head_accessory"] = can_change_head_accessory() + if(data["change_head_accessory"]) + var/head_accessory_styles[0] + for(var/head_accessory_style in valid_head_accessories) + head_accessory_styles[++head_accessory_styles.len] = list("headaccessorystyle" = head_accessory_style) + data["head_accessory_styles"] = head_accessory_styles + data["head_accessory_style"] = head_organ.ha_style + data["change_hair"] = can_change(APPEARANCE_HAIR) if(data["change_hair"]) var/hair_styles[0] for(var/hair_style in valid_hairstyles) hair_styles[++hair_styles.len] = list("hairstyle" = hair_style) data["hair_styles"] = hair_styles - data["hair_style"] = owner.h_style + data["hair_style"] = head_organ.h_style data["change_facial_hair"] = can_change(APPEARANCE_FACIAL_HAIR) if(data["change_facial_hair"]) @@ -121,10 +169,31 @@ for(var/facial_hair_style in valid_facial_hairstyles) facial_hair_styles[++facial_hair_styles.len] = list("facialhairstyle" = facial_hair_style) data["facial_hair_styles"] = facial_hair_styles - data["facial_hair_style"] = owner.f_style + data["facial_hair_style"] = head_organ.f_style + data["change_markings"] = can_change_markings() + if(data["change_markings"]) + var/marking_styles[0] + for(var/marking_style in valid_marking_styles) + marking_styles[++marking_styles.len] = list("markingstyle" = marking_style) + data["marking_styles"] = marking_styles + data["marking_style"] = owner.m_style + + data["change_body_accessory"] = can_change_body_accessory() + if(data["change_body_accessory"]) + var/body_accessory_styles[0] + for(var/body_accessory_style in valid_body_accessories) + body_accessory_styles[++body_accessory_styles.len] = list("bodyaccessorystyle" = body_accessory_style) + data["body_accessory_styles"] = body_accessory_styles + var/datum/body_accessory/BA + if(owner.body_accessory) + BA = owner.body_accessory.name + data["body_accessory_style"] = BA + + data["change_head_accessory_color"] = can_change_head_accessory() data["change_hair_color"] = can_change(APPEARANCE_HAIR_COLOR) data["change_facial_hair_color"] = can_change(APPEARANCE_FACIAL_HAIR_COLOR) + data["change_marking_color"] = can_change_markings() ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) ui = new(user, src, ui_key, "appearance_changer.tmpl", "[src]", 800, 450, state = state) @@ -145,10 +214,22 @@ /datum/nano_module/appearance_changer/proc/can_change_skin_color() return owner && (flags & APPEARANCE_SKIN) && (owner.species.bodyflags & HAS_SKIN_COLOR) +/datum/nano_module/appearance_changer/proc/can_change_head_accessory() + return owner && (flags & APPEARANCE_HEAD_ACCESSORY) && (head_organ.species.bodyflags & HAS_HEAD_ACCESSORY) + +/datum/nano_module/appearance_changer/proc/can_change_markings() + return owner && (flags & APPEARANCE_MARKINGS) && (owner.species.bodyflags & HAS_MARKINGS) + +/datum/nano_module/appearance_changer/proc/can_change_body_accessory() + return owner && (flags & APPEARANCE_BODY_ACCESSORY) && (owner.species.bodyflags & HAS_TAIL) + /datum/nano_module/appearance_changer/proc/cut_and_generate_data() // Making the assumption that the available species remain constant + valid_hairstyles.Cut() valid_facial_hairstyles.Cut() - valid_facial_hairstyles.Cut() + valid_head_accessories.Cut() + valid_marking_styles.Cut() + valid_body_accessories.Cut() generate_data() /datum/nano_module/appearance_changer/proc/generate_data() @@ -158,4 +239,10 @@ valid_species = owner.generate_valid_species(check_whitelist, whitelist, blacklist) if(!valid_hairstyles.len || !valid_facial_hairstyles.len) valid_hairstyles = owner.generate_valid_hairstyles() - valid_facial_hairstyles = owner.generate_valid_facial_hairstyles() \ No newline at end of file + valid_facial_hairstyles = owner.generate_valid_facial_hairstyles() + if(!valid_head_accessories.len) + valid_head_accessories = owner.generate_valid_head_accessories() + if(!valid_marking_styles.len) + valid_marking_styles = owner.generate_valid_markings() + if(!valid_body_accessories.len) + valid_body_accessories = owner.generate_valid_body_accessories() diff --git a/code/modules/nano/modules/power_monitor.dm b/code/modules/nano/modules/power_monitor.dm index d6df0229085..f2c9297b1a9 100644 --- a/code/modules/nano/modules/power_monitor.dm +++ b/code/modules/nano/modules/power_monitor.dm @@ -2,7 +2,7 @@ name = "Power monitor" var/select_monitor = 0 var/obj/machinery/computer/monitor/powermonitor - + /datum/nano_module/power_monitor/silicon select_monitor = 1 @@ -10,33 +10,33 @@ ..() if(!select_monitor) powermonitor = nano_host() - + /datum/nano_module/power_monitor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = default_state) var/data[0] - + data["powermonitor"] = powermonitor if(select_monitor) data["select_monitor"] = 1 data["powermonitors"] = powermonitor_repository.powermonitor_data() - - if (powermonitor && !isnull(powermonitor.powernet)) + + if (powermonitor && !isnull(powermonitor.powernet)) if(select_monitor && (powermonitor.stat & (NOPOWER|BROKEN))) powermonitor = null return data["poweravail"] = powermonitor.powernet.avail - data["powerload"] = num2text(powermonitor.powernet.viewload,10) + data["powerload"] = powermonitor.powernet.viewload data["powerdemand"] = powermonitor.powernet.load data["apcs"] = apc_repository.apc_data(powermonitor) - + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) ui = new(user, src, ui_key, "power_monitor.tmpl", "Power Monitoring Console", 800, 700, state = state) ui.set_initial_data(data) ui.open() ui.set_auto_update(1) - + /datum/nano_module/power_monitor/Topic(href, href_list) - if(..()) + if(..()) return 1 if(href_list["selectmonitor"]) @@ -44,9 +44,8 @@ powermonitor = locate(href_list["selectmonitor"]) powermonitor.powernet = powermonitor.find_powernet() // Refresh the powernet of the monitor return 1 - + if(href_list["return"]) if(issilicon(usr)) powermonitor = null return 1 - \ No newline at end of file diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm index 9cf13e22f1d..d4a2ad141cb 100644 --- a/code/modules/paperwork/photocopier.dm +++ b/code/modules/paperwork/photocopier.dm @@ -226,45 +226,18 @@ /obj/machinery/photocopier/proc/copyass() var/icon/temp_img - if(check_ass()) //You have to be sitting on the copier and either be a xeno or a human without clothes on. - if(ishuman(ass)) //Suit checks are in check_ass - var/mob/living/carbon/human/H = ass - switch(H.get_species()) - if("Human") - temp_img = icon('icons/obj/butts.dmi', "human") - if("Tajaran") - temp_img = icon('icons/obj/butts.dmi', "tajaran") - if("Unathi") - temp_img = icon('icons/obj/butts.dmi', "unathi") - if("Skrell") - temp_img = icon('icons/obj/butts.dmi', "skrell") - if("Vox") - temp_img = icon('icons/obj/butts.dmi', "vox") - if("Kidan") - temp_img = icon('icons/obj/butts.dmi', "kidan") - if("Grey") - temp_img = icon('icons/obj/butts.dmi', "grey") - if("Diona") - temp_img = icon('icons/obj/butts.dmi', "diona") - if("Slime People") - temp_img = icon('icons/obj/butts.dmi', "slime") - if("Vulpkanin") - temp_img = icon('icons/obj/butts.dmi', "vulp") - if("Machine") - temp_img = icon('icons/obj/butts.dmi', "machine") - if("Plasmaman") - temp_img = icon('icons/obj/butts.dmi', "plasma") - if("Drask") - temp_img = icon('icons/obj/butts.dmi', "drask") - else - temp_img = icon('icons/obj/butts.dmi', "human") - else if(istype(ass,/mob/living/silicon/robot/drone)) - temp_img = icon('icons/obj/butts.dmi', "drone") - else if(istype(ass,/mob/living/simple_animal/diona)) - temp_img = icon('icons/obj/butts.dmi', "nymph") - else if(isalien(ass) || istype(ass,/mob/living/simple_animal/hostile/alien)) //Xenos have their own asses, thanks to Pybro. - temp_img = icon('icons/obj/butts.dmi', "xeno") - else return + if(!check_ass()) //You have to be sitting on the copier and either be a xeno or a human without clothes on. + return + + if(ishuman(ass)) //Suit checks are in check_ass + var/mob/living/carbon/human/H = ass + temp_img = icon('icons/obj/butts.dmi', H.species.butt_sprite) + else if(istype(ass,/mob/living/silicon/robot/drone)) + temp_img = icon('icons/obj/butts.dmi', "drone") + else if(istype(ass,/mob/living/simple_animal/diona)) + temp_img = icon('icons/obj/butts.dmi', "nymph") + else if(isalien(ass) || istype(ass,/mob/living/simple_animal/hostile/alien)) //Xenos have their own asses, thanks to Pybro. + temp_img = icon('icons/obj/butts.dmi', "xeno") else return var/obj/item/weapon/photo/p = new /obj/item/weapon/photo (loc) diff --git a/code/modules/pda/core_apps.dm b/code/modules/pda/core_apps.dm index 065253fcfab..4aaaa0667e7 100644 --- a/code/modules/pda/core_apps.dm +++ b/code/modules/pda/core_apps.dm @@ -97,15 +97,15 @@ var/co2_level = environment.carbon_dioxide/total_moles var/plasma_level = environment.toxins/total_moles var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level) - data["aircontents"] = list(\ - "pressure" = "[round(pressure,0.1)]",\ - "nitrogen" = "[round(n2_level*100,0.1)]",\ - "oxygen" = "[round(o2_level*100,0.1)]",\ - "carbon_dioxide" = "[round(co2_level*100,0.1)]",\ - "plasma" = "[round(plasma_level*100,0.01)]",\ - "other" = "[round(unknown_level, 0.01)]",\ - "temp" = "[round(environment.temperature-T0C,0.1)]",\ - "reading" = 1\ + data["aircontents"] = list( + "pressure" = pressure, + "nitrogen" = n2_level*100, + "oxygen" = o2_level*100, + "carbon_dioxide" = co2_level*100, + "plasma" = plasma_level*100, + "other" = unknown_level, + "temp" = environment.temperature-T0C, + "reading" = 1 ) if(isnull(data["aircontents"])) data["aircontents"] = list("reading" = 0) \ No newline at end of file diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index edefabf2aff..a66eba09713 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -815,16 +815,12 @@ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) // the ui does not exist, so we'll create a new one - ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 510, data["siliconUser"] ? 465 : 390) + ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 510, data["siliconUser"] ? 535 : 460) // When the UI is first opened this is the data it will use ui.set_initial_data(data) ui.open() // Auto update every Master Controller tick ui.set_auto_update(1) - else - // The UI is already open so push the new data to it - ui.push_data(data) - return /obj/machinery/power/apc/proc/report() return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])" diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm index 8208635f577..863b231f25a 100644 --- a/code/modules/power/cable.dm +++ b/code/modules/power/cable.dm @@ -520,6 +520,11 @@ obj/structure/cable/proc/cableColor(var/colorC) else return ..() +/obj/item/stack/cable_coil/split() + var/obj/item/stack/cable_coil/C = ..() + C.color = color + return C + /obj/item/stack/cable_coil/update_icon() if (!color) color = pick(COLOR_RED, COLOR_BLUE, COLOR_GREEN, COLOR_ORANGE, COLOR_WHITE, COLOR_PINK, COLOR_YELLOW, COLOR_CYAN) @@ -600,27 +605,6 @@ obj/structure/cable/proc/cableColor(var/colorC) src.use(amt) return -//remove cables from the stack -/* This is probably reduntant -/obj/item/stack/cable_coil/use(var/used) - if(src.amount < used) - return 0 - else if (src.amount == used) - if(ismob(loc)) //handle mob icon update - var/mob/M = loc - M.unEquip(src) - qdel(src) - return 1 - else - amount -= used - update_icon() - return 1 -*/ -/obj/item/stack/cable_coil/use(var/used) - . = ..() - update_icon() - return - //add cables to the stack /obj/item/stack/cable_coil/proc/give(var/extra) if(amount + extra > MAXCOIL) diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm index 81af0089e6f..0f19ce0990e 100644 --- a/code/modules/power/generator.dm +++ b/code/modules/power/generator.dm @@ -17,6 +17,7 @@ var/image/overlay_image + var/power_multiplier = 1 // This is so admins can tweak how good it is to find a good balance for effort -> power var/powercap = 500000 //Not a hard cap, but outputs above this have a 10% chance to cause the TeG to lose half it's power. /obj/machinery/power/generator/New() @@ -81,7 +82,7 @@ var/efficiency = 0.65 var/energy_transfer = delta_temperature*air2_heat_capacity*air1_heat_capacity/(air2_heat_capacity+air1_heat_capacity) var/heat = energy_transfer*(1-efficiency) - lastgen = energy_transfer*efficiency*0.05 + lastgen = energy_transfer*efficiency*0.05*power_multiplier if(air2.temperature > air1.temperature) air2.temperature = air2.temperature - energy_transfer/air2_heat_capacity @@ -97,8 +98,10 @@ circ2.air2.merge(air2) //Update the gas networks - circ1.parent2.update = 1 - circ2.parent2.update = 1 + if(circ1.parent2) + circ1.parent2.update = 1 + if(circ2.parent2) + circ2.parent2.update = 1 // update icon overlays and power usage only if displayed level has changed if(lastgen > powercap && prob(10)) diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm index 0df18d27150..78ac0d7093a 100644 --- a/code/modules/power/lighting.dm +++ b/code/modules/power/lighting.dm @@ -707,3 +707,12 @@ sharp = 1 playsound(src.loc, 'sound/effects/Glasshit.ogg', 75, 1) update() + +/obj/item/weapon/light/suicide_act(mob/living/carbon/human/user) + user.visible_message("[user] touches \the [src], burning their hands off!", "You touch \the [src], burning your hands off!") + + for(var/oname in list("l_hand", "r_hand")) + var/obj/item/organ/external/limb = user.get_organ(oname) + if(limb) + limb.droplimb(0, DROPLIMB_BURN) + return FIRELOSS \ No newline at end of file diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 4f0d72e1511..06ba1a093f8 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -213,7 +213,7 @@ else // Any other A.yo = -20 A.xo = 0 - A.process() //TODO: Carn: check this out + A.fire() //TODO: Carn: check this out /obj/machinery/power/emitter/attackby(obj/item/W, mob/user, params) diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm index 44f78fa4e38..c8f5fc312e8 100644 --- a/code/modules/power/solar.dm +++ b/code/modules/power/solar.dm @@ -293,7 +293,7 @@ var/autostart = 0 // Automatically search for connected devices var/obj/machinery/power/tracker/connected_tracker = null var/list/connected_panels = list() - + // Used for mapping in solar array which automatically starts itself (telecomms, for example) /obj/machinery/power/solar_control/autostart track = 2 // Auto tracking mode @@ -301,7 +301,7 @@ /obj/machinery/power/solar_control/initialize() ..() - if(!powernet) + if(!powernet) return connect_to_network() set_panels(cdir) @@ -375,17 +375,17 @@ /obj/machinery/power/solar_control/attack_ai(mob/user as mob) src.add_hiddenprint(user) ui_interact(user) - + /obj/machinery/power/solar_control/attack_ghost(mob/user as mob) - ui_interact(user) - + ui_interact(user) + /obj/machinery/power/solar_control/attack_hand(mob/user) if(..(user)) return 1 - + if(stat & BROKEN) return - + ui_interact(user) /obj/machinery/power/solar_control/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) @@ -409,9 +409,6 @@ ui.set_initial_data(data) ui.open() ui.set_auto_update(1) - else - ui.push_data(data) - return /obj/machinery/power/solar_control/attackby(I as obj, user as mob, params) if(istype(I, /obj/item/weapon/screwdriver)) diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index 45670ec70b0..f47a4db719b 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -6,14 +6,16 @@ flags = CONDUCT slot_flags = SLOT_BELT throwforce = 1 - w_class = 1.0 - var/caliber = "" //Which kind of guns it can be loaded into - var/projectile_type = ""//The bullet type to create when New() is called + w_class = 1 + var/fire_sound = null //What sound should play when this ammo is fired + var/caliber = null //Which kind of guns it can be loaded into + var/projectile_type = null //The bullet type to create when New() is called var/obj/item/projectile/BB = null //The loaded bullet - var/pellets = 1 - var/deviation = 0 - var/spread = 0 - + var/pellets = 1 //Pellets for spreadshot + var/variance = 0 //Variance for inaccuracy fundamental to the casing + var/delay = 0 //Delay for energy weapons + var/randomspread = 0 //Randomspread for automatics + var/click_cooldown_override = 0 //Override this to make your gun have a faster fire rate, in tenths of a second. 4 is the default gun cooldown. /obj/item/ammo_casing/New() ..() @@ -29,54 +31,50 @@ icon_state = "[initial(icon_state)][BB ? "-live" : ""]" desc = "[initial(desc)][BB ? "" : " This one is spent"]" - - -/obj/item/ammo_casing/attackby(obj/item/weapon/W as obj, mob/user as mob, params) - if(istype(W, /obj/item/weapon/screwdriver)) - if(BB) - if(initial(BB.name) == "bullet") - var/tmp_label = "" - var/label_text = sanitize(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label)) - if(length(label_text) > 20) - to_chat(user, "The inscription can be at most 20 characters long.") - else - if(label_text == "") - to_chat(user, "You scratch the inscription off of [initial(BB)].") - BB.name = initial(BB.name) - else - to_chat(user, "You inscribe \"[label_text]\" into \the [initial(BB.name)].") - BB.name = "[initial(BB.name)] \"[label_text]\"" - else - to_chat(user, "You can only inscribe a metal bullet.")//because inscribing beanbags is silly - - else - to_chat(user, "There is no bullet in the casing to inscribe anything into.") - -/obj/item/ammo_casing/attackby(obj/item/ammo_box/box as obj, mob/user as mob, params) - if(!istype(box, /obj/item/ammo_box)) - return - if(isturf(loc)) - var/boolets = 0 - for(var/obj/item/ammo_casing/pew in loc) - if(box.stored_ammo.len >= box.max_ammo) - break - if(pew.BB) - if(box.give_round(pew)) - boolets++ - else - continue - if(boolets > 0) - box.update_icon() - to_chat(user, "You collect [boolets] shell\s. [box] now contains [box.stored_ammo.len] shell\s.") - else - to_chat(user, "You fail to collect anything.") - /obj/item/ammo_casing/proc/newshot() //For energy weapons, shotgun shells and wands (!). - if(!BB) + if (!BB) BB = new projectile_type(src) return +/obj/item/ammo_casing/attackby(obj/item/I as obj, mob/user as mob, params) + if(istype(I, /obj/item/ammo_box)) + var/obj/item/ammo_box/box = I + if(isturf(loc)) + var/boolets = 0 + for(var/obj/item/ammo_casing/bullet in loc) + if (box.stored_ammo.len >= box.max_ammo) + break + if (bullet.BB) + if (box.give_round(bullet, 0)) + boolets++ + else + continue + if (boolets > 0) + box.update_icon() + to_chat(user, "You collect [boolets] shell\s. [box] now contains [box.stored_ammo.len] shell\s.") + else + to_chat(user, "You fail to collect anything!") + else + if(istype(I, /obj/item/weapon/screwdriver)) + if(BB) + if(initial(BB.name) == "bullet") + var/tmp_label = "" + var/label_text = sanitize(input(user, "Inscribe some text into \the [initial(BB.name)]","Inscription",tmp_label)) + if(length(label_text) > 20) + to_chat(user, "The inscription can be at most 20 characters long.") + else + if(label_text == "") + to_chat(user, "You scratch the inscription off of [initial(BB)].") + BB.name = initial(BB.name) + else + to_chat(user, "You inscribe \"[label_text]\" into \the [initial(BB.name)].") + BB.name = "[initial(BB.name)] \"[label_text]\"" + else + to_chat(user, "You can only inscribe a metal bullet.")//because inscribing beanbags is silly + else + to_chat(user, "There is no bullet in the casing to inscribe anything into.") + ..() //Boxes of ammo /obj/item/ammo_box @@ -89,53 +87,78 @@ item_state = "syringe_kit" materials = list(MAT_METAL=30000) throwforce = 2 - w_class = 1.0 + w_class = 1 throw_speed = 4 throw_range = 10 var/list/stored_ammo = list() - var/obj/item/ammo_casing/ammo_type + var/ammo_type = /obj/item/ammo_casing var/max_ammo = 7 var/multiple_sprites = 0 - var/caliber = "" + var/caliber var/multiload = 1 + /obj/item/ammo_box/New() - for(var/i = 1, i <= max_ammo, i++) + for(var/i in 1 to max_ammo) stored_ammo += new ammo_type(src) update_icon() -/obj/item/ammo_box/proc/get_round(var/keep = 0) - if(!stored_ammo.len) +/obj/item/ammo_box/Destroy() + for(var/atom/A in stored_ammo) + qdel(A) + stored_ammo = null + return ..() + +/obj/item/ammo_box/proc/get_round(keep = 0) + if (!stored_ammo.len) return null else var/b = stored_ammo[stored_ammo.len] stored_ammo -= b - if(keep) + if (keep) stored_ammo.Insert(1,b) return b -/obj/item/ammo_box/proc/give_round(var/obj/item/ammo_casing/r) - var/obj/item/ammo_casing/rb = r - if(rb) - if(stored_ammo.len < max_ammo && rb.caliber == caliber) - stored_ammo += rb - rb.loc = src - return 1 +/obj/item/ammo_box/proc/give_round(obj/item/ammo_casing/R, replace_spent = 0) + // Boxes don't have a caliber type, magazines do. Not sure if it's intended or not, but if we fail to find a caliber, then we fall back to ammo_type. + if(!R || (caliber && R.caliber != caliber) || (!caliber && R.type != ammo_type)) + return 0 + + if (stored_ammo.len < max_ammo) + stored_ammo += R + R.loc = src + return 1 + //for accessibles magazines (e.g internal ones) when full, start replacing spent ammo + else if(replace_spent) + for(var/obj/item/ammo_casing/AC in stored_ammo) + if(!AC.BB)//found a spent ammo + stored_ammo -= AC + AC.loc = get_turf(loc) + + stored_ammo += R + R.loc = src + return 1 + return 0 -/obj/item/ammo_box/attackby(var/obj/item/A as obj, mob/user as mob, var/silent = 0, params) +/obj/item/ammo_box/proc/can_load(mob/user) + return 1 + +/obj/item/ammo_box/attackby(obj/item/A, mob/user, params, silent = 0, replace_spent = 0) var/num_loaded = 0 + if(!can_load(user)) + return if(istype(A, /obj/item/ammo_box)) var/obj/item/ammo_box/AM = A for(var/obj/item/ammo_casing/AC in AM.stored_ammo) - var/didload = give_round(AC) - if(didload) + var/did_load = give_round(AC, replace_spent) + if(did_load) AM.stored_ammo -= AC num_loaded++ - if(!multiload || !didload) + if(!multiload || !did_load) break if(istype(A, /obj/item/ammo_casing)) var/obj/item/ammo_casing/AC = A - if(give_round(AC)) + if(give_round(AC, replace_spent)) user.drop_item() AC.loc = src num_loaded++ @@ -145,6 +168,8 @@ A.update_icon() update_icon() + return num_loaded + /obj/item/ammo_box/attack_self(mob/user as mob) var/obj/item/ammo_casing/A = get_round() if(A) diff --git a/code/modules/projectiles/ammunition/ammo_casings.dm b/code/modules/projectiles/ammunition/ammo_casings.dm index 44189411515..a5af74e4d6c 100644 --- a/code/modules/projectiles/ammunition/ammo_casings.dm +++ b/code/modules/projectiles/ammunition/ammo_casings.dm @@ -1,128 +1,146 @@ /obj/item/ammo_casing/a357 desc = "A .357 bullet casing." caliber = "357" - projectile_type = "/obj/item/projectile/bullet" + projectile_type = /obj/item/projectile/bullet + +/obj/item/ammo_casing/a762 + desc = "A 7.62mm bullet casing." + icon_state = "762-casing" + caliber = "a762" + projectile_type = /obj/item/projectile/bullet + +/obj/item/ammo_casing/a762/enchanted + projectile_type = /obj/item/projectile/bullet/weakbullet3 /obj/item/ammo_casing/a50 desc = "A .50AE bullet casing." caliber = ".50" - projectile_type = "/obj/item/projectile/bullet" + projectile_type = /obj/item/projectile/bullet /obj/item/ammo_casing/c38 desc = "A .38 bullet casing." caliber = "38" - projectile_type = "/obj/item/projectile/bullet/weakbullet2/rubber" - -/obj/item/ammo_casing/cap - desc = "A cap for children toys." - caliber = "caps" - projectile_type = "/obj/item/projectile/bullet/cap" - + projectile_type = /obj/item/projectile/bullet/weakbullet2/rubber /obj/item/ammo_casing/c10mm desc = "A 10mm bullet casing." caliber = "10mm" - projectile_type = "/obj/item/projectile/bullet/midbullet3" - + projectile_type = /obj/item/projectile/bullet/midbullet3 /obj/item/ammo_casing/c9mm desc = "A 9mm bullet casing." caliber = "9mm" - projectile_type = "/obj/item/projectile/bullet/weakbullet3" + projectile_type = /obj/item/projectile/bullet/weakbullet3 /obj/item/ammo_casing/c9mmap desc = "A 9mm bullet casing." caliber = "9mm" - projectile_type = "/obj/item/projectile/bullet/armourpiercing" + projectile_type = /obj/item/projectile/bullet/armourpiercing /obj/item/ammo_casing/c9mmtox desc = "A 9mm bullet casing." caliber = "9mm" - projectile_type = "/obj/item/projectile/bullet/toxinbullet" + projectile_type = /obj/item/projectile/bullet/toxinbullet /obj/item/ammo_casing/c9mminc desc = "A 9mm bullet casing." caliber = "9mm" - projectile_type = "/obj/item/projectile/bullet/incendiary/firebullet" + projectile_type = /obj/item/projectile/bullet/incendiary/firebullet /obj/item/ammo_casing/c46x30mm desc = "A 4.6x30mm bullet casing." caliber = "4.6x30mm" - projectile_type = "/obj/item/projectile/bullet/weakbullet3" + projectile_type = /obj/item/projectile/bullet/weakbullet3 /obj/item/ammo_casing/c46x30mmap desc = "A 4.6x30mm bullet casing." caliber = "4.6x30mm" - projectile_type = "/obj/item/projectile/bullet/armourpiercing" + projectile_type = /obj/item/projectile/bullet/armourpiercing /obj/item/ammo_casing/c46x30mmtox desc = "A 4.6x30mm bullet casing." caliber = "4.6x30mm" - projectile_type = "/obj/item/projectile/bullet/toxinbullet" + projectile_type = /obj/item/projectile/bullet/toxinbullet /obj/item/ammo_casing/c46x30mminc desc = "A 4.6x30mm bullet casing." caliber = "4.6x30mm" - projectile_type = "/obj/item/projectile/bullet/incendiary/firebullet" + projectile_type = /obj/item/projectile/bullet/incendiary/firebullet /obj/item/ammo_casing/c45 desc = "A .45 bullet casing." caliber = ".45" - projectile_type = "/obj/item/projectile/bullet/midbullet" + projectile_type = /obj/item/projectile/bullet/midbullet +/obj/item/ammo_casing/c45nostamina + desc = "A .45 bullet casing." + caliber = ".45" + projectile_type = /obj/item/projectile/bullet/midbullet3 + +/obj/item/ammo_casing/n762 + desc = "A 7.62x38mmR bullet casing." + caliber = "n762" + projectile_type = /obj/item/projectile/bullet + +/obj/item/ammo_casing/caseless/magspear + name = "magnetic spear" + desc = "A reusable spear that is typically loaded into kinetic spearguns." + projectile_type = /obj/item/projectile/bullet/reusable/magspear + caliber = "speargun" + icon_state = "magspear" + throwforce = 15 //still deadly when thrown + throw_speed = 3 /obj/item/ammo_casing/shotgun name = "shotgun slug" desc = "A 12 gauge lead slug." icon_state = "blshell" caliber = "shotgun" - projectile_type = "/obj/item/projectile/bullet" + projectile_type = /obj/item/projectile/bullet materials = list(MAT_METAL=4000) - /obj/item/ammo_casing/shotgun/buckshot name = "buckshot shell" desc = "A 12 gauge buckshot shell." icon_state = "gshell" - projectile_type = "/obj/item/projectile/bullet/pellet" + projectile_type = /obj/item/projectile/bullet/pellet pellets = 6 - deviation = 30 + variance = 25 /obj/item/ammo_casing/shotgun/rubbershot name = "rubber shot" desc = "A shotgun casing filled with densely-packed rubber balls, used to incapacitate crowds from a distance." icon_state = "bshell" - projectile_type = "/obj/item/projectile/bullet/rpellet" + projectile_type = /obj/item/projectile/bullet/rpellet pellets = 6 - deviation = 30 + variance = 25 materials = list(MAT_METAL=4000) /obj/item/ammo_casing/shotgun/beanbag name = "beanbag slug" desc = "A weak beanbag slug for riot control." icon_state = "bshell" - projectile_type = "/obj/item/projectile/bullet/weakbullet/rubber" + projectile_type = /obj/item/projectile/bullet/weakbullet/rubber materials = list(MAT_METAL=250) - /obj/item/ammo_casing/shotgun/improvised name = "improvised shell" desc = "An extremely weak shotgun shell with multiple small pellets made out of metal shards." icon_state = "gshell" - projectile_type = "/obj/item/projectile/bullet/pellet/weak" + projectile_type = /obj/item/projectile/bullet/pellet/weak materials = list(MAT_METAL=250) pellets = 5 - deviation = 30 + variance = 25 /obj/item/ammo_casing/shotgun/improvised/overload name = "overloaded improvised shell" desc = "An extremely weak shotgun shell with multiple small pellets made out of metal shards. This one has been packed with even more \ propellant. It's like playing russian roulette, with a shotgun." icon_state = "improvshell" - projectile_type = "/obj/item/projectile/bullet/pellet/random" + projectile_type = /obj/item/projectile/bullet/pellet/overload materials = list(MAT_METAL=250) pellets = 5 - deviation = 30 + variance = 40 /obj/item/ammo_casing/shotgun/improvised/overload/New() ..() @@ -132,15 +150,20 @@ name = "taser slug" desc = "A stunning taser slug." icon_state = "stunshell" - projectile_type = "/obj/item/projectile/bullet/stunshot" + projectile_type = /obj/item/projectile/bullet/stunshot materials = list(MAT_METAL=250) - /obj/item/ammo_casing/shotgun/meteorshot name = "meteorshot shell" desc = "A shotgun shell rigged with CMC technology, which launches a massive slug when fired." icon_state = "mshell" - projectile_type = "/obj/item/projectile/bullet/meteorshot" + projectile_type = /obj/item/projectile/bullet/meteorshot + +/obj/item/ammo_casing/shotgun/breaching + name = "breaching shell" + desc = "An economic version of the meteorshot, utilizing similar technologies. Great for busting down doors." + icon_state = "mshell" + projectile_type = /obj/item/projectile/bullet/meteorshot/weak /obj/item/ammo_casing/shotgun/pulseslug name = "pulse slug" @@ -148,42 +171,42 @@ energy blast. While the heat and power drain limit it to one use, it can still allow an operator to engage targets that ballistic ammunition \ would have difficulty with." icon_state = "pshell" - projectile_type = "/obj/item/projectile/beam/pulse/shot" + projectile_type = /obj/item/projectile/beam/pulse/shot /obj/item/ammo_casing/shotgun/incendiary name = "incendiary slug" desc = "An incendiary-coated shotgun slug." icon_state = "ishell" - projectile_type = "/obj/item/projectile/bullet/incendiary/shell" + projectile_type = /obj/item/projectile/bullet/incendiary/shell /obj/item/ammo_casing/shotgun/frag12 name = "FRAG-12 slug" desc = "A high explosive breaching round for a 12 gauge shotgun." icon_state = "heshell" - projectile_type = "/obj/item/projectile/bullet/frag12" + projectile_type = /obj/item/projectile/bullet/frag12 /obj/item/ammo_casing/shotgun/incendiary/dragonsbreath name = "dragonsbreath shell" desc = "A shotgun shell which fires a spread of incendiary pellets." icon_state = "ishell2" - projectile_type = "/obj/item/projectile/bullet/incendiary/shell/dragonsbreath" + projectile_type = /obj/item/projectile/bullet/incendiary/shell/dragonsbreath pellets = 4 - deviation = 30 + variance = 35 /obj/item/ammo_casing/shotgun/ion name = "ion shell" desc = "An advanced shotgun shell which uses a subspace ansible crystal to produce an effect similar to a standard ion rifle. \ The unique properties of the crystal splot the pulse into a spread of individually weaker bolts." icon_state = "ionshell" - projectile_type = "/obj/item/projectile/ion/weak" + projectile_type = /obj/item/projectile/ion/weak pellets = 4 - deviation = 30 + variance = 35 /obj/item/ammo_casing/shotgun/laserslug name = "laser slug" desc = "An advanced shotgun shell that uses a micro laser to replicate the effects of a laser weapon in a ballistic package." icon_state = "lshell" - projectile_type = "/obj/item/projectile/beam" + projectile_type = /obj/item/projectile/beam /obj/item/ammo_casing/shotgun/techshell name = "unloaded technological shell" @@ -195,7 +218,7 @@ name = "shotgun dart" desc = "A dart for use in shotguns. Can be injected with up to 30 units of any chemical." icon_state = "cshell" - projectile_type = "/obj/item/projectile/bullet/dart" + projectile_type = /obj/item/projectile/bullet/dart /obj/item/ammo_casing/shotgun/dart/New() ..() @@ -206,93 +229,116 @@ /obj/item/ammo_casing/shotgun/dart/attackby() return +/obj/item/ammo_casing/shotgun/dart/bioterror + desc = "A shotgun dart filled with deadly toxins." + +/obj/item/ammo_casing/shotgun/dart/bioterror/New() + ..() + reagents.add_reagent("neurotoxin", 6) + reagents.add_reagent("spores", 6) + reagents.add_reagent("mutetoxin", 6) //;HELP OPS IN MAINT + reagents.add_reagent("coniine", 6) + reagents.add_reagent("sodium_thiopental", 6) + /obj/item/ammo_casing/shotgun/tranquilizer name = "tranquilizer darts" desc = "A tranquilizer round used to subdue individuals utilizing stimulants." icon_state = "cshell" - projectile_type = "/obj/item/projectile/bullet/dart/syringe/tranquilizer" + projectile_type = /obj/item/projectile/bullet/dart/syringe/tranquilizer materials = list(MAT_METAL=250) -/obj/item/ammo_casing/syringegun - name = "syringe gun spring" - desc = "A high-power spring that throws syringes." - projectile_type = null +/obj/item/ammo_casing/a556 + desc = "A 5.56mm bullet casing." + caliber = "a556" + projectile_type = /obj/item/projectile/bullet/heavybullet /obj/item/ammo_casing/shotgun/fakebeanbag name = "beanbag shell" desc = "A weak beanbag shell." icon_state = "bshell" - projectile_type = "/obj/item/projectile/bullet/weakbullet/booze" - -/obj/item/ammo_casing/a762 - desc = "A 7.62mm bullet casing." - icon_state = "762-casing" - caliber = "a762" - projectile_type = "/obj/item/projectile/bullet" - -/obj/item/ammo_casing/a556 - desc = "A 5.56mm bullet casing." - caliber = "a556" - projectile_type = "/obj/item/projectile/bullet/heavybullet" + projectile_type = /obj/item/projectile/bullet/weakbullet/booze /obj/item/ammo_casing/rocket name = "rocket shell" desc = "A high explosive designed to be fired from a launcher." icon_state = "rocketshell" - projectile_type = "/obj/item/missile" + projectile_type = /obj/item/missile caliber = "rocket" /obj/item/ammo_casing/caseless desc = "A caseless bullet casing." +/obj/item/ammo_casing/caseless/fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, params, distro, quiet) + if (..()) + loc = null + return 1 + else + return 0 + /obj/item/ammo_casing/caseless/a75 desc = "A .75 bullet casing." caliber = "75" - projectile_type = "/obj/item/projectile/bullet/gyro" + projectile_type = /obj/item/projectile/bullet/gyro /obj/item/ammo_casing/a40mm name = "40mm HE shell" desc = "A cased high explosive grenade that can only be activated once fired out of a grenade launcher." caliber = "40mm" icon_state = "40mmHE" - projectile_type = "/obj/item/projectile/bullet/a40mm" + projectile_type = /obj/item/projectile/bullet/a40mm -//FOAM DARTS /obj/item/ammo_casing/caseless/foam_dart name = "foam dart" desc = "It's nerf or nothing! Ages 8 and up." - projectile_type = "/obj/item/projectile/bullet/reusable/foam_dart" + projectile_type = /obj/item/projectile/bullet/reusable/foam_dart caliber = "foam_force" - icon = 'icons/obj/toyguns.dmi' + icon = 'icons/obj/guns/toy.dmi' icon_state = "foamdart" var/modified = 0 /obj/item/ammo_casing/caseless/foam_dart/update_icon() - if(modified) - icon_state = "foamdart_empty" - -/obj/item/ammo_casing/caseless/foam_dart/attackby(var/obj/item/weapon/A as obj, mob/user as mob, params) ..() - if(istype(A, /obj/item/weapon/screwdriver) && !modified) - modified = 1 - BB.damage_type = BRUTE + if (modified) icon_state = "foamdart_empty" - desc = "It's nerf or nothing! ...Although, this one doesn't look too safe." - to_chat(user, "You pop the safety cap off of [src].") - else if((istype(A, /obj/item/weapon/pen)) && modified && !BB.contents.len) + desc = "Its nerf or nothing! ... Although, this one doesn't look too safe." + if(BB) + BB.icon_state = "foamdart_empty" + else + icon_state = "foamdart" + desc = "Its nerf or nothing! Ages 8 and up." + if(BB) + BB.icon_state = "foamdart_empty" + +/obj/item/ammo_casing/caseless/foam_dart/attackby(obj/item/A, mob/user, params) + ..() + var/obj/item/projectile/bullet/reusable/foam_dart/FD = BB + if (istype(A, /obj/item/weapon/screwdriver) && !modified) + modified = 1 + FD.damage_type = BRUTE + update_icon() + else if ((istype(A, /obj/item/weapon/pen)) && modified && !FD.pen) if(!user.unEquip(A)) return - A.forceMove(BB) - BB.damage = 5 - BB.nodamage = 0 + A.loc = FD + FD.pen = A + FD.damage = 5 + FD.nodamage = 0 to_chat(user, "You insert [A] into [src].") return +/obj/item/ammo_casing/caseless/foam_dart/attack_self(mob/living/user) + var/obj/item/projectile/bullet/reusable/foam_dart/FD = BB + if(FD.pen) + FD.damage = initial(FD.damage) + FD.nodamage = initial(FD.nodamage) + user.put_in_hands(FD.pen) + to_chat(user, "You remove [FD.pen] from [src].") + FD.pen = null /obj/item/ammo_casing/caseless/foam_dart/riot name = "riot foam dart" desc = "Whose smart idea was it to use toys as crowd control? Ages 18 and up." - projectile_type = "/obj/item/projectile/bullet/reusable/foam_dart/riot" + projectile_type = /obj/item/projectile/bullet/reusable/foam_dart/riot icon_state = "foamdart_riot" /obj/item/ammo_casing/shotgun/dart/assassination @@ -301,3 +347,8 @@ /obj/item/ammo_casing/shotgun/dart/assassination/New() ..() reagents.add_reagent("neurotoxin", 6) + +/obj/item/ammo_casing/cap + desc = "A cap for children toys." + caliber = "caps" + projectile_type = /obj/item/projectile/bullet/cap diff --git a/code/modules/projectiles/ammunition/boxes.dm b/code/modules/projectiles/ammunition/boxes.dm index eb998823b6a..894b5ac25b1 100644 --- a/code/modules/projectiles/ammunition/boxes.dm +++ b/code/modules/projectiles/ammunition/boxes.dm @@ -1,5 +1,6 @@ /obj/item/ammo_box/a357 name = "speed loader (.357)" + desc = "Designed to quickly reload revolvers." icon_state = "357" ammo_type = /obj/item/ammo_casing/a357 max_ammo = 7 @@ -7,18 +8,12 @@ /obj/item/ammo_box/c38 name = "speed loader (.38)" + desc = "Designed to quickly reload revolvers." icon_state = "38" ammo_type = /obj/item/ammo_casing/c38 max_ammo = 6 multiple_sprites = 1 -/obj/item/ammo_box/caps - name = "speed loader (caps)" - icon_state = "357" - ammo_type = /obj/item/ammo_casing/cap - max_ammo = 7 - multiple_sprites = 1 - /obj/item/ammo_box/c9mm name = "ammo box (9mm)" icon_state = "9mmbox" @@ -55,6 +50,13 @@ max_ammo = 5 multiple_sprites = 1 +/obj/item/ammo_box/n762 + name = "ammo box (7.62x38mmR)" + icon_state = "10mmbox" + origin_tech = "combat=2" + ammo_type = /obj/item/ammo_casing/n762 + max_ammo = 14 + /obj/item/ammo_box/shotgun name = "Ammunition Box (slug)" icon_state = "9mmbox" @@ -91,7 +93,7 @@ //FOAM DARTS /obj/item/ammo_box/foambox name = "ammo box (Foam Darts)" - icon = 'icons/obj/toyguns.dmi' + icon = 'icons/obj/guns/toy.dmi' icon_state = "foambox" ammo_type = /obj/item/ammo_casing/caseless/foam_dart max_ammo = 40 @@ -99,3 +101,10 @@ /obj/item/ammo_box/foambox/riot icon_state = "foambox_riot" ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot + +/obj/item/ammo_box/caps + name = "speed loader (caps)" + icon_state = "357" + ammo_type = /obj/item/ammo_casing/cap + max_ammo = 7 + multiple_sprites = 1 diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm new file mode 100644 index 00000000000..d7f26ff3919 --- /dev/null +++ b/code/modules/projectiles/ammunition/energy.dm @@ -0,0 +1,231 @@ +/obj/item/ammo_casing/energy + name = "energy weapon lens" + desc = "The part of the gun that makes the laser go pew" + caliber = "energy" + projectile_type = /obj/item/projectile/energy + var/e_cost = 1000 //The amount of energy a cell needs to expend to create this shot. + var/select_name = "energy" + fire_sound = 'sound/weapons/Laser.ogg' + +/obj/item/ammo_casing/energy/laser + projectile_type = /obj/item/projectile/beam/laser + select_name = "kill" + +/obj/item/ammo_casing/energy/lasergun + projectile_type = /obj/item/projectile/beam/laser + e_cost = 830 + select_name = "kill" + +/obj/item/ammo_casing/energy/laser/hos //allows balancing of HoS and blueshit guns seperately from other energy weapons + +/obj/item/ammo_casing/energy/laser/practice + projectile_type = /obj/item/projectile/beam/practice + select_name = "practice" + +/obj/item/ammo_casing/energy/laser/scatter + projectile_type = /obj/item/projectile/beam/scatter + pellets = 5 + variance = 25 + select_name = "scatter" + +/obj/item/ammo_casing/energy/laser/heavy + projectile_type = /obj/item/projectile/beam/laser/heavylaser + select_name = "anti-vehicle" + fire_sound = 'sound/weapons/lasercannonfire.ogg' + +/obj/item/ammo_casing/energy/laser/pulse + projectile_type = /obj/item/projectile/beam/pulse + e_cost = 200 + select_name = "DESTROY" + fire_sound = 'sound/weapons/pulse.ogg' + +/obj/item/ammo_casing/energy/laser/scatter/pulse + projectile_type = /obj/item/projectile/beam/pulse + e_cost = 2000 + select_name = "ANNIHILATE" + fire_sound = 'sound/weapons/pulse.ogg' + +/obj/item/ammo_casing/energy/laser/bluetag + projectile_type = /obj/item/projectile/beam/lasertag/bluetag + select_name = "bluetag" + +/obj/item/ammo_casing/energy/laser/redtag + projectile_type = /obj/item/projectile/beam/lasertag/redtag + select_name = "redtag" + +/obj/item/ammo_casing/energy/xray + projectile_type = /obj/item/projectile/beam/xray + e_cost = 500 + fire_sound = 'sound/weapons/laser3.ogg' + +/obj/item/ammo_casing/energy/immolator + projectile_type = /obj/item/projectile/beam/immolator + fire_sound = 'sound/weapons/laser3.ogg' + e_cost = 1250 + +/obj/item/ammo_casing/energy/electrode + projectile_type = /obj/item/projectile/energy/electrode + select_name = "stun" + fire_sound = 'sound/weapons/taser.ogg' + e_cost = 2000 + delay = 15 + +/obj/item/ammo_casing/energy/electrode/gun + fire_sound = 'sound/weapons/gunshot.ogg' + e_cost = 1000 + +/obj/item/ammo_casing/energy/electrode/hos //allows balancing of HoS and blueshit guns seperately from other energy weapons + +/obj/item/ammo_casing/energy/ion + projectile_type = /obj/item/projectile/ion + select_name = "ion" + fire_sound = 'sound/weapons/IonRifle.ogg' + +/obj/item/ammo_casing/energy/declone + projectile_type = /obj/item/projectile/energy/declone + select_name = "declone" + fire_sound = 'sound/weapons/pulse3.ogg' + +/obj/item/ammo_casing/energy/mindflayer + projectile_type = /obj/item/projectile/beam/mindflayer + select_name = "MINDFUCK" + fire_sound = 'sound/weapons/Laser.ogg' + +/obj/item/ammo_casing/energy/flora + fire_sound = 'sound/effects/stealthoff.ogg' + +/obj/item/ammo_casing/energy/flora/yield + projectile_type = /obj/item/projectile/energy/florayield + select_name = "yield" + +/obj/item/ammo_casing/energy/flora/mut + projectile_type = /obj/item/projectile/energy/floramut + select_name = "mutation" + +/obj/item/ammo_casing/energy/temp + projectile_type = /obj/item/projectile/temp + var/temperature = 300 + e_cost = 100 + fire_sound = 'sound/weapons/pulse3.ogg' + +/obj/item/ammo_casing/energy/temp/newshot() + ..() + var/obj/item/projectile/temp/T = BB + T.temperature = temperature + +/obj/item/ammo_casing/energy/meteor + projectile_type = /obj/item/projectile/meteor + select_name = "goddamn meteor" + +/obj/item/ammo_casing/energy/kinetic + projectile_type = /obj/item/projectile/kinetic + select_name = "kinetic" + e_cost = 5000 + fire_sound = 'sound/weapons/Kenetic_accel.ogg' // fine spelling there chap + +/obj/item/ammo_casing/energy/kinetic/super + projectile_type = /obj/item/projectile/kinetic/super + +/obj/item/ammo_casing/energy/kinetic/hyper + projectile_type = /obj/item/projectile/kinetic/hyper + +/obj/item/ammo_casing/energy/disabler + projectile_type = /obj/item/projectile/beam/disabler + select_name = "disable" + e_cost = 500 + fire_sound = "sound/weapons/taser2.ogg" + +/obj/item/ammo_casing/energy/plasma + projectile_type = /obj/item/projectile/plasma + select_name = "plasma burst" + fire_sound = 'sound/weapons/plasma_cutter.ogg' + delay = 15 + e_cost = 250 + +/obj/item/ammo_casing/energy/plasma/adv + projectile_type = /obj/item/projectile/plasma/adv + delay = 10 + e_cost = 100 + +/obj/item/ammo_casing/energy/wormhole + projectile_type = /obj/item/projectile/beam/wormhole + e_cost = 0 + fire_sound = "sound/weapons/pulse3.ogg" + var/obj/item/weapon/gun/energy/wormhole_projector/gun = null + select_name = "blue" + +/obj/item/ammo_casing/energy/wormhole/New(var/obj/item/weapon/gun/energy/wormhole_projector/wh) + gun = wh + +/obj/item/ammo_casing/energy/wormhole/orange + projectile_type = /obj/item/projectile/beam/wormhole/orange + select_name = "orange" + +/obj/item/ammo_casing/energy/bolt + projectile_type = /obj/item/projectile/energy/bolt + select_name = "bolt" + e_cost = 5000 + fire_sound = 'sound/weapons/Genhit.ogg' + +/obj/item/ammo_casing/energy/bolt/large + projectile_type = /obj/item/projectile/energy/bolt/large + select_name = "heavy bolt" + +/obj/item/ammo_casing/energy/dart + projectile_type = /obj/item/projectile/energy/dart + fire_sound = 'sound/weapons/Genhit.ogg' + e_cost = 5000 + select_name = "toxic dart" + +/obj/item/ammo_casing/energy/instakill + projectile_type = /obj/item/projectile/beam/instakill + e_cost = 0 + select_name = "DESTROY" + +/obj/item/ammo_casing/energy/instakill/blue + projectile_type = /obj/item/projectile/beam/instakill/blue + +/obj/item/ammo_casing/energy/instakill/red + projectile_type = /obj/item/projectile/beam/instakill/red + +/obj/item/ammo_casing/energy/plasma + projectile_type = /obj/item/projectile/plasma + select_name = "plasma burst" + fire_sound = 'sound/weapons/pulse.ogg' + +/obj/item/ammo_casing/energy/plasma/adv + projectile_type = /obj/item/projectile/plasma/adv + +/obj/item/ammo_casing/energy/shock_revolver + fire_sound = 'sound/magic/lightningbolt.ogg' + e_cost = 2000 + select_name = "lightning beam" + projectile_type = /obj/item/projectile/energy/shock_revolver + +/obj/item/ammo_casing/energy/toxplasma + projectile_type = /obj/item/projectile/energy/toxplasma + fire_sound = "sound/weapons/taser2.ogg" + select_name = "plasma dart" + +/obj/item/ammo_casing/energy/clown + projectile_type = /obj/item/projectile/clown + fire_sound = 'sound/weapons/Gunshot_smg.ogg' + select_name = "clown" + +/obj/item/ammo_casing/energy/sniper + projectile_type = /obj/item/projectile/beam/sniper + fire_sound = 'sound/weapons/marauder.ogg' + delay = 50 + select_name = "snipe" + +/obj/item/ammo_casing/energy/teleport + projectile_type = /obj/item/projectile/energy/teleport + fire_sound = 'sound/weapons/wave.ogg' + e_cost = 1250 + select_name = "teleport beam" + var/teleport_target + +/obj/item/ammo_casing/energy/teleport/newshot() + ..() + var/obj/item/projectile/energy/teleport/T = BB + T.teleport_target = teleport_target diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm index 32c3eeaa37c..c77dcc07595 100644 --- a/code/modules/projectiles/ammunition/magazines.dm +++ b/code/modules/projectiles/ammunition/magazines.dm @@ -1,113 +1,169 @@ ////////////////INTERNAL MAGAZINES////////////////////// +/obj/item/ammo_box/magazine/internal + desc = "Oh god, this shouldn't be here" + +//internals magazines are accessible, so replace spent ammo if full when trying to put a live one in +/obj/item/ammo_box/magazine/internal/give_round(obj/item/ammo_casing/R) + return ..(R,1) + +// Revolver internal mags /obj/item/ammo_box/magazine/internal/cylinder name = "revolver cylinder" - desc = "Oh god, this shouldn't be here" - ammo_type = "/obj/item/ammo_casing/a357" + ammo_type = /obj/item/ammo_casing/a357 caliber = "357" max_ammo = 7 -/obj/item/ammo_box/magazine/internal/cylinder/ammo_count(var/countempties = 1) - if (!countempties) - var/boolets = 0 - for (var/i = 1, i <= stored_ammo.len, i++) - var/obj/item/ammo_casing/bullet = stored_ammo[i] - if (bullet.BB) - boolets++ - return boolets - else - return stored_ammo.len +/obj/item/ammo_box/magazine/internal/cylinder/ammo_count(countempties = 1) + var/boolets = 0 + for(var/obj/item/ammo_casing/bullet in stored_ammo) + if(bullet && (bullet.BB || countempties)) + boolets++ + return boolets -/obj/item/ammo_box/magazine/internal/cylinder/rus357 - name = "russian revolver cylinder" - desc = "Oh god, this shouldn't be here" - ammo_type = "/obj/item/ammo_casing/a357" - caliber = "357" - max_ammo = 6 - multiload = 0 +/obj/item/ammo_box/magazine/internal/cylinder/get_round(keep = 0) + rotate() -/obj/item/ammo_box/magazine/internal/cylinder/rus357/New() - stored_ammo += new ammo_type(src) + var/b = stored_ammo[1] + if(!keep) + stored_ammo[1] = null + + return b + +/obj/item/ammo_box/magazine/internal/cylinder/proc/rotate() + var/b = stored_ammo[1] + stored_ammo.Cut(1,2) + stored_ammo.Insert(0, b) + +/obj/item/ammo_box/magazine/internal/cylinder/proc/spin() + for(var/i in 1 to rand(0, max_ammo*2)) + rotate() + +/obj/item/ammo_box/magazine/internal/cylinder/give_round(obj/item/ammo_casing/R, replace_spent = 0) + if(!R || (caliber && R.caliber != caliber) || (!caliber && R.type != ammo_type)) + return 0 + + for(var/i in 1 to stored_ammo.len) + var/obj/item/ammo_casing/bullet = stored_ammo[i] + if(!bullet || !bullet.BB) // found a spent ammo + stored_ammo[i] = R + R.loc = src + + if(bullet) + bullet.loc = get_turf(loc) + return 1 + + return 0 /obj/item/ammo_box/magazine/internal/cylinder/rev38 - name = "d-tiv revolver cylinder" - desc = "Oh god, this shouldn't be here" - ammo_type = "/obj/item/ammo_casing/c38" + name = "detective revolver cylinder" + ammo_type = /obj/item/ammo_casing/c38 caliber = "38" max_ammo = 6 +/obj/item/ammo_box/magazine/internal/cylinder/rev762 + name = "nagant revolver cylinder" + ammo_type = /obj/item/ammo_casing/n762 + caliber = "n762" + max_ammo = 7 + /obj/item/ammo_box/magazine/internal/cylinder/cap name = "cap gun revolver cylinder" desc = "Oh god, this shouldn't be here" - ammo_type = "/obj/item/ammo_casing/cap" + ammo_type = /obj/item/ammo_casing/cap caliber = "cap" max_ammo = 7 +// Shotgun internal mags /obj/item/ammo_box/magazine/internal/shot name = "shotgun internal magazine" - desc = "Oh god, this shouldn't be here" - ammo_type = "/obj/item/ammo_casing/shotgun/beanbag" + ammo_type = /obj/item/ammo_casing/shotgun/beanbag caliber = "shotgun" max_ammo = 4 multiload = 0 -/obj/item/ammo_box/magazine/internal/shotcom +/obj/item/ammo_box/magazine/internal/shot/ammo_count(countempties = 1) + if (!countempties) + var/boolets = 0 + for(var/obj/item/ammo_casing/bullet in stored_ammo) + if(bullet.BB) + boolets++ + return boolets + else + return ..() + +/obj/item/ammo_box/magazine/internal/shot/tube + name = "dual feed shotgun internal tube" + ammo_type = /obj/item/ammo_casing/shotgun/rubbershot + max_ammo = 4 + +/obj/item/ammo_box/magazine/internal/shot/lethal + ammo_type = /obj/item/ammo_casing/shotgun/buckshot + +/obj/item/ammo_box/magazine/internal/shot/com name = "combat shotgun internal magazine" - desc = "Oh god, this shouldn't be here" - ammo_type = "/obj/item/ammo_casing/shotgun/buckshot" - caliber = "shotgun" + ammo_type = /obj/item/ammo_casing/shotgun/buckshot max_ammo = 6 - multiload = 0 -/obj/item/ammo_box/magazine/internal/cylinder/dualshot +/obj/item/ammo_box/magazine/internal/shot/dual name = "double-barrel shotgun internal magazine" - desc = "This doesn't even exist" - ammo_type = "/obj/item/ammo_casing/shotgun/beanbag" - caliber = "shotgun" max_ammo = 2 - multiload = 0 -/obj/item/ammo_box/magazine/internal/cylinder/improvised +/obj/item/ammo_box/magazine/internal/shot/improvised name = "improvised shotgun internal magazine" - desc = "This doesn't even exist" - ammo_type = "/obj/item/ammo_casing/shotgun/improvised" - caliber = "shotgun" + ammo_type = /obj/item/ammo_casing/shotgun/improvised max_ammo = 1 - multiload = 0 -/obj/item/ammo_box/magazine/internal/shotriot +/obj/item/ammo_box/magazine/internal/shot/riot name = "riot shotgun internal magazine" - desc = "Oh god, this shouldn't be here" - ammo_type = "/obj/item/ammo_casing/shotgun/rubbershot" - caliber = "shotgun" + ammo_type = /obj/item/ammo_casing/shotgun/rubbershot max_ammo = 6 - multiload = 0 -/obj/item/ammo_box/magazine/internal/cylinder/grenadelauncher +/obj/item/ammo_box/magazine/internal/grenadelauncher name = "grenade launcher internal magazine" - ammo_type = "/obj/item/ammo_casing/a40mm" + ammo_type = /obj/item/ammo_casing/a40mm caliber = "40mm" max_ammo = 1 /obj/item/ammo_box/magazine/internal/cylinder/grenadelauncher/multi - ammo_type = "/obj/item/ammo_casing/a40mm" + ammo_type = /obj/item/ammo_casing/a40mm max_ammo = 6 +/obj/item/ammo_box/magazine/internal/speargun + name = "speargun internal magazine" + ammo_type = /obj/item/ammo_casing/caseless/magspear + caliber = "speargun" + max_ammo = 1 + +/obj/item/ammo_box/magazine/internal/rus357 + name = "russian revolver cylinder" + ammo_type = /obj/item/ammo_casing/a357 + caliber = "357" + max_ammo = 6 + multiload = 0 + +/obj/item/ammo_box/magazine/internal/rus357/New() + stored_ammo += new ammo_type(src) + /obj/item/ammo_box/magazine/internal/boltaction name = "bolt action rifle internal magazine" desc = "Oh god, this shouldn't be here" - ammo_type = "/obj/item/ammo_casing/a762" + ammo_type = /obj/item/ammo_casing/a762 caliber = "a762" max_ammo = 5 multiload = 1 +/obj/item/ammo_box/magazine/internal/boltaction/enchanted + max_ammo =1 + ammo_type = /obj/item/ammo_casing/a762/enchanted + /obj/item/ammo_box/magazine/internal/shot/toy - ammo_type = "/obj/item/ammo_casing/caseless/foam_dart" + ammo_type = /obj/item/ammo_casing/caseless/foam_dart caliber = "foam_force" max_ammo = 4 /obj/item/ammo_box/magazine/internal/shot/toy/crossbow - max_ammo = 5 + max_ammo = 5 /obj/item/ammo_box/magazine/internal/shot/toy/tommygun max_ammo = 10 @@ -116,17 +172,18 @@ /obj/item/ammo_box/magazine/m10mm name = "pistol magazine (10mm)" + desc = "A gun magazine." icon_state = "9x19p" origin_tech = "combat=2" - ammo_type = "/obj/item/ammo_casing/c10mm" + ammo_type = /obj/item/ammo_casing/c10mm caliber = "10mm" max_ammo = 8 multiple_sprites = 2 /obj/item/ammo_box/magazine/m45 name = "handgun magazine (.45)" - icon_state = "45" - ammo_type = "/obj/item/ammo_casing/c45" + icon_state = "45-8" + ammo_type = /obj/item/ammo_casing/c45 caliber = ".45" max_ammo = 8 @@ -137,7 +194,7 @@ /obj/item/ammo_box/magazine/wt550m9 name = "wt550 magazine (4.6x30mm)" icon_state = "46x30mmt-20" - ammo_type = "/obj/item/ammo_casing/c46x30mm" + ammo_type = /obj/item/ammo_casing/c46x30mm caliber = "4.6x30mm" max_ammo = 20 @@ -147,20 +204,20 @@ /obj/item/ammo_box/magazine/wt550m9/wtap name = "wt550 magazine (Armour Piercing 4.6x30mm)" - ammo_type = "/obj/item/ammo_casing/c46x30mmap" + ammo_type = /obj/item/ammo_casing/c46x30mmap /obj/item/ammo_box/magazine/wt550m9/wttx name = "wt550 magazine (Toxin Tipped 4.6x30mm)" - ammo_type = "/obj/item/ammo_casing/c46x30mmtox" + ammo_type = /obj/item/ammo_casing/c46x30mmtox /obj/item/ammo_box/magazine/wt550m9/wtic name = "wt550 magazine (Incindiary 4.6x30mm)" - ammo_type = "/obj/item/ammo_casing/c46x30mminc" + ammo_type = /obj/item/ammo_casing/c46x30mminc /obj/item/ammo_box/magazine/uzim9mm name = "uzi magazine (9mm)" icon_state = "uzi9mm-32" - ammo_type = "/obj/item/ammo_casing/c9mm" + ammo_type = /obj/item/ammo_casing/c9mm caliber = "9mm" max_ammo = 32 @@ -171,35 +228,46 @@ /obj/item/ammo_box/magazine/smgm9mm name = "SMG magazine (9mm)" icon_state = "smg9mm" - ammo_type = "/obj/item/ammo_casing/c9mm" + ammo_type = /obj/item/ammo_casing/c9mm caliber = "9mm" - max_ammo = 30 + max_ammo = 21 materials = list(MAT_METAL = 2000) /obj/item/ammo_box/magazine/smgm9mm/ap name = "SMG magazine (Armour Piercing 9mm)" - ammo_type = "/obj/item/ammo_casing/c9mmap" + ammo_type = /obj/item/ammo_casing/c9mmap materials = list(MAT_METAL = 3000) /obj/item/ammo_box/magazine/smgm9mm/toxin name = "SMG magazine (Toxin Tipped 9mm)" - ammo_type = "/obj/item/ammo_casing/c9mmtox" + ammo_type = /obj/item/ammo_casing/c9mmtox materials = list(MAT_METAL = 3000) /obj/item/ammo_box/magazine/smgm9mm/fire name = "SMG Magazine (Incendiary 9mm)" - ammo_type = "/obj/item/ammo_casing/c9mminc" + ammo_type = /obj/item/ammo_casing/c9mminc materials = list(MAT_METAL = 3000) /obj/item/ammo_box/magazine/smgm9mm/update_icon() ..() icon_state = "[initial(icon_state)]-[round(ammo_count(),6)]" +/obj/item/ammo_box/magazine/pistolm9mm + name = "pistol magazine (9mm)" + icon_state = "9x19p-8" + ammo_type = /obj/item/ammo_casing/c9mm + caliber = "9mm" + max_ammo = 15 + +/obj/item/ammo_box/magazine/pistolm9mm/update_icon() + ..() + icon_state = "9x19p-[ammo_count() ? "8" : "0"]" + /obj/item/ammo_box/magazine/smgm45 name = "SMG magazine (.45)" icon_state = "c20r45" origin_tech = "combat=2" - ammo_type = "/obj/item/ammo_casing/c45" + ammo_type = /obj/item/ammo_casing/c45 caliber = ".45" max_ammo = 20 @@ -210,7 +278,7 @@ /obj/item/ammo_box/magazine/tommygunm45 name = "drum magazine (.45)" icon_state = "drum45" - ammo_type = "/obj/item/ammo_casing/c45" + ammo_type = /obj/item/ammo_casing/c45 caliber = ".45" max_ammo = 50 @@ -218,7 +286,7 @@ name = "handgun magazine (.50ae)" icon_state = "50ae" origin_tech = "combat=2" - ammo_type = "/obj/item/ammo_casing/a50" + ammo_type = /obj/item/ammo_casing/a50 caliber = ".50" max_ammo = 7 multiple_sprites = 1 @@ -226,7 +294,7 @@ /obj/item/ammo_box/magazine/m75 name = "specialized magazine (.75)" icon_state = "75" - ammo_type = "/obj/item/ammo_casing/caseless/a75" + ammo_type = /obj/item/ammo_casing/caseless/a75 caliber = "75" multiple_sprites = 2 max_ammo = 8 @@ -235,50 +303,16 @@ name = "toploader magazine (5.56mm)" icon_state = "5.56m" origin_tech = "combat=5;syndicate=1" - ammo_type = "/obj/item/ammo_casing/a556" + ammo_type = /obj/item/ammo_casing/a556 caliber = "a556" max_ammo = 30 multiple_sprites = 2 -/obj/item/ammo_box/magazine/m762 - name = "box magazine (7.62mm)" - icon_state = "a762" - origin_tech = "combat=2" - ammo_type = "/obj/item/ammo_casing/a762" - caliber = "a762" - max_ammo = 50 - -/obj/item/ammo_box/magazine/m762/update_icon() - ..() - icon_state = "[initial(icon_state)]-[round(ammo_count(),10)]" - -/obj/item/ammo_box/magazine/m762/buckshot - name = "box magazine (buckshot)" - icon_state = "b762" - caliber = "shotgun" - ammo_type ="/obj/item/ammo_casing/shotgun/buckshot" - max_ammo = 300 // Bluespace! - -/obj/item/ammo_box/magazine/m762/buckshot/update_icon() - ..() - icon_state = "[initial(icon_state)]-[round(ammo_count(),60)]" - -/obj/item/ammo_box/magazine/m762/he // I am not a good person. - name = "box magazine (40mm high explosive)" - icon_state = "g762" - caliber = "40mm" - ammo_type ="/obj/item/ammo_casing/a40mm" - max_ammo = 25 - -/obj/item/ammo_box/magazine/m762/he/update_icon() - ..() - icon_state = "[initial(icon_state)]-[round(ammo_count(),5)]" - - /obj/item/ammo_box/magazine/m12g name = "shotgun magazine (12g slugs)" + desc = "A drum magazine." icon_state = "m12gb" - ammo_type = "/obj/item/ammo_casing/shotgun" + ammo_type = /obj/item/ammo_casing/shotgun origin_tech = "combat=3;syndicate=1" caliber = "shotgun" max_ammo = 8 @@ -290,36 +324,45 @@ /obj/item/ammo_box/magazine/m12g/buckshot name = "shotgun magazine (12g buckshot slugs)" icon_state = "m12gb" - ammo_type = "/obj/item/ammo_casing/shotgun/buckshot" + ammo_type = /obj/item/ammo_casing/shotgun/buckshot /obj/item/ammo_box/magazine/m12g/stun name = "shotgun magazine (12g taser slugs)" icon_state = "m12gs" - ammo_type = "/obj/item/ammo_casing/shotgun/stunslug" + ammo_type = /obj/item/ammo_casing/shotgun/stunslug /obj/item/ammo_box/magazine/m12g/dragon name = "shotgun magazine (12g dragon's breath)" icon_state = "m12gf" - ammo_type = "/obj/item/ammo_casing/shotgun/incendiary/dragonsbreath" + ammo_type = /obj/item/ammo_casing/shotgun/incendiary/dragonsbreath + +/obj/item/ammo_box/magazine/m12g/bioterror + name = "shotgun magazine (12g bioterror)" + icon_state = "m12gt" + ammo_type = /obj/item/ammo_casing/shotgun/dart/bioterror + +/obj/item/ammo_box/magazine/m12g/breach + name = "shotgun magazine (12g breacher slugs)" + icon_state = "m12gbc" + ammo_type = /obj/item/ammo_casing/shotgun/breaching -//FOAM DARTS /obj/item/ammo_box/magazine/toy name = "foam force META magazine" - ammo_type = "/obj/item/ammo_casing/caseless/foam_dart" + ammo_type = /obj/item/ammo_casing/caseless/foam_dart caliber = "foam_force" /obj/item/ammo_box/magazine/toy/smg name = "foam force SMG magazine" icon_state = "smg9mm-30" - max_ammo = 30 + max_ammo = 20 /obj/item/ammo_box/magazine/toy/smg/update_icon() ..() - icon_state = "smg9mm-[round(ammo_count(),6)]" + icon_state = "smg9mm-[round(ammo_count(),5)]" /obj/item/ammo_box/magazine/toy/smg/riot - ammo_type = "/obj/item/ammo_casing/caseless/foam_dart/riot" + ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot /obj/item/ammo_box/magazine/toy/pistol name = "foam force pistol magazine" @@ -328,11 +371,11 @@ multiple_sprites = 2 /obj/item/ammo_box/magazine/toy/pistol/riot - ammo_type = "/obj/item/ammo_casing/caseless/foam_dart/riot" + ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot /obj/item/ammo_box/magazine/toy/smgm45 name = "donksoft SMG magazine" - ammo_type = "/obj/item/ammo_casing/caseless/foam_dart/riot" + ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot max_ammo = 20 /obj/item/ammo_box/magazine/toy/smgm45/update_icon() @@ -341,7 +384,7 @@ /obj/item/ammo_box/magazine/toy/m762 name = "donksoft box magazine" - ammo_type = "/obj/item/ammo_casing/caseless/foam_dart/riot" + ammo_type = /obj/item/ammo_casing/caseless/foam_dart/riot max_ammo = 50 /obj/item/ammo_box/magazine/toy/m762/update_icon() diff --git a/code/modules/projectiles/ammunition/special.dm b/code/modules/projectiles/ammunition/special.dm new file mode 100644 index 00000000000..d17d65e9fc8 --- /dev/null +++ b/code/modules/projectiles/ammunition/special.dm @@ -0,0 +1,49 @@ +/obj/item/ammo_casing/magic + name = "magic casing" + desc = "I didn't even know magic needed ammo..." + projectile_type = /obj/item/projectile/magic + +/obj/item/ammo_casing/magic/change + projectile_type = /obj/item/projectile/magic/change + +/obj/item/ammo_casing/magic/animate + projectile_type = /obj/item/projectile/magic/animate + +/obj/item/ammo_casing/magic/heal + projectile_type = /obj/item/projectile/magic/resurrection + +/obj/item/ammo_casing/magic/death + projectile_type = /obj/item/projectile/magic/death + +/obj/item/ammo_casing/magic/teleport + projectile_type = /obj/item/projectile/magic/teleport + +/obj/item/ammo_casing/magic/door + projectile_type = /obj/item/projectile/magic/door + +/obj/item/ammo_casing/magic/fireball + projectile_type = /obj/item/projectile/magic/fireball + +/obj/item/ammo_casing/magic/chaos + projectile_type = /obj/item/projectile/magic + +/obj/item/ammo_casing/magic/chaos/newshot() + projectile_type = pick(typesof(/obj/item/projectile/magic)) + ..() + +/obj/item/ammo_casing/magic/honk + projectile_type = /obj/item/projectile/bullet/honker + +/obj/item/ammo_casing/forcebolt + projectile_type = /obj/item/projectile/forcebolt + +/obj/item/ammo_casing/syringegun + name = "syringe gun spring" + desc = "A high-power spring that throws syringes." + projectile_type = null + +/obj/item/ammo_casing/energy/c3dbullet + projectile_type = /obj/item/projectile/bullet/midbullet3 + select_name = "spraydown" + fire_sound = 'sound/weapons/gunshot_smg.ogg' + e_cost = 200 diff --git a/code/modules/projectiles/firing.dm b/code/modules/projectiles/firing.dm new file mode 100644 index 00000000000..2a75004f223 --- /dev/null +++ b/code/modules/projectiles/firing.dm @@ -0,0 +1,95 @@ +/obj/item/ammo_casing/proc/fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, params, distro, quiet, zone_override = "", spread) + distro += variance + for (var/i = max(1, pellets), i > 0, i--) + var/targloc = get_turf(target) + ready_proj(target, user, quiet, zone_override) + if(distro) //We have to spread a pixel-precision bullet. throw_proj was called before so angles should exist by now... + if(randomspread) + spread = round((rand() - 0.5) * distro) + else //Smart spread + spread = round((i / pellets - 0.5) * distro) + if(!throw_proj(target, targloc, user, params, spread)) + return 0 + if(i > 1) + newshot() + if(click_cooldown_override) + user.changeNext_move(click_cooldown_override) + else + user.changeNext_move(CLICK_CD_RANGE) + user.newtonian_move(get_dir(target, user)) + update_icon() + return 1 + +/obj/item/ammo_casing/proc/ready_proj(atom/target, mob/living/user, quiet, zone_override = "") + if (!BB) + return + BB.original = target + BB.firer = user + if (zone_override) + BB.def_zone = zone_override + else + BB.def_zone = user.zone_sel.selecting + BB.suppressed = quiet + + if(reagents && BB.reagents) + reagents.trans_to(BB, reagents.total_volume) //For chemical darts/bullets + qdel(reagents) + +/obj/item/ammo_casing/proc/throw_proj(atom/target, turf/targloc, mob/living/user, params, spread) + var/turf/curloc = get_turf(user) + if (!istype(targloc) || !istype(curloc) || !BB) + return 0 + BB.ammo_casing = src + if(targloc == curloc) + if(target) //if the target is right on our location we go straight to bullet_act() + target.bullet_act(BB, BB.def_zone) + qdel(BB) + BB = null + return 1 + + BB.preparePixelProjectile(target, targloc, user, params, spread) + if(BB) + BB.fire() + BB = null + return 1 + +/obj/item/ammo_casing/proc/spread(turf/target, turf/current, distro) + var/dx = abs(target.x - current.x) + var/dy = abs(target.y - current.y) + return locate(target.x + round(gaussian(0, distro) * (dy+2)/8, 1), target.y + round(gaussian(0, distro) * (dx+2)/8, 1), target.z) + +/obj/item/projectile/proc/preparePixelProjectile(atom/target, var/turf/targloc, mob/living/user, params, spread) + var/turf/curloc = get_turf(user) + loc = get_turf(user) + starting = get_turf(user) + current = curloc + yo = targloc.y - curloc.y + xo = targloc.x - curloc.x + + if(params) + var/list/mouse_control = params2list(params) + if(mouse_control["icon-x"]) + p_x = text2num(mouse_control["icon-x"]) + if(mouse_control["icon-y"]) + p_y = text2num(mouse_control["icon-y"]) + if(mouse_control["screen-loc"]) + //Split screen-loc up into X+Pixel_X and Y+Pixel_Y + var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",") + + //Split X+Pixel_X up into list(X, Pixel_X) + var/list/screen_loc_X = splittext(screen_loc_params[1],":") + + //Split Y+Pixel_Y up into list(Y, Pixel_Y) + var/list/screen_loc_Y = splittext(screen_loc_params[2],":") + var/x = text2num(screen_loc_X[1]) * world.icon_size + text2num(screen_loc_X[2]) - world.icon_size + (user.client ? user.client.pixel_x : 0) + var/y = text2num(screen_loc_Y[1]) * world.icon_size + text2num(screen_loc_Y[2]) - world.icon_size + (user.client ? user.client.pixel_y : 0) + + //Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average. + var/screenview = (user.client.view * 2 + 1) * world.icon_size //Refer to http://www.byond.com/docs/ref/info.html#/client/var/view for mad maths + + var/ox = round(screenview/2) //"origin" x + var/oy = round(screenview/2) //"origin" y + var/angle = Atan2(y - oy, x - ox) + Angle = angle + if(spread) + Angle += spread diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index cb4f21d2497..f86bfff5abb 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1,54 +1,59 @@ - #define SAWN_INTACT 0 - #define SAWN_OFF 1 - #define SAWN_SAWING -1 - /obj/item/weapon/gun name = "gun" - desc = "Its a gun. It's pretty terrible, though." - icon = 'icons/obj/gun.dmi' + desc = "It's a gun. It's pretty terrible, though." + icon = 'icons/obj/guns/projectile.dmi' icon_state = "detective" item_state = "gun" - lefthand_file = 'icons/mob/inhands/guns_lefthand.dmi' - righthand_file = 'icons/mob/inhands/guns_righthand.dmi' flags = CONDUCT slot_flags = SLOT_BELT materials = list(MAT_METAL=2000) - w_class = 3.0 + w_class = 3 throwforce = 5 - throw_speed = 4 + throw_speed = 3 throw_range = 5 - force = 5.0 + force = 5 origin_tech = "combat=1" needs_permit = 1 attack_verb = list("struck", "hit", "bashed") - var/fire_sound = 'sound/weapons/Gunshot.ogg' - var/obj/item/projectile/in_chamber = null - var/silenced = 0 - var/ghettomodded = 0 - var/recoil = 0 + var/fire_sound = "gunshot" + var/fire_sound_text = "gunshot" //the fire sound that shows in chat messages: laser blast, gunshot, etc. + var/suppressed = 0 //whether or not a message is displayed when fired var/can_suppress = 0 var/can_unsuppress = 1 + var/recoil = 0 //boom boom shake the room var/clumsy_check = 1 - var/sawn_desc = null + var/obj/item/ammo_casing/chambered = null + var/trigger_guard = TRIGGER_GUARD_NORMAL //trigger guard on the weapon, hulks can't fire them with their big meaty fingers + var/sawn_desc = null //description change if weapon is sawn-off var/sawn_state = SAWN_INTACT - var/obj/item/ammo_casing/chambered = null // The round (not bullet) that is in the chamber. THIS MISPLACED ITEM BROUGHT TO YOU BY HACKY BUCKSHOT. - var/tmp/list/mob/living/target //List of who yer targeting. - var/tmp/lock_time = -100 - var/tmp/mouthshoot = 0 ///To stop people from suiciding twice... >.> - var/automatic = 0 //Used to determine if you can target multiple people. - var/tmp/mob/living/last_moved_mob //Used to fire faster at more than one person. - var/tmp/told_cant_shoot = 0 //So that it doesn't spam them with the fact they cannot hit them. - var/firerate = 1 // 0 for one bullet after tarrget moves and aim is lowered, - //1 for keep shooting until aim is lowered - var/fire_delay = 0 - var/last_fired = 0 + var/burst_size = 1 //how large a burst is + var/fire_delay = 0 //rate of fire for burst firing and semi auto + var/firing_burst = 0 //Prevent the weapon from firing again while already firing + var/semicd = 0 //cooldown handler + var/weapon_weight = WEAPON_LIGHT + var/list/restricted_species + + var/spread = 0 + var/randomspread = 1 + + var/unique_rename = 0 //allows renaming with a pen + var/unique_reskin = 0 //allows one-time reskinning + var/current_skin = null //the skin choice if we had a reskin + var/list/options = list() + + lefthand_file = 'icons/mob/inhands/guns_lefthand.dmi' + righthand_file = 'icons/mob/inhands/guns_righthand.dmi' + var/obj/item/device/flashlight/F = null var/can_flashlight = 0 - var/heavy_weapon = 0 - var/randomspread = 0 - var/burst_size = 1 + var/list/upgrades = list() + + var/ammo_x_offset = 0 //used for positioning ammo count overlay on sprite + var/ammo_y_offset = 0 + var/flight_x_offset = 0 + var/flight_y_offset = 0 //Zooming var/zoomable = FALSE //whether the gun generates a Zoom action on creation @@ -56,312 +61,200 @@ var/zoom_amt = 3 //Distance in TURFs to move the user's screen forward (the "zoom" effect) var/datum/action/toggle_scope_zoom/azoom - proc/ready_to_fire() - if(world.time >= last_fired + fire_delay) - last_fired = world.time - return 1 - else - return 0 - - proc/process_chambered() - return 0 - - - proc/special_check(var/mob/M) //Placeholder for any special checks, like detective's revolver. - if(!M.IsAdvancedToolUser()) - return 0 - return 1 - - - proc/shoot_with_empty_chamber(mob/living/user as mob|obj) - to_chat(user, "*click*") - playsound(user, 'sound/weapons/emptyclick.ogg', 40, 1) - return - - emp_act(severity) - for(var/obj/O in contents) - O.emp_act(severity) - - proc/prepare_shot(var/obj/item/projectile/proj) //Transfer properties from the gun to the bullet - proj.shot_from = src - proj.silenced = silenced - return - /obj/item/weapon/gun/New() + ..() + if(F) + verbs += /obj/item/weapon/gun/proc/toggle_gunlight build_zooming() + +/obj/item/weapon/gun/examine(mob/user) ..() + if(unique_reskin && !current_skin) + to_chat(user, "Alt-click it to reskin it.") + if(unique_rename) + to_chat(user, "Use a pen on it to rename it.") -/obj/item/weapon/gun/pickup(mob/user) +/obj/item/weapon/gun/proc/process_chamber() + return 0 - if(azoom) - azoom.Grant(user) - ..() - -/obj/item/weapon/gun/dropped(mob/user) - - zoom(user,FALSE) - if(azoom) - azoom.Remove(user) - ..() - -/obj/item/weapon/gun/afterattack(atom/A as mob|obj|turf|area, mob/living/user as mob|obj, flag, params) - if(flag) return //we're placing gun on a table or in backpack - if(istype(target, /obj/machinery/recharger) && istype(src, /obj/item/weapon/gun/energy)) return//Shouldnt flag take care of this? - Fire(A,user,params) //Otherwise, fire normally. - -/obj/item/weapon/gun/proc/isHandgun() +//check if there's enough ammo/energy/whatever to shoot one time +//i.e if clicking would make it shoot +/obj/item/weapon/gun/proc/can_shoot() return 1 -/obj/item/weapon/gun/proc/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0)//TODO: go over this +/obj/item/weapon/gun/proc/shoot_with_empty_chamber(mob/living/user as mob|obj) + to_chat(user, "*click*") + playsound(user, 'sound/weapons/empty.ogg', 100, 1) + +/obj/item/weapon/gun/proc/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1) + if(recoil) + shake_camera(user, recoil + 1, recoil) + + if(suppressed) + playsound(user, fire_sound, 10, 1) + else + playsound(user, fire_sound, 50, 1) + if(!message) + return + if(pointblank) + user.visible_message("[user] fires [src] point blank at [pbtarget]!", "You fire [src] point blank at [pbtarget]!", "You hear \a [fire_sound_text]!") + else + user.visible_message("[user] fires [src]!", "You fire [src]!", "You hear \a [fire_sound_text]!") + + if(weapon_weight >= WEAPON_MEDIUM) + if(user.get_inactive_hand()) + if(prob(15)) + if(user.drop_item()) + user.visible_message("[src] flies out of [user]'s hands!", "[src] kicks out of your grip!") + +/obj/item/weapon/gun/emp_act(severity) + for(var/obj/O in contents) + O.emp_act(severity) + +/obj/item/weapon/gun/afterattack(atom/target, mob/living/user, flag, params) + if(firing_burst) + return + 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 == "harm") //melee attack + return + if(target == user && user.zone_sel.selecting != "mouth") //so we can't shoot ourselves (unless mouth selected) + return + + if(istype(user))//Check if the user can use the gun, if the user isn't alive(turrets) assume it can. + var/mob/living/L = user + if(!can_trigger_gun(L)) + return + + if(!can_shoot()) //Just because you can pull the trigger doesn't mean it can't shoot. + shoot_with_empty_chamber(user) + return + + if(flag) + if(user.zone_sel.selecting == "mouth") + handle_suicide(user, target, params) + return + + //Exclude lasertag guns from the CLUMSY check. if(clumsy_check) - if(istype(user, /mob/living)) - var/mob/living/M = user - if ((CLUMSY in M.mutations) && prob(50)) - to_chat(M, "[src] blows up in your face.") - M.take_organ_damage(0,20) - M.drop_item() - qdel(src) + if(istype(user)) + if (user.disabilities & CLUMSY && prob(40)) + to_chat(user, "You shoot yourself in the foot with \the [src]!") + var/shot_leg = pick("l_foot", "r_foot") + process_fire(user, user, 0, params, zone_override = shot_leg) + user.drop_item() return - if (!user.IsAdvancedToolUser() || istype(user, /mob/living/simple_animal/diona)) - to_chat(user, "You don't have the dexterity to do this!") + if(weapon_weight == WEAPON_HEAVY && user.get_inactive_hand()) + to_chat(user, "You need both hands free to fire \the [src]!") return - if(istype(user, /mob/living)) - var/mob/living/M = user - if (HULK in M.mutations) - to_chat(M, "Your meaty finger is much too large for the trigger guard!") - return - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.species.flags & NOGUNS) - to_chat(user, "Your fingers don't fit in the trigger guard!") - return - if(H.martial_art && H.martial_art.name == "The Sleeping Carp") //great dishonor to famiry - to_chat(user, "Use of ranged weaponry would bring dishonor to the clan.") - return + process_fire(target,user,1,params) + +/obj/item/weapon/gun/proc/can_trigger_gun(var/mob/living/user) + if(!user.can_use_guns(src)) + return 0 + if(restricted_species && restricted_species.len && !(user.get_species() in restricted_species)) + to_chat(user, "[src] is incompatible with your biology!") + return 0 + return 1 + +obj/item/weapon/gun/proc/newshot() + return + +/obj/item/weapon/gun/proc/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params, zone_override) add_fingerprint(user) - if(!special_check(user)) + if(semicd) return - if (!ready_to_fire()) - if (world.time % 3) //to prevent spam - to_chat(user, "[src] is not ready to fire again!") - return - - if(heavy_weapon) + if(weapon_weight) if(user.get_inactive_hand()) recoil = 4 //one-handed kick else recoil = initial(recoil) - if (istype(in_chamber, /obj/item/projectile/bullet/blank)) // A hacky way of making blank shotgun shells work again. Honk. - in_chamber.delete() - in_chamber = null - return - - user.changeNext_move(CLICK_CD_RANGE) - - var/spread = 0 - var/turf/targloc = get_turf(target) - for(var/f = 1 to burst_size) - if(!process_chambered()) //CHECK - return click_empty(user) - - if(chambered) - for (var/i = max(1, chambered.pellets), i > 0, i--) //Previous way of doing it fucked up math for spreading. This way, even the first projectile is part of the spread code. - if(i != max(1, chambered.pellets)) //Have we fired the initial chambered bullet yet? - in_chamber = new chambered.projectile_type() - ready_projectile(target, user) - prepare_shot(in_chamber) - if(chambered.deviation) - if(randomspread) //Random spread - spread = (rand() - 0.5) * chambered.deviation - else //Smart spread - spread = (i / chambered.pellets - 0.5) * chambered.deviation - if(!process_projectile(targloc, user, params, spread)) - return 0 - else - ready_projectile(target, user) - prepare_shot(in_chamber) - if(!process_projectile(targloc, user, params, spread)) - return 0 - - if(recoil) - spawn() - shake_camera(user, recoil + 1, recoil) - - if(silenced) - playsound(user, fire_sound, 10, 1) - else - playsound(user, fire_sound, 50, 1) - if(f == 1) // Only print this once - user.visible_message("[user] fires [src][reflex ? " by reflex":""]!", \ - "You fire [src][reflex ? "by reflex":""]!", \ - "You hear a [istype(in_chamber, /obj/item/projectile/beam) ? "laser blast" : "gunshot"]!") - - if(heavy_weapon) - if(user.get_inactive_hand()) - if(prob(15)) - user.visible_message("[src] flies out of [user]'s hands!", "[src] kicks out of your grip!") - user.drop_item() + if(burst_size > 1) + firing_burst = 1 + for(var/i = 1 to burst_size) + if(!user) + break + if(!issilicon(user)) + if( i>1 && !(src in get_both_hands(user))) //for burst firing break - - user.newtonian_move(get_dir(target, user)) + if(chambered) + var/sprd = 0 + if(randomspread) + sprd = round((rand() - 0.5) * spread) + else + sprd = round((i / burst_size - 0.5) * spread) + if(!chambered.fire(target, user, params, ,suppressed, zone_override, sprd)) + shoot_with_empty_chamber(user) + break + else + if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot + shoot_live_shot(user, 1, target, message) + else + shoot_live_shot(user, 0, target, message) + else + shoot_with_empty_chamber(user) + break + process_chamber() + update_icon() + sleep(fire_delay) + firing_burst = 0 + else + if(chambered) + if(!chambered.fire(target, user, params, , suppressed, zone_override, spread)) + shoot_with_empty_chamber(user) + return + else + if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot + shoot_live_shot(user, 1, target, message) + else + shoot_live_shot(user, 0, target, message) + else + shoot_with_empty_chamber(user) + return + process_chamber() update_icon() + semicd = 1 + spawn(fire_delay) + semicd = 0 + + if(user) if(user.hand) user.update_inv_l_hand() else user.update_inv_r_hand() - sleep(fire_delay) + feedback_add_details("gun_fired","[type]") -/obj/item/weapon/gun/proc/ready_projectile(atom/target as mob|obj|turf, mob/living/user) - in_chamber.firer = user - in_chamber.def_zone = user.zone_sel.selecting - in_chamber.original = target - return - -/obj/item/weapon/gun/proc/process_projectile(var/turf/targloc, mob/living/user as mob|obj, params, spread) - var/turf/curloc = user.loc - if (!istype(targloc) || !istype(curloc) || !in_chamber) - return 0 - if(targloc == curloc) //Fire the projectile - user.bullet_act(in_chamber) - del(in_chamber) - update_icon() - return 1 - - in_chamber.loc = get_turf(user) - in_chamber.starting = get_turf(user) - in_chamber.current = curloc - in_chamber.OnFired() - in_chamber.yo = targloc.y - curloc.y - in_chamber.xo = targloc.x - curloc.x - if(params) - var/list/mouse_control = params2list(params) - if(mouse_control["icon-x"]) - in_chamber.p_x = text2num(mouse_control["icon-x"]) - if(mouse_control["icon-y"]) - in_chamber.p_y = text2num(mouse_control["icon-y"]) - if(mouse_control["screen-loc"]) - //Split screen-loc up into X+Pixel_X and Y+Pixel_Y - var/list/screen_loc_params = splittext(mouse_control["screen-loc"], ",") - - //Split X+Pixel_X up into list(X, Pixel_X) - var/list/screen_loc_X = splittext(screen_loc_params[1],":") - - //Split Y+Pixel_Y up into list(Y, Pixel_Y) - var/list/screen_loc_Y = splittext(screen_loc_params[2],":") - - var/x = text2num(screen_loc_X[1]) * 32 + text2num(screen_loc_X[2]) - 32 - var/y = text2num(screen_loc_Y[1]) * 32 + text2num(screen_loc_Y[2]) - 32 - var/ox = round(480/2) //"origin" x - Basically center of the screen. This is a bad way of doing it because if you are able to view MORE than 17 tiles at a time your aim will get fucked. - var/oy = round(480/2) //"origin" y - Basically center of the screen. - - var/angle = Atan2(y - oy, x - ox) - - in_chamber.Angle = angle - - if(istype(user, /mob/living/carbon)) //Increase spread based on shock - var/mob/living/carbon/mob = user - if(mob.shock_stage > 120) - spread += rand(-5,5) - else if(mob.shock_stage > 70) - spread += rand(-2,2) - - if(spread) - in_chamber.Angle += spread - if(in_chamber) - in_chamber.process() - in_chamber = null - return 1 - -/obj/item/weapon/gun/proc/can_fire() - return process_chambered() - -/obj/item/weapon/gun/proc/can_hit(var/mob/living/target as mob, var/mob/living/user as mob) - return in_chamber.check_fire(target,user) - -/obj/item/weapon/gun/proc/click_empty(mob/user = null) - if (user) - user.visible_message("*click click*", "\red *click*") - playsound(user, 'sound/weapons/empty.ogg', 100, 1) +/obj/item/weapon/gun/attack(mob/M as mob, mob/user) + if(user.a_intent == "harm") //Flogging + ..() else - src.visible_message("*click click*") - playsound(src.loc, 'sound/weapons/empty.ogg', 100, 1) + return -/obj/item/weapon/gun/attack(mob/living/M as mob, mob/living/user as mob, def_zone) - //Suicide handling. - if (M == user && user.zone_sel.selecting == "mouth" && !mouthshoot) - mouthshoot = 1 - M.visible_message(" [user] sticks their gun in their mouth, ready to pull the trigger...") - if(!do_after(user, 40, target = M)) - M.visible_message(" [user] decided life was worth living") - mouthshoot = 0 - return - if (process_chambered()) - user.visible_message("[user] pulls the trigger.") - if(silenced) - playsound(user, fire_sound, 10, 1) - else - playsound(user, fire_sound, 50, 1) - if(istype(in_chamber, /obj/item/projectile/lasertag) || istype(in_chamber, /obj/item/projectile/bullet/reusable/foam_dart)) - user.show_message("You feel rather silly, trying to commit suicide with a toy.") - mouthshoot = 0 - return - in_chamber.on_hit(M) - if (in_chamber.damage_type != STAMINA) - user.apply_damage(in_chamber.damage*2.5, in_chamber.damage_type, "head", used_weapon = "Point blank shot in the mouth with \a [in_chamber]", sharp=1) - user.death() - else - to_chat(user, "Ow...") - user.apply_effect(110,STAMINA,0) - del(in_chamber) - mouthshoot = 0 - return - else - click_empty(user) - mouthshoot = 0 - return - - if (src.process_chambered()) - //Point blank shooting if on harm intent or target we were targeting. - if(user.a_intent == I_HARM) - user.visible_message("\red \The [user] fires \the [src] point blank at [M]!") - if(istype(in_chamber)) in_chamber.damage *= 1.3 - Fire(M,user,0,0,1) - return - else if(target && M in target) - Fire(M,user,0,0,1) ///Otherwise, shoot! - return - else - return ..() //Pistolwhippin' - - -/obj/item/weapon/gun/attackby(var/obj/item/A as obj, mob/user as mob, params) - if(istype(A, /obj/item/device/flashlight/seclite)) - var/obj/item/device/flashlight/seclite/S = A +/obj/item/weapon/gun/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/device/flashlight/seclite)) + var/obj/item/device/flashlight/seclite/S = I if(can_flashlight) if(!F) - if(user.l_hand != src && user.r_hand != src) - to_chat(user, "You'll need [src] in your hands to do that.") + if(!user.unEquip(I)) return - user.drop_item() to_chat(user, "You click [S] into place on [src].") if(S.on) set_light(0) F = S - A.loc = src + I.loc = src update_icon() update_gunlight(user) verbs += /obj/item/weapon/gun/proc/toggle_gunlight - if(istype(A, /obj/item/weapon/screwdriver)) - if(F) - if(user.l_hand != src && user.r_hand != src) - to_chat(user, "You'll need [src] in your hands to do that.") - return + + if(istype(I, /obj/item/weapon/screwdriver)) + if(F && can_flashlight) for(var/obj/item/device/flashlight/seclite/S in src) to_chat(user, "You unscrew the seclite from [src].") F = null @@ -370,8 +263,11 @@ S.update_brightness(user) update_icon() verbs -= /obj/item/weapon/gun/proc/toggle_gunlight + + if(unique_rename) + if(istype(I, /obj/item/weapon/pen)) + rename_gun(user) ..() - return /obj/item/weapon/gun/proc/toggle_gunlight() set name = "Toggle Gunlight" @@ -383,15 +279,14 @@ var/mob/living/carbon/human/user = usr if(!isturf(user.loc)) - to_chat(user, "You cannot turn the light on while in this [user.loc].") + to_chat(user, "You cannot turn the light on while in this [user.loc]!") F.on = !F.on to_chat(user, "You toggle the gunlight [F.on ? "on":"off"].") playsound(user, 'sound/weapons/empty.ogg', 100, 1) update_gunlight(user) - return -/obj/item/weapon/gun/proc/update_gunlight(var/mob/user = null) +/obj/item/weapon/gun/proc/update_gunlight(mob/user = null) if(F) if(F.on) set_light(F.brightness_on) @@ -400,7 +295,80 @@ update_icon() else set_light(0) + +/obj/item/weapon/gun/pickup(mob/user) + ..() + if(azoom) + azoom.Grant(user) + +/obj/item/weapon/gun/dropped(mob/user) + ..() + zoom(user,FALSE) + if(azoom) + azoom.Remove(user) + +/obj/item/weapon/gun/AltClick(mob/user) + ..() + if(user.incapacitated()) + to_chat(user, "You can't do that right now!") return + if(unique_reskin && !current_skin && loc == user) + reskin_gun(user) + +/obj/item/weapon/gun/proc/reskin_gun(mob/M) + var/choice = input(M,"Warning, you can only reskin your weapon once!","Reskin Gun") in options + + if(src && choice && !current_skin && !M.incapacitated() && in_range(M,src)) + if(options[choice] == null) + return + current_skin = options[choice] + to_chat(M, "Your gun is now skinned as [choice]. Say hello to your new friend.") + update_icon() + +/obj/item/weapon/gun/proc/rename_gun(mob/M) + var/input = stripped_input(M,"What do you want to name the gun?", ,"", MAX_NAME_LEN) + + if(src && input && !M.stat && in_range(M,src) && !M.restrained() && M.canmove) + name = input + to_chat(M, "You name the gun [input]. Say hello to your new friend.") + return + +/obj/item/weapon/gun/proc/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params) + if(!ishuman(user) || !ishuman(target)) + return + + if(semicd) + return + + if(user == target) + target.visible_message("[user] sticks [src] in 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 = 1 + + if(!do_mob(user, target, 120) || user.zone_sel.selecting != "mouth") + if(user) + if(user == target) + user.visible_message("[user] decided life was worth living.") + else if(target && target.Adjacent(user)) + target.visible_message("[user] has decided to spare [target]'s life.", "[user] has decided to spare your life!") + semicd = 0 + return + + semicd = 0 + + target.visible_message("[user] pulls the trigger!", "[user] pulls the trigger!") + + if(chambered && chambered.BB) + chambered.BB.damage *= 5 + + process_fire(target, user, 1, params) + +/obj/item/weapon/gun/proc/isHandgun() + return 1 ///////////// // ZOOMING // @@ -424,8 +392,6 @@ gun.zoom(L, FALSE) ..() - - /obj/item/weapon/gun/proc/zoom(mob/living/user, forced_zoom) if(!user || !user.client) return diff --git a/code/modules/projectiles/guns/alien.dm b/code/modules/projectiles/guns/alien.dm index eeb775be84a..a6bc11ad83e 100644 --- a/code/modules/projectiles/guns/alien.dm +++ b/code/modules/projectiles/guns/alien.dm @@ -1,108 +1,100 @@ -//Vox pinning weapon. -/obj/item/weapon/gun/launcher/spikethrower - - name = "Vox spike thrower" +/obj/item/weapon/gun/projectile/automatic/spikethrower + name = "\improper Vox spike thrower" desc = "A vicious alien projectile weapon. Parts of it quiver gelatinously, as though the thing is insectile and alive." - - var/last_regen = 0 - var/spike_gen_time = 100 - var/max_spikes = 3 - var/spikes = 3 - release_force = 30 - icon = 'icons/obj/gun.dmi' - icon_state = "spikethrower3" + icon_state = "spikethrower" item_state = "spikethrower" + w_class = 2 fire_sound_text = "a strange noise" - fire_sound = 'sound/weapons/bladeslice.ogg' + mag_type = /obj/item/ammo_box/magazine/internal/spikethrower + burst_size = 2 + fire_delay = 3 + can_suppress = 0 + var/charge_tick = 0 + var/charge_delay = 15 + restricted_species = list("Vox", "Vox Armalis") -/obj/item/weapon/gun/launcher/spikethrower/New() +/obj/item/weapon/gun/projectile/automatic/spikethrower/New() ..() processing_objects.Add(src) - last_regen = world.time -/obj/item/weapon/gun/launcher/spikethrower/Destroy() +/obj/item/weapon/gun/projectile/automatic/spikethrower/Destroy() processing_objects.Remove(src) return ..() -/obj/item/weapon/gun/launcher/spikethrower/process() - - if(spikes < max_spikes && world.time > last_regen + spike_gen_time) - spikes++ - last_regen = world.time - update_icon() - -/obj/item/weapon/gun/launcher/spikethrower/examine(mob/user) - ..(user) - to_chat(user, "It has [spikes] [spikes == 1 ? "spike" : "spikes"] remaining.") - -/obj/item/weapon/gun/launcher/spikethrower/update_icon() - icon_state = "spikethrower[spikes]" - -/obj/item/weapon/gun/launcher/spikethrower/emp_act(severity) +/obj/item/weapon/gun/projectile/automatic/spikethrower/update_icon() return -/obj/item/weapon/gun/launcher/spikethrower/special_check(user) - if(istype(user,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = user - if(H.species && H.species.name != "Vox" && H.species.name != "Vox Armalis") - to_chat(user, "\red \The [src] does not respond to you!") - return 0 +/obj/item/weapon/gun/projectile/automatic/spikethrower/process() + charge_tick++ + if(charge_tick < charge_delay || !magazine) + return + charge_tick = 0 + var/obj/item/ammo_casing/caseless/spike/S = new(get_turf(src)) + magazine.give_round(S) return 1 -/obj/item/weapon/gun/launcher/spikethrower/update_release_force() +/obj/item/weapon/gun/projectile/automatic/spikethrower/attack_self() return -/obj/item/weapon/gun/launcher/spikethrower/chamber_round() - if(in_chamber) return 1 - if(spikes < 1) return 0 +/obj/item/weapon/gun/projectile/automatic/spikethrower/process_chamber(eject_casing = 0, empty_chamber = 1) + ..() - spikes-- - in_chamber = new /obj/item/weapon/spike(src) - return 1 +/obj/item/ammo_box/magazine/internal/spikethrower + name = "\improper Vox spikethrower internal magazine" + ammo_type = /obj/item/ammo_casing/caseless/spike + caliber = "spike" + max_ammo = 10 -/obj/item/weapon/gun/launcher/spikethrower/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) - if(..()) update_icon() +/obj/item/ammo_casing/caseless/spike + name = "alloy spike" + desc = "A broadhead spike made out of a weird silvery metal." + projectile_type = /obj/item/projectile/bullet/spike + sharp = 1 + edge = 0 + throwforce = 5 + w_class = 3 + caliber = "spike" + icon_state = "bolt" + fire_sound = 'sound/weapons/bladeslice.ogg' + +/obj/item/projectile/bullet/spike + name = "alloy spike" + desc = "It's about a foot of weird silvery metal with a wicked point." + damage = 25 + stun = 1 + armour_penetration = 30 + icon_state = "magspear" + +/obj/item/projectile/bullet/spike/on_hit(atom/target, blocked = 0) + if((blocked != 100) && istype(target, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = target + H.drip(500) + ..() //This gun only functions for armalis. The on-sprite is too huge to render properly on other sprites. /obj/item/weapon/gun/energy/noisecannon - name = "alien heavy cannon" desc = "It's some kind of enormous alien weapon, as long as a man is tall." - - icon = 'icons/obj/gun.dmi' //Actual on-sprite is handled by icon_override. icon_state = "noisecannon" item_state = "noisecannon" recoil = 1 - force = 10 - projectile_type = "/obj/item/projectile/energy/sonic" + ammo_type = list(/obj/item/ammo_casing/energy/sonic) cell_type = "/obj/item/weapon/stock_parts/cell/super" - fire_delay = 40 - fire_sound = 'sound/effects/basscannon.ogg' - - var/mode = 1 - -/obj/item/weapon/gun/energy/noisecannon/attack_hand(mob/user as mob) - if(loc != user) - var/mob/living/carbon/human/H = user - if(istype(H)) - if(H.species.name == "Vox Armalis") - ..() - return - to_chat(user, "\red \The [src] is far too large for you to pick up.") - return - -/obj/item/weapon/gun/energy/noisecannon/process_chambered() //Does not have ammo. - in_chamber = new projectile_type(src) - return 1 + restricted_species = list("Vox Armalis") /obj/item/weapon/gun/energy/noisecannon/update_icon() return +//Casing +/obj/item/ammo_casing/energy/sonic + projectile_type = /obj/item/projectile/energy/sonic + fire_sound = 'sound/effects/basscannon.ogg' + delay = 40 + //Projectile. /obj/item/projectile/energy/sonic name = "distortion" - icon = 'icons/obj/machines/particle_accelerator.dmi' icon_state = "particle" damage = 60 damage_type = BRUTE @@ -112,7 +104,3 @@ embed = 0 weaken = 5 stun = 5 - -/obj/item/projectile/energy/sonic/proc/split() - //TODO: create two more projectiles to either side of this one, fire at targets to the side of target turf. - return \ No newline at end of file diff --git a/code/modules/reagents/dartgun.dm b/code/modules/projectiles/guns/dartgun.dm similarity index 94% rename from code/modules/reagents/dartgun.dm rename to code/modules/projectiles/guns/dartgun.dm index 4fb705dbcf9..2e55b19b4a9 100644 --- a/code/modules/reagents/dartgun.dm +++ b/code/modules/projectiles/guns/dartgun.dm @@ -33,9 +33,8 @@ var/list/starting_chems = null /obj/item/weapon/gun/dartgun/update_icon() - if(!cartridge) - icon_state = "dartgun-empty" + icon_state = "dartgun-e" return 1 if(!cartridge.darts) @@ -47,7 +46,6 @@ return 1 /obj/item/weapon/gun/dartgun/New() - ..() if(starting_chems) for(var/chem in starting_chems) @@ -104,7 +102,7 @@ to_chat(user, "[src] is empty.") @@ -305,7 +301,7 @@ anchored = 1 density = 0 - New() - var/datum/reagents/R = new/datum/reagents(15) - reagents = R - R.my_atom = src \ No newline at end of file +/obj/effect/syringe_gun_dummy/New() + var/datum/reagents/R = new/datum/reagents(15) + reagents = R + R.my_atom = src diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 8add6a5caf9..24a200915f0 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -2,25 +2,26 @@ icon_state = "energy" name = "energy gun" desc = "A basic energy-based gun." - fire_sound = 'sound/weapons/Taser.ogg' + icon = 'icons/obj/guns/energy.dmi' + fire_sound_text = "laser blast" var/obj/item/weapon/stock_parts/cell/power_supply //What type of power cell this uses - var/charge_cost = 1000 //How much energy is needed to fire. - var/cell_type = "/obj/item/weapon/stock_parts/cell" - var/projectile_type = "/obj/item/projectile/beam" - var/modifystate + var/cell_type = /obj/item/weapon/stock_parts/cell + var/modifystate = 0 + var/list/ammo_type = list(/obj/item/ammo_casing/energy) + var/select = 1 //The state of the select fire switch. Determines from the ammo_type list what kind of shot is fired next. var/can_charge = 1 - - //self-recharging - var/self_recharge = 0 //if set, the weapon will recharge itself + var/charge_sections = 4 + ammo_x_offset = 2 + var/shaded_charge = 0 //if this gun uses a stateful charge bar for more detail + var/selfcharge = 0 var/use_external_power = 0 //if set, the weapon will look for an external power source to draw from, otherwise it recharges magically - var/recharge_time = 4 var/charge_tick = 0 + var/charge_delay = 4 /obj/item/weapon/gun/energy/emp_act(severity) - if(power_supply) - power_supply.use(round(power_supply.charge / severity)) - update_icon() + power_supply.use(round(power_supply.charge / severity)) + update_icon() /obj/item/weapon/gun/energy/New() ..() @@ -29,39 +30,147 @@ else power_supply = new(src) power_supply.give(power_supply.maxcharge) - if(self_recharge) + var/obj/item/ammo_casing/energy/shot + for (var/i = 1, i <= ammo_type.len, i++) + var/shottype = ammo_type[i] + shot = new shottype(src) + ammo_type[i] = shot + shot = ammo_type[select] + fire_sound = shot.fire_sound + fire_delay = shot.delay + if(selfcharge) processing_objects.Add(src) update_icon() /obj/item/weapon/gun/energy/Destroy() - if(self_recharge) + if(selfcharge) processing_objects.Remove(src) return ..() /obj/item/weapon/gun/energy/process() - if(self_recharge) //Every [recharge_time] ticks, recharge a shot for the cyborg + if(selfcharge) //Every [recharge_time] ticks, recharge a shot for the cyborg charge_tick++ - if(charge_tick < recharge_time) return 0 + if(charge_tick < charge_delay) + return charge_tick = 0 - - if(!power_supply || power_supply.charge >= power_supply.maxcharge) - return 0 // check if we actually need to recharge - + if(!power_supply) + return // check if we actually need to recharge + var/obj/item/ammo_casing/energy/E = ammo_type[select] if(use_external_power) var/obj/item/weapon/stock_parts/cell/external = get_external_power_supply() - if(!external || !external.use(charge_cost/10)) //Take power from the borg... - return 0 //Note, uses /10 because of shitty mods to the cell system - - power_supply.give(charge_cost) //... to recharge the shot + if(!external || !external.use((E.e_cost)/10)) //Take power from the borg... + return //Note, uses /10 because of shitty mods to the cell system + power_supply.give(1000) //... to recharge the shot update_icon() - return 1 + +/obj/item/weapon/gun/energy/attack_self(mob/living/user as mob) + if(ammo_type.len > 1) + select_fire(user) + update_icon() + if(istype(user,/mob/living/carbon/human)) //This has to be here or else if you toggle modes by clicking the gun in hand + var/mob/living/carbon/human/H = user //Otherwise the mob icon doesn't update, blame shitty human update_icons() code + H.update_inv_l_hand() + H.update_inv_r_hand() + +/obj/item/weapon/gun/energy/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, params) + newshot() //prepare a new shot + ..() + +/obj/item/weapon/gun/energy/can_shoot() + var/obj/item/ammo_casing/energy/shot = ammo_type[select] + return power_supply.charge >= shot.e_cost + +/obj/item/weapon/gun/energy/newshot() + if (!ammo_type || !power_supply) + return + var/obj/item/ammo_casing/energy/shot = ammo_type[select] + if(power_supply.charge >= shot.e_cost) //if there's enough power in the power_supply cell... + chambered = shot //...prepare a new shot based on the current ammo type selected + chambered.newshot() + return + +/obj/item/weapon/gun/energy/process_chamber() + if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired... + var/obj/item/ammo_casing/energy/shot = chambered + power_supply.use(shot.e_cost)//... drain the power_supply cell + chambered = null //either way, released the prepared shot + return + +/obj/item/weapon/gun/energy/proc/select_fire(mob/living/user) + select++ + if (select > ammo_type.len) + select = 1 + var/obj/item/ammo_casing/energy/shot = ammo_type[select] + fire_sound = shot.fire_sound + fire_delay = shot.delay + if (shot.select_name) + to_chat(user, "[src] is now set to [shot.select_name].") + update_icon() + return + +/obj/item/weapon/gun/energy/update_icon() + overlays.Cut() + var/ratio = Ceiling((power_supply.charge / power_supply.maxcharge) * charge_sections) + var/obj/item/ammo_casing/energy/shot = ammo_type[select] + var/iconState = "[icon_state]_charge" + var/itemState = null + if(!initial(item_state)) + itemState = icon_state + if (modifystate) + overlays += "[icon_state]_[shot.select_name]" + iconState += "_[shot.select_name]" + if(itemState) + itemState += "[shot.select_name]" + if(power_supply.charge < shot.e_cost) + overlays += "[icon_state]_empty" + else + if(!shaded_charge) + for(var/i = ratio, i >= 1, i--) + overlays += image(icon = icon, icon_state = iconState, pixel_x = ammo_x_offset * (i -1)) + else + overlays += image(icon = icon, icon_state = "[icon_state]_[modifystate ? "[shot.select_name]_" : ""]charge[ratio]") + if(F && can_flashlight) + var/iconF = "flight" + if(F.on) + iconF = "flight_on" + overlays += image(icon = icon, icon_state = iconF, pixel_x = flight_x_offset, pixel_y = flight_y_offset) + if(itemState) + itemState += "[ratio]" + item_state = itemState + +/obj/item/weapon/gun/energy/ui_action_click() + toggle_gunlight() + +/obj/item/weapon/gun/energy/suicide_act(mob/user) + if (can_shoot()) + user.visible_message("[user] is putting the barrel of the [name] in \his mouth. It looks like \he's trying to commit suicide.") + sleep(25) + if(user.l_hand == src || user.r_hand == src) + user.visible_message("[user] melts \his face off with the [name]!") + playsound(loc, fire_sound, 50, 1, -1) + var/obj/item/ammo_casing/energy/shot = ammo_type[select] + power_supply.use(shot.e_cost) + update_icon() + return(FIRELOSS) + else + user.visible_message("[user] panics and starts choking to death!") + return(OXYLOSS) + else + user.visible_message("[user] is pretending to blow \his brains out with the [name]! It looks like \he's trying to commit suicide!") + playsound(loc, 'sound/weapons/empty.ogg', 50, 1, -1) + return (OXYLOSS) + +/obj/item/weapon/gun/energy/proc/robocharge() + if(isrobot(loc)) + var/mob/living/silicon/robot/R = loc + if(R && R.cell) + var/obj/item/ammo_casing/energy/shot = ammo_type[select] //Necessary to find cost of shot + if(R.cell.use(shot.e_cost/10)) //Take power from the borg... //Divided by 10 because cells and charge costs are fucked. + power_supply.give(shot.e_cost) //... to recharge the shot /obj/item/weapon/gun/energy/proc/get_external_power_supply() - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - return R.cell - if(istype(src.loc, /obj/item/rig_module)) - var/obj/item/rig_module/module = src.loc + if(istype(loc, /obj/item/rig_module)) + var/obj/item/rig_module/module = loc if(module.holder && module.holder.wearer) var/mob/living/carbon/human/H = module.holder.wearer if(istype(H) && H.back) @@ -69,29 +178,3 @@ if(istype(suit)) return suit.cell return null - -/obj/item/weapon/gun/energy/process_chambered() - if(in_chamber) return 1 - if(!power_supply) return 0 - if(!power_supply.use(charge_cost)) return 0 - if(!projectile_type) return 0 - in_chamber = new projectile_type(src) - return 1 - -/obj/item/weapon/gun/energy/update_icon() - if(cell_type) - var/ratio = power_supply.charge / power_supply.maxcharge - ratio = round(ratio, 0.25) * 100 - if(modifystate) - icon_state = "[modifystate][ratio]" - else - icon_state = "[initial(icon_state)][ratio]" - else - icon_state = "energy0" - overlays.Cut() - if(F) - if(F.on) - overlays += "flight-on" - else - overlays += "flight" - return diff --git a/code/modules/projectiles/guns/energy/advtaser.dm b/code/modules/projectiles/guns/energy/advtaser.dm deleted file mode 100644 index 8601a388f15..00000000000 --- a/code/modules/projectiles/guns/energy/advtaser.dm +++ /dev/null @@ -1,40 +0,0 @@ -/obj/item/weapon/gun/energy/advtaser - name = "hybrid taser" - desc = "A hybrid taser designed to fire both short-range high-power electrodes and long-range disabler beams." - icon_state = "advtaser" - item_state = null //so the human update icon uses the icon_state instead. - cell_type = "/obj/item/weapon/stock_parts/cell" - origin_tech = null - fire_sound = 'sound/weapons/Taser.ogg' - projectile_type = "/obj/item/projectile/energy/electrode" - charge_cost = 2000 - modifystate = "advtaserstun" - can_flashlight = 1 - fire_delay = 15 - - var/mode = 0 //0 = stun, 1 = disable - - - attack_self(mob/living/user as mob) - switch(mode) - if(0) - mode = 1 - charge_cost = 500 - fire_sound = 'sound/weapons/taser2.ogg' - to_chat(user, "\red [src.name] is now set to Disable.") - projectile_type = "/obj/item/projectile/beam/disabler" - modifystate = "advtaserdisable" - fire_delay = 0 - if(1) - mode = 0 - charge_cost = 2000 - fire_sound = 'sound/weapons/Taser.ogg' - to_chat(user, "\red [src.name] is now set to stun.") - projectile_type = "/obj/item/projectile/energy/electrode" - modifystate = "advtaserstun" - fire_delay = 15 - update_icon() - if(user.l_hand == src) - user.update_inv_l_hand() - else - user.update_inv_r_hand() diff --git a/code/modules/projectiles/guns/energy/blueshield.dm b/code/modules/projectiles/guns/energy/blueshield.dm deleted file mode 100644 index 914b92e19a6..00000000000 --- a/code/modules/projectiles/guns/energy/blueshield.dm +++ /dev/null @@ -1,37 +0,0 @@ -/obj/item/weapon/gun/energy/blueshield - name = "advanced stun revolver" - desc = "An advanced stun revolver with the capacity to shoot both electrodes and lasers." - icon_state = "bsgun_stun" - item_state = "gun" - modifystate = "bsgun_stun" - force = 7 - fire_sound = 'sound/weapons/gunshot.ogg' - charge_cost = 2000 - projectile_type = "/obj/item/projectile/energy/electrode" - fire_delay = 15 - var/fire_mode = 0 // 0 for taser, 1 for lethals. - -/obj/item/weapon/gun/energy/blueshield/attack_self(mob/living/user as mob) - if(!fire_mode) - fire_mode = 1 - charge_cost = 1000 - fire_delay = 0 - - fire_sound = 'sound/weapons/Laser.ogg' - projectile_type = "/obj/item/projectile/beam" - modifystate = "bsgun_kill" - - to_chat(user, "You adjust [src.name] to the kill setting.") - - else - fire_mode = 0 - charge_cost = 2000 - fire_delay = 15 - - projectile_type = "/obj/item/projectile/energy/electrode" - fire_sound = 'sound/weapons/gunshot.ogg' - modifystate = "bsgun_stun" - - to_chat(user, "You adjust [src.name] to the stun setting.") - - update_icon() \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy/hos.dm b/code/modules/projectiles/guns/energy/hos.dm deleted file mode 100644 index 6bcb9992c4d..00000000000 --- a/code/modules/projectiles/guns/energy/hos.dm +++ /dev/null @@ -1,45 +0,0 @@ -/obj/item/weapon/gun/energy/hos - name = "head of security's energy gun" - desc = "This is a modern recreation of the captain's antique laser gun. This gun has several unique fire modes, but lacks the ability to recharge over time." - icon_state = "hoslaser" - item_state = null //so the human update icon uses the icon_state instead. - force = 10 - fire_sound = 'sound/weapons/Taser.ogg' - origin_tech = "combat=3;magnets=2" - charge_cost = 2000 - modifystate = "hoslaserstun" - projectile_type = "/obj/item/projectile/energy/electrode" - fire_delay = 15 - var/mode = 2 - - attack_self(mob/living/user as mob) - switch(mode) - if(2) - mode = 0 - charge_cost = 1000 - fire_sound = 'sound/weapons/Laser.ogg' - to_chat(user, "\red [src.name] is now set to kill.") - projectile_type = "/obj/item/projectile/beam" - modifystate = "hoslaserkill" - fire_delay = 0 - if(0) - mode = 1 - charge_cost = 500 - fire_sound = 'sound/weapons/taser2.ogg' - to_chat(user, "\red [src.name] is now set to disable.") - projectile_type = "/obj/item/projectile/beam/disabler" - modifystate = "hoslaserdisable" - fire_delay = 0 - if(1) - mode = 2 - charge_cost = 2000 - fire_sound = 'sound/weapons/taser.ogg' - to_chat(user, "\red [src.name] is now set to stun.") - projectile_type = "/obj/item/projectile/energy/electrode" - modifystate = "hoslaserstun" - fire_delay = 15 - update_icon() - if(user.l_hand == src) - user.update_inv_l_hand() - else - user.update_inv_r_hand() \ No newline at end of file diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 330d9136f17..40356f8a7d9 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -1,59 +1,65 @@ /obj/item/weapon/gun/energy/laser name = "laser gun" - desc = "a basic weapon designed kill with concentrated energy bolts" + desc = "A basic energy-based laser gun that fires concentrated beams of light which pass through glass and thin metal." icon_state = "laser" item_state = "laser" - fire_sound = 'sound/weapons/Laser.ogg' - charge_cost = 760 - w_class = 3.0 + w_class = 3 materials = list(MAT_METAL=2000) origin_tech = "combat=3;magnets=2" - projectile_type = "/obj/item/projectile/beam" + ammo_type = list(/obj/item/ammo_casing/energy/lasergun) + ammo_x_offset = 1 + shaded_charge = 1 /obj/item/weapon/gun/energy/laser/practice name = "practice laser gun" desc = "A modified version of the basic laser gun, this one fires less concentrated energy bolts designed for target practice." - projectile_type = "/obj/item/projectile/practice" + ammo_type = list(/obj/item/ammo_casing/energy/laser/practice) clumsy_check = 0 needs_permit = 0 -obj/item/weapon/gun/energy/laser/retro +/obj/item/weapon/gun/energy/laser/retro name ="retro laser gun" icon_state = "retro" - desc = "An older model of the basic lasergun, no longer used by Nanotrasen's security or military forces. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws." - + desc = "An older model of the basic lasergun, no longer used by Nanotrasen's private security or military forces. Nevertheless, it is still quite deadly and easy to maintain, making it a favorite amongst pirates and other outlaws." + ammo_x_offset = 3 /obj/item/weapon/gun/energy/laser/captain - name = "captain's antique laser gun" + name = "antique laser gun" icon_state = "caplaser" item_state = "caplaser" desc = "This is an antique laser gun. All craftsmanship is of the highest quality. It is decorated with assistant leather and chrome. The object menaces with spikes of energy. On the item is an image of Space Station 13. The station is exploding." force = 10 origin_tech = null + ammo_x_offset = 3 + selfcharge = 1 - self_recharge = 1 - +/obj/item/weapon/gun/energy/laser/captain/scattershot + name = "scatter shot laser rifle" + icon_state = "lasercannon" + item_state = "laser" + desc = "An industrial-grade heavy-duty laser rifle with a modified laser lense to scatter its shot into multiple smaller lasers. The inner-core can self-charge for theorically infinite use." + origin_tech = "combat=5;materials=4;powerstorage=4" + ammo_type = list(/obj/item/ammo_casing/energy/laser/scatter, /obj/item/ammo_casing/energy/laser) + shaded_charge = 0 /obj/item/weapon/gun/energy/laser/cyborg + can_charge = 0 desc = "An energy-based laser gun that draws power from the cyborg's internal energy cell directly. So this is what freedom looks like?" + origin_tech = null -/obj/item/weapon/gun/energy/laser/cyborg/process() - return 1 - -/obj/item/weapon/gun/energy/laser/cyborg/process_chambered() - if(in_chamber) - return 1 - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - if(R && R.cell && R.cell.charge >= 83) - R.cell.use(83) - in_chamber = new/obj/item/projectile/beam(src) - return 1 - return 0 +/obj/item/weapon/gun/energy/laser/cyborg/newshot() + ..() + robocharge() /obj/item/weapon/gun/energy/laser/cyborg/emp_act() return +/obj/item/weapon/gun/energy/laser/scatter + name = "scatter laser gun" + desc = "A laser gun equipped with a refraction kit that spreads bolts." + ammo_type = list(/obj/item/ammo_casing/energy/laser/scatter, /obj/item/ammo_casing/energy/laser) + +///Laser Cannon /obj/item/weapon/gun/energy/lasercannon name = "accelerator laser cannon" @@ -64,13 +70,18 @@ obj/item/weapon/gun/energy/laser/retro force = 10 flags = CONDUCT slot_flags = SLOT_BACK - fire_sound = 'sound/weapons/lasercannonfire.ogg' origin_tech = "combat=4;materials=3;powerstorage=3" - projectile_type = "/obj/item/projectile/beam/laser/accelerator" + ammo_type = list(/obj/item/ammo_casing/energy/laser/accelerator) + ammo_x_offset = 3 /obj/item/weapon/gun/energy/lasercannon/isHandgun() return 0 +/obj/item/ammo_casing/energy/laser/accelerator + projectile_type = /obj/item/projectile/beam/laser/accelerator + select_name = "accelerator" + fire_sound = 'sound/weapons/lasercannonfire.ogg' + /obj/item/projectile/beam/laser/accelerator name = "accelerator laser" icon_state = "heavylaser" @@ -83,40 +94,34 @@ obj/item/weapon/gun/energy/laser/retro /obj/item/weapon/gun/energy/lasercannon/mounted name = "mounted laser cannon" - self_recharge = 1 + selfcharge = 1 use_external_power = 1 - recharge_time = 10 + charge_delay = 10 +/obj/item/weapon/gun/energy/lasercannon/cyborg -/obj/item/weapon/gun/energy/lasercannon/cyborg/process_chambered() - if(in_chamber) - return 1 - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - if(R && R.cell) - R.cell.use(250) - in_chamber = new/obj/item/projectile/beam(src) - return 1 - return 0 +/obj/item/weapon/gun/energy/lasercannon/cyborg/newshot() + ..() + robocharge() + +/obj/item/weapon/gun/energy/lasercannon/cyborg/emp_act() + return /obj/item/weapon/gun/energy/xray name = "xray laser gun" desc = "A high-power laser gun capable of expelling concentrated xray blasts." icon_state = "xray" - fire_sound = 'sound/weapons/laser3.ogg' origin_tech = "combat=5;materials=3;magnets=2;syndicate=2" - projectile_type = "/obj/item/projectile/beam/xray" - charge_cost = 500 + ammo_type = list(/obj/item/ammo_casing/energy/xray) /obj/item/weapon/gun/energy/immolator name = "Immolator laser gun" desc = "A modified laser gun, shooting highly concetrated beams with higher intensity that ignites the target, for the cost of draining more power per shot" icon_state = "immolator" item_state = "laser" - fire_sound = 'sound/weapons/laser3.ogg' - projectile_type = "/obj/item/projectile/beam/immolator" + ammo_type = list(/obj/item/ammo_casing/energy/immolator) origin_tech = "combat=4;materials=4;magnets=3;plasmatech=2" - charge_cost = 1250 + shaded_charge = 1 ////////Laser Tag//////////////////// @@ -124,34 +129,20 @@ obj/item/weapon/gun/energy/laser/retro name = "laser tag gun" icon_state = "bluetag" desc = "Standard issue weapon of the Imperial Guard" - projectile_type = "/obj/item/projectile/lasertag/blue" + ammo_type = list(/obj/item/ammo_casing/energy/laser/bluetag) origin_tech = "combat=1;magnets=2" clumsy_check = 0 needs_permit = 0 - - self_recharge = 1 - -/obj/item/weapon/gun/energy/laser/bluetag/special_check(var/mob/living/carbon/human/M) - if(ishuman(M)) - if(istype(M.wear_suit, /obj/item/clothing/suit/bluetag)) - return 1 - to_chat(M, "\red You need to be wearing your laser tag vest!") - return 0 + ammo_x_offset = 2 + selfcharge = 1 /obj/item/weapon/gun/energy/laser/redtag name = "laser tag gun" icon_state = "redtag" desc = "Standard issue weapon of the Imperial Guard" - projectile_type = "/obj/item/projectile/lasertag/red" + ammo_type = list(/obj/item/ammo_casing/energy/laser/redtag) origin_tech = "combat=1;magnets=2" clumsy_check = 0 needs_permit = 0 - - self_recharge = 1 - -/obj/item/weapon/gun/energy/laser/redtag/special_check(var/mob/living/carbon/human/M) - if(ishuman(M)) - if(istype(M.wear_suit, /obj/item/clothing/suit/redtag)) - return 1 - to_chat(M, "\red You need to be wearing your laser tag vest!") - return 0 \ No newline at end of file + ammo_x_offset = 2 + selfcharge = 1 diff --git a/code/modules/projectiles/guns/energy/nuclear.dm b/code/modules/projectiles/guns/energy/nuclear.dm index 5bc164c5d76..2ef193a6c37 100644 --- a/code/modules/projectiles/guns/energy/nuclear.dm +++ b/code/modules/projectiles/guns/energy/nuclear.dm @@ -1,192 +1,132 @@ /obj/item/weapon/gun/energy/gun name = "energy gun" desc = "A basic energy-based gun with two settings: kill and disable." - icon_state = "energystun100" + icon_state = "energy" item_state = null //so the human update icon uses the icon_state instead. - fire_sound = 'sound/weapons/Taser2.ogg' - charge_cost = 500 - projectile_type = "/obj/item/projectile/beam/disabler" + ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser) origin_tech = "combat=3;magnets=2" - modifystate = "energystun" + modifystate = 2 can_flashlight = 1 - - var/mode = 0 //0 = disable, 1 = kill - - - attack_self(mob/living/user as mob) - switch(mode) - if(0) - mode = 1 - charge_cost = 1000 - fire_sound = 'sound/weapons/Laser.ogg' - to_chat(user, "\red [src.name] is now set to kill.") - projectile_type = "/obj/item/projectile/beam" - modifystate = "energykill" - if(1) - mode = 0 - charge_cost = 500 - fire_sound = 'sound/weapons/Taser2.ogg' - to_chat(user, "\red [src.name] is now set to disable.") - projectile_type = "/obj/item/projectile/beam/disabler" - modifystate = "energystun" - update_icon() - if(user.l_hand == src) - user.update_inv_l_hand() - else - user.update_inv_r_hand() + ammo_x_offset = 3 + flight_x_offset = 15 + flight_y_offset = 10 /obj/item/weapon/gun/energy/gun/cyborg desc = "An energy-based laser gun that draws power from the cyborg's internal energy cell directly. So this is what freedom looks like?" -/obj/item/weapon/gun/energy/gun/cyborg/process() - return 1 - -/obj/item/weapon/gun/energy/gun/cyborg/process_chambered() - if(in_chamber) - return 1 - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - if(R && R.cell && R.cell.charge >= 83) - R.cell.use(83) - in_chamber = new projectile_type(src) - return 1 - return 0 +/obj/item/weapon/gun/energy/gun/cyborg/newshot() + ..() + robocharge() +/obj/item/weapon/gun/energy/gun/cyborg/emp_act() + return /obj/item/weapon/gun/energy/gun/mounted name = "mounted energy gun" - self_recharge = 1 + selfcharge = 1 use_external_power = 1 -/obj/item/weapon/gun/energy/gun/nuclear - name = "Advanced Energy Gun" - desc = "An energy gun with an experimental miniaturized reactor." - icon_state = "nucgun" - origin_tech = "combat=3;materials=5;powerstorage=3" - var/lightfail = 0 - can_flashlight = 0 - can_charge = 0 +/obj/item/weapon/gun/energy/gun/mini + name = "miniature energy gun" + desc = "A small, pistol-sized energy gun with a built-in flashlight. It has two settings: stun and kill." + icon_state = "mini" + item_state = "gun" + w_class = 2 + ammo_x_offset = 2 + charge_sections = 3 + can_flashlight = 0 // Can't attach or detach the flashlight, and override it's icon update - New() - ..() - processing_objects.Add(src) +/obj/item/weapon/gun/energy/gun/mini/New() + F = new /obj/item/device/flashlight/seclite(src) + ..() + power_supply.maxcharge = 6000 + power_supply.charge = 6000 +/obj/item/weapon/gun/energy/gun/mini/update_icon() + ..() + if(F && F.on) + overlays += "mini-light" - Destroy() - processing_objects.Remove(src) - return ..() - - - process() - charge_tick++ - if(charge_tick < 4) return 0 - charge_tick = 0 - if(!power_supply) return 0 - if((power_supply.charge / power_supply.maxcharge) != 1) - if(!failcheck()) return 0 - power_supply.give(1000) - update_icon() - return 1 - - - proc - failcheck() - lightfail = 0 - if (prob(src.reliability)) return 1 //No failure - if (prob(src.reliability)) - for (var/mob/living/M in range(0,src)) //Only a minor failure, enjoy your radiation if you're in the same tile or carrying it - if (src in M.contents) - to_chat(M, "\red Your gun feels pleasantly warm for a moment.") - else - to_chat(M, "\red You feel a warm sensation.") - M.apply_effect(rand(3,120), IRRADIATE) - lightfail = 1 - else - for (var/mob/living/M in range(rand(1,4),src)) //Big failure, TIME FOR RADIATION BITCHES - if (src in M.contents) - to_chat(M, "\red Your gun's reactor overloads!") - to_chat(M, "\red You feel a wave of heat wash over you.") - M.apply_effect(300, IRRADIATE) - crit_fail = 1 //break the gun so it stops recharging - processing_objects.Remove(src) - update_icon() - return 0 - - - update_charge() - if (crit_fail) - overlays += "nucgun-whee" - return - var/ratio = power_supply.charge / power_supply.maxcharge - ratio = round(ratio, 0.25) * 100 - overlays += "nucgun-[ratio]" - - - update_reactor() - if(crit_fail) - overlays += "nucgun-crit" - return - if(lightfail) - overlays += "nucgun-medium" - else if ((power_supply.charge/power_supply.maxcharge) <= 0.5) - overlays += "nucgun-light" - else - overlays += "nucgun-clean" - - - update_mode() - if (mode == 0) - overlays += "nucgun-stun" - else if (mode == 1) - overlays += "nucgun-kill" - - emp_act(severity) - ..() - reliability = max(reliability - round(15/severity), 0) //Do not allow it to go negative! - - - update_icon() - overlays.Cut() - update_charge() - update_reactor() - update_mode() +/obj/item/weapon/gun/energy/gun/hos + name = "\improper X-01 MultiPhase Energy Gun" + desc = "This is a expensive, modern recreation of a antique laser gun. This gun has several unique firemodes, but lacks the ability to recharge over time." + icon_state = "hoslaser" + force = 10 + ammo_type = list(/obj/item/ammo_casing/energy/electrode/hos, /obj/item/ammo_casing/energy/laser/hos, /obj/item/ammo_casing/energy/disabler) + ammo_x_offset = 4 +/obj/item/weapon/gun/energy/gun/blueshield + name = "advanced stun revolver" + desc = "An advanced stun revolver with the capacity to shoot both electrodes and lasers." + icon_state = "bsgun" + force = 7 + ammo_type = list(/obj/item/ammo_casing/energy/electrode/hos, /obj/item/ammo_casing/energy/laser/hos) + ammo_x_offset = 1 + shaded_charge = 1 /obj/item/weapon/gun/energy/gun/turret name = "hybrid turret gun" desc = "A heavy hybrid energy cannon with two settings: Stun and kill." icon_state = "turretlaser" + item_state = "turretlaser" slot_flags = null w_class = 5 - heavy_weapon = 1 + ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser) + weapon_weight = WEAPON_MEDIUM can_flashlight = 0 - projectile_type = /obj/item/projectile/energy/electrode - charge_cost = 1000 - fire_delay = 15 + trigger_guard = TRIGGER_GUARD_NONE + ammo_x_offset = 2 -/obj/item/weapon/gun/energy/gun/turret/update_icon() - icon_state = initial(icon_state) +/obj/item/weapon/gun/energy/gun/nuclear + name = "advanced energy gun" + desc = "An energy gun with an experimental miniaturized nuclear reactor that automatically charges the internal power cell." + icon_state = "nucgun" + item_state = "nucgun" + origin_tech = "combat=3;materials=5;powerstorage=3" + var/fail_tick = 0 + charge_delay = 5 + can_charge = 0 + ammo_x_offset = 1 + ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser, /obj/item/ammo_casing/energy/disabler) + selfcharge = 1 -/obj/item/weapon/gun/energy/gun/turret/attack_self(mob/living/user as mob) - switch(mode) - if(0) - mode = 1 - charge_cost = 500 - fire_sound = 'sound/weapons/Laser.ogg' - to_chat(user, "\red [src.name] is now set to kill.") - projectile_type = /obj/item/projectile/beam - modifystate = "energykill" - fire_delay = 0 - if(1) - mode = 0 - charge_cost = 1000 - fire_sound = 'sound/weapons/Taser.ogg' - to_chat(user, "\red [src.name] is now set to stun.") - projectile_type = /obj/item/projectile/energy/electrode - modifystate = "energystun" - fire_delay = 15 +/obj/item/weapon/gun/energy/gun/nuclear/process() + if(fail_tick > 0) + fail_tick-- + ..() + +/obj/item/weapon/gun/energy/gun/nuclear/shoot_live_shot() + failcheck() update_icon() - if(user.l_hand == src) - user.update_inv_l_hand() + ..() + +/obj/item/weapon/gun/energy/gun/nuclear/proc/failcheck() + if(!prob(reliability) && istype(loc, /mob/living)) + var/mob/living/M = loc + switch(fail_tick) + if(0 to 200) + fail_tick += (2*(100-reliability)) + M.apply_effect(rand(3,120), IRRADIATE) + to_chat(M, "Your [name] feels warmer.") + if(201 to INFINITY) + processing_objects.Remove(src) + M.apply_effect(300, IRRADIATE) + crit_fail = 1 + to_chat(M, "Your [name]'s reactor overloads!") + +/obj/item/weapon/gun/energy/gun/nuclear/emp_act(severity) + ..() + reliability = max(reliability - round(15/severity), 0) //Do not allow it to go negative! + +/obj/item/weapon/gun/energy/gun/nuclear/update_icon() + ..() + if(crit_fail) + overlays += "[icon_state]_fail_3" else - user.update_inv_r_hand() \ No newline at end of file + switch(fail_tick) + if(0) + overlays += "[icon_state]_fail_0" + if(1 to 150) + overlays += "[icon_state]_fail_1" + if(151 to INFINITY) + overlays += "[icon_state]_fail_2" diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm index bc7704d709a..3ffa3b59bbb 100644 --- a/code/modules/projectiles/guns/energy/pulse.dm +++ b/code/modules/projectiles/guns/energy/pulse.dm @@ -1,66 +1,28 @@ -/obj/item/weapon/gun/energy/pulse_rifle +/obj/item/weapon/gun/energy/pulse name = "pulse rifle" - desc = "A heavy-duty, pulse-based energy weapon, preferred by front-line combat personnel." + desc = "A heavy-duty, multifaceted energy rifle with three modes. Preferred by front-line combat personnel." icon_state = "pulse" - item_state = null //so the human update icon uses the icon_state instead. + item_state = null + w_class = 4 force = 10 - fire_sound = 'sound/weapons/pulse.ogg' - charge_cost = 200 - projectile_type = "/obj/item/projectile/beam/pulse" - cell_type = "/obj/item/weapon/stock_parts/cell/super" - var/mode = 2 + flags = CONDUCT slot_flags = SLOT_BACK - w_class = 4.0 + ammo_type = list(/obj/item/ammo_casing/energy/laser/pulse, /obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser) + cell_type = "/obj/item/weapon/stock_parts/cell/pulse" - emp_act() - return +/obj/item/weapon/gun/energy/pulse/emp_act(severity) + return - attack_self(mob/living/user as mob) - switch(mode) - if(2) - mode = 0 - charge_cost = 50 - fire_sound = 'sound/weapons/Taser.ogg' - to_chat(user, "\red [src.name] is now set to stun.") - projectile_type = "/obj/item/projectile/energy/electrode" - if(0) - mode = 1 - charge_cost = 100 - fire_sound = 'sound/weapons/Laser.ogg' - to_chat(user, "\red [src.name] is now set to kill.") - projectile_type = "/obj/item/projectile/beam" - if(1) - mode = 2 - charge_cost = 200 - fire_sound = 'sound/weapons/pulse.ogg' - to_chat(user, "\red [src.name] is now set to DESTROY.") - projectile_type = "/obj/item/projectile/beam/pulse" - return - - isHandgun() - return 0 - -/obj/item/weapon/gun/energy/pulse_rifle/cyborg/process_chambered() - if(in_chamber) - return 1 - if(isrobot(src.loc)) - var/mob/living/silicon/robot/R = src.loc - if(R && R.cell) - R.cell.use(charge_cost) - in_chamber = new projectile_type(src) - return 1 +/obj/item/weapon/gun/energy/pulse/isHandgun() return 0 +/obj/item/weapon/gun/energy/pulse/cyborg -/obj/item/weapon/gun/energy/pulse_rifle/destroyer - name = "pulse destroyer" - desc = "A heavy-duty, pulse-based energy weapon." - cell_type = "/obj/item/weapon/stock_parts/cell/infinite" +/obj/item/weapon/gun/energy/pulse/cyborg/newshot() + ..() + robocharge() - attack_self(mob/living/user as mob) - to_chat(user, "\red [src.name] has three settings, and they are all DESTROY.") - -/obj/item/weapon/gun/energy/pulse_rifle/carbine +/obj/item/weapon/gun/energy/pulse/carbine name = "pulse carbine" desc = "A compact variant of the pulse rifle with less firepower but easier storage." w_class = 3 @@ -69,9 +31,10 @@ item_state = "pulse" cell_type = "/obj/item/weapon/stock_parts/cell/pulse/carbine" can_flashlight = 1 + flight_x_offset = 18 + flight_y_offset = 12 - -/obj/item/weapon/gun/energy/pulse_rifle/pistol +/obj/item/weapon/gun/energy/pulse/pistol name = "pulse pistol" desc = "A pulse rifle in an easily concealed handgun package with low capacity." w_class = 2 @@ -79,15 +42,31 @@ icon_state = "pulse_pistol" item_state = "gun" cell_type = "/obj/item/weapon/stock_parts/cell/pulse/pistol" + can_charge = 0 -/obj/item/weapon/gun/energy/pulse_rifle/pistol/isHandgun() +/obj/item/weapon/gun/energy/pulse/pistol/isHandgun() return 1 -/obj/item/weapon/gun/energy/pulse_rifle/pistol/m1911 +/obj/item/weapon/gun/energy/pulse/destroyer + name = "pulse destroyer" + desc = "A heavy-duty, pulse-based energy weapon." + cell_type = "/obj/item/weapon/stock_parts/cell/infinite" + ammo_type = list(/obj/item/ammo_casing/energy/laser/pulse) + +/obj/item/weapon/gun/energy/pulse/destroyer/attack_self(mob/living/user) + to_chat(user, "[name] has three settings, and they are all DESTROY.") + +/obj/item/weapon/gun/energy/pulse/destroyer/annihilator + name = "pulse ANNIHILATOR" + desc = "For when the situation calls for a little more than a pulse destroyer." + ammo_type = list(/obj/item/ammo_casing/energy/laser/scatter/pulse) + +/obj/item/weapon/gun/energy/pulse/pistol/m1911 name = "\improper M1911-P" desc = "A compact pulse core in a classic handgun frame for Nanotrasen officers. It's not the size of the gun, it's the size of the hole it puts through people." - icon_state = "m1911-p" + icon_state = "m1911" item_state = "gun" cell_type = "/obj/item/weapon/stock_parts/cell/infinite" - isHandgun() - return 1 \ No newline at end of file + +/obj/item/weapon/gun/energy/pulse/pistol/m1911/isHandgun() + return 1 diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index d6c0ad7beb3..49dbc2bf670 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -8,7 +8,10 @@ w_class = 5.0 flags = CONDUCT slot_flags = SLOT_BACK - projectile_type = "/obj/item/projectile/ion" + ammo_type = list(/obj/item/ammo_casing/energy/ion) + ammo_x_offset = 3 + flight_x_offset = 17 + flight_y_offset = 9 /obj/item/weapon/gun/energy/ionrifle/emp_act(severity) return @@ -17,10 +20,12 @@ name = "ion carbine" desc = "The MK.II Prototype Ion Projector is a lightweight carbine version of the larger ion rifle, built to be ergonomic and efficient." icon_state = "ioncarbine" - item_state = "ioncarbine" origin_tech = "combat=4;magnets=4;materials=4" w_class = 3 slot_flags = SLOT_BELT + ammo_x_offset = 2 + flight_x_offset = 18 + flight_y_offset = 11 /obj/item/weapon/gun/energy/decloner name = "biological demolecularisor" @@ -28,65 +33,38 @@ icon_state = "decloner" fire_sound = 'sound/weapons/pulse3.ogg' origin_tech = "combat=5;materials=4;powerstorage=3" - projectile_type = "/obj/item/projectile/energy/declone" + ammo_type = list(/obj/item/ammo_casing/energy/declone) + ammo_x_offset = 1 +/obj/item/weapon/gun/energy/decloner/update_icon() + ..() + var/obj/item/ammo_casing/energy/shot = ammo_type[select] + if(power_supply.charge > shot.e_cost) + overlays += "decloner_spin" /obj/item/weapon/gun/energy/floragun name = "floral somatoray" desc = "A tool that discharges controlled radiation which induces mutation in plant cells." - icon_state = "floramut100" + icon_state = "flora" item_state = "gun" fire_sound = 'sound/effects/stealthoff.ogg' - projectile_type = "/obj/item/projectile/energy/floramut" + ammo_type = list(/obj/item/ammo_casing/energy/flora/yield, /obj/item/ammo_casing/energy/flora/mut) origin_tech = "materials=2;biotech=3;powerstorage=3" - modifystate = "floramut" - var/mode = 0 //0 = mutate, 1 = yield boost - needs_permit = 0 - - self_recharge = 1 - -/obj/item/weapon/gun/energy/floragun/attack_self(mob/living/user as mob) - switch(mode) - if(0) - mode = 1 - charge_cost = 1000 - to_chat(user, "\red The [src.name] is now set to increase yield.") - projectile_type = "/obj/item/projectile/energy/florayield" - modifystate = "florayield" - if(1) - mode = 0 - charge_cost = 1000 - to_chat(user, "\red The [src.name] is now set to induce mutations.") - projectile_type = "/obj/item/projectile/energy/floramut" - modifystate = "floramut" - update_icon() - return - - -/obj/item/weapon/gun/energy/floragun/afterattack(obj/target, mob/user, flag) - - if(flag && istype(target,/obj/machinery/portable_atmospherics/hydroponics)) - var/obj/machinery/portable_atmospherics/hydroponics/tray = target - if(process_chambered()) - user.visible_message("\red \The [user] fires \the [src] into \the [tray]!") - Fire(target,user) - return - - ..() + modifystate = 1 + ammo_x_offset = 1 + selfcharge = 1 /obj/item/weapon/gun/energy/meteorgun name = "meteor gun" desc = "For the love of god, make sure you're aiming this the right way!" + icon = 'icons/obj/guns/projectile.dmi' icon_state = "riotgun" item_state = "c20r" w_class = 4 - projectile_type = "/obj/item/projectile/meteor" + ammo_type = list(/obj/item/ammo_casing/energy/meteor) cell_type = "/obj/item/weapon/stock_parts/cell/potato" clumsy_check = 0 //Admin spawn only, might as well let clowns use it. - - self_recharge = 1 - recharge_time = 5 //Time it takes for shots to recharge (in ticks) - + selfcharge = 1 /obj/item/weapon/gun/energy/meteorgun/pen name = "meteor pen" @@ -98,119 +76,116 @@ righthand_file = 'icons/mob/inhands/items_righthand.dmi' w_class = 1 - /obj/item/weapon/gun/energy/mindflayer name = "\improper Mind Flayer" desc = "A prototype weapon recovered from the ruins of Research-Station Epsilon." icon_state = "xray" - projectile_type = "/obj/item/projectile/beam/mindflayer" - fire_sound = 'sound/weapons/Laser.ogg' - -obj/item/weapon/gun/energy/staff/focus - name = "mental focus" - desc = "An artefact that channels the will of the user into destructive bolts of force. If you aren't careful with it, you might poke someone's brain out." - icon = 'icons/obj/wizard.dmi' - icon_state = "focus" - item_state = "focus" - projectile_type = "/obj/item/projectile/forcebolt" - /* - attack_self(mob/living/user as mob) - if(projectile_type == "/obj/item/projectile/forcebolt") - charge_cost = 200 - to_chat(user, "\red The [src.name] will now strike a small area.") - projectile_type = "/obj/item/projectile/forcebolt/strong" - else - charge_cost = 100 - to_chat(user, "\red The [src.name] will now strike only a single person.") - projectile_type = "/obj/item/projectile/forcebolt" - */ - -/obj/item/weapon/gun/energy/clown - name = "HONK Rifle" - desc = "Clown Planet's finest." - icon_state = "energy" - projectile_type = "/obj/item/projectile/clown" - fire_sound = 'sound/weapons/Gunshot_smg.ogg' - clumsy_check = 0 - - - -/obj/item/weapon/gun/energy/toxgun - name = "plasma pistol" - desc = "A specialized firearm designed to fire lethal bolts of toxins." - icon_state = "toxgun" - fire_sound = 'sound/effects/stealthoff.ogg' - w_class = 3.0 - origin_tech = "combat=4;plasmatech=3" - projectile_type = "/obj/item/projectile/energy/plasma" - -/obj/item/weapon/gun/energy/sniperrifle - name = "L.W.A.P. Sniper Rifle" - desc = "A rifle constructed of lightweight materials, fitted with a SMART aiming-system scope." - icon = 'icons/obj/gun.dmi' - icon_state = "esniper" - fire_sound = 'sound/weapons/marauder.ogg' - origin_tech = "combat=6;materials=5;powerstorage=4" - projectile_type = "/obj/item/projectile/beam/sniper" - slot_flags = SLOT_BACK - charge_cost = 2500 - fire_delay = 50 - w_class = 4.0 - zoomable = TRUE - zoom_amt = 7 //Long range, enough to see in front of you, but no tiles behind you. - + item_state = null + ammo_type = list(/obj/item/ammo_casing/energy/mindflayer) + ammo_x_offset = 2 /obj/item/weapon/gun/energy/kinetic_accelerator name = "proto-kinetic accelerator" desc = "According to Nanotrasen accounting, this is mining equipment. It's been modified for extreme power output to crush rocks, but often serves as a miner's first defense against hostile alien life; it's not very powerful unless used in a low pressure environment." icon_state = "kineticgun" item_state = "kineticgun" - projectile_type = "/obj/item/projectile/kinetic" - fire_sound = 'sound/weapons/Kenetic_accel.ogg' - charge_cost = 5000 - cell_type = "/obj/item/weapon/stock_parts/cell/emproof" - needs_permit = 0 // Aparently these are safe to carry? I'm sure Golliaths would disagree. - fire_delay = 16 //Because guncode is bad and you can bug the reload for rapid fire otherwise. - var/recently_fired = 0 + ammo_type = list(/obj/item/ammo_casing/energy/kinetic) + cell_type = /obj/item/weapon/stock_parts/cell/emproof + // Apparently these are safe to carry? I'm sure goliaths would disagree. + needs_permit = 0 + var/overheat_time = 16 + unique_rename = 1 + weapon_weight = WEAPON_LIGHT + origin_tech = "combat=2;powerstorage=1" + var/holds_charge = FALSE + var/unique_frequency = FALSE // modified by KA modkits + + var/overheat = FALSE /obj/item/weapon/gun/energy/kinetic_accelerator/super name = "super-kinetic accelerator" desc = "An upgraded, superior version of the proto-kinetic accelerator." icon_state = "kineticgun_u" - projectile_type = "/obj/item/projectile/kinetic/super" - fire_delay = 15 + ammo_type = list(/obj/item/ammo_casing/energy/kinetic/super) + overheat_time = 15 origin_tech = "combat=3;powerstorage=2" /obj/item/weapon/gun/energy/kinetic_accelerator/hyper name = "hyper-kinetic accelerator" desc = "An upgraded, even more superior version of the proto-kinetic accelerator." icon_state = "kineticgun_h" - projectile_type = "/obj/item/projectile/kinetic/hyper" - fire_delay = 13 + ammo_type = list(/obj/item/ammo_casing/energy/kinetic/hyper) + overheat_time = 14 origin_tech = "combat=4;powerstorage=3" /obj/item/weapon/gun/energy/kinetic_accelerator/cyborg - flags = NODROP + holds_charge = TRUE + unique_frequency = TRUE -/obj/item/weapon/gun/energy/kinetic_accelerator/Fire() - if(!recently_fired) - recently_fired = 1 - spawn(fire_delay) - reload(usr) - ..() +/obj/item/weapon/gun/energy/kinetic_accelerator/New() + . = ..() + if(!holds_charge) + empty() + +/obj/item/weapon/gun/energy/kinetic_accelerator/shoot_live_shot() + . = ..() + attempt_reload() + +/obj/item/weapon/gun/energy/kinetic_accelerator/equipped(mob/user) + . = ..() + if(!can_shoot()) + attempt_reload() + +/obj/item/weapon/gun/energy/kinetic_accelerator/dropped() + . = ..() + if(!holds_charge) + // Put it on a delay because moving item from slot to hand + // calls dropped(). + spawn(1) + if(!ismob(loc)) + empty() + +/obj/item/weapon/gun/energy/kinetic_accelerator/proc/empty() + power_supply.use(5000) + update_icon() + +/obj/item/weapon/gun/energy/kinetic_accelerator/proc/attempt_reload() + if(overheat) + return + overheat = TRUE + + var/carried = 0 + if(!unique_frequency) + for(var/obj/item/weapon/gun/energy/kinetic_accelerator/K in \ + loc.GetAllContents()) + + carried++ + + carried = max(carried, 1) + else + carried = 1 + + spawn(overheat_time * carried) + reload() + overheat = FALSE /obj/item/weapon/gun/energy/kinetic_accelerator/emp_act(severity) return -/obj/item/weapon/gun/energy/kinetic_accelerator/proc/reload(mob/living/user) +/obj/item/weapon/gun/energy/kinetic_accelerator/proc/reload() power_supply.give(5000) - if(!silenced) - playsound(src.loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) - else if(user) - to_chat(usr, "You silently charge [src].") - recently_fired = 0 + if(!suppressed) + playsound(loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) + else + to_chat(loc, "[src] silently charges up.") update_icon() +/obj/item/weapon/gun/energy/kinetic_accelerator/update_icon() + if(!can_shoot()) + icon_state = "[initial(icon_state)]_empty" + else + icon_state = initial(icon_state) + /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow name = "mini energy crossbow" desc = "A weapon favored by syndicate stealth specialists." @@ -219,10 +194,17 @@ obj/item/weapon/gun/energy/staff/focus w_class = 2 materials = list(MAT_METAL=2000) origin_tech = "combat=2;magnets=2;syndicate=5" - silenced = 1 - projectile_type = "/obj/item/projectile/energy/bolt" - fire_sound = 'sound/weapons/Genhit.ogg' - fire_delay = 20 + suppressed = 1 + ammo_type = list(/obj/item/ammo_casing/energy/bolt) + weapon_weight = WEAPON_LIGHT + unique_rename = 0 + overheat_time = 20 + holds_charge = TRUE + unique_frequency = TRUE + +/obj/item/weapon/gun/energy/kinetic_accelerator/crossbow/ninja + name = "energy dart thrower" + ammo_type = list(/obj/item/ammo_casing/energy/dart) /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow/large name = "energy crossbow" @@ -231,8 +213,8 @@ obj/item/weapon/gun/energy/staff/focus w_class = 3 materials = list(MAT_METAL=4000) origin_tech = "combat=2;magnets=2;syndicate=3" //can be further researched for more syndie tech - silenced = 0 - projectile_type = "/obj/item/projectile/energy/bolt/large" + suppressed = 0 + ammo_type = list(/obj/item/ammo_casing/energy/bolt/large) /obj/item/weapon/gun/energy/kinetic_accelerator/crossbow/large/cyborg desc = "One and done!" @@ -240,27 +222,35 @@ obj/item/weapon/gun/energy/staff/focus origin_tech = null materials = list() +/obj/item/weapon/gun/energy/kinetic_accelerator/suicide_act(mob/user) + if(!suppressed) + playsound(loc, 'sound/weapons/kenetic_reload.ogg', 60, 1) + user.visible_message("[user] cocks the [name] and pretends to blow \his brains out! It looks like \he's trying to commit suicide!") + shoot_live_shot() + return (OXYLOSS) + /obj/item/weapon/gun/energy/plasmacutter name = "plasma cutter" desc = "A mining tool capable of expelling concentrated plasma bursts. You could use it to cut limbs off of xenos! Or, you know, mine stuff." icon_state = "plasmacutter" item_state = "plasmacutter" - modifystate = "plasmacutter" + modifystate = -1 origin_tech = "combat=1;materials=3;magnets=2;plasmatech=2;engineering=1" - projectile_type = /obj/item/projectile/plasma + ammo_type = list(/obj/item/ammo_casing/energy/plasma) fire_sound = 'sound/weapons/laser.ogg' flags = CONDUCT | OPENCONTAINER attack_verb = list("attacked", "slashed", "cut", "sliced") - charge_cost = 250 - fire_delay = 15 + force = 12 + sharp = 1 + edge = 1 can_charge = 0 /obj/item/weapon/gun/energy/plasmacutter/examine(mob/user) - ..(user) + ..() if(power_supply) to_chat(user, "[src] is [round(power_supply.percent())]% charged.") -/obj/item/weapon/gun/energy/plasmacutter/attackby(var/obj/item/A, var/mob/user) +/obj/item/weapon/gun/energy/plasmacutter/attackby(obj/item/A, mob/user) if(istype(A, /obj/item/stack/sheet/mineral/plasma)) var/obj/item/stack/sheet/S = A S.use(1) @@ -273,92 +263,35 @@ obj/item/weapon/gun/energy/staff/focus else ..() +/obj/item/weapon/gun/energy/plasmacutter/update_icon() + return + /obj/item/weapon/gun/energy/plasmacutter/adv name = "advanced plasma cutter" icon_state = "adv_plasmacutter" modifystate = "adv_plasmacutter" origin_tech = "combat=3;materials=4;magnets=3;plasmatech=3;engineering=2" - projectile_type = /obj/item/projectile/plasma/adv - fire_delay = 10 - charge_cost = 100 - -/obj/item/weapon/gun/energy/disabler - name = "disabler" - desc = "A self-defense weapon that exhausts organic targets, weakening them until they collapse." - icon_state = "disabler" - item_state = null - projectile_type = /obj/item/projectile/beam/disabler - fire_sound = 'sound/weapons/taser2.ogg' - cell_type = "/obj/item/weapon/stock_parts/cell" - charge_cost = 500 - -/obj/item/weapon/gun/energy/disabler/cyborg - name = "cyborg disabler" - desc = "An integrated disabler that draws from a cyborg's power cell. This weapon contains a limiter to prevent the cyborg's power cell from overheating." - - self_recharge = 1 - use_external_power = 1 - recharge_time = 2.5 - - -/* 3d printer 'pseudo guns' for borgs */ - -/obj/item/weapon/gun/energy/printer - name = "cyborg lmg" - desc = "A machinegun that fires 3d-printed flachettes slowly regenerated using a cyborg's internal power source." - icon_state = "l6closed0" - icon = 'icons/obj/gun.dmi' - fire_sound = 'sound/weapons/Gunshot_smg.ogg' - cell_type = "/obj/item/weapon/stock_parts/cell/secborg" - projectile_type = "/obj/item/projectile/bullet/midbullet3" - charge_cost = 200 //Yeah, let's NOT give them a 300 round clip that recharges, 20 is more reasonable and will actually hurt the borg's battery for overuse. - - self_recharge = 1 - use_external_power = 1 - recharge_time = 5 - -/obj/item/weapon/gun/energy/printer/update_icon() - return + ammo_type = list(/obj/item/ammo_casing/energy/plasma/adv) + force = 15 /obj/item/weapon/gun/energy/wormhole_projector name = "bluespace wormhole projector" desc = "A projector that emits high density quantum-coupled bluespace beams." - projectile_type = "/obj/item/projectile/beam/wormhole" - charge_cost = 0 - fire_sound = "sound/weapons/pulse3.ogg" + ammo_type = list(/obj/item/ammo_casing/energy/wormhole, /obj/item/ammo_casing/energy/wormhole/orange) item_state = null icon_state = "wormhole_projector100" - modifystate = "wormhole_projector" var/obj/effect/portal/blue var/obj/effect/portal/orange - var/mode = 0 //0 = blue 1 = orange +/obj/item/weapon/gun/energy/wormhole_projector/update_icon() + icon_state = "[initial(icon_state)][select]" + item_state = icon_state + return -/obj/item/weapon/gun/energy/wormhole_projector/attack_self(mob/living/user as mob) - switch_modes() - -/obj/item/weapon/gun/energy/wormhole_projector/proc/switch_modes(mob/living/user as mob) - switch(mode) - if(0) - mode = 1 - to_chat(user, "[name] is now set to orange.") - projectile_type = "/obj/item/projectile/beam/wormhole/orange" - modifystate = "wormhole_projector_orange" - if(1) - mode = 0 - to_chat(user, "[name] is now set to blue.") - projectile_type = "/obj/item/projectile/beam/wormhole" - modifystate = "wormhole_projector" - update_icon() - if(user.hand) - user.update_inv_l_hand() - else - user.update_inv_r_hand() - -/obj/item/weapon/gun/energy/wormhole_projector/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) +/obj/item/weapon/gun/energy/wormhole_projector/process_chamber() ..() - switch_modes(user) + select_fire() /obj/item/weapon/gun/energy/wormhole_projector/proc/portal_destroyed(obj/effect/portal/P) if(P.icon_state == "portal") @@ -373,7 +306,6 @@ obj/item/weapon/gun/energy/staff/focus /obj/item/weapon/gun/energy/wormhole_projector/proc/create_portal(obj/item/projectile/beam/wormhole/W) var/obj/effect/portal/P = new /obj/effect/portal(get_turf(W), null, src) P.precision = 0 - P.failchance = 0 if(W.name == "bluespace beam") qdel(blue) blue = P @@ -383,4 +315,260 @@ obj/item/weapon/gun/energy/staff/focus orange = P if(orange && blue) blue.target = get_turf(orange) - orange.target = get_turf(blue) \ No newline at end of file + orange.target = get_turf(blue) + +/* 3d printer 'pseudo guns' for borgs */ + +/obj/item/weapon/gun/energy/printer + name = "cyborg lmg" + desc = "A machinegun that fires 3d-printed flachettes slowly regenerated using a cyborg's internal power source." + icon_state = "l6closed0" + icon = 'icons/obj/guns/projectile.dmi' + cell_type = "/obj/item/weapon/stock_parts/cell/secborg" + ammo_type = list(/obj/item/ammo_casing/energy/c3dbullet) + can_charge = 0 + +/obj/item/weapon/gun/energy/printer/update_icon() + return + +/obj/item/weapon/gun/energy/printer/emp_act() + return + +/obj/item/weapon/gun/energy/printer/newshot() + ..() + robocharge() + +/obj/item/weapon/gun/energy/laser/instakill + name = "instakill rifle" + icon_state = "instagib" + item_state = "instagib" + desc = "A specialized ASMD laser-rifle, capable of flat-out disintegrating most targets in a single hit." + ammo_type = list(/obj/item/ammo_casing/energy/instakill) + force = 60 + origin_tech = null + +/obj/item/weapon/gun/energy/laser/instakill/emp_act() //implying you could stop the instagib + return + +/obj/item/weapon/gun/energy/laser/instakill/red + desc = "A specialized ASMD laser-rifle, capable of flat-out disintegrating most targets in a single hit. This one has a red design." + icon_state = "instagibred" + item_state = "instagibred" + ammo_type = list(/obj/item/ammo_casing/energy/instakill/red) + +/obj/item/weapon/gun/energy/laser/instakill/blue + desc = "A specialized ASMD laser-rifle, capable of flat-out disintegrating most targets in a single hit. This one has a blue design." + icon_state = "instagibblue" + item_state = "instagibblue" + ammo_type = list(/obj/item/ammo_casing/energy/instakill/blue) + +/obj/item/weapon/gun/energy/clown + name = "HONK Rifle" + desc = "Clown Planet's finest." + icon_state = "disabler" + ammo_type = list(/obj/item/ammo_casing/energy/clown) + clumsy_check = 0 + +/obj/item/weapon/gun/energy/toxgun + name = "plasma pistol" + desc = "A specialized firearm designed to fire lethal bolts of toxins." + icon_state = "toxgun" + fire_sound = 'sound/effects/stealthoff.ogg' + w_class = 3 + origin_tech = "combat=4;plasmatech=3" + ammo_type = list(/obj/item/ammo_casing/energy/toxplasma) + shaded_charge = 1 + +/obj/item/weapon/gun/energy/sniperrifle + name = "L.W.A.P. Sniper Rifle" + desc = "A rifle constructed of lightweight materials, fitted with a SMART aiming-system scope." + icon_state = "esniper" + origin_tech = "combat=6;materials=5;powerstorage=4" + ammo_type = list(/obj/item/ammo_casing/energy/sniper) + slot_flags = SLOT_BACK + w_class = 4 + zoomable = TRUE + zoom_amt = 7 //Long range, enough to see in front of you, but no tiles behind you. + shaded_charge = 1 + +/obj/item/weapon/gun/energy/temperature + name = "temperature gun" + icon = 'icons/obj/guns/gun_temperature.dmi' + icon_state = "tempgun_4" + item_state = "tempgun_4" + slot_flags = SLOT_BACK + w_class = 4 + fire_sound = 'sound/weapons/pulse3.ogg' + desc = "A gun that changes the body temperature of its targets." + var/temperature = 300 + var/target_temperature = 300 + var/e_cost = 1000 + origin_tech = "combat=3;materials=4;powerstorage=3;magnets=2" + + ammo_type = list(/obj/item/ammo_casing/energy/temp) + cell_type = "/obj/item/weapon/stock_parts/cell" + + var/powercost = "" + var/powercostcolor = "" + + var/emagged = 0 //ups the temperature cap from 500 to 1000, targets hit by beams over 500 Kelvin will burst into flames + var/dat = "" + +/obj/item/weapon/gun/energy/temperature/New() + ..() + update_icon() + processing_objects.Add(src) + + +/obj/item/weapon/gun/energy/temperature/Destroy() + processing_objects.Remove(src) + return ..() + +/obj/item/weapon/gun/energy/temperature/newshot() + ..() + var/obj/item/ammo_casing/energy/temp/T = chambered + if(T) + T.temperature = temperature + T.e_cost = e_cost + +/obj/item/weapon/gun/energy/temperature/attack_self(mob/living/user as mob) + user.set_machine(src) + update_dat() + user << browse("Temperature Gun Configuration
    [dat]", "window=tempgun;size=510x120") + onclose(user, "tempgun") + +/obj/item/weapon/gun/energy/temperature/attackby(obj/item/weapon/W as obj, mob/user as mob) + if(istype(W, /obj/item/weapon/card/emag) && !emagged) + emagged = 1 + to_chat(user, "You double the gun's temperature cap! Targets hit by searing beams will burst into flames!") + desc = "A gun that changes the body temperature of its targets. Its temperature cap has been hacked." + +/obj/item/weapon/gun/energy/temperature/Topic(href, href_list) + if (..()) + return + usr.set_machine(src) + add_fingerprint(usr) + + if(href_list["temp"]) + var/amount = text2num(href_list["temp"]) + if(amount > 0) + target_temperature = min((500 + 500*emagged), target_temperature+amount) + else + target_temperature = max(0, target_temperature+amount) + if (istype(loc, /mob)) + attack_self(loc) + add_fingerprint(usr) + return + +/obj/item/weapon/gun/energy/temperature/process() + switch(temperature) + if(0 to 100) + e_cost = 3000 + powercost = "High" + if(100 to 250) + e_cost = 2000 + powercost = "Medium" + if(251 to 300) + e_cost = 1000 + powercost = "Low" + if(301 to 400) + e_cost = 2000 + powercost = "Medium" + if(401 to 1000) + e_cost = 3000 + powercost = "High" + switch(powercost) + if("High") powercostcolor = "orange" + if("Medium") powercostcolor = "green" + else powercostcolor = "blue" + if(target_temperature != temperature) + var/difference = abs(target_temperature - temperature) + if(difference >= (10 + 40*emagged)) //so emagged temp guns adjust their temperature much more quickly + if(target_temperature < temperature) + temperature -= (10 + 40*emagged) + else + temperature += (10 + 40*emagged) + else + temperature = target_temperature + update_icon() + + if (istype(loc, /mob/living/carbon)) + var /mob/living/carbon/M = loc + if (src == M.machine) + update_dat() + M << browse("Temperature Gun Configuration
    [dat]", "window=tempgun;size=510x102") + return + +/obj/item/weapon/gun/energy/temperature/proc/update_dat() + dat = "" + dat += "Current output temperature: " + if(temperature > 500) + dat += "[temperature] ([round(temperature-T0C)]°C)" + dat += " SEARING!" + else if(temperature > (T0C + 50)) + dat += "[temperature] ([round(temperature-T0C)]°C)" + else if(temperature > (T0C - 50)) + dat += "[temperature] ([round(temperature-T0C)]°C)" + else + dat += "[temperature] ([round(temperature-T0C)]°C)" + dat += "
    " + dat += "Target output temperature: " //might be string idiocy, but at least it's easy to read + dat += "- " + dat += "- " + dat += "- " + dat += "[target_temperature] " + dat += "+ " + dat += "+ " + dat += "+" + dat += "
    " + dat += "Power cost: " + dat += "[powercost]" + +/obj/item/weapon/gun/energy/temperature/proc/update_temperature() + switch(temperature) + if(501 to INFINITY) + item_state = "tempgun_8" + if(400 to 500) + item_state = "tempgun_7" + if(360 to 400) + item_state = "tempgun_6" + if(335 to 360) + item_state = "tempgun_5" + if(295 to 335) + item_state = "tempgun_4" + if(260 to 295) + item_state = "tempgun_3" + if(200 to 260) + item_state = "tempgun_2" + if(120 to 260) + item_state = "tempgun_1" + if(-INFINITY to 120) + item_state = "tempgun_0" + icon_state = item_state + +/obj/item/weapon/gun/energy/temperature/update_icon() + overlays = 0 + update_temperature() + update_user() + update_charge() + +/obj/item/weapon/gun/energy/temperature/proc/update_user() + if (istype(loc,/mob/living/carbon)) + var/mob/living/carbon/M = loc + M.update_inv_back() + M.update_inv_l_hand() + M.update_inv_r_hand() + +/obj/item/weapon/gun/energy/temperature/proc/update_charge() + var/charge = power_supply.charge + switch(charge) + if(9000 to INFINITY) overlays += "900" + if(8000 to 9000) overlays += "800" + if(7000 to 8000) overlays += "700" + if(6000 to 7000) overlays += "600" + if(5000 to 6000) overlays += "500" + if(4000 to 5000) overlays += "400" + if(3000 to 4000) overlays += "300" + if(2000 to 3000) overlays += "200" + if(1000 to 2002) overlays += "100" + if(-INFINITY to 1000) overlays += "0" diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 37d22ba5ff7..6fdbe55c171 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -1,84 +1,67 @@ - /obj/item/weapon/gun/energy/taser name = "taser gun" desc = "A small, low capacity gun used for non-lethal takedowns." icon_state = "taser" item_state = null //so the human update icon uses the icon_state instead. - fire_sound = 'sound/weapons/Taser.ogg' - projectile_type = "/obj/item/projectile/energy/electrode" + ammo_type = list(/obj/item/ammo_casing/energy/electrode) + ammo_x_offset = 3 cell_type = "/obj/item/weapon/stock_parts/cell/crap" - fire_delay = 15 /obj/item/weapon/gun/energy/taser/mounted name = "mounted taser gun" - self_recharge = 1 + selfcharge = 1 use_external_power = 1 /obj/item/weapon/gun/energy/taser/cyborg name = "taser gun" desc = "A small, low capacity gun used for non-lethal takedowns." icon_state = "taser" - fire_sound = 'sound/weapons/Taser.ogg' - projectile_type = "/obj/item/projectile/energy/electrode" cell_type = "/obj/item/weapon/stock_parts/cell/secborg" - self_recharge = 1 - recharge_time = 10 //Time it takes for shots to recharge (in ticks) +/obj/item/weapon/gun/energy/disabler/cyborg/newshot() + ..() + robocharge() /obj/item/weapon/gun/energy/shock_revolver name = "tesla revolver" desc = "A high-tech revolver that fires internal, reusable shock cartridges in a revolving cylinder. The cartridges can be recharged using conventional rechargers." icon_state = "stunrevolver" item_state = "gun" - fire_sound = 'sound/weapons/gunshot.ogg' - projectile_type = "/obj/item/projectile/energy/shock_revolver" - charge_cost = 2000 + ammo_type = list(/obj/item/ammo_casing/energy/shock_revolver) can_flashlight = 0 + shaded_charge = 1 -/obj/item/projectile/energy/shock_revolver - name = "shock bolt" - icon_state = "purple_laser" - var/chain +/obj/item/weapon/gun/energy/gun/advtaser + name = "hybrid taser" + desc = "A dual-mode taser designed to fire both short-range high-power electrodes and long-range disabler beams." + icon_state = "advtaser" + ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/disabler) + origin_tech = null + ammo_x_offset = 2 -/obj/item/projectile/energy/shock_revolver/OnFired() - spawn(1) - chain = Beam(firer, icon_state="purple_lightning", icon = 'icons/effects/effects.dmi',time=1000, maxdistance = 30) +/obj/item/weapon/gun/energy/gun/advtaser/cyborg + name = "cyborg taser" + desc = "An integrated hybrid taser that draws directly from a cyborg's power cell. The weapon contains a limiter to prevent the cyborg's power cell from overheating." + can_flashlight = 0 + can_charge = 0 -/obj/item/projectile/energy/shock_revolver/on_hit(atom/target) - . = ..() - if(isliving(target)) - tesla_zap(src, 3, 10000) - qdel(chain) +/obj/item/weapon/gun/energy/gun/advtaser/cyborg/newshot() + ..() + robocharge() -/obj/item/weapon/gun/energy/crossbow - name = "mini energy-crossbow" - desc = "A weapon favored by many of the syndicates stealth specialists." - icon_state = "crossbow" - w_class = 2.0 - item_state = "crossbow" - materials = list(MAT_METAL=2000) - origin_tech = "combat=2;magnets=2;syndicate=5" - silenced = 1 - fire_sound = 'sound/weapons/Genhit.ogg' - projectile_type = "/obj/item/projectile/energy/bolt" - cell_type = "/obj/item/weapon/stock_parts/cell/crap" - - self_recharge = 1 - -/obj/item/weapon/gun/energy/crossbow/ninja - name = "energy dart thrower" - projectile_type = /obj/item/projectile/energy/dart - -/obj/item/weapon/gun/energy/crossbow/update_icon() - return -/obj/item/weapon/gun/energy/crossbow/largecrossbow - name = "Energy Crossbow" - desc = "A weapon favored by syndicate carp hunters." - icon_state = "crossbowlarge" - silenced = 0 - w_class = 3.0 - force = 10 - materials = list(MAT_METAL=4000) - projectile_type = "/obj/item/projectile/energy/bolt/large" +/obj/item/weapon/gun/energy/disabler + name = "disabler" + desc = "A self-defense weapon that exhausts organic targets, weakening them until they collapse." + icon_state = "disabler" + item_state = null + ammo_type = list(/obj/item/ammo_casing/energy/disabler) + ammo_x_offset = 3 +/obj/item/weapon/gun/energy/disabler/cyborg + name = "cyborg disabler" + desc = "An integrated disabler that draws from a cyborg's power cell. This weapon contains a limiter to prevent the cyborg's power cell from overheating." + can_charge = 0 +/obj/item/weapon/gun/energy/disabler/cyborg/newshot() + ..() + robocharge() diff --git a/code/modules/projectiles/guns/energy/telegun.dm b/code/modules/projectiles/guns/energy/telegun.dm index 3819401e031..23dd6455a3e 100644 --- a/code/modules/projectiles/guns/energy/telegun.dm +++ b/code/modules/projectiles/guns/energy/telegun.dm @@ -5,11 +5,10 @@ desc = "An extremely high-tech bluespace energy gun capable of teleporting targets to far off locations." icon_state = "telegun" item_state = "ionrifle" - fire_sound = 'sound/weapons/wave.ogg' origin_tech = "combat=6;materials=7;powerstorage=5;bluespace=5;syndicate=4" cell_type = "/obj/item/weapon/stock_parts/cell/crap" - projectile_type = "/obj/item/projectile/energy/teleport" - charge_cost = 1250 + ammo_type = list(/obj/item/ammo_casing/energy/teleport) + shaded_charge = 1 var/teleport_target = null /obj/item/weapon/gun/energy/telegun/Destroy() @@ -36,4 +35,9 @@ L[tmpname] = R var/desc = input("Please select a location to lock in.", "Telegun Target Interface") in L - teleport_target = L[desc] \ No newline at end of file + teleport_target = L[desc] + +/obj/item/weapon/gun/energy/telegun/newshot() + ..() + var/obj/item/ammo_casing/energy/teleport/T = chambered + T.teleport_target = teleport_target diff --git a/code/modules/projectiles/guns/energy/temperature.dm b/code/modules/projectiles/guns/energy/temperature.dm deleted file mode 100644 index 1e0eb5d08c2..00000000000 --- a/code/modules/projectiles/guns/energy/temperature.dm +++ /dev/null @@ -1,182 +0,0 @@ -/obj/item/weapon/gun/energy/temperature - name = "temperature gun" - icon = 'icons/obj/gun_temperature.dmi' - icon_state = "tempgun_4" - item_state = "tempgun_4" - slot_flags = SLOT_BACK - w_class = 4.0 - fire_sound = 'sound/weapons/pulse3.ogg' - desc = "A gun that changes the body temperature of its targets." - var/temperature = 300 - var/target_temperature = 300 - charge_cost = 90 - origin_tech = "combat=3;materials=4;powerstorage=3;magnets=2" - - projectile_type = /obj/item/projectile/temp - cell_type = /obj/item/weapon/stock_parts/cell/temperaturegun - - var/powercost = "" - var/powercostcolor = "" - - var/emagged = 0 //ups the temperature cap from 500 to 1000, targets hit by beams over 500 Kelvin will burst into flames - var/dat = "" - -/obj/item/weapon/gun/energy/temperature/New() - ..() - update_icon() - processing_objects.Add(src) - - -/obj/item/weapon/gun/energy/temperature/Destroy() - processing_objects.Remove(src) - return ..() - - -/obj/item/weapon/gun/energy/temperature/attack_self(mob/living/user as mob) - user.set_machine(src) - update_dat() - - user << browse("Temperature Gun Configuration
    [dat]", "window=tempgun;size=510x120") - onclose(user, "tempgun") - -/obj/item/weapon/gun/energy/temperature/attackby(obj/item/weapon/W as obj, mob/user as mob) - if(istype(W, /obj/item/weapon/card/emag) && !emagged) - emagged = 1 - to_chat(user, "You double the gun's temperature cap! Targets hit by searing beams will burst into flames!") - desc = "A gun that changes the body temperature of its targets. Its temperature cap has been hacked." - -/obj/item/weapon/gun/energy/temperature/Topic(href, href_list) - if (..()) - return - usr.set_machine(src) - add_fingerprint(usr) - - if(href_list["temp"]) - var/amount = text2num(href_list["temp"]) - if(amount > 0) - target_temperature = min((500 + 500*emagged), target_temperature+amount) - else - target_temperature = max(0, target_temperature+amount) - if (istype(loc, /mob)) - attack_self(loc) - add_fingerprint(usr) - return - - -/obj/item/weapon/gun/energy/temperature/process() - switch(temperature) - if(0 to 100) - charge_cost = 300 - powercost = "High" - if(100 to 250) - charge_cost = 180 - powercost = "Medium" - if(251 to 300) - charge_cost = 90 - powercost = "Low" - if(301 to 400) - charge_cost = 180 - powercost = "Medium" - if(401 to 1000) - charge_cost = 300 - powercost = "High" - switch(powercost) - if("High") powercostcolor = "orange" - if("Medium") powercostcolor = "green" - else powercostcolor = "blue" - if(target_temperature != temperature) - var/difference = abs(target_temperature - temperature) - if(difference >= (10 + 40*emagged)) //so emagged temp guns adjust their temperature much more quickly - if(target_temperature < temperature) - temperature -= (10 + 40*emagged) - else - temperature += (10 + 40*emagged) - else - temperature = target_temperature - update_icon() - - if (istype(loc, /mob/living/carbon)) - var /mob/living/carbon/M = loc - if (src == M.machine) - update_dat() - M << browse("Temperature Gun Configuration
    [dat]", "window=tempgun;size=510x102") - - - if(power_supply) - power_supply.give(50) - update_icon() - return - -/obj/item/weapon/gun/energy/temperature/proc/update_dat() - dat = "" - dat += "Current output temperature: " - if(temperature > 500) - dat += "[temperature] ([round(temperature-T0C)]°C)" - dat += " SEARING!" - else if(temperature > (T0C + 50)) - dat += "[temperature] ([round(temperature-T0C)]°C)" - else if(temperature > (T0C - 50)) - dat += "[temperature] ([round(temperature-T0C)]°C)" - else - dat += "[temperature] ([round(temperature-T0C)]°C)" - dat += "
    " - dat += "Target output temperature: " //might be string idiocy, but at least it's easy to read - dat += "- " - dat += "- " - dat += "- " - dat += "[target_temperature] " - dat += "+ " - dat += "+ " - dat += "+" - dat += "
    " - dat += "Power cost: " - dat += "[powercost]" - -/obj/item/weapon/gun/energy/temperature/proc/update_temperature() - switch(temperature) - if(501 to INFINITY) - item_state = "tempgun_8" - if(400 to 500) - item_state = "tempgun_7" - if(360 to 400) - item_state = "tempgun_6" - if(335 to 360) - item_state = "tempgun_5" - if(295 to 335) - item_state = "tempgun_4" - if(260 to 295) - item_state = "tempgun_3" - if(200 to 260) - item_state = "tempgun_2" - if(120 to 260) - item_state = "tempgun_1" - if(-INFINITY to 120) - item_state = "tempgun_0" - icon_state = item_state - -/obj/item/weapon/gun/energy/temperature/proc/update_charge() - var/charge = power_supply.charge - switch(charge) - if(900 to INFINITY) overlays += "900" - if(800 to 900) overlays += "800" - if(700 to 800) overlays += "700" - if(600 to 700) overlays += "600" - if(500 to 600) overlays += "500" - if(400 to 500) overlays += "400" - if(300 to 400) overlays += "300" - if(200 to 300) overlays += "200" - if(100 to 200) overlays += "100" - if(-INFINITY to 100) overlays += "0" - -/obj/item/weapon/gun/energy/temperature/proc/update_user() - if (istype(loc,/mob/living/carbon)) - var/mob/living/carbon/M = loc - M.update_inv_back() - M.update_inv_l_hand() - M.update_inv_r_hand() - -/obj/item/weapon/gun/energy/temperature/update_icon() - overlays = 0 - update_temperature() - update_user() - update_charge() \ No newline at end of file diff --git a/code/modules/projectiles/guns/grenade_launcher.dm b/code/modules/projectiles/guns/grenade_launcher.dm new file mode 100644 index 00000000000..5abac9ebad9 --- /dev/null +++ b/code/modules/projectiles/guns/grenade_launcher.dm @@ -0,0 +1,54 @@ +/obj/item/weapon/gun/grenadelauncher + name = "grenade launcher" + desc = "a terrible, terrible thing. it's really awful!" + icon = 'icons/obj/guns/projectile.dmi' + icon_state = "riotgun" + item_state = "riotgun" + w_class = 4 + throw_speed = 2 + throw_range = 10 + force = 5 + var/list/grenades = new/list() + var/max_grenades = 3 + + materials = list(MAT_METAL=2000) + +/obj/item/weapon/gun/grenadelauncher/examine(mob/user) + if(..(user, 2)) + to_chat(user, "[grenades.len] / [max_grenades] grenades.") + +/obj/item/weapon/gun/grenadelauncher/attackby(obj/item/I as obj, mob/user as mob, params) + if((istype(I, /obj/item/weapon/grenade))) + if(grenades.len < max_grenades) + if(!user.unEquip(I)) + return + I.loc = src + grenades += I + to_chat(user, "You put the grenade in the [name].") + to_chat(user, "[grenades.len] / [max_grenades] grenades.") + else + to_chat(user, "The grenade launcher cannot hold more grenades.") + +/obj/item/weapon/gun/grenadelauncher/afterattack(obj/target, mob/user , flag) + if(target == user) + return + + if(grenades.len) + fire_grenade(target,user) + else + to_chat(user, "The grenade launcher is empty.") + +/obj/item/weapon/gun/grenadelauncher/proc/fire_grenade(atom/target, mob/user) + user.visible_message("[user] fired a grenade!", \ + "You fire the grenade launcher!") + var/obj/item/weapon/grenade/chem_grenade/F = grenades[1] //Now with less copypasta! + grenades -= F + F.loc = user.loc + F.throw_at(target, 30, 2, user) + message_admins("[key_name_admin(user)] fired a grenade ([F.name]) from a grenade launcher ([name]).") + log_game("[key_name(user)] fired a grenade ([F.name]) from a grenade launcher ([name]).") + F.active = 1 + F.icon_state = initial(icon_state) + "_active" + playsound(user.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) + spawn(15) + F.prime() diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm index 13f92bcef86..870ae85bc63 100644 --- a/code/modules/projectiles/guns/magic.dm +++ b/code/modules/projectiles/guns/magic.dm @@ -1,35 +1,29 @@ /obj/item/weapon/gun/magic name = "staff of nothing" desc = "This staff is boring to watch because even though it came first you've seen everything it can do in other staves for years." - icon = 'icons/obj/gun.dmi' + icon = 'icons/obj/guns/magic.dmi' icon_state = "staffofnothing" item_state = "staff" - lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' //not really a gun and some toys use these inhands - righthand_file = 'icons/mob/inhands/items_righthand.dmi' fire_sound = 'sound/weapons/emitter.ogg' + fire_sound_text = "energy blast" flags = CONDUCT w_class = 5 - var/projectile_type = /obj/item/projectile/magic var/max_charges = 6 var/charges = 0 var/recharge_rate = 4 var/charge_tick = 0 var/can_charge = 1 + var/ammo_type var/no_den_usage origin_tech = null clumsy_check = 0 + trigger_guard = TRIGGER_GUARD_ALLOW_ALL // Has no trigger at all, uses magic instead -/obj/item/weapon/gun/magic/emp_act(severity) - return + lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' //not really a gun and some toys use these inhands + righthand_file = 'icons/mob/inhands/items_righthand.dmi' -/obj/item/weapon/gun/magic/process_chambered() - if(in_chamber) return 1 - if(!charges) return 0 - if(!projectile_type) return 0 - in_chamber = new projectile_type(src) - return 1 - -/obj/item/weapon/gun/magic/afterattack(atom/target as mob, mob/living/user as mob, flag) +/obj/item/weapon/gun/magic/afterattack(atom/target, mob/living/user, flag) + newshot() if(no_den_usage) var/area/A = get_area(user) if(istype(A, /area/wizard_station)) @@ -38,22 +32,38 @@ else no_den_usage = 0 ..() - if(charges && !in_chamber && !flag) charges-- + +/obj/item/weapon/gun/magic/can_shoot() + return charges + +/obj/item/weapon/gun/magic/newshot() + if (charges && chambered) + chambered.newshot() + return + +/obj/item/weapon/gun/magic/process_chamber() + if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired... + charges--//... drain a charge + return /obj/item/weapon/gun/magic/New() ..() charges = max_charges - if(can_charge) processing_objects.Add(src) + chambered = new ammo_type(src) + if(can_charge) + processing_objects.Add(src) /obj/item/weapon/gun/magic/Destroy() - if(can_charge) processing_objects.Remove(src) + if(can_charge) + processing_objects.Remove(src) return ..() /obj/item/weapon/gun/magic/process() charge_tick++ - if(charge_tick < recharge_rate || charges >= max_charges) return 0 + if(charge_tick < recharge_rate || charges >= max_charges) + return 0 charge_tick = 0 charges++ return 1 @@ -63,4 +73,9 @@ /obj/item/weapon/gun/magic/shoot_with_empty_chamber(mob/living/user as mob|obj) to_chat(user, "The [name] whizzles quietly.") - return \ No newline at end of file + return + +/obj/item/weapon/gun/magic/suicide_act(mob/user) + user.visible_message("[user] is twisting the [name] above \his head, releasing a magical blast! It looks like \he's trying to commit suicide.") + playsound(loc, fire_sound, 50, 1, -1) + return FIRELOSS diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index 16fc552397d..85b483b8363 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -4,49 +4,61 @@ obj/item/weapon/gun/magic/staff/ obj/item/weapon/gun/magic/staff/change name = "staff of change" desc = "An artefact that spits bolts of coruscating energy which cause the target's very form to reshape itself" - projectile_type = "/obj/item/projectile/magic/change" + ammo_type = /obj/item/ammo_casing/magic/change icon_state = "staffofchange" item_state = "staffofchange" obj/item/weapon/gun/magic/staff/animate name = "staff of animation" desc = "An artefact that spits bolts of life-force which causes objects which are hit by it to animate and come to life! This magic doesn't affect machines." - projectile_type = "/obj/item/projectile/magic/animate" + ammo_type = /obj/item/ammo_casing/magic/animate icon_state = "staffofanimation" item_state = "staffofanimation" obj/item/weapon/gun/magic/staff/healing name = "staff of healing" desc = "An artefact that spits bolts of restoring magic which can remove ailments of all kinds and even raise the dead." - projectile_type = "/obj/item/projectile/magic/resurrection" + ammo_type = /obj/item/ammo_casing/magic/heal icon_state = "staffofhealing" item_state = "staffofhealing" +/obj/item/weapon/gun/magic/staff/healing/handle_suicide() //Stops people trying to commit suicide to heal themselves + return + obj/item/weapon/gun/magic/staff/chaos name = "staff of chaos" desc = "An artefact that spits bolts of chaotic magic that can potentially do anything." - projectile_type = "/obj/item/projectile/magic" + ammo_type = /obj/item/ammo_casing/magic/chaos icon_state = "staffofchaos" item_state = "staffofchaos" max_charges = 10 recharge_rate = 2 - no_den_usage = 1 -/obj/item/weapon/gun/magic/staff/chaos/process_chambered() //Snowflake proc, because this uses projectile_type instead of ammo_casing for whatever reason. - projectile_type = pick(typesof(/obj/item/projectile/magic)) - if(in_chamber) return 1 - if(!charges) return 0 - in_chamber = new projectile_type(src) - return 1 - obj/item/weapon/gun/magic/staff/door name = "staff of door creation" desc = "An artefact that spits bolts of transformative magic that can create doors in walls." - projectile_type = "/obj/item/projectile/magic/door" + ammo_type = /obj/item/ammo_casing/magic/door icon_state = "staffofdoor" item_state = "staffofdoor" max_charges = 10 recharge_rate = 2 + no_den_usage = 1 - no_den_usage = 1 \ No newline at end of file +/obj/item/weapon/gun/magic/staff/honk + name = "staff of the honkmother" + desc = "Honk" + fire_sound = "sound/items/airhorn.ogg" + ammo_type = /obj/item/ammo_casing/magic/honk + icon_state = "honker" + item_state = "honker" + max_charges = 4 + recharge_rate = 8 + +obj/item/weapon/gun/magic/staff/focus + name = "mental focus" + desc = "An artefact that channels the will of the user into destructive bolts of force. If you aren't careful with it, you might poke someone's brain out." + icon = 'icons/obj/wizard.dmi' + icon_state = "focus" + item_state = "focus" + ammo_type = list(/obj/item/ammo_casing/forcebolt) diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index 6be4e0936bf..abde404e87d 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -1,21 +1,13 @@ /obj/item/weapon/gun/magic/wand/ name = "wand of nothing" desc = "It's not just a stick, it's a MAGIC stick!" - projectile_type = "/obj/item/projectile/magic" + ammo_type = /obj/item/ammo_casing/magic icon_state = "nothingwand" item_state = "wand" w_class = 2 can_charge = 0 max_charges = 100 //100, 50, 50, 34 (max charge distribution by 25%ths) var/variable_charges = 1 - var/drained = 0 - -/obj/item/projectile/magic/fireball/Range() - var/mob/living/L = locate(/mob/living) in (range(src, 1) - firer) - if(L && L.stat != DEAD) - Bump(L) //Magic Bullet #teachthecontroversy - return - ..() /obj/item/weapon/gun/magic/wand/New() if(prob(75) && variable_charges) //25% chance of listed max charges, 50% chance of 1/2 max charges, 25% chance of 1/3 max charges @@ -26,26 +18,21 @@ ..() /obj/item/weapon/gun/magic/wand/examine(mob/user) - ..(user) + ..() to_chat(user, "Has [charges] charge\s remaining.") -/obj/item/weapon/gun/magic/wand/attack_self(mob/living/user as mob) - if(charges) - zap_self(user) - else - to_chat(user, "The [name] whizzles quietly.") - ..() +/obj/item/weapon/gun/magic/wand/update_icon() + icon_state = "[initial(icon_state)][charges ? "" : "-drained"]" -/obj/item/weapon/gun/magic/wand/attack(atom/target as mob, mob/living/user as mob) + +/obj/item/weapon/gun/magic/wand/attack(atom/target, mob/living/user) if(target == user) return ..() -/obj/item/weapon/gun/magic/wand/afterattack(atom/target as mob, mob/living/user as mob) - if(!charges && !drained) - to_chat(user, "The [name] whizzles quietly.") - icon_state = "[icon_state]-drained" - drained = 1 +/obj/item/weapon/gun/magic/wand/afterattack(atom/target, mob/living/user) + if(!charges) + shoot_with_empty_chamber(user) return if(target == user) if(no_den_usage) @@ -53,74 +40,83 @@ if(istype(A, /area/wizard_station)) to_chat(user, "You know better than to violate the security of The Den, best wait until you leave to use [src].") return - else - no_den_usage = 0 + else + no_den_usage = 0 zap_self(user) else ..() + update_icon() -/obj/item/weapon/gun/magic/wand/proc/zap_self(mob/living/user as mob) - user.visible_message("[user] zaps \himself with [src]!") +/obj/item/weapon/gun/magic/wand/proc/zap_self(mob/living/user) + user.visible_message("[user] zaps \himself with [src].") + playsound(user, fire_sound, 50, 1) + user.attack_log += "\[[time_stamp()]\] [user]/[user.ckey] zapped \himself with a [src]" + +///////////////////////////////////// +//WAND OF DEATH +///////////////////////////////////// /obj/item/weapon/gun/magic/wand/death name = "wand of death" desc = "This deadly wand overwhelms the victim's body with pure energy, slaying them without fail." - projectile_type = "/obj/item/projectile/magic/death" + ammo_type = /obj/item/ammo_casing/magic/death icon_state = "deathwand" max_charges = 3 //3, 2, 2, 1 -/obj/item/weapon/gun/magic/wand/death/zap_self(mob/living/user as mob) - if(alert(user, "You really want to zap yourself with the wand of death?",, "Yes", "No") == "Yes" && charges && user.get_active_hand() == src && isliving(user)) - var/message ="You irradiate yourself with pure energy! " - message += pick("Do not pass go. Do not collect 200 zorkmids.","You feel more confident in your spell casting skills.","You Die...","Do you want your possessions identified?") - to_chat(user, message) - user.adjustOxyLoss(500) - charges-- - ..() +/obj/item/weapon/gun/magic/wand/death/zap_self(mob/living/user) + var/message ="You irradiate yourself with pure energy! " + message += pick("Do not pass go. Do not collect 200 zorkmids.","You feel more confident in your spell casting skills.","You Die...","Do you want your possessions identified?") + to_chat(user, message) + user.adjustFireLoss(500) + charges-- + ..() + +///////////////////////////////////// +//WAND OF HEALING +///////////////////////////////////// /obj/item/weapon/gun/magic/wand/resurrection name = "wand of resurrection" desc = "This wand uses healing magics to heal and revive. They are rarely utilized within the Wizard Federation for some reason." - projectile_type = "/obj/item/projectile/magic/resurrection" + ammo_type = /obj/item/ammo_casing/magic/heal icon_state = "revivewand" max_charges = 3 //3, 2, 2, 1 -/obj/item/weapon/gun/magic/wand/resurrection/zap_self(mob/living/user as mob) - user.setToxLoss(0) - user.setOxyLoss(0) - user.setCloneLoss(0) - user.SetParalysis(0) - user.SetStunned(0) - user.SetWeakened(0) - user.radiation = 0 - user.heal_overall_damage(user.getBruteLoss(), user.getFireLoss()) - user.reagents.clear_reagents() +/obj/item/weapon/gun/magic/wand/resurrection/zap_self(mob/living/user) + user.revive() to_chat(user, "You feel great!") charges-- ..() +///////////////////////////////////// +//WAND OF POLYMORPH +///////////////////////////////////// + /obj/item/weapon/gun/magic/wand/polymorph name = "wand of polymorph" desc = "This wand is attuned to chaos and will radically alter the victim's form." - projectile_type = "/obj/item/projectile/magic/change" + ammo_type = /obj/item/ammo_casing/magic/change icon_state = "polywand" max_charges = 10 //10, 5, 5, 4 -/obj/item/weapon/gun/magic/wand/polymorph/zap_self(mob/living/user as mob) - if(alert(user, "Your new form might not have arms to zap with... Continue?",, "Yes", "No") == "Yes" && charges && user.get_active_hand() == src && isliving(user)) - ..() //because the user mob ceases to exists by the time wabbajack fully resolves - wabbajack(user) - charges-- +/obj/item/weapon/gun/magic/wand/polymorph/zap_self(mob/living/user) + ..() //because the user mob ceases to exists by the time wabbajack fully resolves + wabbajack(user) + charges-- + +///////////////////////////////////// +//WAND OF TELEPORTATION +///////////////////////////////////// /obj/item/weapon/gun/magic/wand/teleport name = "wand of teleportation" desc = "This wand will wrench targets through space and time to move them somewhere else." - projectile_type = "/obj/item/projectile/magic/teleport" + ammo_type = /obj/item/ammo_casing/magic/teleport icon_state = "telewand" max_charges = 10 //10, 5, 5, 4 no_den_usage = 1 -/obj/item/weapon/gun/magic/wand/teleport/zap_self(mob/living/user as mob) +/obj/item/weapon/gun/magic/wand/teleport/zap_self(mob/living/user) do_teleport(user, user, 10) var/datum/effect/system/harmless_smoke_spread/smoke = new /datum/effect/system/harmless_smoke_spread() smoke.set_up(10, 0, user.loc) @@ -128,25 +124,34 @@ charges-- ..() +///////////////////////////////////// +//WAND OF DOOR CREATION +///////////////////////////////////// + /obj/item/weapon/gun/magic/wand/door name = "wand of door creation" desc = "This particular wand can create doors in any wall for the unscrupulous wizard who shuns teleportation magics." - projectile_type = "/obj/item/projectile/magic/door" + ammo_type = /obj/item/ammo_casing/magic/door icon_state = "doorwand" max_charges = 20 //20, 10, 10, 7 -/obj/item/weapon/gun/magic/wand/door/zap_self() - return +/obj/item/weapon/gun/magic/wand/door/zap_self(mob/living/user) + to_chat(user, "You feel vaguely more open with your feelings.") + charges-- + ..() + +///////////////////////////////////// +//WAND OF FIREBALL +///////////////////////////////////// /obj/item/weapon/gun/magic/wand/fireball name = "wand of fireball" desc = "This wand shoots scorching balls of fire that explode into destructive flames." - projectile_type = "/obj/item/projectile/magic/fireball" + ammo_type = /obj/item/ammo_casing/magic/fireball icon_state = "firewand" max_charges = 8 //8, 4, 4, 3 -/obj/item/weapon/gun/magic/wand/fireball/zap_self(mob/living/user as mob) - if(alert(user, "Zapping yourself with a wand of fireball is probably a bad idea, do it anyway?",, "Yes", "No") == "Yes" && charges && user.get_active_hand() == src && isliving(user)) - explosion(user.loc, -1, 0, 2, 3, 0, flame_range = 2) - charges-- - ..() \ No newline at end of file +/obj/item/weapon/gun/magic/wand/fireball/zap_self(mob/living/user) + explosion(user.loc, -1, 0, 2, 3, 0, flame_range = 2) + charges-- + ..() diff --git a/code/modules/projectiles/medbeam.dm b/code/modules/projectiles/guns/medbeam.dm similarity index 91% rename from code/modules/projectiles/medbeam.dm rename to code/modules/projectiles/guns/medbeam.dm index 04f8f4b6862..032874c4918 100644 --- a/code/modules/projectiles/medbeam.dm +++ b/code/modules/projectiles/guns/medbeam.dm @@ -4,7 +4,7 @@ icon = 'icons/obj/chronos.dmi' icon_state = "chronogun" item_state = "chronogun" - w_class = 3.0 + w_class = 3 var/mob/living/current_target var/last_check = 0 @@ -13,7 +13,7 @@ var/active = 0 var/datum/beam/current_beam = null - heavy_weapon = 1 + weapon_weight = WEAPON_MEDIUM /obj/item/weapon/gun/medbeam/New() ..() @@ -34,7 +34,7 @@ on_beam_release(current_target) current_target = null -/obj/item/weapon/gun/medbeam/Fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, params) +/obj/item/weapon/gun/medbeam/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params, zone_override) add_fingerprint(user) if(current_target) @@ -48,7 +48,7 @@ spawn(0) current_beam.Start() - feedback_add_details("gun_fired","[src.type]") + feedback_add_details("gun_fired","[type]") /obj/item/weapon/gun/medbeam/process() var/mob/living/carbon/human/H = loc @@ -113,4 +113,4 @@ return /obj/effect/ebeam/medical - name = "medical beam" \ No newline at end of file + name = "medical beam" diff --git a/code/modules/projectiles/guns/mounted.dm b/code/modules/projectiles/guns/mounted.dm index d0e023d0d6d..ae9c8f06d09 100644 --- a/code/modules/projectiles/guns/mounted.dm +++ b/code/modules/projectiles/guns/mounted.dm @@ -1,31 +1,30 @@ -/obj/item/weapon/gun/energy/advtaser/mounted +/obj/item/weapon/gun/energy/gun/advtaser/mounted name = "mounted taser" desc = "An arm mounted dual-mode weapon that fires electrodes and disabler shots." - icon_state = "armcannonstun" - item_state = "armcannonstun" - modifystate = "armcannonstun" + icon_state = "armcannon" force = 5 - self_recharge = 1 flags = NODROP - slot_flags = null - w_class = 5.0 + w_class = 5 can_flashlight = 0 + selfcharge = 1 + trigger_guard = TRIGGER_GUARD_ALLOW_ALL // Has no trigger at all, uses neural signals instead -/obj/item/weapon/gun/energy/advtaser/mounted/dropped()//if somebody manages to drop this somehow... - src.loc = null//send it to nullspace to get retrieved by the implant later on. gotta cover those edge cases. +/obj/item/weapon/gun/energy/gun/advtaser/mounted/dropped()//if somebody manages to drop this somehow... + ..() + loc = null//send it to nullspace to get retrieved by the implant later on. gotta cover those edge cases. /obj/item/weapon/gun/energy/laser/mounted name = "mounted laser" desc = "An arm mounted cannon that fires lethal lasers. Doesn't come with a charge beam." - icon_state = "armcannonlase" + icon_state = "armcannon" item_state = "armcannonlase" - modifystate = "armcannonlase" force = 5 - self_recharge = 1 flags = NODROP - slot_flags = null - w_class = 5.0 + w_class = 5 materials = null + selfcharge = 1 + trigger_guard = TRIGGER_GUARD_ALLOW_ALL /obj/item/weapon/gun/energy/laser/mounted/dropped() - src.loc = null \ No newline at end of file + ..() + loc = null diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm index ffe2cd269b5..03519770eee 100644 --- a/code/modules/projectiles/guns/projectile.dm +++ b/code/modules/projectiles/guns/projectile.dm @@ -1,22 +1,13 @@ -#define SPEEDLOADER 0 -#define FROM_BOX 1 -#define MAGAZINE 2 - /obj/item/weapon/gun/projectile desc = "Now comes in flavors like GUN. Uses 10mm ammo, for some reason" name = "projectile gun" icon_state = "pistol" origin_tech = "combat=2;materials=2" - w_class = 3.0 + w_class = 3 materials = list(MAT_METAL=1000) -// recoil = 1 - var/mag_type = "/obj/item/ammo_box/magazine/m10mm" //Removes the need for max_ammo and caliber info + + var/mag_type = /obj/item/ammo_box/magazine/m10mm //Removes the need for max_ammo and caliber info var/obj/item/ammo_box/magazine/magazine -// var/obj/item/ammo_casing/chambered = null // The round (not bullet) that is in the chamber. - - - - /obj/item/weapon/gun/projectile/New() ..() @@ -26,31 +17,26 @@ update_icon() return +/obj/item/weapon/gun/projectile/update_icon() + ..() + if(current_skin) + icon_state = "[current_skin][suppressed ? "-suppressed" : ""][sawn_state ? "-sawn" : ""]" + else + icon_state = "[initial(icon_state)][suppressed ? "-suppressed" : ""][sawn_state ? "-sawn" : ""]" -/obj/item/weapon/gun/projectile/process_chambered(var/eject_casing = 1, var/empty_chamber = 1 ) -// if(in_chamber) -// return 1 - +/obj/item/weapon/gun/projectile/process_chamber(eject_casing = 1, empty_chamber = 1) var/obj/item/ammo_casing/AC = chambered //Find chambered round if(isnull(AC) || !istype(AC)) - return 0 + chamber_round() + return if(eject_casing) AC.loc = get_turf(src) //Eject casing onto ground. AC.SpinAnimation(10, 1) //next gen special effects + if(empty_chamber) chambered = null chamber_round() - if(AC.BB) - if(AC.reagents && AC.BB.reagents) - var/datum/reagents/casting_reagents = AC.reagents - casting_reagents.trans_to(AC.BB, casting_reagents.total_volume) //For chemical darts/bullets - qdel(casting_reagents) - in_chamber = AC.BB //Load projectile into chamber. - AC.BB.loc = src //Set projectile loc to gun. - AC.update_icon() - return 1 - return 0 - + return /obj/item/weapon/gun/projectile/proc/chamber_round() if(chambered || !magazine) @@ -60,12 +46,16 @@ chambered.loc = src return +/obj/item/weapon/gun/projectile/can_shoot() + if(!magazine || !magazine.ammo_count(0)) + return 0 + return 1 /obj/item/weapon/gun/projectile/attackby(var/obj/item/A as obj, mob/user as mob, params) ..() if(istype(A, /obj/item/ammo_box/magazine)) var/obj/item/ammo_box/magazine/AM = A - if(!magazine && istype(AM, text2path(mag_type))) + if(!magazine && istype(AM, mag_type)) user.remove_from_mob(AM) magazine = AM magazine.loc = src @@ -79,13 +69,11 @@ if(istype(A, /obj/item/weapon/suppressor)) var/obj/item/weapon/suppressor/S = A if(can_suppress) - if(!silenced) - if(user.l_hand != src && user.r_hand != src) - to_chat(user, "You'll need [src] in your hands to do that.") + if(!suppressed) + if(!user.unEquip(A)) return - user.drop_item() to_chat(user, "You screw [S] onto [src].") - silenced = A + suppressed = A S.oldsound = fire_sound S.initial_w_class = w_class fire_sound = 'sound/weapons/Gunshot_silenced.ogg' @@ -101,39 +89,45 @@ return return 0 -/obj/item/weapon/gun/projectile/attack_hand(mob/user as mob) +/obj/item/weapon/gun/projectile/attack_hand(mob/user) if(loc == user) - if(silenced && can_unsuppress) - var/obj/item/weapon/suppressor/S = silenced + if(suppressed && can_unsuppress) + var/obj/item/weapon/suppressor/S = suppressed if(user.l_hand != src && user.r_hand != src) ..() return - to_chat(user, "You unscrew [silenced] from [src].") - user.put_in_hands(silenced) + to_chat(user, "You unscrew [suppressed] from [src].") + user.put_in_hands(suppressed) fire_sound = S.oldsound w_class = S.initial_w_class - silenced = 0 + suppressed = 0 update_icon() return ..() /obj/item/weapon/gun/projectile/attack_self(mob/living/user as mob) + var/obj/item/ammo_casing/AC = chambered //Find chambered round if(magazine) - magazine.loc = get_turf(src.loc) + magazine.loc = get_turf(loc) user.put_in_hands(magazine) magazine.update_icon() magazine = null to_chat(user, "You pull the magazine out of \the [src]!") + else if(chambered) + AC.loc = get_turf(src) + AC.SpinAnimation(10, 1) + chambered = null + to_chat(user, "You unload the round from \the [src]'s chamber.") else to_chat(user, "There's no magazine in \the [src].") update_icon() return /obj/item/weapon/gun/projectile/examine(mob/user) - ..(user) + ..() to_chat(user, "Has [get_ammo()] round\s remaining.") -/obj/item/weapon/gun/projectile/proc/get_ammo(var/countchambered = 1) +/obj/item/weapon/gun/projectile/proc/get_ammo(countchambered = 1) var/boolets = 0 //mature var names for mature people if(chambered && countchambered) boolets++ @@ -141,12 +135,68 @@ boolets += magazine.ammo_count() return boolets +/obj/item/weapon/gun/projectile/suicide_act(mob/user) + if (chambered && chambered.BB && !chambered.BB.nodamage) + user.visible_message("[user] is putting the barrel of the [name] in \his mouth. It looks like \he's trying to commit suicide.") + sleep(25) + if(user.l_hand == src || user.r_hand == src) + process_fire(user, user, 0, zone_override = "head") + user.visible_message("[user] blows \his brains out with the [name]!") + return(BRUTELOSS) + else + user.visible_message("[user] panics and starts choking to death!") + return(OXYLOSS) + else + user.visible_message("[user] is pretending to blow \his brains out with the [name]! It looks like \he's trying to commit suicide!") + playsound(loc, 'sound/weapons/empty.ogg', 50, 1, -1) + return (OXYLOSS) + +/obj/item/weapon/gun/projectile/proc/sawoff(mob/user) + if(sawn_state == SAWN_OFF) + to_chat(user, "\The [src] is already shortened!") + return + user.changeNext_move(CLICK_CD_MELEE) + user.visible_message("[user] begins to shorten \the [src].", "You begin to shorten \the [src]...") + + //if there's any live ammo inside the gun, makes it go off + if(blow_up(user)) + user.visible_message("\The [src] goes off!", "\The [src] goes off in your face!") + return + + if(do_after(user, 30, target = src)) + if(sawn_state == SAWN_OFF) + return + user.visible_message("[user] shortens \the [src]!", "You shorten \the [src].") + name = "sawn-off [name]" + desc = sawn_desc + w_class = 3 + item_state = "gun"//phil235 is it different with different skin? + slot_flags &= ~SLOT_BACK //you can't sling it on your back + slot_flags |= SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally) + sawn_state = SAWN_OFF + update_icon() + return 1 + +// Sawing guns related proc +/obj/item/weapon/gun/projectile/proc/blow_up(mob/user) + . = 0 + for(var/obj/item/ammo_casing/AC in magazine.stored_ammo) + if(AC.BB) + process_fire(user, user,0) + . = 1 + /obj/item/weapon/suppressor name = "suppressor" desc = "A universal syndicate small-arms suppressor for maximum espionage." - icon = 'icons/obj/gun.dmi' + icon = 'icons/obj/guns/projectile.dmi' icon_state = "suppressor" item_state = "suppressor" w_class = 2 var/oldsound = null var/initial_w_class = null + +/obj/item/weapon/suppressor/specialoffer + name = "cheap suppressor" + desc = "A foreign knock-off suppressor, it feels flimsy, cheap, and brittle. Still fits all weapons." + icon = 'icons/obj/guns/projectile.dmi' + icon_state = "suppressor" diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index b56344ce039..7544ecc7b50 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -1,6 +1,5 @@ /obj/item/weapon/gun/projectile/automatic w_class = 3.0 - automatic = 1 var/alarmed = 0 var/select = 1 can_suppress = 1 @@ -11,13 +10,6 @@ /obj/item/weapon/gun/projectile/automatic/isHandgun() return 0 -/obj/item/weapon/gun/projectile/automatic/proto - name = "\improper Nanotrasen Saber SMG" - desc = "A prototype three-round burst 9mm submachine gun, designated 'SABR'. Has a threaded barrel for suppressors." - icon_state = "saber" - mag_type = "/obj/item/ammo_box/magazine/smgm9mm" - origin_tech = "combat=4;materials=2" - /obj/item/weapon/gun/projectile/automatic/update_icon() ..() overlays.Cut() @@ -25,8 +17,7 @@ overlays += "[initial(icon_state)]semi" if(select == 1) overlays += "[initial(icon_state)]burst" - icon_state = "[initial(icon_state)][magazine ? "-[magazine.max_ammo]" : ""][chambered ? "" : "-e"][silenced ? "-suppressed" : ""]" - return + icon_state = "[initial(icon_state)][magazine ? "-[magazine.max_ammo]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]" /obj/item/weapon/gun/projectile/automatic/attackby(var/obj/item/A as obj, mob/user as mob, params) . = ..() @@ -34,17 +25,17 @@ return if(istype(A, /obj/item/ammo_box/magazine)) var/obj/item/ammo_box/magazine/AM = A - if(istype(AM, text2path(mag_type))) + if(istype(AM, mag_type)) if(magazine) to_chat(user, "You perform a tactical reload on \the [src], replacing the magazine.") - magazine.forceMove(get_turf(src.loc)) + magazine.loc = get_turf(loc) magazine.update_icon() magazine = null else to_chat(user, "You insert the magazine into \the [src].") user.remove_from_mob(AM) magazine = AM - magazine.forceMove(src) + magazine.loc = src chamber_round() A.update_icon() update_icon() @@ -67,14 +58,22 @@ playsound(user, 'sound/weapons/empty.ogg', 100, 1) update_icon() - return + +/obj/item/weapon/gun/projectile/automatic/can_shoot() + return get_ammo() /obj/item/weapon/gun/projectile/automatic/proc/empty_alarm() if(!chambered && !get_ammo() && !alarmed) - playsound(src.loc, 'sound/weapons/smg_empty_alarm.ogg', 40, 1) + playsound(loc, 'sound/weapons/smg_empty_alarm.ogg', 40, 1) update_icon() alarmed = 1 - return + +/obj/item/weapon/gun/projectile/automatic/proto + name = "\improper Nanotrasen Saber SMG" + desc = "A prototype three-round burst 9mm submachine gun, designated 'SABR'. Has a threaded barrel for suppressors." + icon_state = "saber" + mag_type = /obj/item/ammo_box/magazine/smgm9mm + origin_tech = "combat=4;materials=2" /obj/item/weapon/gun/projectile/automatic/c20r name = "\improper C-20r SMG" @@ -82,7 +81,7 @@ icon_state = "c20r" item_state = "c20r" origin_tech = "combat=5;materials=2;syndicate=8" - mag_type = "/obj/item/ammo_box/magazine/smgm45" + mag_type = /obj/item/ammo_box/magazine/smgm45 fire_sound = 'sound/weapons/Gunshot_smg.ogg' fire_delay = 2 burst_size = 2 @@ -90,24 +89,21 @@ /obj/item/weapon/gun/projectile/automatic/c20r/New() ..() update_icon() - return /obj/item/weapon/gun/projectile/automatic/c20r/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag) ..() empty_alarm() - return /obj/item/weapon/gun/projectile/automatic/c20r/update_icon() ..() - icon_state = "c20r[magazine ? "-[Ceiling(get_ammo(0)/4)*4]" : ""][chambered ? "" : "-e"][silenced ? "-suppressed" : ""]" - return + icon_state = "c20r[magazine ? "-[Ceiling(get_ammo(0)/4)*4]" : ""][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]" /obj/item/weapon/gun/projectile/automatic/wt550 name = "security auto rifle" desc = "An outdated personal defense weapon utilized by law enforcement. The WT-550 Automatic Rifle fires 4.6x30mm rounds." icon_state = "wt550" item_state = "arg" - mag_type = "/obj/item/ammo_box/magazine/wt550m9" + mag_type = /obj/item/ammo_box/magazine/wt550m9 fire_delay = 2 can_suppress = 0 burst_size = 1 @@ -116,87 +112,22 @@ /obj/item/weapon/gun/projectile/automatic/wt550/update_icon() ..() icon_state = "wt550[magazine ? "-[Ceiling(get_ammo(0)/4)*4]" : ""]" - return /obj/item/weapon/gun/projectile/automatic/mini_uzi name = "\improper 'Type U3' Uzi" desc = "A lightweight, burst-fire submachine gun, for when you really want someone dead. Uses 9mm rounds." icon_state = "mini-uzi" origin_tech = "combat=5;materials=2;syndicate=8" - mag_type = "/obj/item/ammo_box/magazine/uzim9mm" + mag_type = /obj/item/ammo_box/magazine/uzim9mm burst_size = 2 -/obj/item/weapon/gun/projectile/automatic/l6_saw - name = "\improper L6 SAW" - desc = "A heavily modified 7.62 light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the reciever below the designation." - icon_state = "l6closed100" - item_state = "l6closedmag" - w_class = 5 - slot_flags = 0 - origin_tech = "combat=5;materials=1;syndicate=2" - mag_type = "/obj/item/ammo_box/magazine/m762" - fire_sound = 'sound/weapons/Gunshot3.ogg' - - var/cover_open = 0 - can_suppress = 0 - burst_size = 5 - fire_delay = 3 - -/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_self(mob/user as mob) - cover_open = !cover_open - to_chat(user, "You [cover_open ? "open" : "close"] [src]'s cover.") - update_icon() - -/obj/item/weapon/gun/projectile/automatic/l6_saw/update_icon() - if(magazine && magazine.caliber != "a762") - icon_state = "l6[cover_open ? "open" : "closed"]0" - icon_state = "l6[cover_open ? "open" : "closed"][magazine ? round(magazine.ammo_count() * 2, 25) : "-empty"]" - -/obj/item/weapon/gun/projectile/automatic/l6_saw/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params) //what I tried to do here is just add a check to see if the cover is open or not and add an icon_state change because I can't figure out how c-20rs do it with overlays - if(cover_open) - to_chat(user, "[src]'s cover is open! Close it before firing!") - else - ..() - update_icon() - -/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_hand(mob/user as mob) - if(loc != user) - ..() - return //let them pick it up - if(!cover_open || (cover_open && !magazine)) - ..() - else if(cover_open && magazine) - //drop the mag - magazine.update_icon() - magazine.loc = get_turf(src.loc) - user.put_in_hands(magazine) - magazine = null - update_icon() - to_chat(user, "You remove the magazine from [src].") - - -/obj/item/weapon/gun/projectile/automatic/l6_saw/attackby(var/obj/item/A as obj, mob/user as mob, params) - if(!cover_open && istype(A, mag_type)) - to_chat(user, "[src]'s cover is closed! You can't insert a new mag!") - return - ..() - -/obj/item/weapon/gun/projectile/automatic/l6_saw/devastator - name = "\improper 'Devastator' LMG" - desc = "A heavily modified L6 SAW designed to chamber wide rounds. Commonly used by elite Syndicate boarding teams " - mag_type = "/obj/item/ammo_box/magazine/m762/buckshot" - -/obj/item/weapon/gun/projectile/automatic/l6_saw/devastator/New() - ..() - mag_type = "/obj/item/ammo_box/magazine/m762" // Workaround so it spawns with a shotgun mag loaded, but can still load regular LMG mags. - /obj/item/weapon/gun/projectile/automatic/m90 name = "\improper M-90gl Carbine" desc = "A three-round burst 5.56 toploading carbine, designated 'M-90gl'. Has an attached underbarrel grenade launcher which can be toggled on and off." icon_state = "m90" item_state = "m90" origin_tech = "combat=5;materials=2;syndicate=8" - mag_type = "/obj/item/ammo_box/magazine/m556" + mag_type = /obj/item/ammo_box/magazine/m556 fire_sound = 'sound/weapons/Gunshot_smg.ogg' action_button_name = "Toggle Grenade Launcher" can_suppress = 0 @@ -208,19 +139,17 @@ ..() underbarrel = new /obj/item/weapon/gun/projectile/revolver/grenadelauncher(src) update_icon() - return /obj/item/weapon/gun/projectile/automatic/m90/afterattack(var/atom/target, var/mob/living/user, flag, params) if(select == 2) underbarrel.afterattack(target, user, flag, params) else ..() - empty_alarm() return /obj/item/weapon/gun/projectile/automatic/m90/attackby(var/obj/item/A, mob/user, params) if(istype(A, /obj/item/ammo_casing)) - if(istype(A, text2path(underbarrel.magazine.ammo_type))) + if(istype(A, underbarrel.magazine.ammo_type)) underbarrel.attack_self() underbarrel.attackby(A, user, params) else @@ -257,7 +186,6 @@ to_chat(user, "You switch to semi-auto.") playsound(user, 'sound/weapons/empty.ogg', 100, 1) update_icon() - return /obj/item/weapon/gun/projectile/automatic/tommygun name = "\improper Thompson SMG" @@ -267,11 +195,11 @@ w_class = 5 slot_flags = 0 origin_tech = "combat=5;materials=1;syndicate=2" - mag_type = "/obj/item/ammo_box/magazine/tommygunm45" + mag_type = /obj/item/ammo_box/magazine/tommygunm45 fire_sound = 'sound/weapons/Gunshot_smg.ogg' can_suppress = 0 - fire_delay = 1 burst_size = 4 + fire_delay = 1 /obj/item/weapon/gun/projectile/automatic/ar name = "ARG" @@ -280,8 +208,42 @@ item_state = "arg" slot_flags = 0 origin_tech = "combat=5;materials=1" - mag_type = "/obj/item/ammo_box/magazine/m556" + mag_type = /obj/item/ammo_box/magazine/m556 fire_sound = 'sound/weapons/Gunshot_smg.ogg' can_suppress = 0 burst_size = 3 fire_delay = 1 + +// Bulldog shotgun // +/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog + name = "\improper 'Bulldog' Shotgun" + desc = "A compact, mag-fed semi-automatic shotgun for combat in narrow corridors, nicknamed 'Bulldog' by boarding parties. Compatible only with specialized 8-round drum magazines." + icon_state = "bulldog" + item_state = "bulldog" + w_class = 3.0 + origin_tech = "combat=5;materials=4;syndicate=6" + mag_type = /obj/item/ammo_box/magazine/m12g + fire_sound = 'sound/weapons/Gunshot4.ogg' + can_suppress = 0 + burst_size = 1 + fire_delay = 0 + action_button_name = null + +/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog/New() + ..() + update_icon() + +/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog/proc/update_magazine() + if(magazine) + overlays.Cut() + overlays += "[magazine.icon_state]" + return + +/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog/update_icon() + overlays.Cut() + update_magazine() + icon_state = "bulldog[chambered ? "" : "-e"]" + +/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag) + ..() + empty_alarm() diff --git a/code/modules/projectiles/guns/projectile/crossbow.dm b/code/modules/projectiles/guns/projectile/crossbow.dm deleted file mode 100644 index 3645899ab21..00000000000 --- a/code/modules/projectiles/guns/projectile/crossbow.dm +++ /dev/null @@ -1,323 +0,0 @@ -//AMMUNITION - -/obj/item/weapon/arrow - - name = "bolt" - desc = "It's got a tip for you - get the point?" - icon = 'icons/obj/weapons.dmi' - icon_state = "bolt" - item_state = "bolt" - throwforce = 8 - w_class = 3.0 - sharp = 1 - edge = 0 - -/obj/item/weapon/arrow/proc/removed() //Helper for metal rods falling apart. - return - -/obj/item/weapon/spike - name = "alloy spike" - desc = "It's about a foot of weird silver metal with a wicked point." - sharp = 1 - edge = 0 - throwforce = 5 - w_class = 2 - icon = 'icons/obj/weapons.dmi' - icon_state = "metal-rod" - item_state = "bolt" - -/obj/item/weapon/arrow/quill - - name = "vox quill" - desc = "A wickedly barbed quill from some bizarre animal." - icon_state = "quill" - item_state = "quill" - throwforce = 5 - -/obj/item/weapon/arrow/rod - - name = "metal rod" - desc = "Don't cry for me, Orithena." - icon_state = "metal-rod" - -/obj/item/weapon/arrow/rod/removed(mob/user) - if(throwforce == 15) // The rod has been superheated - we don't want it to be useable when removed from the bow. - to_chat(user, "[src] shatters into a scattering of overstressed metal shards as it leaves the crossbow.") - var/obj/item/weapon/shard/shrapnel/S = new() - S.loc = get_turf(src) - qdel(src) - -/obj/item/weapon/arrow/baguette - name = "baguette" - desc = "Still warm from the oven!" - icon = 'icons/obj/weapons.dmi' - icon_state = "baguette" - item_state = "baguette" - throwforce = 3 - sharp = 0 - -/obj/item/weapon/gun/launcher/crossbow - - name = "powered crossbow" - desc = "A 2557AD twist on an old classic. Pick up that can." - icon_state = "crossbow" - item_state = "crossbow-solid" - fire_sound = 'sound/weapons/punchmiss.ogg' // TODO: Decent THWOK noise. -// ejectshell = 0 // No spent shells. - mouthshoot = 1 // No suiciding with this weapon, causes runtimes. - fire_sound_text = "a solid thunk" - fire_delay = 25 - - var/tension = 0 // Current draw on the bow. - var/max_tension = 5 // Highest possible tension. - var/release_speed = 5 // Speed per unit of tension. - var/obj/item/weapon/stock_parts/cell/cell = null // Used for firing superheated rods. - var/current_user // Used to check if the crossbow has changed hands since being drawn. - -/obj/item/weapon/gun/launcher/crossbow/emp_act(severity) - if(cell && severity) - cell.use(100*severity) - -/obj/item/weapon/gun/launcher/crossbow/special_check(user) - if(tension <= 0) - to_chat(user, "\red \The [src] is not drawn back!") - return 0 - return 1 - -/obj/item/weapon/gun/launcher/crossbow/update_release_force() - release_force = tension*release_speed - -/obj/item/weapon/gun/launcher/crossbow/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) - - if(!..()) return //Only do this on a successful shot. - icon_state = "crossbow" - tension = 0 - -/obj/item/weapon/gun/launcher/crossbow/attack_self(mob/living/user as mob) - if(tension) - if(in_chamber && in_chamber.loc == src) //Just in case they click it the tick after firing. - user.visible_message("[user] relaxes the tension on [src]'s string and removes [in_chamber].","You relax the tension on [src]'s string and remove [in_chamber].") - in_chamber.loc = get_turf(src) - var/obj/item/weapon/arrow/A = in_chamber - in_chamber = null - A.removed(user) - else - user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.") - tension = 0 - icon_state = "crossbow" - else - draw(user) - -/obj/item/weapon/gun/launcher/crossbow/proc/draw(var/mob/user as mob) - - if(!in_chamber) - to_chat(user, "You don't have anything nocked to [src].") - return - - if(user.restrained()) - return - - current_user = user - user.visible_message("[user] begins to draw back the string of [src].","You begin to draw back the string of [src].") - tension = 1 - spawn(25) increase_tension(user) //TODO: This needs to be changed to something less shit. - -/obj/item/weapon/gun/launcher/crossbow/proc/increase_tension(var/mob/user as mob) - - if(!in_chamber || !tension || current_user != user) //Arrow has been fired, bow has been relaxed or user has changed. - return - - tension++ - icon_state = "crossbow-drawn" - - if(tension>=max_tension) - tension = max_tension - to_chat(usr, "[src] clunks as you draw the string to its maximum tension!") - else - user.visible_message("[usr] draws back the string of [src]!","You continue drawing back the string of [src]!") - spawn(25) increase_tension(user) - -/obj/item/weapon/gun/launcher/crossbow/attackby(obj/item/W as obj, mob/user as mob, params) - if(!in_chamber) - if (istype(W,/obj/item/weapon/arrow)) - user.drop_item() - in_chamber = W - in_chamber.loc = src - user.visible_message("[user] slides [in_chamber] into [src].","You slide [in_chamber] into [src].") - icon_state = "crossbow-nocked" - return - else if(istype(W,/obj/item/stack/rods)) - var/obj/item/stack/rods/R = W - R.use(1) - in_chamber = new /obj/item/weapon/arrow/rod(src) - in_chamber.fingerprintslast = src.fingerprintslast - in_chamber.loc = src - icon_state = "crossbow-nocked" - user.visible_message("[user] jams [in_chamber] into [src].","You jam [in_chamber] into [src].") - superheat_rod(user) - return - - if(istype(W, /obj/item/weapon/stock_parts/cell)) - if(!cell) - user.drop_item() - W.loc = src - cell = W - to_chat(user, "You jam [cell] into [src] and wire it to the firing coil.") - superheat_rod(user) - else - to_chat(user, "[src] already has a cell installed.") - - else if(istype(W, /obj/item/weapon/screwdriver)) - if(cell) - var/obj/item/C = cell - C.loc = get_turf(user) - to_chat(user, "You jimmy [cell] out of [src] with [W].") - cell = null - else - to_chat(user, "[src] doesn't have a cell installed.") - - else - ..() - -/obj/item/weapon/gun/launcher/crossbow/proc/superheat_rod(var/mob/user) - - if(!user || !cell || !in_chamber) return - if(cell.charge < 500) return - if(in_chamber.throwforce >= 15) return - if(!istype(in_chamber,/obj/item/weapon/arrow/rod)) return - - to_chat(user, "[in_chamber] plinks and crackles as it begins to glow red-hot.") - in_chamber.throwforce = 15 - in_chamber.icon_state = "metal-rod-superheated" - cell.use(500) - - -/obj/item/weapon/gun/launcher/crossbow/french - name = "french powered crossbow" - -/obj/item/weapon/gun/launcher/crossbow/french/attackby(obj/item/W as obj, mob/user as mob, params) - if(!in_chamber) - if (istype(W,/obj/item/weapon/reagent_containers/food/snacks/baguette)) - user.drop_item() - in_chamber = W - in_chamber.loc = src - user.visible_message("[user] slides [in_chamber] into [src].","You slide [in_chamber] into [src].") - icon_state = "crossbow-nocked" - return - - else if (istype(W,/obj/item/weapon/arrow)) - user.visible_message("\The [src] only takes baguettes.") - return - else if(istype(W,/obj/item/stack/rods)) - user.visible_message("\The [src] only takes baguettes.") - return - - if(istype(W, /obj/item/weapon/stock_parts/cell)) - user.visible_message("The [src] is too simple be adapted with a cell.") - return - - else - ..() - -/obj/item/weapon/gun/launcher/crossbow/french/increase_tension(var/mob/user as mob) - - if(!in_chamber || !tension || current_user != user) //Arrow has been fired, bow has been relaxed or user has changed. - return - - tension++ - icon_state = "fcrossbow-drawn" - - if(tension>=max_tension) - tension = max_tension - to_chat(usr, "[src] clunks as you draw the string to its maximum tension!") - else - user.visible_message("[usr] draws back the string of [src]!","You continue drawing back the string of [src]!") - spawn(25) increase_tension(user) - -// Crossbow construction. -/obj/item/weapon/crossbowframe - name = "crossbow frame" - desc = "A half-finished crossbow." - icon_state = "crossbowframe0" - item_state = "crossbow-solid" - - var/buildstate = 0 - -/obj/item/weapon/crossbowframe/update_icon() - icon_state = "crossbowframe[buildstate]" - -/obj/item/weapon/crossbowframe/examine(mob/user) - ..(user) - switch(buildstate) - if(1) - to_chat(user, "It has a loose rod frame in place.") - if(2) - to_chat(user, "It has a steel backbone welded in place.") - if(3) - to_chat(user, "It has a steel backbone and a cell mount installed.") - if(4) - to_chat(user, "It has a steel backbone, plastic lath and a cell mount installed.") - if(5) - to_chat(user, "It has a steel cable loosely strung across the lath.") - -/obj/item/weapon/crossbowframe/attackby(obj/item/W as obj, mob/user as mob, params) - if(istype(W,/obj/item/stack/rods)) - if(buildstate == 0) - var/obj/item/stack/rods/R = W - if(R.amount >= 3) - R.use(3) - to_chat(user, "\blue You assemble a backbone of rods around the wooden stock.") - buildstate++ - update_icon() - else - to_chat(user, "\blue You need at least three rods to complete this task.") - return - else if(istype(W,/obj/item/weapon/weldingtool)) - if(buildstate == 1) - var/obj/item/weapon/weldingtool/T = W - if(T.remove_fuel(0,user)) - if(!src || !T.isOn()) return - playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) - to_chat(user, "\blue You weld the rods into place.") - buildstate++ - update_icon() - return - else if(istype(W,/obj/item/stack/cable_coil)) - var/obj/item/stack/cable_coil/C = W - if(buildstate == 2) - if(C.amount >= 5) - C.use(5) - to_chat(user, "\blue You wire a crude cell mount into the top of the crossbow.") - buildstate++ - update_icon() - else - to_chat(user, "\blue You need at least five segments of cable coil to complete this task.") - return - else if(buildstate == 4) - if(C.amount >= 5) - C.use(5) - to_chat(user, "\blue You string a steel cable across the crossbow's lath.") - buildstate++ - update_icon() - else - to_chat(user, "\blue You need at least five segments of cable coil to complete this task.") - return - else if(istype(W,/obj/item/stack/sheet/mineral/plastic)) - if(buildstate == 3) - var/obj/item/stack/sheet/mineral/plastic/P = W - if(P.amount >= 3) - P.use(3) - to_chat(user, "\blue You assemble and install a heavy plastic lath onto the crossbow.") - buildstate++ - update_icon() - else - to_chat(user, "\blue You need at least three plastic sheets to complete this task.") - return - else if(istype(W,/obj/item/weapon/screwdriver)) - if(buildstate == 5) - to_chat(user, "\blue You secure the crossbow's various parts.") - new /obj/item/weapon/gun/launcher/crossbow(get_turf(src)) - qdel(src) - return - else - ..() diff --git a/code/modules/projectiles/guns/projectile/grenade launcher.dm b/code/modules/projectiles/guns/projectile/grenade launcher.dm deleted file mode 100644 index 28dc0c3a4b9..00000000000 --- a/code/modules/projectiles/guns/projectile/grenade launcher.dm +++ /dev/null @@ -1,91 +0,0 @@ -/obj/item/weapon/gun/launcher - - name = "launcher" - desc = "A device that launches things." - icon = 'icons/obj/weapons.dmi' - w_class = 5.0 - flags = CONDUCT - slot_flags = SLOT_BACK - - var/release_force = 0 - var/fire_sound_text = "a launcher firing" - -//Check if we're drawing and if the bow is loaded. -/obj/item/weapon/gun/launcher/proc/chamber_round() - return (!isnull(in_chamber)) - -//This should not fit in a combat belt or holster. -/obj/item/weapon/gun/launcher/isHandgun() - return 0 - -//Launchers are mechanical, no other impact. -/obj/item/weapon/gun/launcher/emp_act(severity) - return - -//This normally uses a proc on projectiles and our ammo is not strictly speaking a projectile. -/obj/item/weapon/gun/launcher/can_hit(var/mob/living/target as mob, var/mob/living/user as mob) - return - -//Override this to avoid a runtime with suicide handling. -/obj/item/weapon/gun/launcher/attack(mob/living/M as mob, mob/living/user as mob, def_zone) - if (M == user && user.zone_sel.selecting == "mouth") - to_chat(user, "\red Shooting yourself with \a [src] is pretty tricky. You can't seem to manage it.") - return - ..() - -/obj/item/weapon/gun/launcher/proc/update_release_force() - return 0 - -/obj/item/weapon/gun/launcher/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) - - if (!user.IsAdvancedToolUser()) - to_chat(user, "\red You don't have the dexterity to do this!") - return 0 - - add_fingerprint(user) - - //Make sure target turfs both exist. - var/turf/curloc = get_turf(user) - var/turf/targloc = get_turf(target) - if (!istype(targloc) || !istype(curloc)) - return 0 - - if(!special_check(user)) - return 0 - - if (!ready_to_fire()) - if (world.time % 3) //to prevent spam - to_chat(user, "[src] is not ready to fire again!") - return 0 - - if(!chamber_round()) //CHECK - return click_empty(user) - - if(!in_chamber) - return 0 - - update_release_force() - - playsound(user, fire_sound, 50, 1) - user.visible_message("[user] fires [src][reflex ? " by reflex":""]!", \ - "You fire [src][reflex ? "by reflex":""]!", \ - "You hear [fire_sound_text]!") - - in_chamber.loc = get_turf(user) - in_chamber.throw_at(target,10,release_force) - - sleep(1) - - in_chamber = null - - update_icon() - - if(user.hand) - user.update_inv_l_hand() - else - user.update_inv_r_hand() - - return 1 - -/obj/item/weapon/gun/launcher/attack_self(mob/living/user as mob) - return \ No newline at end of file diff --git a/code/modules/projectiles/guns/projectile/launchers.dm b/code/modules/projectiles/guns/projectile/launchers.dm index 6bcca0cdf68..635ab22cc8c 100644 --- a/code/modules/projectiles/guns/projectile/launchers.dm +++ b/code/modules/projectiles/guns/projectile/launchers.dm @@ -1,44 +1,12 @@ //KEEP IN MIND: These are different from gun/grenadelauncher. These are designed to shoot premade rocket and grenade projectiles, not flashbangs or chemistry casings etc. //Put handheld rocket launchers here if someone ever decides to make something so hilarious ~Paprika - -/obj/item/weapon/gun/projectile/automatic/gyropistol - name = "gyrojet pistol" - desc = "A prototype pistol designed to fire self propelled rockets." - icon_state = "gyropistol" - fire_sound = 'sound/effects/Explosion1.ogg' - origin_tech = "combat=3" - mag_type = "/obj/item/ammo_box/magazine/m75" - burst_size = 1 - fire_delay = 0 - -/obj/item/weapon/gun/projectile/automatic/gyropistol/isHandgun() - return 1 - -/obj/item/weapon/gun/projectile/automatic/gyropistol/New() - ..() - update_icon() - return - -/obj/item/weapon/gun/projectile/automatic/gyropistol/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag) - ..() - if(!chambered && !get_ammo() && !alarmed) - playsound(user, 'sound/weapons/smg_empty_alarm.ogg', 40, 1) - update_icon() - alarmed = 1 - return - -/obj/item/weapon/gun/projectile/automatic/gyropistol/update_icon() - ..() - icon_state = "[initial(icon_state)][magazine ? "loaded" : ""]" - return - /obj/item/weapon/gun/projectile/revolver/grenadelauncher//this is only used for underbarrel grenade launchers at the moment, but admins can still spawn it if they feel like being assholes desc = "A break-operated grenade launcher." name = "grenade launcher" icon_state = "dshotgun-sawn" item_state = "gun" - mag_type = "/obj/item/ammo_box/magazine/internal/cylinder/grenadelauncher" + mag_type = /obj/item/ammo_box/magazine/internal/cylinder/grenadelauncher fire_sound = 'sound/weapons/grenadelaunch.ogg' w_class = 3 @@ -52,7 +20,7 @@ name = "multi grenade launcher" icon_state = "bulldog" item_state = "bulldog" - mag_type = "/obj/item/ammo_box/magazine/internal/cylinder/grenadelauncher/multi" + mag_type = /obj/item/ammo_box/magazine/internal/cylinder/grenadelauncher/multi /obj/item/weapon/gun/projectile/revolver/grenadelauncher/multi/cyborg desc = "A 6-shot grenade launcher." @@ -60,4 +28,57 @@ icon_state = "mecha_grenadelnchr" /obj/item/weapon/gun/projectile/revolver/grenadelauncher/multi/cyborg/attack_self() - return \ No newline at end of file + return + +/obj/item/weapon/gun/projectile/automatic/gyropistol + name = "gyrojet pistol" + desc = "A prototype pistol designed to fire self propelled rockets." + icon_state = "gyropistol" + fire_sound = 'sound/effects/Explosion1.ogg' + origin_tech = "combat=3" + mag_type = /obj/item/ammo_box/magazine/m75 + burst_size = 1 + fire_delay = 0 + action_button_name = null + +/obj/item/weapon/gun/projectile/automatic/gyropistol/isHandgun() + return 1 + +/obj/item/weapon/gun/projectile/automatic/gyropistol/process_chamber(eject_casing = 0, empty_chamber = 1) + ..() + +/obj/item/weapon/gun/projectile/automatic/gyropistol/update_icon() + ..() + icon_state = "[initial(icon_state)][magazine ? "loaded" : ""]" + return + +/obj/item/weapon/gun/projectile/automatic/speargun + name = "kinetic speargun" + desc = "A weapon favored by carp hunters. Fires specialized spears using kinetic energy." + icon_state = "speargun" + item_state = "speargun" + w_class = 4 + force = 10 + can_suppress = 0 + mag_type = /obj/item/ammo_box/magazine/internal/speargun + fire_sound = 'sound/weapons/grenadelaunch.ogg' + burst_size = 1 + fire_delay = 0 + select = 0 + action_button_name = null + +/obj/item/weapon/gun/projectile/automatic/speargun/update_icon() + return + +/obj/item/weapon/gun/projectile/automatic/speargun/attack_self() + return + +/obj/item/weapon/gun/projectile/automatic/speargun/process_chamber(eject_casing = 0, empty_chamber = 1) + ..() + +/obj/item/weapon/gun/projectile/automatic/speargun/attackby(obj/item/A, mob/user, params) + var/num_loaded = magazine.attackby(A, user, params, 1) + if(num_loaded) + to_chat(user, "You load [num_loaded] spear\s into \the [src].") + update_icon() + chamber_round() diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm index 99aded2663b..b2c0aa823be 100644 --- a/code/modules/projectiles/guns/projectile/pistol.dm +++ b/code/modules/projectiles/guns/projectile/pistol.dm @@ -4,27 +4,26 @@ icon_state = "pistol" w_class = 2 origin_tech = "combat=2;materials=2;syndicate=2" - mag_type = "/obj/item/ammo_box/magazine/m10mm" + mag_type = /obj/item/ammo_box/magazine/m10mm can_suppress = 1 burst_size = 1 fire_delay = 0 action_button_name = null - + /obj/item/weapon/gun/projectile/automatic/pistol/isHandgun() return 1 /obj/item/weapon/gun/projectile/automatic/pistol/update_icon() ..() - icon_state = "[initial(icon_state)][chambered ? "" : "-e"][silenced ? "-suppressed" : ""]" + icon_state = "[initial(icon_state)][chambered ? "" : "-e"][suppressed ? "-suppressed" : ""]" return -/obj/item/weapon/gun/projectile/automatic/pistol/m2411 - name = "M2411" - desc = "John Browning's classic updated for the modern day. Uses .45 rounds." - icon_state = "m2411" - w_class = 3.0 - origin_tech = "combat=3;materials=2" - mag_type = "/obj/item/ammo_box/magazine/m45" +/obj/item/weapon/gun/projectile/automatic/pistol/m1911 + name = "\improper M1911" + desc = "A classic .45 handgun with a small magazine capacity." + icon_state = "m1911" + w_class = 3 + mag_type = /obj/item/ammo_box/magazine/m45 can_suppress = 0 /obj/item/weapon/gun/projectile/automatic/pistol/deagle @@ -32,7 +31,7 @@ desc = "A robust .50 AE handgun." icon_state = "deagle" force = 14.0 - mag_type = "/obj/item/ammo_box/magazine/m50" + mag_type = /obj/item/ammo_box/magazine/m50 can_suppress = 0 /obj/item/weapon/gun/projectile/automatic/pistol/deagle/update_icon() @@ -47,4 +46,16 @@ /obj/item/weapon/gun/projectile/automatic/pistol/deagle/camo desc = "A Deagle brand Deagle for operators operating operationally. Uses .50 AE ammo." icon_state = "deaglecamo" - item_state = "deagleg" \ No newline at end of file + item_state = "deagleg" + +/obj/item/weapon/gun/projectile/automatic/pistol/APS + name = "stechkin APS pistol" + desc = "The original russian version of a widely used Syndicate sidearm. Uses 9mm ammo." + icon_state = "aps" + w_class = 3 + origin_tech = "combat=3;materials=2;syndicate=3" + mag_type = /obj/item/ammo_box/magazine/pistolm9mm + can_suppress = 0 + burst_size = 3 + fire_delay = 2 + action_button_name = "Toggle Firemode" diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm index 2cb3c849e4b..299ffbc9a6c 100644 --- a/code/modules/projectiles/guns/projectile/revolver.dm +++ b/code/modules/projectiles/guns/projectile/revolver.dm @@ -2,57 +2,80 @@ name = "\improper .357 revolver" desc = "A suspicious revolver. Uses .357 ammo." icon_state = "revolver" - mag_type = "/obj/item/ammo_box/magazine/internal/cylinder" + mag_type = /obj/item/ammo_box/magazine/internal/cylinder -/obj/item/weapon/gun/projectile/revolver/chamber_round() - if (chambered || !magazine) - return - else if (magazine.ammo_count()) +/obj/item/weapon/gun/projectile/revolver/New() + ..() + if(!istype(magazine, /obj/item/ammo_box/magazine/internal/cylinder)) + verbs -= /obj/item/weapon/gun/projectile/revolver/verb/spin + +/obj/item/weapon/gun/projectile/revolver/chamber_round(var/spin = 1) + if(spin) chambered = magazine.get_round(1) + else + chambered = magazine.stored_ammo[1] return -/obj/item/weapon/gun/projectile/revolver/process_chambered() +/obj/item/weapon/gun/projectile/revolver/shoot_with_empty_chamber(mob/living/user as mob|obj) + ..() + chamber_round(1) + +/obj/item/weapon/gun/projectile/revolver/process_chamber() return ..(0, 1) -/obj/item/weapon/gun/projectile/revolver/attackby(var/obj/item/A as obj, mob/user as mob, params) - var/num_loaded = 0 - if(istype(A, /obj/item/ammo_box)) - var/obj/item/ammo_box/AM = A - for(var/obj/item/ammo_casing/AC in AM.stored_ammo) - var/didload = magazine.give_round(AC) - if(didload) - AM.stored_ammo -= AC - num_loaded++ - if(!didload || !magazine.multiload) - break - if(istype(A, /obj/item/ammo_casing)) - var/obj/item/ammo_casing/AC = A - if(magazine.give_round(AC)) - user.drop_item() - AC.loc = src - num_loaded++ +/obj/item/weapon/gun/projectile/revolver/attackby(obj/item/A, mob/user, params) + . = ..() + if(.) + return + var/num_loaded = magazine.attackby(A, user, params, 1) if(num_loaded) - to_chat(user, "You load [num_loaded] shell\s into \the [src]!") + to_chat(user, "You load [num_loaded] shell\s into \the [src].") A.update_icon() update_icon() - chamber_round() + chamber_round(0) -/obj/item/weapon/gun/projectile/revolver/attack_self(mob/living/user as mob) + if(unique_rename) + if(istype(A, /obj/item/weapon/pen)) + rename_gun(user) + +/obj/item/weapon/gun/projectile/revolver/attack_self(mob/living/user) var/num_unloaded = 0 + chambered = null while (get_ammo() > 0) var/obj/item/ammo_casing/CB CB = magazine.get_round(0) - chambered = null - CB.loc = get_turf(src.loc) - CB.SpinAnimation(10, 1) - CB.update_icon() - num_unloaded++ + if(CB) + CB.loc = get_turf(loc) + CB.SpinAnimation(10, 1) + CB.update_icon() + num_unloaded++ if (num_unloaded) - to_chat(user, "You unload [num_unloaded] shell\s from [src]!") + to_chat(user, "You unload [num_unloaded] shell\s from [src].") else - to_chat(user, "[src] is empty.") + to_chat(user, "[src] is empty!") -/obj/item/weapon/gun/projectile/revolver/get_ammo(var/countchambered = 0, var/countempties = 1) +/obj/item/weapon/gun/projectile/revolver/verb/spin() + set name = "Spin Chamber" + set category = "Object" + set desc = "Click to spin your revolver's chamber." + + var/mob/M = usr + + if(M.stat || !in_range(M,src)) + return + + if(istype(magazine, /obj/item/ammo_box/magazine/internal/cylinder)) + var/obj/item/ammo_box/magazine/internal/cylinder/C = magazine + C.spin() + chamber_round(0) + usr.visible_message("[usr] spins [src]'s chamber.", "You spin [src]'s chamber.") + else + verbs -= /obj/item/weapon/gun/projectile/revolver/verb/spin + +/obj/item/weapon/gun/projectile/revolver/can_shoot() + return get_ammo(0,0) + +/obj/item/weapon/gun/projectile/revolver/get_ammo(countchambered = 0, countempties = 1) var/boolets = 0 //mature var names for mature people if (chambered && countchambered) boolets++ @@ -61,119 +84,66 @@ return boolets /obj/item/weapon/gun/projectile/revolver/examine(mob/user) - ..(user) + ..() to_chat(user, "[get_ammo(0,0)] of those are live rounds.") -/obj/item/weapon/gun/projectile/revolver/verb/spin_revolver() - set name = "Spin cylinder" - set desc = "Fun when you're bored out of your skull." - set category = "Object" - - usr.visible_message("[usr] spins the chamber of the revolver.", "You spin the revolver's chamber.") - playsound(src.loc, 'sound/weapons/revolver_spin.ogg', 100, 1) - Spin() - -/obj/item/weapon/gun/projectile/revolver/proc/Spin() - chambered = null - var/random = rand(1, magazine.max_ammo) - if(random <= get_ammo(0,0)) - chamber_round() - update_icon() - -/obj/item/weapon/gun/projectile/revolver/capgun - name = "cap gun" - desc = "Looks almost like the real thing! Ages 8 and up." - origin_tech = "combat=1;materials=1" - mag_type = "/obj/item/ammo_box/magazine/internal/cylinder/cap" - /obj/item/weapon/gun/projectile/revolver/detective desc = "A cheap Martian knock-off of a classic law enforcement firearm. Uses .38-special rounds." name = "\improper .38 Mars Special" icon_state = "detective" origin_tech = "combat=2;materials=2" - mag_type = "/obj/item/ammo_box/magazine/internal/cylinder/rev38" + mag_type = /obj/item/ammo_box/magazine/internal/cylinder/rev38 + unique_rename = 1 + unique_reskin = 1 - -/obj/item/weapon/gun/projectile/revolver/detective/special_check(var/mob/living/carbon/human/M) - if(!ghettomodded) - return 1 - if(prob(70 - (magazine.ammo_count() * 10))) //minimum probability of 10, maximum of 60 - to_chat(M, "[src] blows up in your face!") - M.take_organ_damage(0,20) - M.drop_item() - qdel(src) - return 0 - return 1 - -/obj/item/weapon/gun/projectile/revolver/detective/verb/rename_gun() - set name = "Name Gun" - set category = "Object" - set desc = "Click to rename your gun." - - var/mob/M = usr - var/input = stripped_input(M,"What do you want to name the gun?", ,"", MAX_NAME_LEN) - - if(src && input && !M.stat && in_range(M,src)) - name = input - to_chat(M, "You name the gun [input]. Say hello to your new friend.") - return 1 - -/obj/item/weapon/gun/projectile/revolver/detective/verb/reskin_gun() - set name = "Reskin gun" - set category = "Object" - set desc = "Click to reskin your gun." - - var/mob/M = usr - var/list/options = list() +/obj/item/weapon/gun/projectile/revolver/detective/New() + ..() options["The Original"] = "detective" options["Leopard Spots"] = "detective_leopard" options["Black Panther"] = "detective_panther" options["Gold Trim"] = "detective_gold" options["The Peacemaker"] = "detective_peacemaker" - var/choice = input(M,"What do you want to skin the gun to?","Reskin Gun") in options + options["Cancel"] = null - if(src && choice && !M.stat && in_range(M,src)) - icon_state = options[choice] - to_chat(M, "Your gun is now skinned as [choice]. Say hello to your new friend.") - return 1 - -/obj/item/weapon/gun/projectile/revolver/detective/attackby(var/obj/item/A as obj, mob/user as mob, params) +/obj/item/weapon/gun/projectile/revolver/detective/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params, zone_override = "") + if(magazine.caliber != initial(magazine.caliber)) + if(prob(70 - (magazine.ammo_count() * 10))) //minimum probability of 10, maximum of 60 + playsound(user, fire_sound, 50, 1) + to_chat(user, "[src] blows up in your face!") + user.take_organ_damage(0,20) + user.unEquip(src) + return 0 ..() - if(istype(A, /obj/item/weapon/screwdriver) || istype(A, /obj/item/weapon/conversion_kit)) + +/obj/item/weapon/gun/projectile/revolver/detective/attackby(obj/item/A, mob/user, params) + ..() + if(istype(A, /obj/item/weapon/screwdriver)) if(magazine.caliber == "38") - to_chat(user, "You begin to reinforce the barrel of [src].") + to_chat(user, "You begin to reinforce the barrel of [src]...") if(magazine.ammo_count()) afterattack(user, user) //you know the drill - user.visible_message("[src] goes off!", "[src] goes off in your face!") + user.visible_message("[src] goes off!", "[src] goes off in your face!") return if(do_after(user, 30, target = src)) if(magazine.ammo_count()) - to_chat(user, "You can't modify it!") + to_chat(user, "You can't modify it!") return - if (istype(A, /obj/item/weapon/conversion_kit)) - ghettomodded = 0 - else - ghettomodded = 1 magazine.caliber = "357" - desc = "[initial(desc)] The barrel and chamber assembly seems to have been modified." - to_chat(user, "You reinforce the barrel of [src]! Now it will fire .357 rounds.") + desc = "The barrel and chamber assembly seems to have been modified." + to_chat(user, "You reinforce the barrel of [src]. Now it will fire .357 rounds.") else - to_chat(user, "You begin to revert the modifications to [src].") + to_chat(user, "You begin to revert the modifications to [src]...") if(magazine.ammo_count()) afterattack(user, user) //and again - user.visible_message("[src] goes off!", "[src] goes off in your face!") + user.visible_message("[src] goes off!", "[src] goes off in your face!") return if(do_after(user, 30, target = src)) if(magazine.ammo_count()) - to_chat(user, "You can't modify it!") + to_chat(user, "You can't modify it!") return - ghettomodded = 0 magazine.caliber = "38" desc = initial(desc) - to_chat(user, "You remove the modifications on [src]! Now it will fire .38 rounds.") - - - + to_chat(user, "You remove the modifications on [src]. Now it will fire .38 rounds.") /obj/item/weapon/gun/projectile/revolver/mateba name = "\improper Unica 6 auto-revolver" @@ -181,6 +151,21 @@ icon_state = "mateba" origin_tech = "combat=2;materials=2" +/obj/item/weapon/gun/projectile/revolver/golden + name = "\improper Golden revolver" + desc = "This ain't no game, ain't never been no show, And I'll gladly gun down the oldest lady you know. Uses .357 ammo." + icon_state = "goldrevolver" + fire_sound = 'sound/weapons/resonator_blast.ogg' + recoil = 8 + +/obj/item/weapon/gun/projectile/revolver/nagant + name = "nagant revolver" + desc = "An old model of revolver that originated in Russia. Able to be suppressed. Uses 7.62x38mmR ammo." + icon_state = "nagant" + origin_tech = "combat=3" + can_suppress = 1 + mag_type = /obj/item/ammo_box/magazine/internal/cylinder/rev762 + // A gun to play Russian Roulette! // You can spin the chamber to randomize the position of the bullet. @@ -188,35 +173,239 @@ name = "\improper Russian Revolver" desc = "A Russian-made revolver for drinking games. Uses .357 ammo, and has a mechanism that spins the chamber before each trigger pull." origin_tech = "combat=2;materials=2" - mag_type = "/obj/item/ammo_box/magazine/internal/cylinder/rus357" + mag_type = /obj/item/ammo_box/magazine/internal/rus357 + var/spun = 0 /obj/item/weapon/gun/projectile/revolver/russian/New() ..() Spin() + update_icon() -/obj/item/weapon/gun/projectile/revolver/russian/attack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj) +/obj/item/weapon/gun/projectile/revolver/russian/proc/Spin() + chambered = null + var/random = rand(1, magazine.max_ammo) + if(random <= get_ammo(0,0)) + chamber_round() + spun = 1 - if(!chambered && target == user) - user.visible_message("\red *click*", "\red *click*") - return +/obj/item/weapon/gun/projectile/revolver/russian/attackby(obj/item/A, mob/user, params) + var/num_loaded = ..() + if(num_loaded) + user.visible_message("[user] loads a single bullet into the revolver and spins the chamber.", "You load a single bullet into the chamber and spin it.") + else + user.visible_message("[user] spins the chamber of the revolver.", "You spin the revolver's chamber.") + if(get_ammo() > 0) + Spin() + update_icon() + A.update_icon() + return - if(isliving(target) && isliving(user)) - if(target == user) - var/obj/item/organ/external/affecting = user.zone_sel.selecting - if(affecting == "head") - var/obj/item/ammo_casing/AC = chambered - if(!process_chambered()) - user.visible_message("\red *click*", "\red *click*") - return - if(!in_chamber) - return - var/obj/item/projectile/P = new AC.projectile_type - playsound(user, fire_sound, 50, 1) - user.visible_message("[user.name] fires [src] at \his head!", "You fire [src] at your head!", "You hear a [istype(in_chamber, /obj/item/projectile/beam) ? "laser blast" : "gunshot"]!") - if(!P.nodamage) - user.apply_damage(300, BRUTE, affecting, sharp=1) // You are dead, dead, dead. +/obj/item/weapon/gun/projectile/revolver/russian/attack_self(mob/user) + if(!spun && can_shoot()) + user.visible_message("[user] spins the chamber of the revolver.", "You spin the revolver's chamber.") + Spin() + else + var/num_unloaded = 0 + while (get_ammo() > 0) + var/obj/item/ammo_casing/CB + CB = magazine.get_round() + chambered = null + CB.loc = get_turf(loc) + CB.update_icon() + num_unloaded++ + if (num_unloaded) + to_chat(user, "You unload [num_unloaded] shell\s from [src].") + else + to_chat(user, "[src] is empty.") + +/obj/item/weapon/gun/projectile/revolver/russian/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params) + if(flag) + if(!(target in user.contents) && ismob(target)) + if(user.a_intent == "harm") // Flogging action return - ..() + if(isliving(user)) + if(!can_trigger_gun(user)) + return + if(target != user) + if(ismob(target)) + to_chat(user, "A mechanism prevents you from shooting anyone but yourself!") + return + if(ishuman(user)) + if(!spun) + to_chat(user, "You need to spin the revolver's chamber first!") + return + + spun = 0 + + if(chambered) + var/obj/item/ammo_casing/AC = chambered + if(AC.fire(user, user)) + playsound(user, fire_sound, 50, 1) + var/zone = check_zone(user.zone_sel.selecting) + if(zone == "head" || zone == "eyes" || zone == "mouth") + shoot_self(user, zone) + else + user.visible_message("[user.name] cowardly fires [src] at \his [zone]!", "You cowardly fire [src] at your [zone]!", "You hear a gunshot!") + return + + user.visible_message("*click*") + playsound(user, 'sound/weapons/empty.ogg', 100, 1) + +/obj/item/weapon/gun/projectile/revolver/russian/proc/shoot_self(mob/living/carbon/human/user, affecting = "head") + user.apply_damage(300, BRUTE, affecting) + user.visible_message("[user.name] fires [src] at \his head!", "You fire [src] at your head!", "You hear a gunshot!") + +/obj/item/weapon/gun/projectile/revolver/capgun + name = "cap gun" + desc = "Looks almost like the real thing! Ages 8 and up." + origin_tech = "combat=1;materials=1" + mag_type = /obj/item/ammo_box/magazine/internal/cylinder/cap + +///////////////////////////// +// DOUBLE BARRELED SHOTGUN // +///////////////////////////// + +/obj/item/weapon/gun/projectile/revolver/doublebarrel + name = "double-barreled shotgun" + desc = "A true classic." + icon_state = "dshotgun" + item_state = "shotgun" + w_class = 4 + force = 10 + flags = CONDUCT + slot_flags = SLOT_BACK + origin_tech = "combat=3;materials=1" + mag_type = /obj/item/ammo_box/magazine/internal/shot/dual + sawn_desc = "Omar's coming!" + unique_rename = 1 + unique_reskin = 1 + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/New() + ..() + options["Default"] = "dshotgun" + options["Dark Red Finish"] = "dshotgun-d" + options["Ash"] = "dshotgun-f" + options["Faded Grey"] = "dshotgun-g" + options["Maple"] = "dshotgun-l" + options["Rosewood"] = "dshotgun-p" + options["Cancel"] = null + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/attackby(obj/item/A, mob/user, params) + ..() + if(istype(A, /obj/item/ammo_box) || istype(A, /obj/item/ammo_casing)) + chamber_round() + if(istype(A, /obj/item/weapon/melee/energy)) + var/obj/item/weapon/melee/energy/W = A + if(W.active) + sawoff(user) + if(istype(A, /obj/item/weapon/circular_saw) || istype(A, /obj/item/weapon/gun/energy/plasmacutter)) + sawoff(user) + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/attack_self(mob/living/user) + var/num_unloaded = 0 + while (get_ammo() > 0) + var/obj/item/ammo_casing/CB + CB = magazine.get_round(0) + chambered = null + CB.loc = get_turf(loc) + CB.update_icon() + num_unloaded++ + if (num_unloaded) + to_chat(user, "You break open \the [src] and unload [num_unloaded] shell\s.") + else + to_chat(user, "[src] is empty.") + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/isHandgun() //contrary to popular opinion, double barrels are not, shockingly, handguns + return 0 + +// IMPROVISED SHOTGUN // + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised + name = "improvised shotgun" + desc = "Essentially a tube that aims shotgun shells." + icon_state = "ishotgun" + item_state = "shotgun" + w_class = 4 + force = 10 + slot_flags = null + origin_tech = "combat=2;materials=2" + mag_type = /obj/item/ammo_box/magazine/internal/shot/improvised + sawn_desc = "I'm just here for the gasoline." + unique_rename = 0 + unique_reskin = 0 + var/slung = 0 + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/attackby(obj/item/A, mob/user, params) + ..() + if(istype(A, /obj/item/stack/cable_coil) && !sawn_state) + var/obj/item/stack/cable_coil/C = A + if(C.use(10)) + slot_flags = SLOT_BACK + icon_state = "ishotgunsling" + to_chat(user, "You tie the lengths of cable to the shotgun, making a sling.") + slung = 1 + update_icon() + else + to_chat(user, "You need at least ten lengths of cable if you want to make a sling.") + return + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/update_icon() + ..() + if (slung && (slot_flags & SLOT_BELT) ) + slung = 0 + icon_state = "ishotgun-sawn" + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/sawoff(mob/user) + . = ..() + if(. && slung) //sawing off the gun removes the sling + new /obj/item/stack/cable_coil(get_turf(src), 10) + slung = 0 + update_icon() + +//caneshotgun + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/cane + name = "cane" + desc = "A cane used by a true gentleman. Or a clown." + icon = 'icons/obj/weapons.dmi' + lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' + righthand_file = 'icons/mob/inhands/items_righthand.dmi' + icon_state = "cane" + item_state = "stick" + sawn_state = SAWN_OFF + w_class = 2 + force = 10 + can_unsuppress = 0 + slot_flags = null + origin_tech = "" // NO GIVAWAYS + mag_type = /obj/item/ammo_box/magazine/internal/shot/improvised + sawn_desc = "I'm sorry, but why did you saw your cane in the first place?" + attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") + fire_sound = 'sound/weapons/Gunshot_silenced.ogg' + suppressed = 1 + needs_permit = 0 //its just a cane beepsky..... + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/cane/update_icon() + return + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/cane/attackby(obj/item/A, mob/user, params) + ..() + if(istype(A, /obj/item/stack/cable_coil)) + return + +/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/cane/examine(mob/user) // HAD TO REPEAT EXAMINE CODE BECAUSE GUN CODE DOESNT STEALTH + var/f_name = "\a [src]." + if(blood_DNA && !istype(src, /obj/effect/decal)) + if(gender == PLURAL) + f_name = "some " + else + f_name = "a " + f_name += "blood-stained [name]!" + + to_chat(user, "\icon[src] That's [f_name]") + + if(desc) + to_chat(user, desc) diff --git a/code/modules/projectiles/guns/projectile/rocket.dm b/code/modules/projectiles/guns/projectile/rocket.dm deleted file mode 100644 index e667d9323ce..00000000000 --- a/code/modules/projectiles/guns/projectile/rocket.dm +++ /dev/null @@ -1,50 +0,0 @@ -/obj/item/weapon/gun/rocketlauncher - var/projectile - name = "rocket launcher" - desc = "Say hello to my little friend" - icon_state = "rocket" - item_state = "rocket" - w_class = 4.0 - throw_speed = 2 - throw_range = 10 - force = 5.0 - flags = CONDUCT - origin_tech = "combat=8;materials=5" - projectile = /obj/item/missile - var/missile_speed = 2 - var/missile_range = 30 - var/max_rockets = 1 - var/list/rockets = new/list() - -/obj/item/weapon/gun/rocketlauncher/examine(mob/user) - if(..(user, 2)) - to_chat(user, "\blue [rockets.len] / [max_rockets] rockets.") - -/obj/item/weapon/gun/rocketlauncher/attackby(obj/item/I as obj, mob/user as mob, params) - if(istype(I, /obj/item/ammo_casing/rocket)) - if(rockets.len < max_rockets) - user.drop_item() - I.loc = src - rockets += I - to_chat(user, "\blue You put the rocket in [src].") - to_chat(user, "\blue [rockets.len] / [max_rockets] rockets.") - else - to_chat(usr, "\red [src] cannot hold more rockets.") - -/obj/item/weapon/gun/rocketlauncher/can_fire() - return rockets.len - -/obj/item/weapon/gun/rocketlauncher/Fire(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, params, reflex = 0) - if(rockets.len) - var/obj/item/ammo_casing/rocket/I = rockets[1] - var/obj/item/missile/M = new projectile(user.loc) - playsound(user.loc, 'sound/effects/bang.ogg', 50, 1) - M.primed = 1 - M.throw_at(target, missile_range, missile_speed,user) - message_admins("[key_name_admin(user)] fired a rocket from a rocket launcher ([src.name]).") - log_game("[key_name_admin(user)] used a rocket launcher ([src.name]).") - rockets -= I - qdel(I) - return - else - to_chat(usr, "\red [src] is empty.") diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm new file mode 100644 index 00000000000..097f5fb4a58 --- /dev/null +++ b/code/modules/projectiles/guns/projectile/saw.dm @@ -0,0 +1,157 @@ +/obj/item/weapon/gun/projectile/automatic/l6_saw + name = "\improper L6 SAW" + desc = "A heavily modified 7.62 light machine gun, designated 'L6 SAW'. Has 'Aussec Armoury - 2531' engraved on the reciever below the designation." + icon_state = "l6closed100" + item_state = "l6closedmag" + w_class = 5 + slot_flags = 0 + origin_tech = "combat=5;materials=1;syndicate=2" + mag_type = /obj/item/ammo_box/magazine/mm556x45 + weapon_weight = WEAPON_MEDIUM + fire_sound = 'sound/weapons/Gunshot3.ogg' + var/cover_open = 0 + can_suppress = 0 + burst_size = 3 + fire_delay = 1 + +/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_self(mob/user) + cover_open = !cover_open + to_chat(user, "You [cover_open ? "open" : "close"] [src]'s cover.") + update_icon() + +/obj/item/weapon/gun/projectile/automatic/l6_saw/update_icon() + icon_state = "l6[cover_open ? "open" : "closed"][magazine ? Ceiling(get_ammo(0)/12.5)*25 : "-empty"][suppressed ? "-suppressed" : ""]" + item_state = "l6[cover_open ? "openmag" : "closedmag"]" + +/obj/item/weapon/gun/projectile/automatic/l6_saw/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, flag, params) //what I tried to do here is just add a check to see if the cover is open or not and add an icon_state change because I can't figure out how c-20rs do it with overlays + if(cover_open) + to_chat(user, "[src]'s cover is open! Close it before firing!") + else + ..() + update_icon() + +/obj/item/weapon/gun/projectile/automatic/l6_saw/attack_hand(mob/user) + if(loc != user) + ..() + return //let them pick it up + if(!cover_open || (cover_open && !magazine)) + ..() + else if(cover_open && magazine) + //drop the mag + magazine.update_icon() + magazine.loc = get_turf(loc) + user.put_in_hands(magazine) + magazine = null + update_icon() + to_chat(user, "You remove the magazine from [src].") + + +/obj/item/weapon/gun/projectile/automatic/l6_saw/attackby(obj/item/A, mob/user, params) + . = ..() + if(.) + return + if(!cover_open) + to_chat(user, "[src]'s cover is closed! You can't insert a new mag.") + return + ..() + +//ammo// + +/obj/item/projectile/bullet/saw + damage = 45 + armour_penetration = 5 + +/obj/item/projectile/bullet/saw/bleeding + damage = 20 + armour_penetration = 0 + +/obj/item/projectile/bullet/saw/bleeding/on_hit(atom/target, blocked = 0, hit_zone) + . = ..() + if((blocked != 100) && istype(target, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = target + H.drip(350) + +/obj/item/projectile/bullet/saw/hollow + damage = 60 + armour_penetration = -10 + +/obj/item/projectile/bullet/saw/ap + damage = 40 + armour_penetration = 75 + +/obj/item/projectile/bullet/saw/incen + damage = 7 + armour_penetration = 0 + +obj/item/projectile/bullet/saw/incen/Move() + ..() + var/turf/location = get_turf(src) + if(location) + PoolOrNew(/obj/effect/hotspot, location) + location.hotspot_expose(700, 50, 1) + +/obj/item/projectile/bullet/saw/incen/on_hit(atom/target, blocked = 0) + . = ..() + if(iscarbon(target)) + var/mob/living/carbon/M = target + M.adjust_fire_stacks(3) + M.IgniteMob() + +//magazines// + +/obj/item/ammo_box/magazine/mm556x45 + name = "box magazine (5.56x45mm)" + icon_state = "a762-50" + origin_tech = "combat=2" + ammo_type = /obj/item/ammo_casing/mm556x45 + caliber = "mm55645" + max_ammo = 50 + +/obj/item/ammo_box/magazine/mm556x45/bleeding + name = "box magazine (Bleeding 5.56x45mm)" + origin_tech = "combat=3" + ammo_type = /obj/item/ammo_casing/mm556x45/bleeding + +/obj/item/ammo_box/magazine/mm556x45/hollow + name = "box magazine (Hollow-Point 5.56x45mm)" + origin_tech = "combat=3" + ammo_type = /obj/item/ammo_casing/mm556x45/hollow + +/obj/item/ammo_box/magazine/mm556x45/ap + name = "box magazine (Armor Penetrating 5.56x45mm)" + origin_tech = "combat=4" + ammo_type = /obj/item/ammo_casing/mm556x45/ap + +/obj/item/ammo_box/magazine/mm556x45/incen + name = "box magazine (Incendiary 5.56x45mm)" + origin_tech = "combat=4" + ammo_type = /obj/item/ammo_casing/mm556x45/incen + +/obj/item/ammo_box/magazine/mm556x45/update_icon() + ..() + icon_state = "a762-[round(ammo_count(),10)]" + +//casings// + +/obj/item/ammo_casing/mm556x45 + desc = "A 556x45mm bullet casing." + icon_state = "762-casing" + caliber = "mm55645" + projectile_type = /obj/item/projectile/bullet/saw + +/obj/item/ammo_casing/mm556x45/bleeding + desc = "A 556x45mm bullet casing with specialized inner-casing, that when it makes contact with a target, release tiny shrapnel to induce internal bleeding." + icon_state = "762-casing" + projectile_type = /obj/item/projectile/bullet/saw/bleeding + +/obj/item/ammo_casing/mm556x45/hollow + desc = "A 556x45mm bullet casing designed to cause more damage to unarmored targets." + projectile_type = /obj/item/projectile/bullet/saw/hollow + +/obj/item/ammo_casing/mm556x45/ap + desc = "A 556x45mm bullet casing designed with a hardened-tipped core to help penetrate armored targets." + projectile_type = /obj/item/projectile/bullet/saw/ap + +/obj/item/ammo_casing/mm556x45/incen + desc = "A 556x45mm bullet casing designed with a chemical-filled capsule on the tip that when bursted, reacts with the atmosphere to produce a fireball, engulfing the target in flames. " + projectile_type = /obj/item/projectile/bullet/saw/incen diff --git a/code/modules/projectiles/guns/projectile/shotgun.dm b/code/modules/projectiles/guns/projectile/shotgun.dm index 7ae951ad908..ddec7543009 100644 --- a/code/modules/projectiles/guns/projectile/shotgun.dm +++ b/code/modules/projectiles/guns/projectile/shotgun.dm @@ -8,40 +8,34 @@ flags = CONDUCT slot_flags = SLOT_BACK origin_tech = "combat=4;materials=2" + mag_type = /obj/item/ammo_box/magazine/internal/shot var/recentpump = 0 // to prevent spammage - mag_type = "/obj/item/ammo_box/magazine/internal/shot" -/obj/item/weapon/gun/projectile/shotgun/attackby(var/obj/item/A as obj, mob/user as mob, params) - var/num_loaded = 0 - if(istype(A, /obj/item/ammo_box)) - var/obj/item/ammo_box/AM = A - for(var/obj/item/ammo_casing/AC in AM.stored_ammo) - var/didload = magazine.give_round(AC) - if(didload) - AM.stored_ammo -= AC - num_loaded++ - if(!didload || !magazine.multiload) - break - if(istype(A, /obj/item/ammo_casing)) - var/obj/item/ammo_casing/AC = A - if(magazine && magazine.give_round(AC)) - user.drop_item() - AC.loc = src - num_loaded++ +/obj/item/weapon/gun/projectile/shotgun/attackby(obj/item/A, mob/user, params) + . = ..() + if(.) + return + var/num_loaded = magazine.attackby(A, user, params, 1) if(num_loaded) to_chat(user, "You load [num_loaded] shell\s into \the [src]!") A.update_icon() update_icon() -/obj/item/weapon/gun/projectile/shotgun/process_chambered() +/obj/item/weapon/gun/projectile/shotgun/process_chamber() return ..(0, 0) /obj/item/weapon/gun/projectile/shotgun/chamber_round() return -/obj/item/weapon/gun/projectile/shotgun/attack_self(mob/living/user as mob) - if(recentpump) return +/obj/item/weapon/gun/projectile/shotgun/can_shoot() + if(!chambered) + return 0 + return (chambered.BB ? 1 : 0) + +/obj/item/weapon/gun/projectile/shotgun/attack_self(mob/living/user) + if(recentpump) + return pump(user) recentpump = 1 spawn(10) @@ -49,7 +43,7 @@ return -/obj/item/weapon/gun/projectile/shotgun/proc/pump(mob/M as mob) +/obj/item/weapon/gun/projectile/shotgun/proc/pump(mob/M) playsound(M, 'sound/weapons/shotgunpump.ogg', 60, 1) pump_unload(M) pump_reload(M) @@ -61,36 +55,41 @@ chambered.loc = get_turf(src)//Eject casing chambered.SpinAnimation(5, 1) chambered = null - if(in_chamber) - in_chamber = null /obj/item/weapon/gun/projectile/shotgun/proc/pump_reload(mob/M) - if(!magazine.ammo_count()) return 0 + if(!magazine.ammo_count()) + return 0 var/obj/item/ammo_casing/AC = magazine.get_round() //load next casing. chambered = AC /obj/item/weapon/gun/projectile/shotgun/examine(mob/user) - ..(user) + ..() if (chambered) to_chat(user, "A [chambered.BB ? "live" : "spent"] one is in the chamber.") /obj/item/weapon/gun/projectile/shotgun/isHandgun() //You cannot, in fact, holster a shotgun. return 0 +/obj/item/weapon/gun/projectile/shotgun/lethal + mag_type = /obj/item/ammo_box/magazine/internal/shot/lethal + // RIOT SHOTGUN // /obj/item/weapon/gun/projectile/shotgun/riot //for spawn in the armory name = "riot shotgun" desc = "A sturdy shotgun with a longer magazine and a fixed tactical stock designed for non-lethal riot control." icon_state = "riotshotgun" - mag_type = "/obj/item/ammo_box/magazine/internal/shotriot" + mag_type = /obj/item/ammo_box/magazine/internal/shot/riot sawn_desc = "Come with me if you want to live." -/obj/item/weapon/gun/projectile/shotgun/riot/attackby(var/obj/item/A as obj, mob/user as mob, params) +/obj/item/weapon/gun/projectile/shotgun/riot/attackby(obj/item/A, mob/user, params) ..() - if(istype(A, /obj/item/weapon/circular_saw) || istype(A, /obj/item/weapon/melee/energy) || istype(A, /obj/item/weapon/gun/energy/plasmacutter)) + if(istype(A, /obj/item/weapon/circular_saw) || istype(A, /obj/item/weapon/gun/energy/plasmacutter)) sawoff(user) - + if(istype(A, /obj/item/weapon/melee/energy)) + var/obj/item/weapon/melee/energy/W = A + if(W.active) + sawoff(user) /////////////////////// // BOLT ACTION RIFLE // @@ -102,7 +101,7 @@ icon_state = "moistnugget" item_state = "moistnugget" slot_flags = 0 //no SLOT_BACK sprite, alas - mag_type = "/obj/item/ammo_box/magazine/internal/boltaction" + mag_type = /obj/item/ammo_box/magazine/internal/boltaction var/bolt_open = 0 /obj/item/weapon/gun/projectile/shotgun/boltaction/pump(mob/M) @@ -115,21 +114,27 @@ update_icon() //I.E. fix the desc return 1 -/obj/item/weapon/gun/projectile/shotgun/boltaction/attackby(var/obj/item/A as obj, mob/user as mob) +/obj/item/weapon/gun/projectile/shotgun/blow_up(mob/user) + . = 0 + if(chambered && chambered.BB) + process_fire(user, user,0) + . = 1 + +/obj/item/weapon/gun/projectile/shotgun/boltaction/attackby(obj/item/A, mob/user, params) if(!bolt_open) to_chat(user, "The bolt is closed!") return . = ..() /obj/item/weapon/gun/projectile/shotgun/boltaction/examine(mob/user) - ..(user) + ..() to_chat(user, "The bolt is [bolt_open ? "open" : "closed"].") /obj/item/weapon/gun/projectile/shotgun/boltaction/enchanted name = "enchanted bolt action rifle" desc = "Careful not to lose your head." var/guns_left = 30 - mag_type = "/obj/item/ammo_box/magazine/internal/boltaction/enchanted" + mag_type = /obj/item/ammo_box/magazine/internal/boltaction/enchanted /obj/item/weapon/gun/projectile/shotgun/boltaction/enchanted/New() ..() @@ -137,13 +142,14 @@ pump() /obj/item/weapon/gun/projectile/shotgun/boltaction/enchanted/dropped() + ..() guns_left = 0 -/obj/item/weapon/gun/projectile/shotgun/boltaction/enchanted/Fire(atom/target as mob|obj|turf|area, mob/living/carbon/user as mob|obj, params, reflex = 0) +/obj/item/weapon/gun/projectile/shotgun/boltaction/enchanted/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1) ..() if(guns_left) var/obj/item/weapon/gun/projectile/shotgun/boltaction/enchanted/GUN = new - GUN.guns_left = src.guns_left - 1 + GUN.guns_left = guns_left - 1 user.drop_item() user.swap_hand() user.put_in_hands(GUN) @@ -153,205 +159,59 @@ throw_at(pick(oview(7,get_turf(user))),1,1) user.visible_message("[user] tosses aside the spent rifle!") +// Automatic Shotguns// -/obj/item/ammo_box/magazine/internal/boltaction/enchanted - max_ammo =1 +/obj/item/weapon/gun/projectile/shotgun/automatic -///////////////////////////// -// DOUBLE BARRELED SHOTGUN // -///////////////////////////// - -/obj/item/weapon/gun/projectile/revolver/doublebarrel - name = "double-barreled shotgun" - desc = "A true classic." - icon_state = "dshotgun" - item_state = "shotgun" - w_class = 4.0 - force = 10 - flags = CONDUCT - slot_flags = SLOT_BACK - origin_tech = "combat=3;materials=1" - mag_type = "/obj/item/ammo_box/magazine/internal/cylinder/dualshot" - sawn_desc = "Omar's coming!" - -/obj/item/weapon/gun/projectile/revolver/doublebarrel/attackby(var/obj/item/A as obj, mob/user as mob, params) - ..() - if(istype(A, /obj/item/ammo_box) || istype(A, /obj/item/ammo_casing)) - chamber_round() - if(istype(A, /obj/item/weapon/circular_saw) || istype(A, /obj/item/weapon/melee/energy) || istype(A, /obj/item/weapon/gun/energy/plasmacutter)) - sawoff(user) - -/obj/item/weapon/gun/projectile/revolver/doublebarrel/attack_self(mob/living/user as mob) - var/num_unloaded = 0 - while (get_ammo() > 0) - var/obj/item/ammo_casing/CB - CB = magazine.get_round(0) - chambered = null - CB.loc = get_turf(src.loc) - CB.update_icon() - num_unloaded++ - if (num_unloaded) - to_chat(user, "You break open \the [src] and unload [num_unloaded] shell\s.") - else - to_chat(user, "[src] is empty.") - -/obj/item/weapon/gun/projectile/revolver/doublebarrel/isHandgun() //contrary to popular opinion, double barrels are not, shockingly, handguns - return 0 - -// IMPROVISED SHOTGUN // - -/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised - name = "improvised shotgun" - desc = "Essentially a tube that aims shotgun shells." - icon_state = "ishotgun" - item_state = "shotgun" - w_class = 4.0 - force = 10 - slot_flags = null - origin_tech = "combat=2;materials=2" - mag_type = "/obj/item/ammo_box/magazine/internal/cylinder/improvised" - sawn_desc = "I'm just here for the gasoline." - -/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/attackby(var/obj/item/A as obj, mob/user as mob, params) - ..() - if(istype(A, /obj/item/stack/cable_coil) && !sawn_state) - var/obj/item/stack/cable_coil/C = A - if(C.use(10)) - slot_flags = SLOT_BACK - icon_state = "ishotgunsling" - to_chat(user, "You tie the lengths of cable to the shotgun, making a sling.") - update_icon() - else - to_chat(user, "You need at least ten lengths of cable if you want to make a sling.") - return - -// Sawing guns related procs // - -/obj/item/weapon/gun/projectile/proc/blow_up(mob/user as mob) - if(get_ammo()) - afterattack(user, user) - playsound(user, fire_sound, 50, 1) - user.visible_message("The [src] goes off!", "The [src] goes off in your face!") - return - -/obj/item/weapon/gun/projectile/proc/sawoff(mob/user as mob) - if(sawn_state == SAWN_OFF) - to_chat(user, "\The [src] is already shortened.") - return - - if(sawn_state == SAWN_SAWING) - return - - user.visible_message("[user] begins to shorten \the [src].", "You begin to shorten \the [src].") - - //if there's any live ammo inside the gun, makes it go off - if(blow_up(user)) - user.visible_message("\The [src] goes off!", "\The [src] goes off in your face!") - return - - sawn_state = SAWN_SAWING - - if(do_after(user, 30, target = src)) - user.visible_message("[user] shortens \the [src]!", "You shorten \the [src]!") - name = "sawn-off [src.name]" - desc = sawn_desc - icon_state = "[icon_state]-sawn" - w_class = 3.0 - item_state = "gun" - slot_flags &= ~SLOT_BACK //you can't sling it on your back - slot_flags |= SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally) - sawn_state = SAWN_OFF - update_icon() - return - else - sawn_state = SAWN_INTACT - -/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog - name = "\improper 'Bulldog' Shotgun" - desc = "A compact, mag-fed semi-automatic shotgun for combat in narrow corridors, nicknamed 'Bulldog' by boarding parties. Compatible only with specialized 8-round drum magazines." - icon_state = "bulldog" - item_state = "bulldog" - w_class = 3.0 - origin_tech = "combat=5;materials=4;syndicate=6" - mag_type = "/obj/item/ammo_box/magazine/m12g" - fire_sound = 'sound/weapons/Gunshot4.ogg' - can_suppress = 0 - burst_size = 1 - fire_delay = 0 - action_button_name = null - -/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog/New() - ..() - update_icon() - return - -/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog/proc/update_magazine() - if(magazine) - overlays.Cut() - overlays += "[magazine.icon_state]" - return - -/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog/update_icon() - overlays.Cut() - update_magazine() - icon_state = "bulldog[chambered ? "" : "-e"]" - return - -/obj/item/weapon/gun/projectile/automatic/shotgun/bulldog/afterattack(atom/target as mob|obj|turf|area, mob/living/user as mob|obj, flag) - ..() - empty_alarm() - return - -/obj/item/weapon/gun/projectile/shotgun/automatic/Fire(mob/living/user as mob|obj) +/obj/item/weapon/gun/projectile/shotgun/automatic/shoot_live_shot(mob/living/user as mob|obj) ..() pump(user) -// COMBAT SHOTGUN // - /obj/item/weapon/gun/projectile/shotgun/automatic/combat name = "combat shotgun" desc = "A semi automatic shotgun with tactical furniture and a six-shell capacity underneath." icon_state = "cshotgun" origin_tech = "combat=5;materials=2" - mag_type = "/obj/item/ammo_box/magazine/internal/shotcom" + mag_type = /obj/item/ammo_box/magazine/internal/shot/com w_class = 5 -//caneshotgun +//Dual Feed Shotgun -/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/cane - name = "cane" - desc = "A cane used by a true gentlemen. Or a clown." - icon = 'icons/obj/weapons.dmi' - icon_state = "cane" - item_state = "stick" - sawn_state = SAWN_OFF - w_class = 2 - force = 10 - can_unsuppress = 0 - slot_flags = null - origin_tech = "" // NO GIVAWAYS - mag_type = "/obj/item/ammo_box/magazine/internal/cylinder/improvised" - sawn_desc = "I'm sorry, but why did you saw your cane in the first place?" - attack_verb = list("bludgeoned", "whacked", "disciplined", "thrashed") - fire_sound = 'sound/weapons/Gunshot_silenced.ogg' - silenced = 1 - needs_permit = 0 //its just a cane beepsky..... +/obj/item/weapon/gun/projectile/shotgun/automatic/dual_tube + name = "cycler shotgun" + desc = "An advanced shotgun with two separate magazine tubes, allowing you to quickly toggle between ammo types." + icon_state = "cycler" + origin_tech = "combat=4;materials=2" + mag_type = /obj/item/ammo_box/magazine/internal/shot/tube + w_class = 5 + var/toggled = 0 + var/obj/item/ammo_box/magazine/internal/shot/alternate_magazine -/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/cane/attackby(obj/item/A, mob/user, params) +/obj/item/weapon/gun/projectile/shotgun/automatic/dual_tube/New() ..() - if(istype(A, /obj/item/stack/cable_coil)) + if (!alternate_magazine) + alternate_magazine = new mag_type(src) + +/obj/item/weapon/gun/projectile/shotgun/automatic/dual_tube/attack_self(mob/living/user) + if(!chambered && magazine.contents.len) + pump() + else + toggle_tube(user) + +/obj/item/weapon/gun/projectile/shotgun/automatic/dual_tube/proc/toggle_tube(mob/living/user) + var/current_mag = magazine + var/alt_mag = alternate_magazine + magazine = alt_mag + alternate_magazine = current_mag + toggled = !toggled + if(toggled) + to_chat(user, "You switch to tube B.") + else + to_chat(user, "You switch to tube A.") + +/obj/item/weapon/gun/projectile/shotgun/automatic/dual_tube/AltClick(mob/living/user) + if(user.incapacitated() || !Adjacent(user) || !istype(user)) return + pump() -/obj/item/weapon/gun/projectile/revolver/doublebarrel/improvised/cane/examine(mob/user) // HAD TO REPEAT EXAMINE CODE BECAUSE GUN CODE DOESNT STEALTH - var/f_name = "\a [src]." - if(src.blood_DNA && !istype(src, /obj/effect/decal)) - if(gender == PLURAL) - f_name = "some " - else - f_name = "a " - f_name += "blood-stained [name]!" - - to_chat(user, "\icon[src] That's [f_name]") - - if(desc) - to_chat(user, desc) \ No newline at end of file +// DOUBLE BARRELED SHOTGUN, IMPROVISED SHOTGUN, and CANE SHOTGUN are in revolver.dm diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm index ee70bb3f80b..59bd7fb649b 100644 --- a/code/modules/projectiles/guns/projectile/sniper.dm +++ b/code/modules/projectiles/guns/projectile/sniper.dm @@ -4,8 +4,8 @@ icon_state = "sniper" item_state = "sniper" recoil = 2 - heavy_weapon = 1 - mag_type = "/obj/item/ammo_box/magazine/sniper_rounds" + weapon_weight = WEAPON_MEDIUM + mag_type = /obj/item/ammo_box/magazine/sniper_rounds fire_delay = 40 origin_tech = "combat=8" can_unsuppress = 1 @@ -35,18 +35,18 @@ max_ammo = 6 caliber = ".50" -/obj/item/ammo_casing/point50 - desc = "A .50 bullet casing." - caliber = ".50" - projectile_type = /obj/item/projectile/bullet/sniper - icon_state = ".50" - /obj/item/ammo_box/magazine/sniper_rounds/update_icon() if(ammo_count()) icon_state = "[initial(icon_state)]-ammo" else icon_state = "[initial(icon_state)]" +/obj/item/ammo_casing/point50 + desc = "A .50 bullet casing." + caliber = ".50" + projectile_type = /obj/item/projectile/bullet/sniper + icon_state = ".50" + /obj/item/projectile/bullet/sniper damage = 70 stun = 5 @@ -69,8 +69,6 @@ origin_tech = "combat=6;syndicate=3" ammo_type = /obj/item/ammo_casing/soporific max_ammo = 3 - caliber = ".50" - icon_state = ".50" /obj/item/ammo_casing/soporific desc = "A .50 bullet casing, specialised in sending the target to sleep, instead of hell." @@ -79,10 +77,10 @@ icon_state = ".50" /obj/item/projectile/bullet/sniper/soporific + armour_penetration = 0 nodamage = 1 stun = 0 weaken = 0 - armour_penetration = 0 breakthings = FALSE /obj/item/projectile/bullet/sniper/soporific/on_hit(atom/target, blocked = 0, hit_zone) @@ -102,8 +100,6 @@ origin_tech = "combat=7;syndicate=5" ammo_type = /obj/item/ammo_casing/haemorrhage max_ammo = 5 - caliber = ".50" - icon_state = ".50" /obj/item/ammo_casing/haemorrhage desc = "A .50 bullet casing, specialised in causing massive bloodloss" @@ -112,11 +108,11 @@ icon_state = ".50" /obj/item/projectile/bullet/sniper/haemorrhage + armour_penetration = 15 damage = 15 stun = 0 weaken = 0 breakthings = FALSE - armour_penetration = 15 /obj/item/projectile/bullet/sniper/haemorrhage/on_hit(atom/target, blocked = 0, hit_zone) if((blocked != 100) && istype(target, /mob/living/carbon/human)) @@ -145,4 +141,4 @@ forcedodge = 1 stun = 0 weaken = 0 - breakthings = FALSE \ No newline at end of file + breakthings = FALSE diff --git a/code/modules/projectiles/guns/projectile/toy.dm b/code/modules/projectiles/guns/projectile/toy.dm index 7bb290f4f46..c0465a83beb 100644 --- a/code/modules/projectiles/guns/projectile/toy.dm +++ b/code/modules/projectiles/guns/projectile/toy.dm @@ -1,10 +1,11 @@ /obj/item/weapon/gun/projectile/automatic/toy name = "foam force SMG" desc = "A prototype three-round burst toy submachine gun. Ages 8 and up." - icon = 'icons/obj/toyguns.dmi' + icon = 'icons/obj/guns/toy.dmi' icon_state = "saber" item_state = "gun" - mag_type = "/obj/item/ammo_box/magazine/toy/smg" + mag_type = /obj/item/ammo_box/magazine/toy/smg + fire_sound = 'sound/weapons/Gunshot_smg.ogg' force = 0 throwforce = 0 burst_size = 3 @@ -12,15 +13,15 @@ clumsy_check = 0 needs_permit = 0 -/obj/item/weapon/gun/projectile/automatic/toy/process_chambered() - return ..(0, 1) +/obj/item/weapon/gun/projectile/automatic/toy/process_chamber(eject_casing = 0, empty_chamber = 1) + ..() /obj/item/weapon/gun/projectile/automatic/toy/pistol name = "foam force pistol" desc = "A small, easily concealable toy handgun. Ages 8 and up." icon_state = "pistol" w_class = 2 - mag_type = "/obj/item/ammo_box/magazine/toy/pistol" + mag_type = /obj/item/ammo_box/magazine/toy/pistol fire_sound = 'sound/weapons/Gunshot.ogg' can_suppress = 0 burst_size = 1 @@ -34,67 +35,65 @@ /obj/item/weapon/gun/projectile/automatic/toy/pistol/riot name = "foam force riot pistol" desc = "RIOT! Ages 8 and up." + mag_type = /obj/item/ammo_box/magazine/toy/pistol/riot /obj/item/weapon/gun/projectile/automatic/toy/pistol/riot/New() magazine = new /obj/item/ammo_box/magazine/toy/pistol/riot(src) ..() -/obj/item/weapon/gun/projectile/automatic/c20r/toy - name = "donksoft SMG" - desc = "A bullpup two-round burst toy SMG, designated 'C-20r'. Ages 8 and up." - icon = 'icons/obj/toyguns.dmi' - can_suppress = 0 - needs_permit = 0 - mag_type = "/obj/item/ammo_box/magazine/toy/smgm45" - -/obj/item/weapon/gun/projectile/automatic/c20r/toy/process_chambered() - return ..(0, 1) - -/obj/item/weapon/gun/projectile/automatic/l6_saw/toy - name = "donksoft LMG" - desc = "A heavily modified toy light machine gun, designated 'L6 SAW'. Ages 8 and up." - icon = 'icons/obj/toyguns.dmi' - can_suppress = 0 - needs_permit = 0 - mag_type = "/obj/item/ammo_box/magazine/toy/m762" - -/obj/item/weapon/gun/projectile/automatic/l6_saw/toy/process_chambered() - return ..(0, 1) - - - /obj/item/weapon/gun/projectile/shotgun/toy name = "foam force shotgun" desc = "A toy shotgun with wood furniture and a four-shell capacity underneath. Ages 8 and up." - icon = 'icons/obj/toyguns.dmi' + icon = 'icons/obj/guns/toy.dmi' force = 0 throwforce = 0 origin_tech = null - mag_type = "/obj/item/ammo_box/magazine/internal/shot/toy" + mag_type = /obj/item/ammo_box/magazine/internal/shot/toy clumsy_check = 0 needs_permit = 0 -/obj/item/weapon/gun/projectile/shotgun/toy/pump_unload() - if(chambered)//We have a shell in the chamber - chambered = null - if(in_chamber) - in_chamber = null +/obj/item/weapon/gun/projectile/shotgun/toy/process_chamber() + ..() + if(chambered && !chambered.BB) + qdel(chambered) /obj/item/weapon/gun/projectile/shotgun/toy/crossbow name = "foam force crossbow" desc = "A weapon favored by many overactive children. Ages 8 and up." icon_state = "crossbow" item_state = "crossbow" - mag_type = "/obj/item/ammo_box/magazine/internal/shot/toy/crossbow" + mag_type = /obj/item/ammo_box/magazine/internal/shot/toy/crossbow fire_sound = 'sound/items/syringeproj.ogg' slot_flags = SLOT_BELT w_class = 2 +/obj/item/weapon/gun/projectile/automatic/c20r/toy + name = "donksoft SMG" + desc = "A bullpup two-round burst toy SMG, designated 'C-20r'. Ages 8 and up." + icon = 'icons/obj/guns/toy.dmi' + can_suppress = 0 + needs_permit = 0 + mag_type = /obj/item/ammo_box/magazine/toy/smgm45 + +/obj/item/weapon/gun/projectile/automatic/c20r/toy/process_chamber(eject_casing = 0, empty_chamber = 1) + ..() + +/obj/item/weapon/gun/projectile/automatic/l6_saw/toy + name = "donksoft LMG" + desc = "A heavily modified toy light machine gun, designated 'L6 SAW'. Ages 8 and up." + icon = 'icons/obj/guns/toy.dmi' + can_suppress = 0 + needs_permit = 0 + mag_type = /obj/item/ammo_box/magazine/toy/m762 + +/obj/item/weapon/gun/projectile/automatic/l6_saw/toy/process_chamber(eject_casing = 0, empty_chamber = 1) + ..() + /obj/item/weapon/gun/projectile/shotgun/toy/tommygun name = "tommy gun" desc = "Looks almost like the real thing! Great for practicing Drive-bys. Ages 8 and up." - icon = 'icons/obj/gun.dmi' + icon = 'icons/obj/guns/projectile.dmi' icon_state = "tommy" item_state = "shotgun" - mag_type = "/obj/item/ammo_box/magazine/internal/shot/toy/tommygun" + mag_type = /obj/item/ammo_box/magazine/internal/shot/toy/tommygun w_class = 2 diff --git a/code/modules/projectiles/guns/rocket.dm b/code/modules/projectiles/guns/rocket.dm new file mode 100644 index 00000000000..72ab89bf40e --- /dev/null +++ b/code/modules/projectiles/guns/rocket.dm @@ -0,0 +1,58 @@ +/obj/item/weapon/gun/rocketlauncher + var/projectile + name = "rocket launcher" + desc = "Say hello to my little friend" + icon_state = "rocket" + item_state = "rocket" + w_class = 4.0 + throw_speed = 2 + throw_range = 10 + force = 5.0 + flags = CONDUCT + origin_tech = "combat=8;materials=5" + var/missile_speed = 2 + var/missile_range = 30 + var/max_rockets = 1 + var/list/rockets = new/list() + +/obj/item/weapon/gun/rocketlauncher/examine(mob/user) + ..() + to_chat(user, "[rockets.len] / [max_rockets] rockets.") + +/obj/item/weapon/gun/rocketlauncher/Destroy() + for(var/datum/D in rockets) + qdel(D) + rockets = null + + return ..() + +/obj/item/weapon/gun/rocketlauncher/update_icon() + return + +/obj/item/weapon/gun/rocketlauncher/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/ammo_casing/rocket)) + if(rockets.len < max_rockets) + user.drop_item() + I.loc = src + rockets += I + to_chat(user, "You put the rocket in [src].") + to_chat(user, "[rockets.len] / [max_rockets] rockets.") + else + to_chat(usr, "[src] cannot hold more rockets.") + +/obj/item/weapon/gun/rocketlauncher/can_shoot() + return rockets.len + +/obj/item/weapon/gun/rocketlauncher/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params, zone_override = "") + if(rockets.len) + var/obj/item/ammo_casing/rocket/I = rockets[1] + var/obj/item/missile/M = new /obj/item/missile(user.loc) + playsound(user.loc, 'sound/effects/bang.ogg', 50, 1) + M.primed = 1 + M.throw_at(target, missile_range, missile_speed, user, 1) + message_admins("[key_name_admin(user)] fired a rocket from a rocket launcher ([name]).") + log_game("[key_name_admin(user)] used a rocket launcher ([name]).") + rockets -= I + qdel(I) + else + to_chat(usr, "[src] is empty.") diff --git a/code/modules/projectiles/guns/syringe_gun.dm b/code/modules/projectiles/guns/syringe_gun.dm index 0e43d550c85..332d279376b 100644 --- a/code/modules/projectiles/guns/syringe_gun.dm +++ b/code/modules/projectiles/guns/syringe_gun.dm @@ -13,25 +13,41 @@ var/list/syringes = list() var/max_syringes = 1 -/obj/item/weapon/gun/syringe/process_chambered() - if(!syringes.len) return 0 +/obj/item/weapon/gun/syringe/New() + ..() + chambered = new /obj/item/ammo_casing/syringegun(src) + +/obj/item/weapon/gun/syringe/newshot() + if(!syringes.len) + return var/obj/item/weapon/reagent_containers/syringe/S = syringes[1] - if(!S) return 0 + if(!S) + return - in_chamber = new /obj/item/projectile/bullet/dart/syringe(src) - S.reagents.trans_to(in_chamber, S.reagents.total_volume) - in_chamber.name = S.name + chambered.BB = new S.projectile_type (src) + + S.reagents.trans_to(chambered.BB, S.reagents.total_volume) + chambered.BB.name = S.name syringes.Remove(S) qdel(S) - return 1 + return + +/obj/item/weapon/gun/syringe/process_chamber() + return + +/obj/item/weapon/gun/syringe/afterattack(atom/target as mob|obj|turf, mob/living/user as mob|obj, params) + if(target == loc) + return + newshot() + ..() /obj/item/weapon/gun/syringe/examine(mob/user) - ..(user) + ..() to_chat(user, "Can hold [max_syringes] syringe\s. Has [syringes.len] syringe\s remaining.") - + /obj/item/weapon/gun/syringe/attack_self(mob/living/user as mob) if(!syringes.len) to_chat(user, "[src] is empty.") @@ -39,24 +55,26 @@ var/obj/item/weapon/reagent_containers/syringe/S = syringes[syringes.len] - if(!S) return 0 - S.forceMove(user.loc) + if(!S) + return 0 + S.loc = user.loc syringes.Remove(S) to_chat(user, "You unload [S] from \the [src]!") return 1 -/obj/item/weapon/gun/syringe/attackby(var/obj/item/A as obj, mob/user as mob, var/show_msg = 1, params) +/obj/item/weapon/gun/syringe/attackby(obj/item/A, mob/user, params, show_msg = 1) if(istype(A, /obj/item/weapon/reagent_containers/syringe)) if(syringes.len < max_syringes) - user.drop_item() + if(!user.unEquip(A)) + return to_chat(user, "You load [A] into \the [src]!") syringes.Add(A) - A.forceMove(src) + A.loc = src return 1 else - to_chat(usr, "[src] cannot hold more syringes.") + to_chat(user, "[src] cannot hold more syringes.") return 0 /obj/item/weapon/gun/syringe/rapidsyringe @@ -64,7 +82,7 @@ desc = "A modification of the syringe gun design, using a rotating cylinder to store up to six syringes." icon_state = "rapidsyringegun" max_syringes = 6 - + /obj/item/weapon/gun/syringe/syndicate name = "dart pistol" desc = "A small spring-loaded sidearm that functions identically to a syringe gun." @@ -73,5 +91,5 @@ w_class = 2 origin_tech = "combat=2;syndicate=2" force = 2 //Also very weak because it's smaller - silenced = 1 //Softer fire sound + suppressed = 1 //Softer fire sound can_unsuppress = 0 //Permanently silenced diff --git a/code/modules/projectiles/guns/throw.dm b/code/modules/projectiles/guns/throw.dm new file mode 100644 index 00000000000..d1bcda59067 --- /dev/null +++ b/code/modules/projectiles/guns/throw.dm @@ -0,0 +1,93 @@ +/obj/item/weapon/gun/throw + name = "abstract item thrower" + desc = "This shouldn't be here, yell at a coder." + fire_sound = 'sound/weapons/punchmiss.ogg' + fire_sound_text = "thwock" + + var/obj/item/to_launch + var/list/valid_projectile_type + var/max_capacity = 1 + var/list/loaded_projectiles = list() + + var/projectile_speed = 1 + var/projectile_range = 1 + +/obj/item/weapon/gun/throw/proc/notify_ammo_count(mob/user) + return + +/obj/item/weapon/gun/throw/proc/get_throwrange() + return projectile_speed + +/obj/item/weapon/gun/throw/proc/get_throwspeed() + return projectile_range + +/obj/item/weapon/gun/throw/proc/modify_projectile(obj/item/I, on_chamber = 0) + return + +/obj/item/weapon/gun/throw/proc/get_ammocount(include_loaded = 1) + var/count = loaded_projectiles.len + if(include_loaded && to_launch) + count++ + return count + +/obj/item/weapon/gun/throw/examine(mob/user) + ..() + to_chat(user, "It is [to_launch ? "loaded with \a [to_launch]" : "not loaded"].") + notify_ammo_count(user) + +/obj/item/weapon/gun/throw/Destroy() + qdel(to_launch) + to_launch = null + for(var/atom/A in loaded_projectiles) + qdel(A) + loaded_projectiles = null + + return ..() + +/obj/item/weapon/gun/throw/update_icon() + return + +/obj/item/weapon/gun/throw/attackby(obj/item/I, mob/user, params) + if(istype(I, valid_projectile_type) && !(I.flags & NODROP)) + if(get_ammocount() < max_capacity) + user.drop_item() + I.forceMove(src) + loaded_projectiles += I + to_chat(user, "You load [I] into [src].") + if(!to_launch) + process_chamber() + notify_ammo_count(user) + else + to_chat(user, "[src] cannot hold any more projectiles.") + else + to_chat(user, "You cannot load [I] into [src]!") + +/obj/item/weapon/gun/throw/process_chamber() + if(!to_launch && loaded_projectiles.len) + to_launch = loaded_projectiles[1] + loaded_projectiles -= to_launch + return + +/obj/item/weapon/gun/throw/can_shoot() + if(to_launch) + return 1 + return 0 + +/obj/item/weapon/gun/throw/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params, zone_override) + add_fingerprint(user) + if(semicd) + return + + var/obj/item/I = to_launch + I.forceMove(get_turf(src)) + to_launch = null + modify_projectile(I) + playsound(user, fire_sound, 50, 1) + I.throw_at(target, get_throwrange(), get_throwspeed(), user, 1) + message_admins("[key_name_admin(user)] fired \a [I] from a [src].") + log_game("[key_name_admin(user)] used \a [src].") + process_chamber() + + semicd = 1 + spawn(fire_delay) + semicd = 0 diff --git a/code/modules/projectiles/guns/throw/crossbow.dm b/code/modules/projectiles/guns/throw/crossbow.dm new file mode 100644 index 00000000000..55e76bec6b7 --- /dev/null +++ b/code/modules/projectiles/guns/throw/crossbow.dm @@ -0,0 +1,181 @@ +#define XBOW_TENSION_20 "20%" +#define XBOW_TENSION_40 "40%" +#define XBOW_TENSION_60 "60%" +#define XBOW_TENSION_80 "80%" +#define XBOW_TENSION_FULL "100%" + +/obj/item/weapon/gun/throw/crossbow + name = "powered crossbow" + desc = "A modern twist on an old classic. Pick up that can." + icon_state = "crossbow" + item_state = "crossbow-solid" + fire_sound_text = "a solid thunk" + fire_delay = 25 + + valid_projectile_type = /obj/item/weapon/arrow + + var/tension = 0 + var/drawtension = 5 + var/maxtension = 5 + var/speed_multiplier = 5 + var/range_multiplier = 3 + var/obj/item/weapon/stock_parts/cell/cell = null // Used for firing superheated rods. + var/list/possible_tensions = list(XBOW_TENSION_20, XBOW_TENSION_40, XBOW_TENSION_60, XBOW_TENSION_80, XBOW_TENSION_FULL) + +/obj/item/weapon/gun/throw/crossbow/emp_act(severity) + if(cell && severity) + emp_act(severity) + +/obj/item/weapon/gun/throw/crossbow/update_icon() + if(!tension) + if(!to_launch) + icon_state = "[initial(icon_state)]" + else + icon_state = "[initial(icon_state)]-nocked" + else + icon_state = "[initial(icon_state)]-drawn" + +/obj/item/weapon/gun/throw/crossbow/examine(mob/user) + ..() + if(cell) + to_chat(user, "\A [cell] is mounted onto [src]. Battery cell charge: [cell.charge]/[cell.maxcharge]") + else + to_chat(user, "It has an empty mount for a battery cell.") + +/obj/item/weapon/gun/throw/crossbow/modify_projectile(obj/item/I, on_chamber = 0) + if(cell && on_chamber && istype(I, /obj/item/weapon/arrow/rod)) + var/obj/item/weapon/arrow/rod/R = I + visible_message("[R] plinks and crackles as it begins to glow red-hot.") + R.throwforce = 15 + R.superheated = 1 + cell.use(500) + +/obj/item/weapon/gun/throw/crossbow/get_throwspeed() + return tension * speed_multiplier + +/obj/item/weapon/gun/throw/crossbow/get_throwrange() + return tension * range_multiplier + +/obj/item/weapon/gun/throw/crossbow/process_chamber() + ..() + if(to_launch) + modify_projectile(to_launch, 1) + update_icon() + +/obj/item/weapon/gun/throw/crossbow/attack_self(mob/living/user) + if(tension) + if(to_launch) + user.visible_message("[user] relaxes the tension on [src]'s string and removes [to_launch].","You relax the tension on [src]'s string and remove [to_launch].") + to_launch.forceMove(get_turf(src)) + var/obj/item/weapon/arrow/A = to_launch + to_launch = null + A.removed() + process_chamber() + else + user.visible_message("[user] relaxes the tension on [src]'s string.","You relax the tension on [src]'s string.") + tension = 0 + update_icon() + else + draw(user) + +/obj/item/weapon/gun/throw/crossbow/proc/draw(mob/living/user) + if(user.incapacitated()) + return + if(!to_launch) + to_chat(user, "You can't draw [src] without a bolt nocked.") + return + + user.visible_message("[user] begins to draw back the string of [src].","You begin to draw back the string of [src].") + if(do_after(user, 25 * drawtension, target = user)) + tension = drawtension + user.visible_message("[usr] draws back the string of [src]!","[src] clunks as you draw the string to its maximum tension!!") + update_icon() + +/obj/item/weapon/gun/throw/crossbow/attackby(obj/item/W as obj, mob/user as mob, params) + if(istype(W, /obj/item/weapon/stock_parts/cell)) + if(!cell) + user.drop_item() + W.loc = src + cell = W + to_chat(user, "You jam [cell] into [src] and wire it to the firing coil.") + process_chamber() + else + to_chat(user, "[src] already has a cell installed.") + else if(istype(W, /obj/item/weapon/screwdriver)) + if(cell) + cell.loc = get_turf(src) + to_chat(user, "You jimmy [cell] out of [src] with [W].") + cell = null + else + to_chat(user, "[src] doesn't have a cell installed.") + else + ..() + +/obj/item/weapon/gun/throw/crossbow/verb/set_tension() + set name = "Adjust Tension" + set category = "Object" + set src in range(0) + + var/mob/user = usr + if(user.incapacitated()) + return + var/choice = input("Select tension to draw to:", "[src]", XBOW_TENSION_FULL) as null|anything in possible_tensions + if(!choice) + return + + switch(choice) + if(XBOW_TENSION_20) + drawtension = Ceiling(0.2 * maxtension) + if(XBOW_TENSION_40) + drawtension = Ceiling(0.4 * maxtension) + if(XBOW_TENSION_60) + drawtension = Ceiling(0.6 * maxtension) + if(XBOW_TENSION_80) + drawtension = Ceiling(0.8 * maxtension) + if(XBOW_TENSION_FULL) + drawtension = maxtension + +/obj/item/weapon/gun/throw/crossbow/process_fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, message = 1, params, zone_override) + ..() + tension = 0 + update_icon() +/obj/item/weapon/gun/throw/crossbow/french + name = "french powered crossbow" + icon_state = "fcrossbow" + valid_projectile_type = /obj/item/weapon/reagent_containers/food/snacks/baguette + +/obj/item/weapon/gun/throw/crossbow/french/modify_projectile(obj/item/I, on_chamber = 0) + return + +/obj/item/weapon/arrow + name = "bolt" + desc = "It's got a tip for you - get the point?" + icon_state = "bolt" + item_state = "bolt" + throwforce = 20 + w_class = 3.0 + sharp = 1 + edge = 0 + +/obj/item/weapon/arrow/proc/removed() //Helper for metal rods falling apart. + return + +/obj/item/weapon/arrow/rod + name = "makeshift bolt" + desc = "A sharpened metal rod that can be fired out of a crossbow." + icon_state = "metal-rod" + throwforce = 8 + var/superheated = 0 + +/obj/item/weapon/arrow/rod/removed() + if(superheated) // The rod has been superheated - we don't want it to be useable when removed from the bow. + visible_message("[src] shatters into a scattering of overstressed metal shards as it leaves the crossbow.") + var/obj/item/weapon/shard/shrapnel/S = new /obj/item/weapon/shard/shrapnel + S.loc = get_turf(src) + qdel(src) + +#undef XBOW_TENSION_20 +#undef XBOW_TENSION_40 +#undef XBOW_TENSION_60 +#undef XBOW_TENSION_80 +#undef XBOW_TENSION_FULL diff --git a/code/modules/projectiles/guns/throw/pielauncher.dm b/code/modules/projectiles/guns/throw/pielauncher.dm new file mode 100644 index 00000000000..f6405f47194 --- /dev/null +++ b/code/modules/projectiles/guns/throw/pielauncher.dm @@ -0,0 +1,36 @@ +/obj/item/weapon/gun/throw/piecannon + name = "pie cannon" + desc = "A projectile weapon that fires pies." + icon_state = "piecannon" + w_class = 5 + throw_speed = 2 + throw_range = 3 + force = 5 + + clumsy_check = 0 + valid_projectile_type = /obj/item/weapon/reagent_containers/food/snacks/pie + max_capacity = 5 + projectile_speed = 2 + projectile_range = 30 + + +/obj/item/weapon/gun/throw/piecannon/New() + ..() + for(var/i in 1 to max_capacity) + var/obj/item/weapon/reagent_containers/food/snacks/pie/P = new /obj/item/weapon/reagent_containers/food/snacks/pie(src) + loaded_projectiles += P + process_chamber() + +/obj/item/weapon/gun/throw/piecannon/notify_ammo_count(mob/user) + to_chat(user, "[src] has [get_ammocount()] of [max_capacity] pies left.") + +/obj/item/weapon/gun/throw/piecannon/update_icon() + if(to_launch) + icon_state = "piecannon1" + else + icon_state = "piecannon0" + item_state = icon_state + +/obj/item/weapon/gun/throw/piecannon/process_chamber() + ..() + update_icon() diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 5a028a1084a..5a8fa77e268 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -1,353 +1,223 @@ -/* -#define BRUTE "brute" -#define BURN "burn" -#define TOX "tox" -#define OXY "oxy" -#define CLONE "clone" - -#define ADD "add" -#define SET "set" -*/ - /obj/item/projectile name = "projectile" icon = 'icons/obj/projectiles.dmi' icon_state = "bullet" - density = 1 + density = 0 unacidable = 1 anchored = 1 //There's a reason this is here, Mport. God fucking damn it -Agouri. Find&Fix by Pete. The reason this is here is to stop the curving of emitter shots. + flags = ABSTRACT pass_flags = PASSTABLE mouse_opacity = 0 hitsound = 'sound/weapons/pierce.ogg' - animate_movement = 0 - var/bumped = 0 //Prevents it from hitting more than one guy at once + var/hitsound_wall = "" + pressure_resistance = INFINITY var/def_zone = "" //Aiming at var/mob/firer = null//Who shot it - var/silenced = 0 //Attack message + var/obj/item/ammo_casing/ammo_casing = null + var/suppressed = 0 //Attack message var/yo = null var/xo = null var/current = null - var/obj/shot_from = null // the object which shot us var/atom/original = null // the original target clicked var/turf/starting = null // the projectile's starting turf var/list/permutated = list() // we've passed through these atoms, don't try to hit them again var/paused = FALSE //for suspending the projectile midair - var/p_x = 16 var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center + var/speed = 1 //Amount of deciseconds it takes for projectile to travel + var/Angle = 0 + var/spread = 0 //amount (in degrees) of projectile spread + var/legacy = 0 //legacy projectile system + animate_movement = 0 var/damage = 10 var/damage_type = BRUTE //BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here var/nodamage = 0 //Determines if the projectile will skip any damage inflictions var/flag = "bullet" //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb //Cael - bio and rad are also valid var/projectile_type = "/obj/item/projectile" - var/kill_count = 50 //This will de-increment every process(). When 0, it will delete the projectile. - //Effects + var/range = 50 //This will de-increment every step. When 0, it will delete the projectile. + //Effects var/stun = 0 var/weaken = 0 var/paralyze = 0 var/irradiate = 0 - var/slur = 0 var/stutter = 0 + var/slur = 0 var/eyeblur = 0 var/drowsy = 0 var/stamina = 0 var/jitter = 0 var/embed = 0 // whether or not the projectile can embed itself in the mob - var/forcedodge = 0 + var/forcedodge = 0 //to pass through everything - var/range = 0 - var/proj_hit = 0 +/obj/item/projectile/New() + permutated = list() + return ..() - var/chatlog_attacks = 1 +/obj/item/projectile/proc/Range() + range-- + if(range <= 0 && loc) + on_range() - var/speed = 1 //Amount of deciseconds it takes for projectile to travel. Animation is adjusted accordingly. - var/Angle = 0 //For new projectiles - var/spread = 0 //Amount of degrees by which the projectiles will be spread DURING MOVEMENT. It exists for chaotic types of projectiles, like bees or something. - var/legacy = 0 //Use the legacy projectile system or new pixel movement? +/obj/item/projectile/proc/on_range() //if we want there to be effects when they reach the end of their range + qdel(src) - proc/delete() - // Garbage collect the projectiles - loc = null - - proc/Range() - if(range) - range-- - if(range <= 0) - on_range() - else - return - - proc/on_range() //if we want there to be effects when they reach the end of their range - proj_hit = 1 - del(src) - - proc/on_hit(var/atom/target, var/blocked = 0, var/hit_zone) - if(!isliving(target)) return 0 - if(isanimal(target)) return 0 - var/mob/living/L = target - return L.apply_effects(stun, weaken, paralyze, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter) - - proc/OnFired() //if assigned, allows for code when the projectile gets fired - return 1 - - proc/check_fire(var/mob/living/target as mob, var/mob/living/user as mob) //Checks if you can hit them or not. - if(!istype(target) || !istype(user)) - return 0 - var/obj/item/projectile/test/in_chamber = new /obj/item/projectile/test(get_step_to(user,target)) //Making the test.... - in_chamber.target = target - in_chamber.flags = flags //Set the flags... - in_chamber.pass_flags = pass_flags //And the pass flags to that of the real projectile... - in_chamber.firer = user - var/output = in_chamber.process() //Test it! - del(in_chamber) //No need for it anymore - return output //Send it back to the gun! - - Bump(atom/A as mob|obj|turf|area) - if(A == firer) - loc = A.loc - return 0 //cannot shoot yourself - - if(bumped) - return 1 - bumped = 1 - if(firer && istype(A, /mob)) - var/mob/M = A - if(!istype(A, /mob/living)) - loc = A.loc - return 0// nope.avi - - var/reagent_note - if(reagents && reagents.reagent_list) - reagent_note = " REAGENTS:" - for(var/datum/reagent/R in reagents.reagent_list) - reagent_note += R.id + " (" - reagent_note += num2text(R.volume) + ") " - //Lower accurancy/longer range tradeoff. Distance matters a lot here, so at - // close distance, actually RAISE the chance to hit. - var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations. - def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use. - /* - if(!def_zone) - visible_message("\blue \The [src] misses [M] narrowly!") - forcedodge = -1 - else - */ - if(ishuman(A)) - var/mob/living/carbon/human/H = A - var/obj/item/organ/external/organ = H.get_organ(check_zone(def_zone)) - if(isnull(organ)) - return - if(silenced) - playsound(loc, hitsound, 5, 1, -1) - to_chat(M, "\red You've been shot in the [parse_zone(def_zone)] by the [src.name]!") - else - playsound(loc, hitsound, 20, 1, -1) - visible_message("\red [A.name] is hit by the [src.name] in the [parse_zone(def_zone)]!")//X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter - if(istype(firer, /mob)) - M.attack_log += "\[[time_stamp()]\] [key_name(firer)] shot [M]/[M.ckey] with a [src.type][reagent_note]" - firer.attack_log += "\[[time_stamp()]\] [key_name(firer)] shot [M]/[M.ckey] with a [src.type][reagent_note]" - if(M.ckey && chatlog_attacks) - msg_admin_attack("[key_name_admin(firer)] shot [key_name_admin(M)] with a [src][reagent_note]") //BS12 EDIT ALG - if(!iscarbon(firer)) - M.LAssailant = null - else - M.LAssailant = firer - else - M.attack_log += "\[[time_stamp()]\] UNKNOWN SUBJECT (No longer exists) shot [key_name(M)] with a [src][reagent_note]" - if(M.ckey && chatlog_attacks) - msg_admin_attack("UNKNOWN shot [key_name_admin(M)] with a [src][reagent_note] (JMP)") //BS12 EDIT ALG - - spawn(0) - if(A) - var/turf/new_loc = get_turf(A) - var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null - if(permutation == -1 || forcedodge)// the bullet passes through a dense object! - spawn(1) - bumped = 0 // reset bumped variable... after a delay. We don't want the projectile to hit AGAIN. Fixes deflecting projectiles. - loc = new_loc - permutated.Add(A) - return 0 - if(istype(A,/turf)) - for(var/obj/O in A) - O.bullet_act(src) - for(var/mob/M in A) - M.bullet_act(src, def_zone) - if(!istype(src, /obj/item/projectile/beam/lightning)) - density = 0 - invisibility = 101 - del(src) - return 1 - - - CanPass(atom/movable/mover, turf/target, height=0, air_group=0) - if(air_group || (height==0)) return 1 - - if(istype(mover, /obj/item/projectile)) - return prob(95) - else - return 1 - - - Process_Spacemove(var/movement_dir = 0) - return 1 //Bullets don't drift in space - - - - process(var/setAngle) - if(setAngle) Angle = setAngle - if(!legacy) - spawn() //New projectile system - while(loc) - if(kill_count < 1) - del(src) - return - if(!paused) - kill_count-- - if((!( current ) || loc == current)) - current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z) - - if(!Angle) - Angle=round(Get_Angle(src,current)) -// to_chat(world, "[Angle] angle") - //overlays.Cut() - //var/icon/I=new(initial(icon),icon_state) //using initial(icon) makes sure that the angle for that is reset as well - //I.Turn(Angle) - //I.DrawBox(rgb(255,0,0,50),1,1,32,32) - //icon = I - if(spread) //Chaotic spread - Angle += (rand() - 0.5) * spread - var/matrix/M = new//matrix(transform) - M.Turn(Angle) - transform = M - - var/Pixel_x=round(sin(Angle)+16*sin(Angle)*2) - var/Pixel_y=round(cos(Angle)+16*cos(Angle)*2) - var/pixel_x_offset = pixel_x + Pixel_x - var/pixel_y_offset = pixel_y + Pixel_y - var/new_x = x - var/new_y = y - //Not sure if using whiles for this is good - while(pixel_x_offset > 16) -// to_chat(world, "Pre-adjust coords (x++): xy [pixel_x] xy offset [pixel_x_offset]") - pixel_x_offset -= 32 - pixel_x -= 32 - new_x++// x++ - while(pixel_x_offset < -16) -// to_chat(world, "Pre-adjust coords (x--): xy [pixel_x] xy offset [pixel_x_offset]") - pixel_x_offset += 32 - pixel_x += 32 - new_x-- - - while(pixel_y_offset > 16) -// to_chat(world, "Pre-adjust coords (y++): py [pixel_y] py offset [pixel_y_offset]") - pixel_y_offset -= 32 - pixel_y -= 32 - new_y++ - while(pixel_y_offset < -16) -// to_chat(world, "Pre-adjust coords (y--): py [pixel_y] py offset [pixel_y_offset]") - pixel_y_offset += 32 - pixel_y += 32 - new_y-- - - speed = round(speed) //Just in case. - step_towards(src, locate(new_x, new_y, z)) //Original projectiles stepped towards 'current' - if(speed <= 1) //We should really only animate at speed 2 - pixel_x = pixel_x_offset - pixel_y = pixel_y_offset - else - animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (speed <= 3 ? speed - 1 : speed))) - - /* - var/turf/T = get_turf(src) - if(T) - T.color = "#6666FF" - spawn(10) - T.color = initial(T.color) - */ - - if(!bumped && ((original && original.layer>=2.75) || ismob(original))) - if(loc == get_turf(original)) - if(!(original in permutated)) - Bump(original) - Range() - sleep(max(1, speed)) - else - spawn() //Old projectile system - while(loc) - if(kill_count < 1) - del(src) - return - if(!paused) - kill_count-- - if((!( current ) || loc == current)) - current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z) - if(!Angle) - Angle=round(Get_Angle(src,current)) - var/matrix/M = new//matrix(transform) - M.Turn(Angle) - transform = M //So there's no need to give icons directions again - step_towards(src, current) - if(!bumped && ((original && original.layer>=2.75) || ismob(original))) - if(loc == get_turf(original)) - if(!(original in permutated)) - Bump(original) - Range() - sleep(1) - - proc/dumbfire(var/dir) - current = get_ranged_target_turf(src, dir, world.maxx) //world.maxx is the range. Not sure how to handle this better. - process() - -/obj/item/projectile/test //Used to see if you can hit them. - invisibility = 101 //Nope! Can't see me! - yo = null - xo = null - var/target = null - var/result = 0 //To pass the message back to the gun. - - Bump(atom/A as mob|obj|turf|area) - if(A == firer) - loc = A.loc - return //cannot shoot yourself - if(istype(A, /obj/item/projectile)) - return - if(istype(A, /mob/living) || istype(A, /obj/mecha) || istype(A, /obj/spacepod) || istype(A, /obj/vehicle)) - result = 2 //We hit someone, return 1! - return - result = 1 - return - - process() - var/turf/curloc = get_turf(src) - var/turf/targloc = get_turf(target) - if(!curloc || !targloc) - return 0 - yo = targloc.y - curloc.y - xo = targloc.x - curloc.x - target = targloc - while(src) //Loop on through! - if(result) - return (result - 1) - if((!( target ) || loc == target)) - target = locate(min(max(x + xo, 1), world.maxx), min(max(y + yo, 1), world.maxy), z) //Finding the target turf at map edge - step_towards(src, target) - var/mob/living/M = locate() in get_turf(src) - if(istype(M)) //If there is someting living... - return 1 //Return 1 - else - M = locate() in get_step(src,target) - if(istype(M)) - return 1 - -/proc/check_trajectory(atom/target as mob|obj, atom/firer as mob|obj, var/pass_flags=PASSTABLE|PASSGLASS|PASSGRILLE, flags=null) //Checks if you can hit them or not. - if(!istype(target) || !istype(firer)) +/obj/item/projectile/proc/on_hit(atom/target, blocked = 0, hit_zone) + if(!isliving(target)) return 0 - var/obj/item/projectile/test/trace = new /obj/item/projectile/test(get_turf(firer)) //Making the test.... - trace.target = target - if(!isnull(flags)) - trace.flags = flags //Set the flags... - trace.pass_flags = pass_flags //And the pass flags to that of the real projectile... - var/output = trace.process() //Test it! - qdel(trace) //No need for it anymore - return output //Send it back to the gun! + var/mob/living/L = target + if(blocked < 100) // not completely blocked + var/organ_hit_text = "" + if(L.has_limbs) + organ_hit_text = " in \the [parse_zone(def_zone)]" + if(suppressed) + playsound(loc, hitsound, 5, 1, -1) + to_chat(L, "You're shot by \a [src][organ_hit_text]!") + else + if(hitsound) + var/volume = vol_by_damage() + playsound(loc, hitsound, volume, 1, -1) + L.visible_message("[L] is hit by \a [src][organ_hit_text]!", \ + "[L] is hit by \a [src][organ_hit_text]!") //X has fired Y is now given by the guns so you cant tell who shot you if you could not see the shooter + + var/reagent_note + if(reagents && reagents.reagent_list) + reagent_note = " REAGENTS:" + for(var/datum/reagent/R in reagents.reagent_list) + reagent_note += R.id + " (" + reagent_note += num2text(R.volume) + ") " + add_logs(L, firer, "shot", src, reagent_note) + return L.apply_effects(stun, weaken, paralyze, irradiate, slur, stutter, eyeblur, drowsy, blocked, stamina, jitter) + +/obj/item/projectile/proc/vol_by_damage() + if(damage) + return Clamp((damage) * 0.67, 30, 100)// Multiply projectile damage by 0.67, then clamp the value between 30 and 100 + else + return 50 //if the projectile doesn't do damage, play its hitsound at 50% volume + +/obj/item/projectile/Bump(atom/A, yes) + if(!yes) //prevents double bumps. + return + if(firer) + if(A == firer || (A == firer.loc && istype(A, /obj/mecha))) //cannot shoot yourself or your mech + loc = A.loc + return 0 + + var/distance = get_dist(get_turf(A), starting) // Get the distance between the turf shot from and the mob we hit and use that for the calculations. + def_zone = ran_zone(def_zone, max(100-(7*distance), 5)) //Lower accurancy/longer range tradeoff. 7 is a balanced number to use. + + if(isturf(A) && hitsound_wall) + var/volume = Clamp(vol_by_damage() + 20, 0, 100) + if(suppressed) + volume = 5 + playsound(loc, hitsound_wall, volume, 1, -1) + else if(ishuman(A)) + var/mob/living/carbon/human/H = A + var/obj/item/organ/external/organ = H.get_organ(check_zone(def_zone)) + if(isnull(organ)) + return + + var/turf/target_turf = get_turf(A) + + var/permutation = A.bullet_act(src, def_zone) // searches for return value, could be deleted after run so check A isn't null + if(permutation == -1 || forcedodge)// the bullet passes through a dense object! + loc = target_turf + if(A) + permutated.Add(A) + return 0 + else + if(A && A.density && !ismob(A) && !(A.flags & ON_BORDER)) //if we hit a dense non-border obj or dense turf then we also hit one of the mobs on that tile. + var/list/mobs_list = list() + for(var/mob/living/L in target_turf) + mobs_list += L + if(mobs_list.len) + var/mob/living/picked_mob = pick(mobs_list) + picked_mob.bullet_act(src, def_zone) + qdel(src) + +/obj/item/projectile/Process_Spacemove(var/movement_dir = 0) + return 1 //Bullets don't drift in space + +/obj/item/projectile/proc/fire(var/setAngle) + if(setAngle) + Angle = setAngle + if(!legacy) //new projectiles + set waitfor = 0 + while(loc) + if(!paused) + if((!( current ) || loc == current)) + current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z) + + if(!Angle) + Angle=round(Get_Angle(src,current)) + if(spread) + Angle += (rand() - 0.5) * spread + var/matrix/M = new + M.Turn(Angle) + transform = M + + var/Pixel_x=round(sin(Angle)+16*sin(Angle)*2) + var/Pixel_y=round(cos(Angle)+16*cos(Angle)*2) + var/pixel_x_offset = pixel_x + Pixel_x + var/pixel_y_offset = pixel_y + Pixel_y + var/new_x = x + var/new_y = y + + while(pixel_x_offset > 16) + pixel_x_offset -= 32 + pixel_x -= 32 + new_x++// x++ + while(pixel_x_offset < -16) + pixel_x_offset += 32 + pixel_x += 32 + new_x-- + + while(pixel_y_offset > 16) + pixel_y_offset -= 32 + pixel_y -= 32 + new_y++ + while(pixel_y_offset < -16) + pixel_y_offset += 32 + pixel_y += 32 + new_y-- + + speed = round(speed) + step_towards(src, locate(new_x, new_y, z)) + if(speed <= 1) + pixel_x = pixel_x_offset + pixel_y = pixel_y_offset + else + animate(src, pixel_x = pixel_x_offset, pixel_y = pixel_y_offset, time = max(1, (speed <= 3 ? speed - 1 : speed))) + + if(original && (original.layer>=2.75) || ismob(original)) + if(loc == get_turf(original)) + if(!(original in permutated)) + Bump(original, 1) + Range() + sleep(max(1, speed)) + else //old projectile system + set waitfor = 0 + while(loc) + if(!paused) + if((!( current ) || loc == current)) + current = locate(Clamp(x+xo,1,world.maxx),Clamp(y+yo,1,world.maxy),z) + step_towards(src, current) + if(original && (original.layer>=2.75) || ismob(original)) + if(loc == get_turf(original)) + if(!(original in permutated)) + Bump(original, 1) + Range() + sleep(1) + +obj/item/projectile/Crossed(atom/movable/AM) //A mob moving on a tile with a projectile is hit by it. + ..() + if(isliving(AM) && AM.density && !checkpass(PASSMOB)) + Bump(AM, 1) + +/obj/item/projectile/Destroy() + ammo_casing = null + return ..() + +/obj/item/projectile/proc/dumbfire(var/dir) + current = get_ranged_target_turf(src, dir, world.maxx) //world.maxx is the range. Not sure how to handle this better. + fire() diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm index e86d8e7a739..d9cf8360d2a 100644 --- a/code/modules/projectiles/projectile/beams.dm +++ b/code/modules/projectiles/projectile/beams.dm @@ -5,56 +5,34 @@ damage = 20 damage_type = BURN hitsound = 'sound/weapons/sear.ogg' + hitsound_wall = 'sound/weapons/effects/searwall.ogg' flag = "laser" eyeblur = 2 -/obj/item/projectile/practice - name = "laser" - icon_state = "laser" - pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE +/obj/item/projectile/beam/laser + +/obj/item/projectile/beam/laser/heavylaser + name = "heavy laser" + icon_state = "heavylaser" + damage = 40 + +/obj/item/projectile/beam/practice + name = "practice laser" damage = 0 - hitsound = null - damage_type = BURN - flag = "laser" - eyeblur = 2 - chatlog_attacks = 0 + nodamage = 1 /obj/item/projectile/beam/scatter name = "laser pellet" icon_state = "scatterlaser" damage = 5 - -/obj/item/projectile/beam/heavylaser - name = "heavy laser" - icon_state = "heavylaser" - damage = 40 - -/obj/item/projectile/beam/sniper - name = "sniper beam" - icon_state = "sniperlaser" - damage = 60 - stun = 5 - weaken = 5 - stutter = 5 - - -/obj/item/projectile/beam/immolator - name = "immolation beam" - -/obj/item/projectile/beam/immolator/on_hit(var/atom/target, var/blocked = 0) - . = ..() - if(istype(target, /mob/living/carbon)) - var/mob/living/carbon/M = target - M.adjust_fire_stacks(1) - M.IgniteMob() - /obj/item/projectile/beam/xray name = "xray beam" icon_state = "xray" damage = 15 irradiate = 30 forcedodge = 1 + range = 15 /obj/item/projectile/beam/disabler name = "disabler beam" @@ -82,204 +60,75 @@ name = "emitter beam" icon_state = "emitter" damage = 30 + legacy = 1 + animate_movement = SLIDE_STEPS /obj/item/projectile/beam/emitter/singularity_pull() return //don't want the emitters to miss -/obj/item/projectile/lasertag +/obj/item/projectile/beam/lasertag name = "laser tag beam" icon_state = "omnilaser" hitsound = null damage = 0 damage_type = STAMINA flag = "laser" - pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE var/suit_types = list(/obj/item/clothing/suit/redtag, /obj/item/clothing/suit/bluetag) - chatlog_attacks = 0 -/obj/item/projectile/lasertag/on_hit(var/atom/target, var/blocked = 0) - if(istype(target, /mob/living/carbon/human)) +/obj/item/projectile/beam/lasertag/on_hit(atom/target, blocked = 0) + . = ..() + if(ishuman(target)) var/mob/living/carbon/human/M = target if(istype(M.wear_suit)) if(M.wear_suit.type in suit_types) M.adjustStaminaLoss(34) return 1 -/obj/item/projectile/lasertag/omni +/obj/item/projectile/beam/lasertag/omni name = "laser tag beam" icon_state = "omnilaser" -/obj/item/projectile/lasertag/red +/obj/item/projectile/beam/lasertag/redtag icon_state = "laser" suit_types = list(/obj/item/clothing/suit/bluetag) -/obj/item/projectile/lasertag/blue +/obj/item/projectile/beam/lasertag/bluetag icon_state = "bluelaser" suit_types = list(/obj/item/clothing/suit/redtag) -/obj/item/projectile/beam/lightning - invisibility = 101 - name = "lightning" - damage = 0 - icon = 'icons/obj/lightning.dmi' - icon_state = "lightning" - stun = 10 - weaken = 10 - stutter = 50 - eyeblur = 50 - var/tang = 0 - layer = 3 - var/turf/last = null - kill_count = 6 - var/bullet_acted = 0 +/obj/item/projectile/beam/sniper + name = "sniper beam" + icon_state = "sniperlaser" + damage = 60 + stun = 5 + weaken = 5 + stutter = 5 - Bump(var/atom/A) - if((A != firer) && !bullet_acted) - A.bullet_act(src) - bullet_acted = 1 +/obj/item/projectile/beam/immolator + name = "immolation beam" - proc/adjustAngle(angle) - angle = round(angle) + 45 - if(angle > 180) - angle -= 180 - else - angle += 180 - if(!angle) - angle = 1 - /*if(angle < 0) - //angle = (round(abs(get_angle(A, user))) + 45) - 90 - angle = round(angle) + 45 + 180 - else - angle = round(angle) + 45*/ - return angle +/obj/item/projectile/beam/immolator/on_hit(var/atom/target, var/blocked = 0) + . = ..() + if(istype(target, /mob/living/carbon)) + var/mob/living/carbon/M = target + M.adjust_fire_stacks(1) + M.IgniteMob() - process() - var/first = 1 //So we don't make the overlay in the same tile as the firer - var/broke = 0 - var/broken - var/atom/curr = current - var/Angle=round(Get_Angle(firer,curr)) - var/icon/I=new('icons/obj/zap.dmi',"lightning") - I.Turn(Angle) - var/DX=(32*curr.x+curr.pixel_x)-(32*firer.x+firer.pixel_x) - var/DY=(32*curr.y+curr.pixel_y)-(32*firer.y+firer.pixel_y) - var/N=0 - var/length=round(sqrt((DX)**2+(DY)**2)) - var/count = 0 - for(N,N= kill_count) - break - count++ - var/obj/effect/overlay/beam/X=new(loc) - X.BeamSource=src - if(N+32>length) - var/icon/II=new(icon,icon_state) - II.DrawBox(null,1,(length-N),32,32) - II.Turn(Angle) - X.icon=II - else X.icon=I - var/Pixel_x=round(sin(Angle)+32*sin(Angle)*(N+16)/32) - var/Pixel_y=round(cos(Angle)+32*cos(Angle)*(N+16)/32) - if(DX==0) Pixel_x=0 - if(DY==0) Pixel_y=0 - if(Pixel_x>32) - for(var/a=0, a<=Pixel_x,a+=32) - X.x++ - Pixel_x-=32 - if(Pixel_x<-32) - for(var/a=0, a>=Pixel_x,a-=32) - X.x-- - Pixel_x+=32 - if(Pixel_y>32) - for(var/a=0, a<=Pixel_y,a+=32) - X.y++ - Pixel_y-=32 - if(Pixel_y<-32) - for(var/a=0, a>=Pixel_y,a-=32) - X.y-- - Pixel_y+=32 - X.pixel_x=Pixel_x - X.pixel_y=Pixel_y - var/turf/TT = get_turf(X.loc) - if(TT == firer.loc) - continue - if(TT.density) - qdel(X) - break - for(var/atom/O in TT) - if(istype(O,/mob/living)) - if(O.density) - qdel(X) - broke = 1 - break - if(!O.CanPass(src)) - qdel(X) - broke = 1 - break - if(broke) - if(X) - qdel(X) - break - spawn - while(src) //Move until we hit something - if(first) - icon = midicon - if((!( current ) || loc == current)) //If we pass our target - broken = 1 - icon = endicon - tang = adjustAngle(get_angle(original,current)) - if(tang > 180) - tang -= 180 - else - tang += 180 - icon_state = "[tang]" - var/turf/simulated/floor/f = current - if(f && istype(f)) - if(!bullet_acted) - f.break_tile() - f.hotspot_expose(1000,CELL_VOLUME) - if((x == 1 || x == world.maxx || y == 1 || y == world.maxy)) -// to_chat(world, "deleting") - //qdel(src) //Delete if it passes the world edge - broken = 1 - return - if(kill_count < 1) -// to_chat(world, "deleting") - //qdel(src) - broken = 1 - kill_count-- -// to_chat(world, "[x] [y]") - if(!bumped && !isturf(original)) - if(loc == get_turf(original)) - if(!(original in permutated)) - icon = endicon - if(!broken) - tang = adjustAngle(get_angle(original,current)) - if(tang > 180) - tang -= 180 - else - tang += 180 - icon_state = "[tang]" - Bump(original) - first = 0 - if(broken) -// to_chat(world, "breaking") - break - else - last = get_turf(src.loc) - step_towards(src, current) //Move~ - if(src.loc != current) - tang = adjustAngle(get_angle(src.loc,current)) - icon_state = "[tang]" - qdel(src) - return - /*cleanup(reference) //Waits .3 seconds then removes the overlay. -// to_chat(world, "setting invisibility") - sleep(50) - src.invisibility = 101 - return*/ - on_hit(atom/target, blocked = 0) - if(istype(target, /mob/living)) - var/mob/living/M = target - M.playsound_local(src, "explosion", 50, 1) - ..() \ No newline at end of file +/obj/item/projectile/beam/instakill + name = "instagib laser" + icon_state = "purple_laser" + damage = 200 + damage_type = BURN + +/obj/item/projectile/beam/instakill/blue + icon_state = "blue_laser" + +/obj/item/projectile/beam/instakill/red + icon_state = "red_laser" + +/obj/item/projectile/beam/instakill/on_hit(atom/target) + . = ..() + if(iscarbon(target)) + var/mob/living/carbon/M = target + M.visible_message("[M] explodes into a shower of gibs!") + M.gib() diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 879bbf7fad0..8f8809c504f 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -3,21 +3,10 @@ icon_state = "bullet" damage = 60 damage_type = BRUTE - nodamage = 0 flag = "bullet" embed = 1 sharp = 1 - -/obj/item/projectile/bullet/cap - name = "cap" - damage = 0 - nodamage = 1 - embed = 0 - sharp = 0 - -/obj/item/projectile/bullet/cap/process() - loc = null - del(src) + hitsound_wall = "ricochet" /obj/item/projectile/bullet/weakbullet //beanbag, heavy stamina damage damage = 5 @@ -27,6 +16,26 @@ embed = 0 sharp = 0 +/obj/item/projectile/bullet/weakbullet/booze + embed = 0 + +/obj/item/projectile/bullet/weakbullet/booze/on_hit(atom/target, blocked = 0) + if(..(target, blocked)) + var/mob/living/M = target + M.dizziness += 20 + M.slurring += 20 + M.confused += 20 + M.eye_blurry += 20 + M.drowsyness += 20 + for(var/datum/reagent/ethanol/A in M.reagents.reagent_list) + M.AdjustParalysis(2) + M.dizziness += 10 + M.slurring += 10 + M.confused += 10 + M.eye_blurry += 10 + M.drowsyness += 10 + A.volume += 5 //Because we can + /obj/item/projectile/bullet/weakbullet2 //detective revolver instastuns, but multiple shots are better for keeping punks down damage = 5 weaken = 3 @@ -44,6 +53,15 @@ damage = 15 damage_type = TOX +/obj/item/projectile/bullet/incendiary + +/obj/item/projectile/bullet/incendiary/on_hit(var/atom/target, var/blocked = 0) + ..() + if(istype(target, /mob/living/carbon)) + var/mob/living/carbon/M = target + M.adjust_fire_stacks(1) + M.IgniteMob() + /obj/item/projectile/bullet/incendiary/firebullet damage = 10 @@ -55,15 +73,34 @@ name = "pellet" damage = 15 -/obj/item/projectile/bullet/blank - name = "blankshot" - nodamage = 1 - /obj/item/projectile/bullet/pellet/weak + damage = 6 + +/obj/item/projectile/bullet/pellet/weak/New() + range = rand(8) + +/obj/item/projectile/bullet/pellet/weak/on_range() + var/datum/effect/system/spark_spread/sparks = new /datum/effect/system/spark_spread + sparks.set_up(1, 1, src) + sparks.start() + ..() + +/obj/item/projectile/bullet/pellet/overload damage = 3 -/obj/item/projectile/bullet/pellet/random/New() - damage = rand(10) +/obj/item/projectile/bullet/pellet/overload/New() + range = rand(10) + +/obj/item/projectile/bullet/pellet/overload/on_hit(atom/target, blocked = 0) + ..() + explosion(target, 0, 0, 2) + +/obj/item/projectile/bullet/pellet/overload/on_range() + explosion(src, 0, 0, 2) + var/datum/effect/system/spark_spread/sparks = new /datum/effect/system/spark_spread + sparks.set_up(3, 3, src) + sparks.start() + ..() /obj/item/projectile/bullet/midbullet damage = 20 @@ -89,39 +126,11 @@ weaken = 5 stutter = 5 jitter = 20 - icon_state = "spark" range = 7 embed = 0 sharp = 0 - - -/obj/item/projectile/bullet/weakbullet/booze - embed = 0 - on_hit(var/atom/target, var/blocked = 0) - if(..(target, blocked)) - var/mob/living/M = target - M.dizziness += 20 - M.slurring += 20 - M.confused += 20 - M.eye_blurry += 20 - M.drowsyness += 20 - for(var/datum/reagent/ethanol/A in M.reagents.reagent_list) - M.AdjustParalysis(2) - M.dizziness += 10 - M.slurring += 10 - M.confused += 10 - M.eye_blurry += 10 - M.drowsyness += 10 - A.volume += 5 //Because we can - -/obj/item/projectile/bullet/incendiary - -/obj/item/projectile/bullet/incendiary/on_hit(var/atom/target, var/blocked = 0) - ..() - if(istype(target, /mob/living/carbon)) - var/mob/living/carbon/M = target - M.adjust_fire_stacks(1) - M.IgniteMob() + icon_state = "spark" + color = "#FFFF00" /obj/item/projectile/bullet/incendiary/shell name = "incendiary slug" @@ -130,8 +139,9 @@ /obj/item/projectile/bullet/incendiary/shell/Move() ..() var/turf/location = get_turf(src) - new /obj/effect/hotspot(location) - location.hotspot_expose(700, 50, 1) + if(location) + new /obj/effect/hotspot(location) + location.hotspot_expose(700, 50, 1) /obj/item/projectile/bullet/incendiary/shell/dragonsbreath name = "dragonsbreath round" @@ -157,7 +167,26 @@ ..() SpinAnimation() +/obj/item/projectile/bullet/meteorshot/weak + damage = 10 + weaken = 4 + stun = 4 +/obj/item/projectile/bullet/honker + damage = 0 + weaken = 5 + stun = 5 + forcedodge = 1 + nodamage = 1 + pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE + hitsound = 'sound/items/bikehorn.ogg' + icon = 'icons/obj/harvest.dmi' + icon_state = "banana" + range = 200 + +/obj/item/projectile/bullet/honker/New() + ..() + SpinAnimation() /obj/item/projectile/bullet/mime damage = 0 @@ -168,7 +197,7 @@ /obj/item/projectile/bullet/mime/on_hit(var/atom/target, var/blocked = 0) ..(target, blocked) - if(istype(target, /mob/living/carbon)) + if(iscarbon(target)) var/mob/living/carbon/M = target M.silent = max(M.silent, 10) else if(istype(target, /obj/mecha/combat/honker)) @@ -184,32 +213,38 @@ damage = 6 embed = 0 sharp = 0 + var/piercing = 0 - New() - ..() - flags |= NOREACT - create_reagents(50) +/obj/item/projectile/bullet/dart/New() + ..() + flags |= NOREACT + create_reagents(50) - on_hit(var/atom/target, var/blocked = 0, var/hit_zone) - if(istype(target, /mob/living/carbon)) - var/mob/living/carbon/M = target +/obj/item/projectile/bullet/dart/on_hit(var/atom/target, var/blocked = 0, var/hit_zone) + if(iscarbon(target)) + var/mob/living/carbon/M = target + if(blocked != 100) if(M.can_inject(null,0,hit_zone)) // Pass the hit zone to see if it can inject by whether it hit the head or the body. + ..() reagents.reaction(M, INGEST) reagents.trans_to(M, reagents.total_volume) return 1 else + blocked = 100 target.visible_message("The [name] was deflected!", \ - "You were protected against the [name]!") - flags &= ~NOREACT - reagents.handle_reactions() - return 1 + "You were protected against the [name]!") + ..(target, blocked, hit_zone) + flags &= ~NOREACT + reagents.handle_reactions() + return 1 /obj/item/projectile/bullet/dart/metalfoam - New() - ..() - reagents.add_reagent("aluminum", 15) - reagents.add_reagent("fluorosurfactant", 5) - reagents.add_reagent("sacid", 5) + +/obj/item/projectile/bullet/dart/metalfoam/New() + ..() + reagents.add_reagent("aluminum", 15) + reagents.add_reagent("fluorosurfactant", 5) + reagents.add_reagent("sacid", 5) //This one is for future syringe guns update /obj/item/projectile/bullet/dart/syringe @@ -218,9 +253,9 @@ icon_state = "syringeproj" /obj/item/projectile/bullet/dart/syringe/tranquilizer - New() - ..() - reagents.add_reagent("haloperidol", 15) +/obj/item/projectile/bullet/dart/syringe/tranquilizer/New() + ..() + reagents.add_reagent("haloperidol", 15) /obj/item/projectile/bullet/neurotoxin name = "neurotoxin spit" @@ -231,5 +266,17 @@ /obj/item/projectile/bullet/neurotoxin/on_hit(var/atom/target, var/blocked = 0) if(isalien(target)) - return 0 - ..() // Execute the rest of the code. + weaken = 0 + nodamage = 1 + . = ..() // Execute the rest of the code. + +/obj/item/projectile/bullet/cap + name = "cap" + damage = 0 + nodamage = 1 + embed = 0 + sharp = 0 + +/obj/item/projectile/bullet/cap/fire() + loc = null + qdel(src) diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm index b5665a6af1c..79ffc1d0898 100644 --- a/code/modules/projectiles/projectile/energy.dm +++ b/code/modules/projectiles/projectile/energy.dm @@ -5,7 +5,6 @@ damage_type = BURN flag = "energy" - /obj/item/projectile/energy/electrode name = "electrode" icon_state = "spark" @@ -20,26 +19,23 @@ //Damage will be handled on the MOB side, to prevent window shattering. /obj/item/projectile/energy/electrode/on_hit(var/atom/target, var/blocked = 0) - if(!proj_hit) - if(!ismob(target) || blocked >= 2) //Fully blocked by mob or collided with dense object - burst into sparks! - var/datum/effect/system/spark_spread/sparks = new /datum/effect/system/spark_spread - sparks.set_up(1, 1, src) - sparks.start() - proj_hit = 1 - else if(iscarbon(target)) - var/mob/living/carbon/C = target - if(HULK in C.mutations) - C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) - else if(C.status_flags & CANWEAKEN) - C.do_jitter_animation(jitter) - ..() - -/obj/item/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet - if(!proj_hit) + . = ..() + if(!ismob(target) || blocked >= 100) //Fully blocked by mob or collided with dense object - burst into sparks! var/datum/effect/system/spark_spread/sparks = new /datum/effect/system/spark_spread sparks.set_up(1, 1, src) sparks.start() - proj_hit = 1 + else if(iscarbon(target)) + var/mob/living/carbon/C = target + if(HULK in C.mutations) + C.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" )) + else if(C.status_flags & CANWEAKEN) + spawn(5) + C.do_jitter_animation(jitter) + +/obj/item/projectile/energy/electrode/on_range() //to ensure the bolt sparks when it reaches the end of its range if it didn't hit a target yet + var/datum/effect/system/spark_spread/sparks = new /datum/effect/system/spark_spread + sparks.set_up(1, 1, src) + sparks.start() ..() /obj/item/projectile/energy/declone @@ -49,7 +45,6 @@ damage_type = CLONE irradiate = 10 - /obj/item/projectile/energy/dart name = "dart" icon_state = "toxin" @@ -63,7 +58,6 @@ icon_state = "toxin" damage = 10 damage_type = TOX - nodamage = 0 weaken = 5 stutter = 5 @@ -77,12 +71,28 @@ stutter = 5 /obj/item/projectile/energy/bolt/large - name = "largebolt" damage = 20 -/obj/item/projectile/energy/plasma +/obj/item/projectile/energy/shock_revolver + name = "shock bolt" + icon_state = "purple_laser" + var/chain + +/obj/item/ammo_casing/energy/shock_revolver/ready_proj(atom/target, mob/living/user, quiet, zone_override = "") + ..() + var/obj/item/projectile/energy/shock_revolver/P = BB + spawn(1) + P.chain = P.Beam(user,icon_state="purple_lightning",icon = 'icons/effects/effects.dmi',time=1000, maxdistance = 30) + +/obj/item/projectile/energy/shock_revolver/on_hit(atom/target) + . = ..() + if(isliving(target)) + tesla_zap(src, 3, 10000) + qdel(chain) + +/obj/item/projectile/energy/toxplasma name = "plasma bolt" icon_state = "energy" damage = 20 damage_type = TOX - irradiate = 20 \ No newline at end of file + irradiate = 20 diff --git a/code/modules/projectiles/projectile/force.dm b/code/modules/projectiles/projectile/force.dm index 2fab1a4da18..4e5c6d27700 100644 --- a/code/modules/projectiles/projectile/force.dm +++ b/code/modules/projectiles/projectile/force.dm @@ -10,21 +10,8 @@ name = "force bolt" /obj/item/projectile/forcebolt/on_hit(var/atom/target, var/blocked = 0) - - var/obj/T = target - var/throwdir = get_dir(firer,target) - T.throw_at(get_edge_target_turf(target, throwdir),10,10) - return 1 - -/* -/obj/item/projectile/forcebolt/strong/on_hit(var/atom/target, var/blocked = 0) - - // NONE OF THIS WORKS. DO NOT USE. - var/throwdir = null - - for(var/mob/M in hearers(2, src)) - if(M.loc != src.loc) - throwdir = get_dir(src,target) - M.throw_at(get_edge_target_turf(M, throwdir),15,1) - return ..() -*/ \ No newline at end of file + . = ..() + if(blocked < 100) + var/obj/T = target + var/throwdir = get_dir(firer,target) + T.throw_at(get_edge_target_turf(target, throwdir),10,10) diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index ecbbfb530f8..1d1f6dc93a8 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -4,15 +4,14 @@ damage = 0 damage_type = OXY nodamage = 1 + armour_penetration = 100 flag = "magic" /obj/item/projectile/magic/death name = "bolt of death" icon_state = "pulse1_bl" - damage = 9001 - damage_type = OXY - nodamage = 0 - flag = "magic" + damage_type = BURN //OXY does not kill IPCs + damage = 50000 /obj/item/projectile/magic/fireball name = "bolt of fireball" @@ -20,9 +19,22 @@ damage = 10 damage_type = BRUTE nodamage = 0 - flag = "magic" + +/obj/item/projectile/magic/fireball/Range() + var/turf/T1 = get_step(src,turn(dir, -45)) + var/turf/T2 = get_step(src,turn(dir, 45)) + var/mob/living/L = locate(/mob/living) in T1 //if there's a mob alive in our front right diagonal, we hit it. + if(L && L.stat != DEAD) + Bump(L) //Magic Bullet #teachthecontroversy + return + L = locate(/mob/living) in T2 + if(L && L.stat != DEAD) + Bump(L) + return + ..() /obj/item/projectile/magic/fireball/on_hit(var/target) + . = ..() var/turf/T = get_turf(target) explosion(T, -1, 0, 2, 3, 0, flame_range = 2) if(ismob(target)) //multiple flavors of pain @@ -32,35 +44,13 @@ /obj/item/projectile/magic/resurrection name = "bolt of resurrection" icon_state = "ion" - damage = 0 - damage_type = OXY - nodamage = 1 - flag = "magic" /obj/item/projectile/magic/resurrection/on_hit(var/mob/living/carbon/target) - - if(istype(target,/mob)) + . = ..() + if(ismob(target)) var/old_stat = target.stat - if(isanimal(target) && target.stat == DEAD) - var/mob/living/simple_animal/O = target - var/mob/living/simple_animal/A = new O.type(O.loc) - A.real_name = O.real_name - A.name = O.name - if(iscorgi(O)) - var/mob/living/simple_animal/pet/corgi/C = O - if(C.inventory_head) - C.inventory_head.loc = C.loc - if(C.inventory_back) - C.inventory_back.loc = C.loc - if(O.mind) - O.mind.transfer_to(A) - else - A.key = O.key - qdel(O) - target = A - else - target.revive() - target.suiciding = 0 + target.suiciding = 0 + target.revive() if(!target.ckey) for(var/mob/dead/observer/ghost in player_list) if(target.real_name == ghost.real_name) @@ -74,14 +64,11 @@ /obj/item/projectile/magic/teleport name = "bolt of teleportation" icon_state = "bluespace" - damage = 0 - damage_type = OXY - nodamage = 1 - flag = "magic" var/inner_tele_radius = 0 var/outer_tele_radius = 6 /obj/item/projectile/magic/teleport/on_hit(var/mob/target) + . = ..() var/teleammount = 0 var/teleloc = target if(!isturf(target)) @@ -97,37 +84,46 @@ /obj/item/projectile/magic/door name = "bolt of door creation" icon_state = "energy" - damage = 0 - damage_type = OXY - nodamage = 1 - flag = "magic" + var/list/door_types = list(/obj/structure/mineral_door/wood,/obj/structure/mineral_door/iron,/obj/structure/mineral_door/silver,\ + /obj/structure/mineral_door/gold,/obj/structure/mineral_door/uranium,/obj/structure/mineral_door/sandstone,/obj/structure/mineral_door/transparent/plasma,\ + /obj/structure/mineral_door/transparent/diamond) /obj/item/projectile/magic/door/on_hit(var/atom/target) + . = ..() var/atom/T = target.loc - if(isturf(target)) - if(target.density) - new /obj/structure/mineral_door/wood(target) - target:ChangeTurf(/turf/simulated/floor/plating) - else if (isturf(T)) - if(T.density) - new /obj/structure/mineral_door/wood(T) - T:ChangeTurf(/turf/simulated/floor/plating) + if(isturf(target) && target.density) + CreateDoor(target) + else if (isturf(T) && T.density) + CreateDoor(T) + else if(istype(target, /obj/machinery/door)) + OpenDoor(target) + +/obj/item/projectile/magic/door/proc/CreateDoor(turf/T) + var/door_type = pick(door_types) + var/obj/structure/mineral_door/D = new door_type(T) + T.ChangeTurf(/turf/simulated/floor/plasteel) + D.Open() + +/obj/item/projectile/magic/door/proc/OpenDoor(var/obj/machinery/door/D) + if(istype(D,/obj/machinery/door/airlock)) + var/obj/machinery/door/airlock/A = D + A.locked = 0 + D.open() /obj/item/projectile/magic/change name = "bolt of change" icon_state = "ice_1" - damage = 0 damage_type = BURN - nodamage = 1 - flag = "magic" /obj/item/projectile/magic/change/on_hit(var/atom/change) + . = ..() wabbajack(change) proc/wabbajack(mob/living/M) if(istype(M)) if(istype(M, /mob/living) && M.stat != DEAD) - if(M.notransform) return + if(M.notransform) + return M.notransform = 1 M.canmove = 0 M.icon = null @@ -136,7 +132,9 @@ proc/wabbajack(mob/living/M) if(istype(M, /mob/living/silicon/robot)) var/mob/living/silicon/robot/Robot = M - if(Robot.mmi) qdel(Robot.mmi) + if(Robot.mmi) + qdel(Robot.mmi) + Robot.notify_ai(1) else if(ishuman(M)) var/mob/living/carbon/human/H = M @@ -146,7 +144,8 @@ proc/wabbajack(mob/living/M) for(var/i in H.internal_organs) qdel(i) for(var/obj/item/W in M) - M.unEquip(W) + M.unEquip(W, 1) + qdel(W) var/mob/living/new_mob @@ -166,8 +165,6 @@ proc/wabbajack(mob/living/M) Robot.mmi.transfer_identity(M) //Does not transfer key/client. if("slime") new_mob = new /mob/living/carbon/slime(M.loc) -/* if(prob(50)) - new_mob.is_adult = 1*/ new_mob.universal_speak = 1 if("xeno") if(prob(50)) @@ -175,14 +172,6 @@ proc/wabbajack(mob/living/M) else new_mob = new /mob/living/carbon/alien/humanoid/sentinel(M.loc) new_mob.universal_speak = 1 - - /*var/alien_caste = pick("Hunter","Sentinel","Drone","Larva") - switch(alien_caste) - if("Hunter") new_mob = new /mob/living/carbon/alien/humanoid/hunter(M.loc) - if("Sentinel") new_mob = new /mob/living/carbon/alien/humanoid/sentinel(M.loc) - if("Drone") new_mob = new /mob/living/carbon/alien/humanoid/drone(M.loc) - else new_mob = new /mob/living/carbon/alien/larva(M.loc) - new_mob.universal_speak = 1*/ if("animal") if(prob(50)) var/beast = pick("carp","bear","mushroom","statue", "bat", "goat", "tomato") @@ -225,7 +214,6 @@ proc/wabbajack(mob/living/M) randomize = picked_species var/datum/preferences/A = new() //Randomize appearance for the human A.copy_to(new_mob) - else return @@ -246,13 +234,10 @@ proc/wabbajack(mob/living/M) /obj/item/projectile/magic/animate name = "bolt of animation" icon_state = "red_1" - damage = 0 damage_type = BURN - nodamage = 1 - flag = "magic" /obj/item/projectile/magic/animate/Bump(var/atom/change) - . = ..() + ..() if(istype(change, /obj/item) || istype(change, /obj/structure) && !is_type_in_list(change, protected_objects)) if(istype(change, /obj/structure/closet/statue)) for(var/mob/living/carbon/human/H in change.contents) @@ -273,4 +258,4 @@ proc/wabbajack(mob/living/M) else if(istype(change, /mob/living/simple_animal/hostile/mimic/copy)) // Change our allegiance! var/mob/living/simple_animal/hostile/mimic/copy/C = change - C.ChangeOwner(firer) \ No newline at end of file + C.ChangeOwner(firer) diff --git a/code/modules/projectiles/projectile/reusable.dm b/code/modules/projectiles/projectile/reusable.dm index 81defd55743..12e7b30c759 100644 --- a/code/modules/projectiles/projectile/reusable.dm +++ b/code/modules/projectiles/projectile/reusable.dm @@ -1,42 +1,63 @@ /obj/item/projectile/bullet/reusable name = "reusable bullet" desc = "How do you even reuse a bullet?" - var/obj/item/ammo_casing/caseless/ammo_type = /obj/item/ammo_casing/caseless/ - var/hit = 0 + var/ammo_type = /obj/item/ammo_casing/caseless/ + var/dropped = 0 -/obj/item/projectile/bullet/reusable/on_hit(var/atom/target, var/blocked = 0) - if(!proj_hit) - proj_hit = 1 - if (src.contents.len) - var/obj/content - for(content in src.contents) - content.loc = src.loc - else - new ammo_type(src.loc) - ..() +/obj/item/projectile/bullet/reusable/on_hit(atom/target, blocked = 0) + . = ..() + handle_drop() /obj/item/projectile/bullet/reusable/on_range() - if(!proj_hit) - if (src.contents.len) - var/obj/content - for(content in src.contents) - content.loc = src.loc - else - new ammo_type(src.loc) + handle_drop() ..() +/obj/item/projectile/bullet/reusable/proc/handle_drop() + if(!dropped) + new ammo_type(loc) + dropped = 1 + +/obj/item/projectile/bullet/reusable/magspear + name = "magnetic spear" + desc = "WHITE WHALE, HOLY GRAIL" + damage = 30 //takes 3 spears to kill a mega carp, one to kill a normal carp + icon_state = "magspear" + ammo_type = /obj/item/ammo_casing/caseless/magspear + /obj/item/projectile/bullet/reusable/foam_dart name = "foam dart" desc = "I hope you're wearing eye protection." damage = 0 // It's a damn toy. damage_type = OXY nodamage = 1 - edge = 0 - embed = 0 - icon = 'icons/obj/toyguns.dmi' + icon = 'icons/obj/guns/toy.dmi' icon_state = "foamdart" ammo_type = /obj/item/ammo_casing/caseless/foam_dart - range = 10 + range = 10 + var/obj/item/weapon/pen/pen = null + edge = 0 + embed = 0 + +/obj/item/projectile/bullet/reusable/foam_dart/handle_drop() + if(dropped) + return + dropped = 1 + var/obj/item/ammo_casing/caseless/foam_dart/newdart = new ammo_type(loc) + var/obj/item/ammo_casing/caseless/foam_dart/old_dart = ammo_casing + newdart.modified = old_dart.modified + if(pen) + var/obj/item/projectile/bullet/reusable/foam_dart/newdart_FD = newdart.BB + newdart_FD.pen = pen + pen.loc = newdart_FD + pen = null + newdart.BB.damage = damage + newdart.BB.nodamage = nodamage + newdart.BB.damage_type = damage_type + newdart.update_icon() + +/obj/item/projectile/bullet/reusable/foam_dart/Destroy() + pen = null + return ..() /obj/item/projectile/bullet/reusable/foam_dart/riot name = "riot foam dart" diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index ed64d73df4e..0d0eba709ff 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -6,15 +6,15 @@ nodamage = 1 flag = "energy" - - on_hit(var/atom/target, var/blocked = 0) - empulse(target, 1, 1) - return 1 - +/obj/item/projectile/ion/on_hit(var/atom/target, var/blocked = 0) + ..() + empulse(target, 1, 1) + return 1 /obj/item/projectile/ion/weak /obj/item/projectile/ion/weak/on_hit(atom/target, blocked = 0) + ..() empulse(target, 0, 0) return 1 @@ -26,9 +26,10 @@ sharp = 1 edge = 1 - on_hit(var/atom/target, var/blocked = 0) - explosion(target, -1, 0, 2) - return 1 +/obj/item/projectile/bullet/gyro/on_hit(var/atom/target, var/blocked = 0) + ..() + explosion(target, -1, 0, 2) + return 1 /obj/item/projectile/bullet/a40mm name ="40mm grenade" @@ -43,18 +44,17 @@ return 1 /obj/item/projectile/temp - name = "freeze beam" + name = "temperature beam" icon_state = "temp_4" damage = 0 damage_type = BURN nodamage = 1 flag = "energy" - var/temperature = 300 - var/obj/item/weapon/gun/energy/temperature/T = null + var/temperature = null + pass_flags = PASSTABLE | PASSGLASS | PASSGRILLE - OnFired() - T = shot_from - temperature = T.temperature +/obj/item/projectile/temp/New() + spawn(1) switch(temperature) if(501 to INFINITY) name = "searing beam" //if emagged @@ -86,47 +86,40 @@ else name = "temperature beam"//failsafe icon_state = "temp_4" + ..() - on_hit(var/atom/target, var/blocked = 0)//These two could likely check temp protection on the mob - if(istype(target, /mob/living)) - var/mob/living/M = target - M.bodytemperature = temperature - if(temperature > 500)//emagged - M.adjust_fire_stacks(0.5) - M.IgniteMob() - playsound(M.loc, 'sound/effects/bamf.ogg', 50, 0) - return 1 +/obj/item/projectile/temp/on_hit(var/atom/target, var/blocked = 0)//These two could likely check temp protection on the mob + ..() + if(isliving(target)) + var/mob/living/M = target + M.bodytemperature = temperature + if(temperature > 500)//emagged + M.adjust_fire_stacks(0.5) + M.IgniteMob() + playsound(M.loc, 'sound/effects/bamf.ogg', 50, 0) + return 1 /obj/item/projectile/meteor name = "meteor" icon = 'icons/obj/meteor.dmi' - icon_state = "smallf" + icon_state = "small" damage = 0 damage_type = BRUTE nodamage = 1 flag = "bullet" - Bump(atom/A as mob|obj|turf|area) - if(A == firer) - loc = A.loc - return - - sleep(-1) //Might not be important enough for a sleep(-1) but the sleep/spawn itself is necessary thanks to explosions and metoerhits - - if(src)//Do not add to this if() statement, otherwise the meteor won't delete them - if(A) - - A.ex_act(2) - playsound(src.loc, 'sound/effects/meteorimpact.ogg', 40, 1) - - for(var/mob/M in range(10, src)) - if(!M.stat && !istype(M, /mob/living/silicon/ai))\ - shake_camera(M, 3, 1) - qdel(src) - return 1 - else - return 0 +/obj/item/projectile/meteor/Bump(atom/A, yes) + if(yes) + return + if(A == firer) + loc = A.loc + return + playsound(loc, 'sound/effects/meteorimpact.ogg', 40, 1) + for(var/mob/M in urange(10, src)) + if(!M.stat) + shake_camera(M, 3, 1) + qdel(src) /obj/item/projectile/energy/floramut name = "alpha somatoray" @@ -136,36 +129,31 @@ nodamage = 1 flag = "energy" - on_hit(var/atom/target, var/blocked = 0) - var/mob/living/M = target - if(ishuman(target)) - var/mob/living/carbon/human/H = M - if((H.species.flags & IS_PLANT) && (M.nutrition < 500)) - if(prob(15)) - M.apply_effect((rand(30,80)),IRRADIATE) - M.Weaken(5) - for (var/mob/V in viewers(src)) - V.show_message("\red [M] writhes in pain as \his vacuoles boil.", 3, "\red You hear the crunching of leaves.", 2) - if(prob(35)) - // for (var/mob/V in viewers(src)) //Public messages commented out to prevent possible metaish genetics experimentation and stuff. - Cheridan - // V.show_message("\red [M] is mutated by the radiation beam.", 3, "\red You hear the snapping of twigs.", 2) - if(prob(80)) - randmutb(M) - domutcheck(M,null) - else - randmutg(M) - domutcheck(M,null) +/obj/item/projectile/energy/floramut/on_hit(var/atom/target, var/blocked = 0) + ..() + var/mob/living/M = target + if(ishuman(target)) + var/mob/living/carbon/human/H = M + if((H.species.flags & IS_PLANT) && (M.nutrition < 500)) + if(prob(15)) + M.apply_effect((rand(30,80)),IRRADIATE) + M.Weaken(5) + for (var/mob/V in viewers(src)) + V.show_message("[M] writhes in pain as \his vacuoles boil.", 3, "You hear the crunching of leaves.", 2) + if(prob(35)) + if(prob(80)) + randmutb(M) + domutcheck(M,null) else - M.adjustFireLoss(rand(5,15)) - M.show_message("\red The radiation beam singes you!") - // for (var/mob/V in viewers(src)) - // V.show_message("\red [M] is singed by the radiation beam.", 3, "\red You hear the crackle of burning leaves.", 2) - else if(istype(target, /mob/living/carbon/)) - // for (var/mob/V in viewers(src)) - // V.show_message("The radiation beam dissipates harmlessly through [M]", 3) - M.show_message("\blue The radiation beam dissipates harmlessly through your body.") - else - return 1 + randmutg(M) + domutcheck(M,null) + else + M.adjustFireLoss(rand(5,15)) + M.show_message("The radiation beam singes you!") + else if(istype(target, /mob/living/carbon/)) + M.show_message("The radiation beam dissipates harmlessly through your body.") + else + return 1 /obj/item/projectile/energy/florayield name = "beta somatoray" @@ -175,40 +163,42 @@ nodamage = 1 flag = "energy" - on_hit(var/atom/target, var/blocked = 0) - var/mob/M = target - if(ishuman(target)) //These rays make plantmen fat. - var/mob/living/carbon/human/H = M - if((H.species.flags & IS_PLANT) && (M.nutrition < 500)) - M.nutrition += 30 - else if (istype(target, /mob/living/carbon/)) - M.show_message("\blue The radiation beam dissipates harmlessly through your body.") - else - return 1 +/obj/item/projectile/energy/florayield/on_hit(var/atom/target, var/blocked = 0) + ..() + var/mob/M = target + if(ishuman(target)) //These rays make plantmen fat. + var/mob/living/carbon/human/H = M + if((H.species.flags & IS_PLANT) && (M.nutrition < 500)) + M.nutrition += 30 + else if (istype(target, /mob/living/carbon/)) + M.show_message("The radiation beam dissipates harmlessly through your body.") + else + return 1 /obj/item/projectile/beam/mindflayer name = "flayer ray" - on_hit(var/atom/target, var/blocked = 0) - if(ishuman(target)) - var/mob/living/carbon/human/M = target - M.adjustBrainLoss(20) - M.hallucination += 20 +/obj/item/projectile/beam/mindflayer/on_hit(var/atom/target, var/blocked = 0) + . = ..() + if(ishuman(target)) + var/mob/living/carbon/human/M = target + M.adjustBrainLoss(20) + M.hallucination += 20 /obj/item/projectile/clown name = "snap-pop" icon = 'icons/obj/toy.dmi' icon_state = "snappop" - Bump(atom/A as mob|obj|turf|area) - var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - new /obj/effect/decal/cleanable/ash(src.loc) - src.visible_message("\red The [src.name] explodes!","\red You hear a snap!") - playsound(src, 'sound/effects/snap.ogg', 50, 1) - qdel(src) +/obj/item/projectile/clown/Bump(atom/A as mob|obj|turf|area) + var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread + s.set_up(3, 1, src) + s.start() + new /obj/effect/decal/cleanable/ash(loc) + visible_message("The [name] explodes!","You hear a snap!") + playsound(src, 'sound/effects/snap.ogg', 50, 1) + qdel(src) /obj/item/projectile/kinetic name = "kinetic force" @@ -239,11 +229,9 @@ obj/item/projectile/kinetic/New() damage *= 4 ..() -/obj/item/projectile/kinetic/Range() - range-- - if(range <= 0) - new /obj/item/effect/kinetic_blast(src.loc) - qdel(src) +/obj/item/projectile/kinetic/on_range() + new /obj/effect/kinetic_blast(loc) + ..() /obj/item/projectile/kinetic/on_hit(atom/target) . = ..() @@ -251,23 +239,57 @@ obj/item/projectile/kinetic/New() if(istype(target_turf, /turf/simulated/mineral)) var/turf/simulated/mineral/M = target_turf M.gets_drilled(firer) - new /obj/item/effect/kinetic_blast(target_turf) - if(src.splash) + new /obj/effect/kinetic_blast(target_turf) + if(splash) for(var/turf/T in range(splash, target_turf)) if(istype(T, /turf/simulated/mineral)) var/turf/simulated/mineral/M = T M.gets_drilled(firer) -/obj/item/effect/kinetic_blast +/obj/effect/kinetic_blast name = "kinetic explosion" icon = 'icons/obj/projectiles.dmi' icon_state = "kinetic_blast" layer = 4.1 -/obj/item/effect/kinetic_blast/New() +/obj/effect/kinetic_blast/New() spawn(4) qdel(src) +/obj/item/projectile/beam/wormhole + name = "bluespace beam" + icon_state = "spark" + hitsound = "sparks" + damage = 3 + var/obj/item/weapon/gun/energy/wormhole_projector/gun + color = "#33CCFF" + +/obj/item/projectile/beam/wormhole/orange + name = "orange bluespace beam" + color = "#FF6600" + +/obj/item/projectile/beam/wormhole/New(var/obj/item/ammo_casing/energy/wormhole/casing) + if(casing) + gun = casing.gun + +/obj/item/projectile/beam/wormhole/on_hit(atom/target) + if(ismob(target)) + var/turf/portal_destination = pick(orange(6, src)) + do_teleport(target, portal_destination) + return ..() + if(!gun) + qdel(src) + gun.create_portal(src) + +/obj/item/projectile/beam/wormhole/on_hit(atom/target) + if(ismob(target)) + var/turf/portal_destination = pick(orange(6, src)) + do_teleport(target, portal_destination) + return ..() + if(!gun) + qdel(src) + gun.create_portal(src) + /obj/item/projectile/bullet/frag12 name ="explosive slug" damage = 25 @@ -278,25 +300,6 @@ obj/item/projectile/kinetic/New() explosion(target, -1, 0, 1) return 1 -/obj/item/projectile/energy/teleport - name = "teleportation burst" - icon_state = "bluespace" - damage = 0 - nodamage = 1 - var/obj/item/weapon/gun/energy/telegun/T = null - var/teleport_target = null - - OnFired() - T = shot_from - teleport_target = T.teleport_target - -/obj/item/projectile/energy/teleport/on_hit(var/atom/target, var/blocked = 0) - if(isliving(target)) - if(teleport_target) - do_teleport(target, teleport_target, 0)//teleport what's in the tile to the beacon - else - do_teleport(target, target, 15) //Otherwise it just warps you off somewhere. - /obj/item/projectile/plasma name = "plasma blast" icon_state = "plasmacutter" @@ -321,8 +324,9 @@ obj/item/projectile/kinetic/New() if(istype(target, /turf/simulated/mineral)) var/turf/simulated/mineral/M = target M.gets_drilled(firer) - range = max(range - 1, 1) - return -1 + Range() + if(range > 0) + return -1 /obj/item/projectile/plasma/adv range = 5 @@ -331,29 +335,19 @@ obj/item/projectile/kinetic/New() damage = 10 range = 6 -/obj/item/projectile/beam/wormhole - name = "bluespace beam" - icon_state = "spark" - hitsound = "sparks" - damage = 3 - var/obj/item/weapon/gun/energy/wormhole_projector/gun = null - color = "#33CCFF" +/obj/item/projectile/energy/teleport + name = "teleportation burst" + icon_state = "bluespace" + damage = 0 + nodamage = 1 + var/teleport_target = null -/obj/item/projectile/beam/wormhole/orange - name = "orange bluespace beam" - color = "#FF6600" - -/obj/item/projectile/beam/wormhole/OnFired() - gun = shot_from - -/obj/item/projectile/beam/wormhole/on_hit(atom/target) - if(ismob(target)) - var/turf/portal_destination = pick(orange(6, src)) - do_teleport(target, portal_destination) - return ..() - if(!gun) - qdel(src) - gun.create_portal(src) +/obj/item/projectile/energy/teleport/on_hit(var/atom/target, var/blocked = 0) + if(isliving(target)) + if(teleport_target) + do_teleport(target, teleport_target, 0)//teleport what's in the tile to the beacon + else + do_teleport(target, target, 15) //Otherwise it just warps you off somewhere. /obj/item/projectile/snowball name = "snowball" @@ -363,6 +357,7 @@ obj/item/projectile/kinetic/New() damage_type = BURN /obj/item/projectile/snowball/on_hit(atom/target) //chilling + . = ..() if(istype(target, /mob/living)) var/mob/living/M = target M.bodytemperature = max(0, M.bodytemperature - 50) //each hit will drop your body temp, so don't get surrounded! @@ -380,9 +375,10 @@ obj/item/projectile/kinetic/New() ..() /obj/item/projectile/ornament/on_hit(atom/target) //knockback + ..() if(istype(target, /turf)) return 0 var/obj/T = target var/throwdir = get_dir(firer,target) T.throw_at(get_edge_target_turf(target, throwdir),10,10) - return 1 \ No newline at end of file + return 1 diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm index 1b2e9a0b3d4..9be9ea9c124 100644 --- a/code/modules/reagents/Chemistry-Holder.dm +++ b/code/modules/reagents/Chemistry-Holder.dm @@ -387,45 +387,48 @@ var/const/INGEST = 2 can_process = 1 return can_process -/datum/reagents/proc/reaction(var/atom/A, var/method=TOUCH, var/volume_modifier=0) - +/datum/reagents/proc/reaction(atom/A, method=TOUCH, volume_modifier = 1) switch(method) if(TOUCH) for(var/datum/reagent/R in reagent_list) if(ismob(A)) - spawn(0) - if(!R) return - var/check = reaction_check(A, R) - if(!check) - continue - else - R.reaction_mob(A, TOUCH, R.volume+volume_modifier) + if(!R) + return + var/check = reaction_check(A, R) + if(!check) + continue + else + R.reaction_mob(A, TOUCH, R.volume*volume_modifier) if(isturf(A)) - spawn(0) - if(!R) return - else R.reaction_turf(A, R.volume+volume_modifier) + if(!R) + return + else + R.reaction_turf(A, R.volume*volume_modifier) if(isobj(A)) - spawn(0) - if(!R) return - else R.reaction_obj(A, R.volume+volume_modifier) + if(!R) + return + else + R.reaction_obj(A, R.volume*volume_modifier) if(INGEST) for(var/datum/reagent/R in reagent_list) if(ismob(A) && R) - spawn(0) - if(!R) return - var/check = reaction_check(A, R) - if(!check) - continue - else - R.reaction_mob(A, INGEST, R.volume+volume_modifier) + if(!R) + return + var/check = reaction_check(A, R) + if(!check) + continue + else + R.reaction_mob(A, INGEST, R.volume*volume_modifier) if(isturf(A) && R) - spawn(0) - if(!R) return - else R.reaction_turf(A, R.volume+volume_modifier) + if(!R) + return + else + R.reaction_turf(A, R.volume*volume_modifier) if(isobj(A) && R) - spawn(0) - if(!R) return - else R.reaction_obj(A, R.volume+volume_modifier) + if(!R) + return + else + R.reaction_obj(A, R.volume*volume_modifier) return /datum/reagents/proc/add_reagent_list(list/list_reagents, list/data=null) // Like add_reagent but you can enter a list. Format it like this: list("toxin" = 10, "beer" = 15) diff --git a/code/modules/reagents/grenade_launcher.dm b/code/modules/reagents/grenade_launcher.dm deleted file mode 100644 index 9b9484ba60e..00000000000 --- a/code/modules/reagents/grenade_launcher.dm +++ /dev/null @@ -1,111 +0,0 @@ - - -/obj/item/weapon/gun/grenadelauncher - name = "grenade launcher" - icon = 'icons/obj/gun.dmi' - icon_state = "riotgun" - item_state = "riotgun" - w_class = 4.0 - throw_speed = 2 - throw_range = 10 - force = 5.0 - var/list/grenades = new/list() - var/max_grenades = 3 - var/ammo_name = "grenade" - var/ammo_type = /obj/item/weapon/grenade - var/unloaded - - materials = list(MAT_METAL=2000) - -/obj/item/weapon/gun/grenadelauncher/examine(mob/user) - if(..(user, 2)) - to_chat(user, "\blue [grenades.len] / [max_grenades] [ammo_name]s.") - -/obj/item/weapon/gun/grenadelauncher/attackby(obj/item/I as obj, mob/user as mob, params) - - if((istype(I, ammo_type))) - if(grenades.len < max_grenades) - user.drop_item() - I.loc = src - grenades += I - to_chat(user, "\blue You put the [ammo_name] in the [name].") - to_chat(user, "\blue [grenades.len] / [max_grenades] [ammo_name]s.") - else - to_chat(usr, "\red The grenade launcher cannot hold more [ammo_name]s.") - -/obj/item/weapon/gun/grenadelauncher/afterattack(obj/target, mob/user , flag) - - if (istype(target, /obj/item/weapon/storage/backpack )) - return - - else if (locate (/obj/structure/table, src.loc)) - return - - else if(target == user) - return - - if(grenades.len) - spawn(0) fire_grenade(target,user) - else - to_chat(usr, "\red The [name] is empty.") - -/obj/item/weapon/gun/grenadelauncher/proc/fire_grenade(atom/target, mob/user) - for(var/mob/O in viewers(world.view, user)) - O.show_message(text("\red [] fired a [ammo_name]!", user), 1) - to_chat(user, "\red You fire the [name]!") - var/obj/item/weapon/grenade/chem_grenade/F = grenades[1] //Now with less copypasta! - grenades -= F - F.loc = user.loc - F.throw_at(target, 30, 2, user) - message_admins("[key_name_admin(user)] fired a [ammo_name] ([F.name]) from a launcher ([name]).") - log_game("[key_name_admin(user)] used a [ammo_name] ([name]).") - F.active = 1 - F.icon_state = initial(icon_state) + "_active" - playsound(user.loc, 'sound/weapons/armbomb.ogg', 75, 1, -3) - spawn(15) - F.prime() - - -/obj/item/weapon/gun/grenadelauncher/piecannon - name = "pie cannon" - icon = 'icons/obj/gun.dmi' - icon_state = "piecannon1" - item_state = "piecannon1" - w_class = 4.0 - throw_speed = 2 - throw_range = 10 - force = 5.0 - clumsy_check = 0 - grenades = new/list() - max_grenades = 5 - ammo_name = "cream pie" - ammo_type = /obj/item/weapon/reagent_containers/food/snacks/pie - -/obj/item/weapon/gun/grenadelauncher/piecannon/New() - ..() - for(var/i=0, i < max_grenades, i++) - var/obj/item/weapon/reagent_containers/food/snacks/pie/P = new /obj/item/weapon/reagent_containers/food/snacks/pie(src) - grenades += P - -/obj/item/weapon/gun/grenadelauncher/piecannon/attackby(obj/item/I as obj, mob/user as mob, params) - if((istype(I, ammo_type))) - if(grenades.len < max_grenades) - user.drop_item() - I.loc = src - grenades += I - to_chat(user, "\blue You put the [ammo_name] in the [name].") - to_chat(user, "\blue [grenades.len] / [max_grenades] [ammo_name]s.") - icon_state = "piecannon1" - else - to_chat(usr, "\red The grenade launcher cannot hold more [ammo_name]s.") - -/obj/item/weapon/gun/grenadelauncher/piecannon/fire_grenade(atom/target, mob/user) - for(var/mob/O in viewers(world.view, user)) - O.show_message(text("\red [] fired a [ammo_name]!", user), 1) - to_chat(user, "\red You fire the [name]!") - var/obj/item/weapon/reagent_containers/food/snacks/pie/P = grenades[1] //Now with less copypasta! - grenades -= P - P.loc = user.loc - P.throw_at(target, 30, 2, user) - if(!grenades.len) - icon_state = "piecannon0" diff --git a/code/modules/reagents/newchem/drinks.dm b/code/modules/reagents/newchem/drinks.dm index 01920c617c3..c09b1a06fba 100644 --- a/code/modules/reagents/newchem/drinks.dm +++ b/code/modules/reagents/newchem/drinks.dm @@ -67,7 +67,7 @@ mix_sound = 'sound/goonstation/misc/drinkfizz.ogg' -/datum/reagent/ethanol/dragons_breath +/datum/reagent/ethanol/dragons_breath //inaccessible to players, but here for admin shennanigans name = "Dragon's Breath" id = "dragonsbreath" description = "Possessing this stuff probably breaks the Geneva convention." @@ -108,15 +108,6 @@ return ..() -/datum/chemical_reaction/dragons_breath - name = "Dragon's Breath" - id = "dragonsbreath" - result = "dragonsbreath" - required_reagents = list("whiskey" = 1, "phlogiston" = 1, "pyrosium" = 1, "fuel" = 1, "ghostchilijuice"= 1) - result_amount = 1 - mix_message = "A tiny mushroom cloud erupts from the container. That's not worrying at all!" - mix_sound = 'sound/effects/meteorimpact.ogg' - // ROBOT ALCOHOL PAST THIS POINT // WOOO! diff --git a/code/modules/reagents/newchem/drugs.dm b/code/modules/reagents/newchem/drugs.dm index 127a37593d1..20607ac87a4 100644 --- a/code/modules/reagents/newchem/drugs.dm +++ b/code/modules/reagents/newchem/drugs.dm @@ -242,10 +242,6 @@ addiction_chance = 60 metabolization_rate = 0.6 -/datum/reagent/methamphetamine/meth2 //for donk pockets - id = "methamphetamine2" - addiction_chance = 0 - /datum/reagent/methamphetamine/on_mob_life(var/mob/living/M as mob) if(!M) M = holder.my_atom if(prob(5)) @@ -337,9 +333,10 @@ var/check = rand(0,100) if(ishuman(M)) var/mob/living/carbon/human/H = M - if(check < 8 && H.h_style != "Very Long Beard") - H.h_style = "Very Long Hair" - H.f_style = "Very Long Beard" + var/obj/item/organ/external/head/head_organ = H.get_organ("head") + if(check < 8 && head_organ.h_style != "Very Long Beard") + head_organ.h_style = "Very Long Hair" + head_organ.f_style = "Very Long Beard" H.update_hair() H.update_fhair() H.visible_message("[H] has a wild look in their eyes!") diff --git a/code/modules/reagents/newchem/food.dm b/code/modules/reagents/newchem/food.dm index e8b5ed3f681..97643169e6f 100644 --- a/code/modules/reagents/newchem/food.dm +++ b/code/modules/reagents/newchem/food.dm @@ -600,45 +600,4 @@ datum/reagent/pepperoni/reaction_mob(var/mob/living/M, var/method=TOUCH, var/vol var/mob/living/carbon/human/H = M if(!H.heart_attack) H.heart_attack = 1 - ..() - -/datum/reagent/ghost_chili_juice - name = "Ghost chili juice" - id = "ghostchilijuice" - description = "Juice from the universe's hottest chilli. Do not consume." - reagent_state = LIQUID - color = "#FF7F32" - -/datum/reagent/ghost_chili_juice/on_mob_life(var/mob/living/M as mob) - if(!M) M = holder.my_atom - if(M.reagents.has_reagent("milk")) - to_chat(M, "The milk stops the burning. Ahhh.") - M.reagents.del_reagent("milk") - M.reagents.del_reagent("ghostchilijuice") - return - if(prob(8)) - to_chat(M, "Oh god! Oh GODD!!") - if(prob(50)) - to_chat(M, "Your throat burns furiously!") - M.emote(pick("scream","cry","choke","gasp")) - M.Stun(1) - if(prob(8)) - to_chat(M, "Why!? WHY!?") - if(prob(8)) - to_chat(M, "ARGHHHH!") - if(prob(33)) - M.visible_message("[M] suddenly and violently vomits!") - M.fakevomit(no_text = 1) - to_chat(M, "Thank goodness. You're not sure how long you could have held out with heat that intense!") - M.reagents.del_reagent("ghostchilijuice") - return - if(prob(10)) - to_chat(M, "OH GOD OH GOD PLEASE NO!!") - if(M.on_fire) - M.adjust_fire_stacks(5) - if(prob(50)) - to_chat(M, "IT BURNS!!!!") - M.visible_message("[M] is consumed in flames!") - M.dust() - return ..() \ No newline at end of file diff --git a/code/modules/reagents/newchem/medicine.dm b/code/modules/reagents/newchem/medicine.dm index aca5897735c..33f04d5e6a8 100644 --- a/code/modules/reagents/newchem/medicine.dm +++ b/code/modules/reagents/newchem/medicine.dm @@ -646,11 +646,14 @@ datum/reagent/strange_reagent metabolization_rate = 0.2 datum/reagent/strange_reagent/reaction_mob(var/mob/living/M as mob, var/method=TOUCH, var/volume) - if(istype(M, /mob/living/simple_animal)) + if(isanimal(M)) if(method == TOUCH) - if(M.stat == DEAD) - M.revive() - M.visible_message("[M] seems to rise from the dead!") + var/mob/living/simple_animal/SM = M + if(SM.stat == DEAD) + SM.revive() + SM.loot.Cut() //no abusing strange reagent for unlimited farming of resources + SM.visible_message("[M] seems to rise from the dead!") + if(istype(M, /mob/living/carbon)) if(method == INGEST) if(M.stat == DEAD) diff --git a/code/modules/reagents/newchem/other.dm b/code/modules/reagents/newchem/other.dm index 7ef7dff6ff5..1e31ba5b506 100644 --- a/code/modules/reagents/newchem/other.dm +++ b/code/modules/reagents/newchem/other.dm @@ -198,12 +198,13 @@ datum/reagent/hair_dye datum/reagent/hair_dye/reaction_mob(var/mob/living/M, var/volume) if(M && ishuman(M)) var/mob/living/carbon/human/H = M - H.r_facial = rand(0,255) - H.g_facial = rand(0,255) - H.b_facial = rand(0,255) - H.r_hair = rand(0,255) - H.g_hair = rand(0,255) - H.b_hair = rand(0,255) + var/obj/item/organ/external/head/head_organ = H.get_organ("head") + head_organ.r_facial = rand(0,255) + head_organ.g_facial = rand(0,255) + head_organ.b_facial = rand(0,255) + head_organ.r_hair = rand(0,255) + head_organ.g_hair = rand(0,255) + head_organ.b_hair = rand(0,255) H.update_hair() H.update_fhair() ..() @@ -228,8 +229,9 @@ datum/reagent/hairgrownium datum/reagent/hairgrownium/reaction_mob(var/mob/living/M, var/volume) if(M && ishuman(M)) var/mob/living/carbon/human/H = M - H.h_style = random_hair_style(H.gender, H.species) - H.f_style = random_facial_hair_style(H.gender, H.species) + var/obj/item/organ/external/head/head_organ = H.get_organ("head") + head_organ.h_style = random_hair_style(H.gender, head_organ.species.name) + head_organ.f_style = random_facial_hair_style(H.gender, head_organ.species.name) H.update_hair() H.update_fhair() ..() @@ -252,12 +254,21 @@ datum/reagent/super_hairgrownium result_amount = 3 mix_message = "The liquid becomes amazingly furry and smells peculiar." -datum/reagent/super_hairgrownium/on_mob_life(var/mob/living/M as mob) - if(!M) M = holder.my_atom +datum/reagent/super_hairgrownium/reaction_mob(var/mob/living/M, var/volume) if(M && ishuman(M)) var/mob/living/carbon/human/H = M - H.h_style = "Very Long Hair" - H.f_style = "Very Long Beard" + var/obj/item/organ/external/head/head_organ = H.get_organ("head") + var/datum/sprite_accessory/tmp_hair_style = hair_styles_list["Very Long Hair"] + var/datum/sprite_accessory/tmp_facial_hair_style = facial_hair_styles_list["Very Long Beard"] + + if(head_organ.species.name in tmp_hair_style.species_allowed) //If 'Very Long Hair' is a style the person's species can have, give it to them. + head_organ.h_style = "Very Long Hair" + else //Otherwise, give them a random hair style. + head_organ.h_style = random_hair_style(H.gender, head_organ.species.name) + if(head_organ.species.name in tmp_facial_hair_style.species_allowed) //If 'Very Long Beard' is a style the person's species can have, give it to them. + head_organ.f_style = "Very Long Beard" + else //Otherwise, give them a random facial hair style. + head_organ.f_style = random_facial_hair_style(H.gender, head_organ.species.name) H.update_hair() H.update_fhair() if(!H.wear_mask || H.wear_mask && !istype(H.wear_mask, /obj/item/clothing/mask/fakemoustache)) diff --git a/code/modules/reagents/newchem/pyro.dm b/code/modules/reagents/newchem/pyro.dm index b4070440ab3..655b8e996eb 100644 --- a/code/modules/reagents/newchem/pyro.dm +++ b/code/modules/reagents/newchem/pyro.dm @@ -293,7 +293,7 @@ datum/reagent/blackpowder/reaction_turf(var/turf/T, var/volume) //oh shit required_reagents = list("potassium" = 1, "sugar" = 1, "phosphorus" = 1) result_amount = 1 mix_message = "The mixture quickly turns into a pall of smoke!" - var/forbidden_reagents = list("sugar", "phosphorus", "potassium") //Do not transfer this stuff through smoke. + var/forbidden_reagents = list("sugar", "phosphorus", "potassium", "stimulants") //Do not transfer this stuff through smoke. /datum/chemical_reaction/smoke/on_reaction(var/datum/reagents/holder, var/created_volume) for(var/f_reagent in forbidden_reagents) @@ -325,7 +325,7 @@ datum/reagent/blackpowder/reaction_turf(var/turf/T, var/volume) //oh shit min_temp = 374 secondary = 1 result_amount = 1 - forbidden_reagents = list() + forbidden_reagents = list("stimulants") mix_sound = null /datum/reagent/sonic_powder diff --git a/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_drink.dm b/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_drink.dm index 4479d24aa7c..c394af15a4e 100644 --- a/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_drink.dm +++ b/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_drink.dm @@ -509,6 +509,14 @@ result_amount = 2 mix_sound = 'sound/goonstation/misc/drinkfizz.ogg' +/datum/chemical_reaction/cafe_mocha + name = "Cafe Mocha" + id = "cafe_mocha" + result = "cafe_mocha" + required_reagents = list("cafe_latte" = 1, "chocolate" = 1) + result_amount = 2 + mix_sound = 'sound/goonstation/misc/drinkfizz.ogg' + /datum/chemical_reaction/acidspit name = "Acid Spit" id = "acidspit" diff --git a/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_food.dm b/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_food.dm index 65b19133fa3..5f96f794b34 100644 --- a/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_food.dm +++ b/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_food.dm @@ -110,6 +110,16 @@ mix_message = "Ice forms as the water freezes." mix_sound = null +/datum/chemical_reaction/water + name = "Water" + id = "water" + result = "water" + required_reagents = list("ice" = 1) + result_amount = 1 + min_temp = 301 // In Space.....ice melts at 82F...don't ask + mix_message = "Water pools as the ice melts." + mix_sound = null + /datum/chemical_reaction/dough name = "Dough" id = "dough" diff --git a/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_slime.dm b/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_slime.dm index e9dd50dcf67..9a48e07e6a5 100644 --- a/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_slime.dm +++ b/code/modules/reagents/oldchem/chemical_reaction/chemical_reaction_slime.dm @@ -510,7 +510,7 @@ feedback_add_details("slime_cores_used","[type]") var/obj/effect/golemrune/Z = new /obj/effect/golemrune Z.forceMove(get_turf(holder.my_atom)) - notify_ghosts("Golem rune created in [get_area(Z)].", 'sound/effects/ghost2.ogg', source = Z) + notify_ghosts("Golem rune created in [get_area(Z)].", source = Z) //Bluespace /datum/chemical_reaction/slimefloor2 diff --git a/code/modules/reagents/oldchem/reagents/_reagent_base.dm b/code/modules/reagents/oldchem/reagents/_reagent_base.dm index 9221c42f0c8..5b755c1ee98 100644 --- a/code/modules/reagents/oldchem/reagents/_reagent_base.dm +++ b/code/modules/reagents/oldchem/reagents/_reagent_base.dm @@ -63,13 +63,11 @@ return /datum/reagent/proc/on_mob_life(var/mob/living/M as mob, var/alien) - if(!istype(M, /mob/living)) // YOU'RE A FUCKING RETARD NEO WHY CAN'T YOU JUST FIX THE PROBLEM ON THE REAGENT - Iamgoofball - return //Noticed runtime errors from facid trying to damage ghosts, this should fix. --NEO - // Certain elements in too large amounts cause side-effects + if(!istype(M)) + return if(holder) - holder.remove_reagent(src.id, metabolization_rate) //By default it slowly disappears. + holder.remove_reagent(id, metabolization_rate) //By default it slowly disappears. current_cycle++ - return // Called when two reagents of the same are mixing. /datum/reagent/proc/on_merge(var/data) diff --git a/code/modules/reagents/oldchem/reagents/drink/reagents_alcohol.dm b/code/modules/reagents/oldchem/reagents/drink/reagents_alcohol.dm index 12e1a554edd..82d46d60519 100644 --- a/code/modules/reagents/oldchem/reagents/drink/reagents_alcohol.dm +++ b/code/modules/reagents/oldchem/reagents/drink/reagents_alcohol.dm @@ -36,8 +36,7 @@ if(ishuman(M) && !M.isSynthetic()) var/mob/living/carbon/human/H = M L = H.get_int_organ(/obj/item/organ/internal/liver) - if(!L || (istype(L) && L.dna.species in list("Skrell", "Neara"))) - d*=5 + d *= L ? L.alcohol_intensity : 5 M.dizziness += dizzy_adj. if(d >= slur_start && d < pass_out) diff --git a/code/modules/reagents/oldchem/reagents/drink/reagents_drink.dm b/code/modules/reagents/oldchem/reagents/drink/reagents_drink.dm index 45e0e2e8ac2..d52743c6ae6 100644 --- a/code/modules/reagents/oldchem/reagents/drink/reagents_drink.dm +++ b/code/modules/reagents/oldchem/reagents/drink/reagents_drink.dm @@ -241,6 +241,12 @@ M.adjustBruteLoss(-1) return +/datum/reagent/drink/coffee/cafe_latte/cafe_mocha + name = "Cafe Mocha" + id = "cafe_mocha" + description = "The perfect blend of coffe, milk, and chocolate." + color = "#673629" + /datum/reagent/drink/tea name = "Tea" id = "tea" diff --git a/code/modules/reagents/oldchem/reagents/reagents_misc.dm b/code/modules/reagents/oldchem/reagents/reagents_misc.dm index 8c3352243eb..889a2011d48 100644 --- a/code/modules/reagents/oldchem/reagents/reagents_misc.dm +++ b/code/modules/reagents/oldchem/reagents/reagents_misc.dm @@ -42,16 +42,6 @@ reagent_state = GAS color = "#808080" // rgb: 128, 128, 128 -/datum/reagent/oxygen/on_mob_life(var/mob/living/M as mob, var/alien) - if(M.stat == 2) return - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.species && (H.species.name == "Vox" || H.species.name =="Vox Armalis")) - M.adjustToxLoss(REAGENTS_METABOLISM) - holder.remove_reagent(src.id, REAGENTS_METABOLISM) //By default it slowly disappears. - return - ..() - /datum/reagent/nitrogen name = "Nitrogen" @@ -60,16 +50,6 @@ reagent_state = GAS color = "#808080" // rgb: 128, 128, 128 -/datum/reagent/nitrogen/on_mob_life(var/mob/living/M as mob, var/alien) - if(M.stat == 2) return - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(H.species && (H.species.name == "Vox" || H.species.name =="Vox Armalis")) - M.adjustOxyLoss(-2*REM) - holder.remove_reagent(src.id, REAGENTS_METABOLISM) //By default it slowly disappears. - return - ..() - /datum/reagent/hydrogen name = "Hydrogen" diff --git a/code/modules/reagents/oldchem/reagents/reagents_water.dm b/code/modules/reagents/oldchem/reagents/reagents_water.dm index df9e0b29b64..11a5759fa5b 100644 --- a/code/modules/reagents/oldchem/reagents/reagents_water.dm +++ b/code/modules/reagents/oldchem/reagents/reagents_water.dm @@ -297,6 +297,13 @@ if(data >= 75 && prob(33)) // 30 units, 150 seconds if (!M.confused) M.confused = 1 M.confused += 3 + if(isvampirethrall(M)) + ticker.mode.remove_vampire_mind(M.mind) + holder.remove_reagent(src.id, src.volume) + M.jitteriness = 0 + M.stuttering = 0 + M.confused = 0 + return if(iscultist(M)) ticker.mode.remove_cultist(M.mind) holder.remove_reagent(src.id, src.volume) // maybe this is a little too perfect and a max() cap on the statuses would be better?? diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm index b92aceb4c79..9d67bb22881 100644 --- a/code/modules/reagents/reagent_containers/borghydro.dm +++ b/code/modules/reagents/reagent_containers/borghydro.dm @@ -2,7 +2,7 @@ /obj/item/weapon/reagent_containers/borghypo name = "Cyborg Hypospray" desc = "An advanced chemical synthesizer and injection system, designed for heavy-duty medical equipment." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/obj/hypo.dmi' item_state = "hypo" icon_state = "borghypo" amount_per_transfer_from_this = 5 @@ -23,7 +23,7 @@ /obj/item/weapon/reagent_containers/borghypo/crisis reagent_ids = list("salglu_solution", "epinephrine", "sal_acid") - + /obj/item/weapon/reagent_containers/borghypo/syndicate name = "syndicate cyborg hypospray" desc = "An experimental piece of Syndicate technology used to produce powerful restorative nanites used to very quickly restore injuries of all types. Also metabolizes potassium iodide, for radiation poisoning, and morphine, for offense." diff --git a/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm b/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm index c7351d1c3fd..981bb7148a2 100644 --- a/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm +++ b/code/modules/reagents/reagent_containers/food/drinks/drinkingglass.dm @@ -459,6 +459,10 @@ icon_state = "cafe_latte" name = "Cafe Latte" desc = "A nice, strong and refreshing beverage while you are reading." + if("cafe_mocha") + icon_state = "cafe_latte" + name = "Cafe Mocha" + desc = "The perfect blend of coffe, milk, and chocolate." if("acidspit") icon_state = "acidspitglass" name = "Acid Spit" diff --git a/code/modules/reagents/reagent_containers/food/snacks.dm b/code/modules/reagents/reagent_containers/food/snacks.dm index 902892d3f7e..8538db0b13d 100644 --- a/code/modules/reagents/reagent_containers/food/snacks.dm +++ b/code/modules/reagents/reagent_containers/food/snacks.dm @@ -25,7 +25,7 @@ to_chat(user, "You finish eating \the [src].") user.visible_message("[user] finishes eating \the [src].") user.unEquip(src) //so icons update :[ - + Post_Consume(M) if(trash) if(ispath(trash,/obj/item)) var/obj/item/TrashItem = new trash(user) @@ -35,6 +35,9 @@ qdel(src) return +/obj/item/weapon/reagent_containers/food/snacks/proc/Post_Consume(mob/living/M) + return + /obj/item/weapon/reagent_containers/food/snacks/attack_self(mob/user as mob) return @@ -756,27 +759,32 @@ desc = "The food of choice for the seasoned traitor." icon_state = "donkpocket" filling_color = "#DEDEAB" + New() ..() reagents.add_reagent("nutriment", 4) - reagents.add_reagent("omnizine", 4) + + Post_Consume(mob/living/M) + M.reagents.add_reagent("omnizine", 15) /obj/item/weapon/reagent_containers/food/snacks/syndidonkpocket name = "Donk-pocket" desc = "This donk-pocket is emitting a small amount of heat." icon_state = "donkpocket" filling_color = "#DEDEAB" - volume = 90 bitesize = 100 //nom the whole thing at once. New() ..() - reagents.add_reagent("omnizine", 15) - reagents.add_reagent("teporone", 15) - reagents.add_reagent("synaptizine", 15) - reagents.add_reagent("salglu_solution", 15) - reagents.add_reagent("salbutamol", 15) - reagents.add_reagent("methamphetamine2", 15) + reagents.add_reagent("nutriment", 1) + + Post_Consume(mob/living/M) + M.reagents.add_reagent("omnizine", 15) + M.reagents.add_reagent("teporone", 15) + M.reagents.add_reagent("synaptizine", 15) + M.reagents.add_reagent("salglu_solution", 15) + M.reagents.add_reagent("salbutamol", 15) + M.reagents.add_reagent("methamphetamine", 15) /obj/item/weapon/reagent_containers/food/snacks/brainburger name = "brainburger" diff --git a/code/modules/reagents/reagent_containers/food/snacks/candy.dm b/code/modules/reagents/reagent_containers/food/snacks/candy.dm index 39abcac4a6a..1370eff0093 100644 --- a/code/modules/reagents/reagent_containers/food/snacks/candy.dm +++ b/code/modules/reagents/reagent_containers/food/snacks/candy.dm @@ -96,6 +96,34 @@ reagents.add_reagent("chocolate",6) bitesize = 3 +/obj/item/weapon/reagent_containers/food/snacks/candy/fudge/peanut + name = "Peanut Fudge" + desc = "Chocolate fudge, with bits of peanuts mixed in. People with nut allergies shouldn't eat this." + icon_state = "fudge_peanut" + filling_color = "#7D5F46" + +/obj/item/weapon/reagent_containers/food/snacks/candy/fudge/cherry + name = "Chocolate Cherry Fudge" + desc = "Chocolate fudge surrounding sweet cherries. Good for tricking kids into eating some fruit." + icon_state = "fudge_cherry" + filling_color = "#7D5F46" + +/obj/item/weapon/reagent_containers/food/snacks/candy/fudge/cookies_n_cream + name = "Cookies 'n' Cream Fudge" + desc = "An extra creamy fudge with bits of real chocolate cookie mixed in. Crunchy!" + icon_state = "fudge_cookies_n_cream" + filling_color = "#7D5F46" + +/obj/item/weapon/reagent_containers/food/snacks/candy/fudge/cookies_n_cream/New() + ..() + reagents.add_reagent("cream", 3) + +/obj/item/weapon/reagent_containers/food/snacks/candy/fudge/turtle + name = "Turtle Fudge" + desc = "Chocolate fudge with caramel and nuts. It doesn't contain real turtles, thankfully." + icon_state = "fudge_turtle" + filling_color = "#7D5F46" + // *********************************************************** // Candy Products (Pre-existing) // *********************************************************** diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 22466811e3e..a9181138a85 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -5,7 +5,7 @@ /obj/item/weapon/reagent_containers/hypospray name = "hypospray" desc = "The DeForest Medical Corporation hypospray is a sterile, air-needle autoinjector for rapid administration of drugs to patients." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/obj/hypo.dmi' item_state = "hypo" icon_state = "hypo" amount_per_transfer_from_this = 5 diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 32a0e752913..efc6a48b1f9 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -155,7 +155,7 @@ /obj/item/weapon/reagent_containers/spray/chemsprayer name = "chem sprayer" desc = "A utility used to spray large amounts of reagents in a given area." - icon = 'icons/obj/gun.dmi' + icon = 'icons/obj/guns/projectile.dmi' icon_state = "chemsprayer" item_state = "chemsprayer" throwforce = 0 @@ -234,4 +234,4 @@ if (istype(A, /obj/effect/blob)) // blob damage in blob code return - ..() \ No newline at end of file + ..() diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm index e95e213fd9f..332375dae8d 100644 --- a/code/modules/reagents/reagent_containers/syringes.dm +++ b/code/modules/reagents/reagent_containers/syringes.dm @@ -8,7 +8,7 @@ /obj/item/weapon/reagent_containers/syringe name = "Syringe" desc = "A syringe." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/goonstation/objects/syringe.dmi' item_state = "syringe_0" icon_state = "0" amount_per_transfer_from_this = 5 @@ -17,6 +17,7 @@ w_class = 1 sharp = 1 var/mode = SYRINGE_DRAW + var/projectile_type = /obj/item/projectile/bullet/dart/syringe /obj/item/weapon/reagent_containers/syringe/on_reagent_change() update_icon() @@ -336,7 +337,7 @@ /obj/item/weapon/reagent_containers/ld50_syringe name = "Lethal Injection Syringe" desc = "A syringe used for lethal injections." - icon = 'icons/obj/syringe.dmi' + icon = 'icons/goonstation/objects/syringe.dmi' item_state = "syringe_0" icon_state = "0" amount_per_transfer_from_this = 50 @@ -533,4 +534,4 @@ reagents.add_reagent("capulettium_plus", 5) reagents.add_reagent("sodium_thiopental", 5) mode = SYRINGE_INJECT - update_icon() \ No newline at end of file + update_icon() diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index b5d44579d07..8337e0ffaf7 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -688,6 +688,14 @@ build_path = /obj/item/weapon/hand_labeler category = list("initial", "Electronics") +/datum/design/floorpainter + name = "Floor painter" + id = "floor_painter" + build_type = AUTOLATHE + materials = list(MAT_METAL = 150, MAT_GLASS = 125) + build_path = /obj/item/device/floor_painter + category = list("initial", "Electronics") + /datum/design/logic_board name = "Logic Circuit" id = "logic_board" diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm index d2da596b692..385969c3f3f 100644 --- a/code/modules/research/designs/machine_designs.dm +++ b/code/modules/research/designs/machine_designs.dm @@ -92,6 +92,16 @@ build_path = /obj/item/weapon/circuitboard/teleporter_station category = list ("Teleportation Machinery") +/datum/design/teleport_perma + name = "Machine Board (Permanent Teleporter)" + desc = "Allows for the construction of circuit boards used to build a Permanent Teleporter." + id = "tele_perma" + req_tech = list("programming" = 3, "bluespace" = 5, "materials" = 4, "engineering" = 5) + build_type = IMPRINTER + materials = list(MAT_GLASS = 1000, "sacid" = 20) + build_path = /obj/item/weapon/circuitboard/teleporter_perma + category = list ("Teleportation Machinery") + /datum/design/bodyscanner name = "Machine Board (Body Scanner)" desc = "Allows for the construction of circuit boards used to build a Body Scanner." diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm index 00530d2a8a3..7bcc42e4979 100644 --- a/code/modules/research/designs/medical_designs.dm +++ b/code/modules/research/designs/medical_designs.dm @@ -280,6 +280,17 @@ build_path = /obj/item/organ/internal/cyberimp/brain/anti_stun category = list("Misc", "Medical") +/datum/design/cyberimp_clownvoice + name = "Comical implant" + desc = "Uh oh." + id = "ci-clownvoice" + req_tech = list("materials" = 2, "biotech" = 2) + build_type = PROTOLATHE | MECHFAB + construction_time = 60 + materials = list(MAT_METAL = 200, MAT_GLASS = 200, MAT_BANANIUM = 200) + build_path = /obj/item/organ/internal/cyberimp/brain/clown_voice + category = list("Misc", "Medical") + /datum/design/cyberimp_nutriment name = "Nutriment pump implant" desc = "This implant with synthesize and pump into your bloodstream a small amount of nutriment when you are starving." diff --git a/code/modules/research/designs/spacepod_designs.dm b/code/modules/research/designs/spacepod_designs.dm index c1927e47654..759af82404d 100644 --- a/code/modules/research/designs/spacepod_designs.dm +++ b/code/modules/research/designs/spacepod_designs.dm @@ -12,6 +12,7 @@ ////////////////////////////////////////////////// /////////SPACEPOD PARTS/////////////////////////// ////////////////////////////////////////////////// + /datum/design/podframe_fp construction_time = 200 name = "Fore port pod frame" @@ -89,6 +90,7 @@ ////////////////////////////////////////// //////SPACEPOD GUNS/////////////////////// ////////////////////////////////////////// + /datum/design/pod_gun_taser construction_time = 200 name = "Spacepod Equipment (Taser)" @@ -157,6 +159,7 @@ materials = list(MAT_METAL = 10000, MAT_GLASS = 5000, MAT_SILVER = 4000, MAT_GOLD = 4000, MAT_DIAMOND = 4000) build_path = /obj/item/device/spacepod_equipment/weaponry/mining_laser_hyper category = list("Pod_Weaponry") + ////////////////////////////////////////// //////SPACEPOD MISC. ITEMS//////////////// ////////////////////////////////////////// @@ -172,16 +175,57 @@ build_path = /obj/item/device/spacepod_equipment/misc/tracker category = list("Pod_Parts") +////////////////////////////////////////// +//////SPACEPOD CARGO ITEMS//////////////// +////////////////////////////////////////// + /datum/design/pod_cargo_ore construction_time = 100 name = "Spacepod Ore Storage Module" desc = "Allows for the construction of a Space Pod Ore Storage Module." id = "podcargo_ore" - req_tech = list("materials" = 3) + req_tech = list("materials" = 3, "engineering" = 2) build_type = PODFAB materials = list(MAT_METAL=20000, MAT_GLASS=2000) build_path = /obj/item/device/spacepod_equipment/cargo/ore - category = list("Pod_Parts") + category = list("Pod_Cargo") + +/datum/design/pod_cargo_crate + construction_time = 100 + name = "Spacepod Crate Storage Module" + desc = "Allows the construction of a Space Pod Crate Storage Module." + id = "podcargo_crate" + req_tech = list("materials" = 4, "engineering" = 2) //hollowing out this much of the pod without compromising structural integrity is hard + build_type = PODFAB + materials = list(MAT_METAL=25000) + build_path = /obj/item/device/spacepod_equipment/cargo/crate + category = list("Pod_Cargo") + +////////////////////////////////////////// +//////SPACEPOD SEC CARGO ITEMS//////////// +////////////////////////////////////////// + +/datum/design/passenger_seat + construction_time = 100 + name = "Spacepod Passenger Seat" + desc = "Allows the construction of a Space Pod Passenger Seat Module." + id = "podcargo_sec_seat" + req_tech = list("materials" = 1) // Because rule number one of refactoring + build_type = PODFAB + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/device/spacepod_equipment/sec_cargo/chair + category = list("Pod_Cargo") + +/datum/design/loot_box + construction_time = 100 + name = "Spacepod Loot Storage Module" + desc = "Allows the construction of a Space Pod Auxillary Cargo Module." + id = "podcargo_sec_lootbox" + req_tech = list("materials" = 1) //it's just a set of shelves, It's not that hard to make + build_type = PODFAB + materials = list(MAT_METAL=7500, MAT_GLASS=2500) + build_path = /obj/item/device/spacepod_equipment/sec_cargo/loot_box + category = list("Pod_Cargo") ////////////////////////////////////////// //////SPACEPOD LOCK ITEMS//////////////// diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm index f0e3c089cfd..c9ed686645a 100644 --- a/code/modules/research/experimentor.dm +++ b/code/modules/research/experimentor.dm @@ -89,8 +89,9 @@ component_parts += new /obj/item/weapon/stock_parts/manipulator(src) component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) component_parts += new /obj/item/weapon/stock_parts/micro_laser(src) - trackedIan = locate(/mob/living/simple_animal/pet/corgi/Ian) in mob_list - trackedRuntime = locate(/mob/living/simple_animal/pet/cat/Runtime) in mob_list + spawn(1) + trackedIan = locate(/mob/living/simple_animal/pet/corgi/Ian) in mob_list + trackedRuntime = locate(/mob/living/simple_animal/pet/cat/Runtime) in mob_list SetTypeReactions() RefreshParts() @@ -213,10 +214,12 @@ if(loaded_item) if(cloneMode && cloneCount > 0) visible_message("A duplicate [loaded_item] pops out!") - new loaded_item(get_turf(pick(oview(1,src)))) + var/type_to_make = loaded_item.type + new type_to_make(get_turf(pick(oview(1,src)))) --cloneCount if(cloneCount == 0) cloneMode = FALSE + return var/turf/dropturf = get_turf(pick(view(1,src))) if(!dropturf) //Failsafe to prevent the object being lost in the void forever. dropturf = get_turf(src) @@ -247,7 +250,7 @@ recentlyExperimented = 1 icon_state = "h_lathe_wloop" var/chosenchem - var/criticalReaction = locate(exp_on) in critical_items ? TRUE : FALSE + var/criticalReaction = (exp_on.type in critical_items) ? TRUE : FALSE //////////////////////////////////////////////////////////////////////////////////////////////// if(exp == SCANTYPE_POKE) visible_message("[src] prods at [exp_on] with mechanical arms.") @@ -371,8 +374,7 @@ FB.current = start FB.yo = MT.y - start.y FB.xo = MT.x - start.x - spawn(1) - FB.process() + FB.fire() if(prob(EFFECT_PROB_LOW-badThingCoeff)) visible_message("[src] malfunctions, melting [exp_on] and releasing a burst of flame!") explosion(src.loc, -1, 0, 0, 0, 0, flame_range = 2) @@ -404,7 +406,7 @@ visible_message("[src] lowers [exp_on]'s temperature.") if(prob(EFFECT_PROB_LOW) && criticalReaction) visible_message("[src]'s emergency coolant system gives off a small ding!") - var/obj/machinery/vending/coffee/C = new /obj/machinery/vending/coffee(get_turf(pick(oview(1,src)))) + var/obj/item/weapon/reagent_containers/food/drinks/coffee/C = new /obj/item/weapon/reagent_containers/food/drinks/coffee(get_turf(pick(oview(1,src)))) playsound(src.loc, 'sound/machines/ding.ogg', 50, 1) //Ding! Your death coffee is ready! chosenchem = pick("uranium","frostoil","ephedrine") C.reagents.remove_any(25) @@ -490,8 +492,21 @@ ejectItem() //Global reactions - if(prob(EFFECT_PROB_VERYLOW-badThingCoeff)) - var/globalMalf = rand(1,100) + + if(prob(EFFECT_PROB_VERYLOW) && prob(13)) + visible_message("[src] improves [exp_on], drawing the life essence of those nearby!") + for(var/mob/living/m in view(4,src)) + to_chat(m, "You feel your flesh being torn from you, mists of blood drifting to [src]!") + m.take_overall_damage(50) + investigate_log("Experimentor has taken 50 brute a blood sacrifice from [m]", "experimentor") + var/list/reqs = ConvertReqString2List(exp_on.origin_tech) + for(var/T in reqs) + reqs[T] = reqs[T] + 1 + exp_on.origin_tech = list2params(reqs) + investigate_log("Experimentor has set the origin tech of [exp_on] to [exp_on.origin_tech]", "experimentor") + + if(prob(EFFECT_PROB_VERYLOW-badThingCoeff) && prob(87)) + var/globalMalf = rand(1,87) if(globalMalf < 15) visible_message("[src]'s onboard detection system has malfunctioned!") item_reactions["[exp_on.type]"] = pick(SCANTYPE_POKE,SCANTYPE_IRRADIATE,SCANTYPE_GAS,SCANTYPE_HEAT,SCANTYPE_COLD,SCANTYPE_OBLITERATE) @@ -507,18 +522,7 @@ new /mob/living/simple_animal/pet/corgi(src.loc) investigate_log("Experimentor has spawned a new corgi.", "experimentor") ejectItem(TRUE) - if(globalMalf > 36 && globalMalf < 50) - visible_message("[src] improves [exp_on], drawing the life essence of those nearby!") - for(var/mob/living/m in view(4,src)) - to_chat(m, "You feel your flesh being torn from you, mists of blood drifting to [src]!") - m.take_overall_damage(50) - investigate_log("Experimentor has taken 50 brute a blood sacrifice from [m]", "experimentor") - var/list/reqs = ConvertReqString2List(exp_on.origin_tech) - for(var/T in reqs) - reqs[T] = reqs[T] + 1 - exp_on.origin_tech = list2params(reqs) - investigate_log("Experimentor has set the origin tech of [exp_on] to [exp_on.origin_tech]", "experimentor") - if(globalMalf > 51 && globalMalf < 75) + if(globalMalf > 36 && globalMalf < 59) visible_message("[src] encounters a run-time error!") throwSmoke(src.loc) if(trackedRuntime) @@ -529,7 +533,7 @@ new /mob/living/simple_animal/pet/cat(src.loc) investigate_log("Experimentor failed to steal runtime, and instead spawned a new cat.", "experimentor") ejectItem(TRUE) - if(globalMalf > 76) + if(globalMalf > 60) visible_message("[src] begins to smoke and hiss, shaking violently!") use_power(500000) investigate_log("Experimentor has drained power from its APC", "experimentor") diff --git a/code/modules/research/xenoarchaeology/finds/finds_misc.dm b/code/modules/research/xenoarchaeology/finds/finds_misc.dm index 68293501b77..e94049a74f1 100644 --- a/code/modules/research/xenoarchaeology/finds/finds_misc.dm +++ b/code/modules/research/xenoarchaeology/finds/finds_misc.dm @@ -25,7 +25,6 @@ return /obj/item/weapon/shard/plasma/attackby(obj/item/weapon/W as obj, mob/user as mob, params) - ..() if ( istype(W, /obj/item/weapon/weldingtool)) var/obj/item/weapon/weldingtool/WT = W if(WT.remove_fuel(0, user)) diff --git a/code/modules/research/xenoarchaeology/machinery/coolant.dm b/code/modules/research/xenoarchaeology/machinery/coolant.dm index f6d844fb889..b2dd9ce2a9e 100644 --- a/code/modules/research/xenoarchaeology/machinery/coolant.dm +++ b/code/modules/research/xenoarchaeology/machinery/coolant.dm @@ -27,7 +27,7 @@ datum/chemical_reaction/coolant /obj/structure/reagent_dispensers/coolanttank/bullet_act(var/obj/item/projectile/Proj) if(istype(Proj ,/obj/item/projectile/beam)||istype(Proj,/obj/item/projectile/bullet)) - if(!istype(Proj ,/obj/item/projectile/lasertag) && !istype(Proj ,/obj/item/projectile/practice) ) + if(!Proj.damage) explode() /obj/structure/reagent_dispensers/coolanttank/blob_act() diff --git a/code/modules/scripting/Implementations/Telecomms.dm b/code/modules/scripting/Implementations/Telecomms.dm index b85d63fac2b..273ccb67d0e 100644 --- a/code/modules/scripting/Implementations/Telecomms.dm +++ b/code/modules/scripting/Implementations/Telecomms.dm @@ -60,6 +60,9 @@ return interpreter.container = src + + interpreter.CreateGlobalScope() // Reset the variables. + interpreter.curScope = interpreter.globalScope interpreter.SetVar("PI", 3.141592653) // value of pi interpreter.SetVar("E", 2.718281828) // value of e @@ -127,7 +130,7 @@ @param time: time to sleep in deciseconds (1/10th second) */ - interpreter.SetProc("sleep", /proc/delay) + interpreter.SetProc("sleep", "delay", signal, list("time")) /* -> Replaces a string with another string @@ -255,6 +258,28 @@ signal.data["reject"] = 1 /* -- Actual language proc code -- */ +/datum/signal/proc/delay(var/time) + var/obj/machinery/telecomms/server/S = data["server"] + var/datum/n_Interpreter/TCS_Interpreter/interpreter = S.Compiler.interpreter + // Backup the scope + var/datum/scope/globalScope = interpreter.globalScope + var/datum/scope/curScope = interpreter.curScope + var/list/scopes = interpreter.scopes.stack.Copy() + var/list/functions = interpreter.functions.stack.Copy() + var/datum/node/statement/FunctionDefinition/curFunction = interpreter.curFunction + var/status = interpreter.status + var/returnVal = interpreter.returnVal + // Sleep + sleep(time) + // Restore the scope + interpreter.returnVal = returnVal + interpreter.status = status + interpreter.curFunction = curFunction + interpreter.functions.stack = functions + interpreter.scopes.stack = scopes + interpreter.curScope = curScope + interpreter.globalScope = globalScope + /datum/signal/proc/mem(var/address, var/value) if(istext(address)) var/obj/machinery/telecomms/server/S = data["server"] diff --git a/code/modules/scripting/Implementations/_Logic.dm b/code/modules/scripting/Implementations/_Logic.dm index 6befaa6f0eb..c31d55f3077 100644 --- a/code/modules/scripting/Implementations/_Logic.dm +++ b/code/modules/scripting/Implementations/_Logic.dm @@ -99,11 +99,6 @@ // --- Miscellaneous functions --- -// Clone of sleep() -/proc/delay(var/time) - //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/delay() called tick#: [world.time]") - sleep(time) - // Clone of rand() /proc/rand_chance(var/low = 0, var/high) //writepanic("[__FILE__].[__LINE__] (no type)([usr ? usr.ckey : ""]) \\/proc/rand_chance() called tick#: [world.time]") diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index 2a794de2ff8..2d5b0acb8ed 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -135,6 +135,8 @@ var/turf_type = /turf/space var/area_type = /area/space + + var/lock_shuttle_doors = 0 /obj/docking_port/stationary/register() if(!shuttle_master) @@ -165,6 +167,8 @@ /obj/docking_port/stationary/transit name = "In Transit" turf_type = /turf/space/transit + + lock_shuttle_doors = 1 /obj/docking_port/stationary/transit/register() if(!..()) @@ -452,7 +456,7 @@ dir = S1.dir unlockPortDoors(S1) - if(S1 && S1.id != "[id]_transit") + if(S1 && !S1.lock_shuttle_doors) for(var/obj/machinery/door/airlock/A in door_unlock_list) spawn(-1) A.unlock() @@ -615,6 +619,7 @@ var/possible_destinations = "" var/admin_controlled var/max_connect_range = 7 + var/docking_request = 0 /obj/machinery/computer/shuttle/New(location, obj/item/weapon/circuitboard/shuttle/C) ..() @@ -667,6 +672,8 @@ if(admin_controlled) dat += "Authorized personnel only
    " dat += "Request Authorization
    " + if(docking_request) + dat += "Request docking at NSS Cyberiad
    " dat += "Close" var/datum/browser/popup = new(user, "computer", M ? M.name : "shuttle", 300, 200) @@ -683,7 +690,12 @@ to_chat(usr, "Access denied.") return + var/list/options = params2list(possible_destinations) if(href_list["move"]) + if(!options.Find(href_list["move"])) //I see you're trying Href exploits, I see you're failing, I SEE ADMIN WARNING. + // Seriously, though, NEVER trust a Topic with something like this. Ever. + message_admins("move HREF ([src] attempted to move to: [href_list["move"]]) exploit attempted by [key_name_admin(usr)] on [src] (JMP)") + return switch(shuttle_master.moveShuttle(shuttleId, href_list["move"], 1)) if(0) to_chat(usr, "Shuttle received message and will be sent shortly.") @@ -763,6 +775,41 @@ shuttleId = "admin" possible_destinations = "admin_home;admin_away" +var/global/trade_dock_timelimit = 0 +var/global/trade_dockrequest_timelimit = 0 + +/obj/machinery/computer/shuttle/trade + name = "Freighter Console" + docking_request = 1 + var/possible_destinations_dock + var/possible_destinations_nodock + var/docking_request_message = "A trading ship has requested docking aboard the NSS Cyberiad for trading. This request can be accepted or denied using a communications console." + +/obj/machinery/computer/shuttle/trade/attack_hand(mob/user) + if(world.time < trade_dock_timelimit) + possible_destinations = possible_destinations_dock + else + possible_destinations = possible_destinations_nodock + + docking_request = (world.time > trade_dockrequest_timelimit && world.time > trade_dock_timelimit) + ..(user) + +/obj/machinery/computer/shuttle/trade/Topic(href, href_list) + ..() + if(href_list["request"]) + if(world.time < trade_dockrequest_timelimit || world.time < trade_dock_timelimit) + return + to_chat(usr, "Request sent.") + command_announcement.Announce(docking_request_message, "Docking Request") + trade_dockrequest_timelimit = world.time + 1200 // They have 2 minutes to approve the request. + +/obj/machinery/computer/shuttle/trade/sol + req_access = list(access_trade_sol) + possible_destinations_dock = "trade_sol_base;trade_sol_offstation;trade_dock" + possible_destinations_nodock = "trade_sol_base;trade_sol_offstation" + shuttleId = "trade_sol" + docking_request_message = "A trading ship of Sol origin has requested docking aboard the NSS Cyberiad for trading. This request can be accepted or denied using a communications console." + #undef DOCKING_PORT_HIGHLIGHT diff --git a/code/game/vehicles/spacepods/construction.dm b/code/modules/spacepods/construction.dm similarity index 100% rename from code/game/vehicles/spacepods/construction.dm rename to code/modules/spacepods/construction.dm diff --git a/code/game/vehicles/spacepods/equipment.dm b/code/modules/spacepods/equipment.dm similarity index 75% rename from code/game/vehicles/spacepods/equipment.dm rename to code/modules/spacepods/equipment.dm index 91588fa0a8b..07c49752d15 100644 --- a/code/game/vehicles/spacepods/equipment.dm +++ b/code/modules/spacepods/equipment.dm @@ -30,11 +30,9 @@ var/obj/item/projectile/projone = new proj_type(firstloc) var/obj/item/projectile/projtwo = new proj_type(secondloc) projone.starting = get_turf(my_atom) - projone.shot_from = src projone.firer = usr projone.def_zone = "chest" projtwo.starting = get_turf(my_atom) - projtwo.shot_from = src projtwo.firer = usr projtwo.def_zone = "chest" spawn() @@ -46,12 +44,13 @@ /datum/spacepod/equipment var/obj/spacepod/my_atom + var/list/obj/item/device/spacepod_equipment/installed_modules = list() // holds an easy to access list of installed modules + var/obj/item/device/spacepod_equipment/weaponry/weapon_system // weapons system var/obj/item/device/spacepod_equipment/misc/misc_system // misc system var/obj/item/device/spacepod_equipment/cargo/cargo_system // cargo system + var/obj/item/device/spacepod_equipment/cargo/sec_cargo_system // secondary cargo system var/obj/item/device/spacepod_equipment/lock/lock_system // lock system - //var/obj/item/device/spacepod_equipment/engine/engine_system // engine system - //var/obj/item/device/spacepod_equipment/shield/shield_system // shielding system /datum/spacepod/equipment/New(var/obj/spacepod/SP) ..() @@ -61,11 +60,17 @@ /obj/item/device/spacepod_equipment name = "equipment" var/obj/spacepod/my_atom + var/occupant_mod = 0 // so any module can modify occupancy + var/list/storage_mod = list("slots" = 0, "w_class" = 0) // so any module can modify storage slots /obj/item/device/spacepod_equipment/proc/removed(var/mob/user) // So that you can unload cargo when you remove the module return -// base item for spacepod weapons +/* +/////////////////////////////////////// +/////////Weapon System/////////////////// +/////////////////////////////////////// +*/ /obj/item/device/spacepod_equipment/weaponry name = "pod weapon" @@ -135,7 +140,12 @@ fire_delay = 8 fire_sound = 'sound/weapons/Kenetic_accel.ogg' -//base item for spacepod misc equipment (tracker) +/* +/////////////////////////////////////// +/////////Misc. System/////////////////// +/////////////////////////////////////// +*/ + /obj/item/device/spacepod_equipment/misc name = "pod misc" desc = "You shouldn't be seeing this" @@ -160,37 +170,79 @@ else ..() +/* +/////////////////////////////////////// +/////////Cargo System////////////////// +/////////////////////////////////////// +*/ + /obj/item/device/spacepod_equipment/cargo name = "pod cargo" desc = "You shouldn't be seeing this" icon = 'icons/vehicles/spacepod.dmi' - icon_state = "blank" + icon_state = "cargo_blank" + var/obj/storage = null /obj/item/device/spacepod_equipment/cargo/proc/passover(var/obj/item/I) return -/obj/item/device/spacepod_equipment/cargo/proc/unload() - return +/obj/item/device/spacepod_equipment/cargo/proc/unload() // called by unload verb + if(storage) + storage.forceMove(get_turf(my_atom)) + storage = null -/obj/item/device/spacepod_equipment/cargo/ore - name = "\improper spacepod ore storage system" - desc = "An ore storage system for spacepods. Scoops up any ore you drive over." - icon_state = "cargo_ore" - var/obj/structure/ore_box/box - -/obj/item/device/spacepod_equipment/cargo/ore/passover(var/obj/item/I) - if(box && istype(I,/obj/item/weapon/ore)) - I.forceMove(box) - -/obj/item/device/spacepod_equipment/cargo/ore/unload() - if(box) - box.forceMove(get_turf(my_atom)) - box = null - -/obj/item/device/spacepod_equipment/cargo/ore/removed(var/mob/user) +/obj/item/device/spacepod_equipment/cargo/removed(var/mob/user) // called when system removed . = ..() unload() +// Ore System +/obj/item/device/spacepod_equipment/cargo/ore + name = "spacepod ore storage system" + desc = "An ore storage system for spacepods. Scoops up any ore you drive over." + icon_state = "cargo_ore" + +/obj/item/device/spacepod_equipment/cargo/ore/passover(var/obj/item/I) + if(storage && istype(I,/obj/item/weapon/ore)) + I.forceMove(storage) + +// Crate System +/obj/item/device/spacepod_equipment/cargo/crate + name = "spacepod crate storage system" + desc = "A heavy duty storage system for spacepods. Holds one crate." + icon_state = "cargo_crate" + +/* +/////////////////////////////////////// +/////////Secondary Cargo System//////// +/////////////////////////////////////// +*/ + +/obj/item/device/spacepod_equipment/sec_cargo + name = "secondary cargo" + desc = "you shouldn't be seeing this" + icon = 'icons/vehicles/spacepod.dmi' + icon_state = "blank" + +// Passenger Seat +/obj/item/device/spacepod_equipment/sec_cargo/chair + name = "passanger seat" + desc = "A passenger seat for a spacepod" + icon_state = "sec_cargo_chair" + occupant_mod = 1 + +// Loot Box +/obj/item/device/spacepod_equipment/sec_cargo/loot_box + name = "loot box" + desc = "A small compartment to store valuables" + icon_state = "sec_cargo_loot" + storage_mod = list("slots" = 7, "w_class" = 14) + +/* +/////////////////////////////////////// +/////////Lock System/////////////////// +/////////////////////////////////////// +*/ + /obj/item/device/spacepod_equipment/lock name = "pod lock" desc = "You shouldn't be seeing this" diff --git a/code/modules/spacepods/lock_buster.dm b/code/modules/spacepods/lock_buster.dm new file mode 100644 index 00000000000..276386d89a6 --- /dev/null +++ b/code/modules/spacepods/lock_buster.dm @@ -0,0 +1,13 @@ +/obj/item/device/lock_buster + name = "pod lock buster" + desc = "Destroys a podlock in mere seconds once applied. Waranty void if used." + icon_state = "lock_buster_off" + var/on = 0 + +/obj/item/device/lock_buster/attack_self(mob/user as mob) + on = !on + if(on) + icon_state = "lock_buster_on" + else + icon_state = "lock_buster_off" + to_chat(usr, "You turn the [src] [on ? "on" : "off"].") \ No newline at end of file diff --git a/code/game/vehicles/spacepods/parts.dm b/code/modules/spacepods/parts.dm similarity index 100% rename from code/game/vehicles/spacepods/parts.dm rename to code/modules/spacepods/parts.dm diff --git a/code/game/vehicles/spacepods/pod_fabricator.dm b/code/modules/spacepods/pod_fabricator.dm similarity index 99% rename from code/game/vehicles/spacepods/pod_fabricator.dm rename to code/modules/spacepods/pod_fabricator.dm index 948491c6d29..ed7f421f33e 100644 --- a/code/game/vehicles/spacepods/pod_fabricator.dm +++ b/code/modules/spacepods/pod_fabricator.dm @@ -35,6 +35,7 @@ var/list/part_sets = list( "Pod_Weaponry", "Pod_Armor", + "Pod_Cargo", "Pod_Parts", "Pod_Frame", "Misc", diff --git a/code/game/vehicles/spacepods/spacepod.dm b/code/modules/spacepods/spacepod.dm similarity index 57% rename from code/game/vehicles/spacepods/spacepod.dm rename to code/modules/spacepods/spacepod.dm index 707b8912460..2156977d6fe 100644 --- a/code/game/vehicles/spacepods/spacepod.dm +++ b/code/modules/spacepods/spacepod.dm @@ -14,8 +14,10 @@ layer = 3.9 infra_luminosity = 15 - var/mob/living/carbon/occupant - var/mob/living/carbon/occupant2 //two seaters + var/list/mob/pilot //There is only ever one pilot and he gets all the privledge + var/list/mob/passengers = list() //passengers can't do anything and are variable in number + var/max_passengers = 0 + var/obj/item/weapon/storage/internal/cargo_hold var/datum/spacepod/equipment/equipment_system @@ -47,7 +49,7 @@ "pod_black" = "#3B8FE5", \ "pod_industrial" = "#CCCC00") - var/allow2enter = 1 + var/unlocked = 1 var/move_delay = 2 var/next_move = 0 @@ -71,13 +73,21 @@ pr_int_temp_processor = new /datum/global_iterator/pod_preserve_temp(list(src)) pr_give_air = new /datum/global_iterator/pod_tank_give_air(list(src)) equipment_system = new(src) + equipment_system.installed_modules += battery spacepods_list += src + cargo_hold = new/obj/item/weapon/storage/internal(src) + cargo_hold.w_class = 5 //so you can put bags in + cargo_hold.storage_slots = 0 //You need to install cargo modules to use it. + cargo_hold.max_w_class = 5 //fit almost anything + cargo_hold.max_combined_w_class = 0 //you can optimize your stash with larger items /obj/spacepod/Destroy() if (equipment_system.cargo_system) equipment_system.cargo_system.removed(null) qdel(equipment_system) equipment_system = null + qdel(cargo_hold) + cargo_hold = null qdel(battery) battery = null qdel(cabin_air) @@ -91,12 +101,10 @@ qdel(ion_trail) ion_trail = null occupant_sanity_check() - if(occupant) - occupant.forceMove(get_turf(src)) - occupant = null - if(occupant2) - occupant2.forceMove(get_turf(src)) - occupant2 = null + if(passengers) + for(var/mob/M in passengers) + M.forceMove(get_turf(src)) + passengers -= M spacepods_list -= src return ..() @@ -106,7 +114,6 @@ else processing_objects.Remove(src) - /obj/spacepod/proc/update_icons() if(!pod_overlays) pod_overlays = new/list(2) @@ -155,34 +162,29 @@ health = max(0, health - damage) var/percentage = (health / initial(health)) * 100 occupant_sanity_check() - if(occupant && oldhealth > health && percentage <= 25 && percentage > 0) + if(passengers && oldhealth > health && percentage <= 25 && percentage > 0) var/sound/S = sound('sound/effects/engine_alert2.ogg') S.wait = 0 //No queue S.channel = 0 //Any channel S.volume = 50 - to_chat(occupant, S) - if(occupant2) - to_chat(occupant2, S) - if(occupant && oldhealth > health && !health) + for(var/mob/M in passengers) + to_chat(M, S) + if(passengers && oldhealth > health && !health) var/sound/S = sound('sound/effects/engine_alert1.ogg') S.wait = 0 S.channel = 0 S.volume = 50 - to_chat(occupant, S) - if(occupant2) - to_chat(occupant2, S) + for(var/mob/M in passengers) + to_chat(M, S) if(!health) spawn(0) - if(occupant) - to_chat(occupant, "Critical damage to the vessel detected, core explosion imminent!") - if(occupant2) - to_chat(occupant2, "Critical damage to the vessel detected, core explosion imminent!") - + if(passengers) + for(var/mob/M in passengers) + to_chat(M, "Critical damage to the vessel detected, core explosion imminent!") for(var/i = 10, i >= 0; --i) - if(occupant) - to_chat(occupant, "[i]") - if(occupant2) - to_chat(occupant2, "[i]") + if(passengers) + for(var/mob/M in passengers) + to_chat(M, "[i]") if(i == 0) explosion(loc, 2, 4, 8) qdel(src) @@ -200,16 +202,12 @@ occupant_sanity_check() switch(severity) if(1) - var/mob/living/carbon/human/H = occupant - var/mob/living/carbon/human/H2 = occupant2 - if(H) - H.forceMove(get_turf(src)) - H.ex_act(severity + 1) - to_chat(H, "You are forcefully thrown from \the [src]!") - if(H2) - H2.forceMove(get_turf(src)) - H2.ex_act(severity + 1) - to_chat(H2, "You are forcefully thrown from \the [src]!") + for(var/mob/M in passengers) + var/mob/living/carbon/human/H = M + if(H) + H.forceMove(get_turf(src)) + H.ex_act(severity + 1) + to_chat(H, "You are forcefully thrown from \the [src]!") qdel(ion_trail) qdel(src) if(2) @@ -220,12 +218,14 @@ /obj/spacepod/emp_act(severity) occupant_sanity_check() + cargo_hold.emp_act(severity) switch(severity) if(1) - if(occupant) - to_chat(occupant, "The pod console flashes 'Heavy EMP WAVE DETECTED'.")//warn the occupants - if(occupant2) - to_chat(occupant2, "The pod console flashes 'Heavy EMP WAVE DETECTED'.")//warn the occupants + if(pilot) + to_chat(pilot, "The pod console flashes 'Heavy EMP WAVE DETECTED'.") + if(passengers) + for(var/mob/M in passengers) + to_chat(M, "The pod console flashes 'Heavy EMP WAVE DETECTED'.")//warn the passengers if(battery) @@ -236,10 +236,11 @@ processing_objects.Add(src) if(2) - if(occupant) - to_chat(occupant, "The pod console flashes 'EMP WAVE DETECTED'.")//warn the occupants - if(occupant2) - to_chat(occupant2, "The pod console flashes 'EMP WAVE DETECTED'.")//warn the occupants + if(pilot) + to_chat(pilot, "The pod console flashes 'EMP WAVE DETECTED'.") + if(passengers) + for(var/mob/M in passengers) + to_chat(M, "The pod console flashes 'EMP WAVE DETECTED'.")//warn the passengers deal_damage(40) if(battery) @@ -250,12 +251,13 @@ /obj/spacepod/attackby(obj/item/W as obj, mob/user as mob, params) if(iscrowbar(W)) - if(!equipment_system.lock_system || allow2enter || hatch_open) + if(!equipment_system.lock_system || unlocked || hatch_open) hatch_open = !hatch_open playsound(loc, 'sound/items/Crowbar.ogg', 50, 1) to_chat(user, "You [hatch_open ? "open" : "close"] the maintenance hatch.") else to_chat(user, "The hatch is locked shut!") + return if(istype(W, /obj/item/weapon/stock_parts/cell)) if(!hatch_open) to_chat(user, "\red The maintenance hatch is closed!") @@ -272,61 +274,32 @@ to_chat(user, "\red The maintenance hatch is closed!") return if(!equipment_system) - to_chat(user, "The pod has no equipment datum, yell at pomf") + to_chat(user, "The pod has no equipment datum, yell at the coders") return if(istype(W, /obj/item/device/spacepod_equipment/weaponry)) - if(equipment_system.weapon_system) - to_chat(user, "The pod already has a weapon system, remove it first.") - return - else - to_chat(user, "You insert \the [W] into the equipment system.") - user.drop_item(W) - W.forceMove(src) - equipment_system.weapon_system = W - equipment_system.weapon_system.my_atom = src - return - + add_equipment(user, W, "weapon_system") + return if(istype(W, /obj/item/device/spacepod_equipment/misc)) - if(equipment_system.misc_system) - to_chat(user, "The pod already has a miscellaneous system, remove it first.") - return - else - to_chat(user, "You insert \the [W] into the equipment system.") - user.drop_item(W) - W.forceMove(src) - equipment_system.misc_system = W - equipment_system.misc_system.my_atom = src - return + add_equipment(user, W, "misc_system") + return if(istype(W, /obj/item/device/spacepod_equipment/cargo)) - if(equipment_system.cargo_system) - to_chat(user, "The pod already has a cargo system, remove it first.") - return - else - to_chat(user, "You insert \the [W] into the cargo system.") - user.drop_item(W) - W.forceMove(src) - equipment_system.cargo_system = W - equipment_system.cargo_system.my_atom = src - return + add_equipment(user, W, "cargo_system") + return + if(istype(W, /obj/item/device/spacepod_equipment/sec_cargo)) + add_equipment(user, W, "sec_cargo_system") + return if(istype(W, /obj/item/device/spacepod_equipment/lock)) - if(equipment_system.lock_system) - to_chat(user, "The pod already has a lock system, remove it first.") - return - else - to_chat(user, "You insert \the [W] into the lock system.") - user.drop_item(W) - W.forceMove(src) - equipment_system.lock_system = W - equipment_system.lock_system.my_atom = src - return + add_equipment(user, W, "lock_system") + return if(istype(W, /obj/item/device/spacepod_key) && istype(equipment_system.lock_system, /obj/item/device/spacepod_equipment/lock/keyed)) var/obj/item/device/spacepod_key/key = W if (key.id == equipment_system.lock_system.id) - locksecondseat() + lock_pod() + return else to_chat(user, "This is the wrong key!") - return + return if(istype(W, /obj/item/weapon/weldingtool)) if(!hatch_open) @@ -343,15 +316,76 @@ if(!src || !WT.remove_fuel(3, user)) return repair_damage(10) to_chat(user, "\blue You mend some [pick("dents","bumps","damage")] with \the [WT]") - else - to_chat(user, "\blue \The [src] is fully repaired!") + return + to_chat(user, "\blue \The [src] is fully repaired!") + return + if(istype(W, /obj/item/device/lock_buster)) + var/obj/item/device/lock_buster/L = W + if(L.on & equipment_system.lock_system) + user.visible_message(user, "[user] is drilling through the [src]'s lock!", + "You start drilling through the [src]'s lock!") + if(do_after(user, 100, target = src)) + qdel(equipment_system.lock_system) + equipment_system.lock_system = null + user.visible_message(user, "[user] has destroyed the [src]'s lock!", + "You destroy the [src]'s lock!") + else + user.visible_message(user, "[user] fails to break through the [src]'s lock!", + "You were unable to break through the [src]'s lock!") + return + to_chat(user, "Turn the [L] on first.") + return + + if(cargo_hold.storage_slots > 0 && !hatch_open && unlocked) // must be the last option as all items not listed prior will be stored + cargo_hold.attackby(W, user, params) + +obj/spacepod/proc/add_equipment(mob/user, var/obj/item/device/spacepod_equipment/SPE, var/slot) + if(equipment_system.vars[slot]) + to_chat(user, "The pod already has a [slot], remove it first.") + return + else + to_chat(user, "You insert \the [SPE] into the pod.") + user.drop_item(SPE) + SPE.forceMove(src) + equipment_system.vars[slot] = SPE + var/obj/item/device/spacepod_equipment/system = equipment_system.vars[slot] + system.my_atom = src + equipment_system.installed_modules += SPE + max_passengers += SPE.occupant_mod + cargo_hold.storage_slots += SPE.storage_mod["slots"] + cargo_hold.max_combined_w_class += SPE.storage_mod["w_class"] /obj/spacepod/attack_hand(mob/user as mob) + if(user.a_intent == I_GRAB && unlocked) + var/mob/target + if(pilot) + target = pilot + else if(passengers.len > 0) + target = passengers[1] + + if(target && istype(target)) + src.visible_message("[user] is trying to rip the door open and pull [target] out of the [src]!", + "You see [user] outside the door trying to rip it open!") + if(do_after(user, 50, target = src)) + target.forceMove(get_turf(src)) + target.Stun(1) + passengers -= target + target.visible_message("[user] flings the door open and tears [target] out of the [src]", + "The door flies open and you are thrown out of the [src] and to the ground!") + return + target.visible_message("[user] was unable to get the door open!", + "You manage to keep [user] out of the [src]!") + if(!hatch_open) + if(cargo_hold.storage_slots > 0) + if(unlocked) + cargo_hold.open(user) + else + to_chat(user, "The storage compartment is locked") return ..() if(!equipment_system || !istype(equipment_system)) - to_chat(user, "The pod has no equpment datum, or is the wrong type, yell at pomf.") + to_chat(user, "The pod has no equpment datum, or is the wrong type, yell at IK3I.") return var/list/possible = list() if(battery) @@ -362,74 +396,81 @@ possible.Add("Misc. System") if(equipment_system.cargo_system) possible.Add("Cargo System") + if(equipment_system.sec_cargo_system) + possible.Add("Secondary Cargo System") if(equipment_system.lock_system) possible.Add("Lock System") - /* Not yet implemented - if(equipment_system.engine_system) - possible.Add("Engine System") - if(equipment_system.shield_system) - possible.Add("Shield System") - */ - var/obj/item/device/spacepod_equipment/SPE switch(input(user, "Remove which equipment?", null, null) as null|anything in possible) if("Energy Cell") if(user.put_in_any_hand_if_possible(battery)) to_chat(user, "You remove \the [battery] from the space pod") battery = null + else + to_chat(user, "You need an open hand to do that.") + return if("Weapon System") - SPE = equipment_system.weapon_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - SPE.removed(user) - SPE.my_atom = null - equipment_system.weapon_system = null - else - to_chat(user, "You need an open hand to do that.") + remove_equipment(user, equipment_system.weapon_system, "weapon_system") + return if("Misc. System") - SPE = equipment_system.misc_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - SPE.removed(user) - SPE.my_atom = null - equipment_system.misc_system = null - else - to_chat(user, "You need an open hand to do that.") + remove_equipment(user, equipment_system.misc_system, "misc_system") + return if("Cargo System") - SPE = equipment_system.cargo_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - SPE.removed(user) - SPE.my_atom = null - equipment_system.cargo_system = null - else - to_chat(user, "You need an open hand to do that.") + remove_equipment(user, equipment_system.cargo_system, "cargo_system") + return + if("Secondary Cargo System") + remove_equipment(user, equipment_system.sec_cargo_system, "sec_cargo_system") + return if("Lock System") - SPE = equipment_system.lock_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - SPE.removed(user) - SPE.my_atom = null - equipment_system.lock_system = null - else - to_chat(user, "You need an open hand to do that.") - /* - if("engine system") - SPE = equipment_system.engine_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - equipment_system.engine_system = null - else - to_chat(user, "You need an open hand to do that.") - if("shield system") - SPE = equipment_system.shield_system - if(user.put_in_any_hand_if_possible(SPE)) - to_chat(user, "You remove \the [SPE] from the equipment system.") - equipment_system.shield_system = null - else - to_chat(user, "You need an open hand to do that.") - */ + remove_equipment(user, equipment_system.lock_system, "lock_system") - return +/obj/spacepod/proc/remove_equipment(mob/user, var/obj/item/device/spacepod_equipment/SPE, var/slot) + + if(passengers.len > max_passengers - SPE.occupant_mod) + to_chat(user, "Someone is sitting in \the [SPE]!") + return + + var/sum_w_class = 0 + for(var/obj/item/I in cargo_hold.contents) + sum_w_class += I.w_class + if(cargo_hold.contents.len > cargo_hold.storage_slots - SPE.storage_mod["slots"] || sum_w_class > cargo_hold.max_combined_w_class - SPE.storage_mod["w_class"]) + to_chat(user, "Empty \the [SPE] first!") + return + + if(user.put_in_any_hand_if_possible(SPE)) + to_chat(user, "You remove \the [SPE] from the equipment system.") + equipment_system.installed_modules -= SPE + max_passengers -= SPE.occupant_mod + cargo_hold.storage_slots -= SPE.storage_mod["slots"] + cargo_hold.max_combined_w_class -= SPE.storage_mod["w_class"] + SPE.removed(user) + SPE.my_atom = null + equipment_system.vars[slot] = null + return + to_chat(user, "You need an open hand to do that.") + + +/obj/spacepod/hear_talk/hear_talk(mob/M, var/msg) + cargo_hold.hear_talk(M, msg) + ..() + +/obj/spacepod/hear_message(mob/M, var/msg) + cargo_hold.hear_message(M, msg) + ..() + +/obj/spacepod/proc/return_inv() + + var/list/L = list( ) + + L += src.contents + + for(var/obj/item/weapon/storage/S in src) + L += S.return_inv() + for(var/obj/item/weapon/gift/G in src) + L += G.gift + if (istype(G.gift, /obj/item/weapon/storage)) + var/obj/item/weapon/storage/inv = G.gift + L += inv.return_inv() + return L /obj/spacepod/civilian icon_state = "pod_civ" @@ -451,17 +492,25 @@ T.loc = equipment_system equipment_system.weapon_system = T equipment_system.weapon_system.my_atom = src + equipment_system.installed_modules += T var/obj/item/device/spacepod_equipment/misc/tracker/L = new /obj/item/device/spacepod_equipment/misc/tracker L.loc = equipment_system equipment_system.misc_system = L equipment_system.misc_system.my_atom = src equipment_system.misc_system.enabled = 1 + equipment_system.installed_modules += L + var/obj/item/device/spacepod_equipment/sec_cargo/chair/C = new /obj/item/device/spacepod_equipment/sec_cargo/chair + C.loc = equipment_system + equipment_system.sec_cargo_system = C + equipment_system.sec_cargo_system.my_atom = src + equipment_system.installed_modules += C + max_passengers = 1 var/obj/item/device/spacepod_equipment/lock/keyed/K = new /obj/item/device/spacepod_equipment/lock/keyed K.loc = equipment_system equipment_system.lock_system = K equipment_system.lock_system.my_atom = src equipment_system.lock_system.id = 100000 - return + equipment_system.installed_modules += K /obj/spacepod/random/New() ..() @@ -486,11 +535,11 @@ set category = "Spacepod" set src = usr.loc set popup_menu = 0 - if(usr!=src.occupant) + if(usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") return use_internal_tank = !use_internal_tank - to_chat(occupant, "Now taking air from [use_internal_tank?"internal airtank":"environment"].") - return + to_chat(usr, "Now taking air from [use_internal_tank?"internal airtank":"environment"].") /obj/spacepod/proc/add_cabin() cabin_air = new @@ -508,7 +557,6 @@ var/turf/T = get_turf(src) if(T) . = T.return_air() - return /obj/spacepod/remove_air(amount) if(use_internal_tank) @@ -517,7 +565,6 @@ var/turf/T = get_turf(src) if(T) return T.remove_air(amount) - return /obj/spacepod/return_air() if(use_internal_tank) @@ -532,7 +579,6 @@ var/datum/gas_mixture/t_air = get_turf_air() if(t_air) . = t_air.return_pressure() - return /obj/spacepod/proc/return_temperature() . = 0 @@ -542,19 +588,21 @@ var/datum/gas_mixture/t_air = get_turf_air() if(t_air) . = t_air.return_temperature() - return /obj/spacepod/proc/moved_other_inside(var/mob/living/carbon/human/H as mob) occupant_sanity_check() - if(!occupant2) + if(passengers.len < max_passengers) H.stop_pulling() H.forceMove(src) - occupant2 = H + passengers += H H.forceMove(src) playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) return 1 /obj/spacepod/MouseDrop_T(atom/A, mob/user) + if(user == pilot || user in passengers) + return + if(istype(A,/mob)) var/mob/M = A if(!isliving(M)) @@ -562,48 +610,51 @@ occupant_sanity_check() - if(M != user && M.stat == DEAD && allow2enter) - if(occupant2 && !occupant) - to_chat(usr, "You can't put a corpse into the driver's seat!") + if(M != user && unlocked && (M.stat == DEAD || M.incapacitated())) + if(passengers.len >= max_passengers && !pilot) + to_chat(usr, "That person can't fly the pod!") return 0 - if(!occupant2) + if(passengers.len < max_passengers) visible_message("[user.name] starts loading [M.name] into the pod!") - sleep(10) - moved_other_inside(M) + if(do_after(user, 50, target = M)) + moved_other_inside(M) + return if(M == user) - if(!equipment_system.lock_system || allow2enter) - enter_pod(user) - else - to_chat(user, "\The [src]'s doors are locked!") + enter_pod(user) + return - - if(istype(A, /obj/structure/ore_box)) // For loading ore boxes - var/obj/structure/ore_box/O = A - if(equipment_system.cargo_system && istype(equipment_system.cargo_system,/obj/item/device/spacepod_equipment/cargo/ore)) - var/obj/item/device/spacepod_equipment/cargo/ore/C = equipment_system.cargo_system - if(!C.box) - to_chat(user, "You begin loading \the [O] into \the [src]'s [equipment_system.cargo_system]") - if(do_after(user, 40, target = src)) - C.box = O - O.forceMove(C) - to_chat(user, "You load \the [O] into \the [src]'s [equipment_system.cargo_system]!") - else - to_chat(user, "You fail to load \the [O] into \the [src]'s [equipment_system.cargo_system]") - else - to_chat(user, "\The [src] already has \an [C.box]") - -/obj/spacepod/verb/enter_pod(mob/user = usr) - set category = "Object" - set name = "Enter Pod" - set src in oview(1) - - if (usr.stat != CONSCIOUS) + if(istype(A, /obj/structure/ore_box) && equipment_system.cargo_system && istype(equipment_system.cargo_system,/obj/item/device/spacepod_equipment/cargo/ore)) // For loading ore boxes + load_cargo(user, A) return + if(istype(A, /obj/structure/closet/crate) && equipment_system.cargo_system && istype(equipment_system.cargo_system, /obj/item/device/spacepod_equipment/cargo/crate)) // For loading crates + load_cargo(user, A) + +/obj/spacepod/proc/load_cargo(mob/user, var/obj/O) + var/obj/item/device/spacepod_equipment/cargo/ore/C = equipment_system.cargo_system + if(!C.storage) + to_chat(user, "You begin loading \the [O] into \the [src]'s [equipment_system.cargo_system]") + if(do_after(user, 40, target = src)) + C.storage = O + O.forceMove(C) + to_chat(user, "You load \the [O] into \the [src]'s [equipment_system.cargo_system]!") + else + to_chat(user, "You fail to load \the [O] into \the [src]'s [equipment_system.cargo_system]") + else + to_chat(user, "\The [src] already has \an [C.storage]") + +/obj/spacepod/proc/enter_pod(mob/user) + if (usr.stat != CONSCIOUS) + return 0 + + if(equipment_system.lock_system && !unlocked) + to_chat(user, "\The [src]'s doors are locked!") + return 0 + if(get_dist(src, user) > 2 || get_dist(usr, user) > 1) to_chat(usr, "They are too far away to put inside") - return + return 0 if(!istype(user)) return 0 @@ -632,53 +683,45 @@ occupant_sanity_check() - if(!occupant) + if(passengers.len <= max_passengers) visible_message("[user] starts to climb into \the [src].") if(do_after(user, 40, target = src)) - if(!occupant) + if(!pilot || pilot == null) user.stop_pulling() - occupant = user + pilot = user + user.forceMove(src) + add_fingerprint(user) + playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) + return + if(passengers.len < max_passengers) + user.stop_pulling() + passengers += user user.forceMove(src) add_fingerprint(user) playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) else - to_chat(user, "[occupant] was faster. Try better next time, loser.") - else - to_chat(user, "You stop entering \the [src].") - - else if(!occupant2) - visible_message("[user] starts to climb into \the [src].") - if(do_after(user, 40, target = src)) - if(!occupant2) - user.stop_pulling() - occupant2 = user - user.forceMove(src) - add_fingerprint(user) - playsound(src, 'sound/machines/windowdoor.ogg', 50, 1) - else - to_chat(user, "[occupant] was faster. Try better next time, loser.") + to_chat(user, "You were too slow. Try better next time, loser.") else to_chat(user, "You stop entering \the [src].") else to_chat(user, "You can't fit in \the [src], it's full!") -/obj/spacepod/proc/occupant_sanity_check() - if(occupant) - if(!ismob(occupant)) - occupant.forceMove(get_turf(src)) - log_debug("##SPACEPOD WARNING: NON-MOB OCCUPANT [occupant], TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") - occupant = null - else if(occupant.loc != src) - log_debug("##SPACEPOD WARNING: OCCUPANT [occupant] ESCAPED, TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") - occupant = null - if(occupant2) - if(!ismob(occupant2)) - occupant2.forceMove(get_turf(src)) - log_debug("##SPACEPOD WARNING: NON-MOB OCCUPANT [occupant2], TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") - occupant2 = null - else if(occupant2.loc != src) - log_debug("##SPACEPOD WARNING: OCCUPANT [occupant2] ESCAPED, TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") - occupant2 = null +/obj/spacepod/proc/occupant_sanity_check() // going to have to adjust this later for cargo refactor + if(passengers) + if(passengers.len > max_passengers) + for(var/i = passengers.len; i <= max_passengers; i--) + var/mob/occupant = passengers[i - 1] + occupant.forceMove(get_turf(src)) + log_debug("##SPACEPOD WARNING: passengers EXCEED CAP: MAX passengers [max_passengers], passengers [english_list(passengers)], TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") + passengers[i - 1] = null + for(var/mob/M in passengers) + if(!ismob(M)) + M.forceMove(get_turf(src)) + log_debug("##SPACEPOD WARNING: NON-MOB OCCUPANT [M], TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") + passengers -= M + else if(M.loc != src) + log_debug("##SPACEPOD WARNING: OCCUPANT [M] ESCAPED, TURF [get_turf(src)] | AREA [get_area(src)] | COORDS [x], [y], [z]") + passengers -= M /obj/spacepod/verb/exit_pod() set name = "Exit pod" @@ -686,64 +729,34 @@ set src = usr.loc var/mob/user = usr - var/spos = 0 if(!istype(user)) return - occupant_sanity_check() - - if(occupant == user) spos = 1 - if(occupant2 == user) spos = 2 - - switch(spos) - if(0) return - if(1) - if(occupant2) - to_chat(occupant2, "[occupant.name] climbs out of the pod!") - occupant.forceMove(src.loc) - occupant = null - to_chat(user, "You climb out of \the [src].") - if(2) - if(occupant) - to_chat(occupant, "[occupant2.name] climbs out of the pod!") - occupant2.forceMove(src.loc) - occupant2 = null - to_chat(user, "You climb out of \the [src].") - -/obj/spacepod/verb/exit_pod2() - set name = "Eject Secondary Seat" - set category = "Spacepod" - set src = usr.loc + if (user.stat != CONSCIOUS || user.incapacitated()) // unconscious and restrained people can't let themselves out + return occupant_sanity_check() - if(!occupant2) - to_chat(usr, "There is no one in the second seat.") - return + if(user == pilot) + user.forceMove(get_turf(src)) + pilot = null + to_chat(user, "You climb out of \the [src].") + if(user in passengers) + user.forceMove(get_turf(src)) + passengers -= user + to_chat(user, "You climb out of \the [src].") - if(usr == occupant2) - to_chat(usr, "How do you plan to do that? The eject button is out of reach.") - return - - if(usr == occupant) - to_chat(usr, "You eject [occupant2.name].") - to_chat(occupant2, "\The [src] ejects you forcefully!") - inertia_dir = 0 - occupant2.forceMove(src.loc) - occupant2 = null - -/obj/spacepod/verb/locksecondseat() +/obj/spacepod/verb/lock_pod() set name = "Lock Doors" set category = "Spacepod" set src = usr.loc - if(CheckIfOccupant2(usr)) - if(!allow2enter) - to_chat(usr, "You can't [allow2enter ? "lock" : "unlock"] the doors from your seat.") - return + if(usr in passengers && usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") + return - allow2enter = !allow2enter - to_chat(usr, "You [allow2enter ? "unlock" : "lock"] the doors.") + unlocked = !unlocked + to_chat(usr, "You [unlocked ? "unlock" : "lock"] the doors.") /obj/spacepod/verb/toggleDoors() @@ -751,7 +764,10 @@ set category = "Spacepod" set src = usr.loc - if(CheckIfOccupant2(usr)) return + if(usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") + return + for(var/obj/machinery/door/poddoor/multi_tile/P in orange(3,src)) var/mob/living/carbon/human/L = usr if(P.check_access(L.get_active_hand()) || P.check_access(L.wear_id)) @@ -761,41 +777,53 @@ else P.close() return 1 + for(var/mob/living/carbon/human/O in passengers) + if(P.check_access(O.get_active_hand()) || P.check_access(O.wear_id)) + if(P.density) + P.open() + return 1 + else + P.close() + return 1 to_chat(usr, "Access denied.") return to_chat(usr, "You are not close to any pod doors.") - return - /obj/spacepod/verb/fireWeapon() - if(!CheckIfOccupant2(usr)) - set name = "Fire Pod Weapons" - set desc = "Fire the weapons." - set category = "Spacepod" - set src = usr.loc - if(!equipment_system.weapon_system) - to_chat(usr, "\The [src] has no weapons!") - return - equipment_system.weapon_system.fire_weapons() + set name = "Fire Pod Weapons" + set desc = "Fire the weapons." + set category = "Spacepod" + set src = usr.loc + if(usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") + return + if(!equipment_system.weapon_system) + to_chat(usr, "\The [src] has no weapons!") + return + equipment_system.weapon_system.fire_weapons() /obj/spacepod/verb/unload() - if(!CheckIfOccupant2(usr)) - set name = "Unload Cargo" - set desc = "Unloads the cargo" - set category = "Spacepod" - set src = usr.loc - if(!equipment_system.cargo_system) - to_chat(usr, "\The [src] has no cargo system!") - return - equipment_system.cargo_system.unload() + set name = "Unload Cargo" + set desc = "Unloads the cargo" + set category = "Spacepod" + set src = usr.loc + if(usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") + return + if(!equipment_system.cargo_system) + to_chat(usr, "\The [src] has no cargo system!") + return + equipment_system.cargo_system.unload() /obj/spacepod/verb/toggleLights() set name = "Toggle Lights" set category = "Spacepod" set src = usr.loc - if(!CheckIfOccupant2(usr)) - lightsToggle() + if(usr != src.pilot) + to_chat(usr, "You can't reach the controls from your chair") + return + lightsToggle() /obj/spacepod/proc/lightsToggle() lights = !lights @@ -803,8 +831,30 @@ set_light(lights_power) else set_light(0) - to_chat(occupant, "Toggled lights [lights ? "on" : "off"].") - return + to_chat(usr, "Lights toggled [lights ? "on" : "off"].") + for(var/mob/M in passengers) + to_chat(M, "Lights toggled [lights ? "on" : "off"].") + +/obj/spacepod/verb/checkSeat() + set name = "Check under Seat" + set category = "Spacepod" + set src = usr.loc + var/mob/user = usr + to_chat(user, "You start rooting around under the seat for lost items") + if(do_after(user, 40, target = src)) + var/obj/badlist = list(internal_tank, cargo_hold, pilot, battery) + passengers + equipment_system.installed_modules + var/list/true_contents = contents - badlist + if(true_contents.len > 0) + var/obj/I = pick(true_contents) + if(user.put_in_any_hand_if_possible(I)) + src.contents -= I + to_chat(user, "You find a [I] [pick("under the seat", "under the console", "in the mainenance access")]!") + else + to_chat(user, "You think you saw something shiny, but you can't reach it!") + else + to_chat(user, "You fail to find anything of value.") + else + to_chat(user, "You decide against searching the [src]") /obj/spacepod/proc/enter_after(delay as num, var/mob/user as mob, var/numticks = 5) var/delayfraction = delay/numticks @@ -825,7 +875,6 @@ if(spacepod.cabin_air && spacepod.cabin_air.return_volume() > 0) var/delta = spacepod.cabin_air.temperature - T20C spacepod.cabin_air.temperature -= max(-10, min(10, round(delta/4,0.1))) - return /datum/global_iterator/pod_tank_give_air delay = 15 @@ -858,11 +907,11 @@ qdel(removed) else return stop() - return /obj/spacepod/relaymove(mob/user, direction) - if(!CheckIfOccupant2(user)) - handlerelaymove(user, direction) + if(usr != src.pilot) + return + handlerelaymove(user, direction) /obj/spacepod/proc/handlerelaymove(mob/user, direction) if(world.time < next_move) @@ -909,15 +958,6 @@ battery.charge = max(0, battery.charge - 1) next_move = world.time + move_delay -/obj/spacepod/proc/CheckIfOccupant2(mob/user) - if(!src.occupant2) - return 0 - if(src.occupant2) - if(user == src.occupant2) - return 1 - else - return 0 - /obj/effect/landmark/spacepod/random name = "spacepod spawner" invisibility = 101 @@ -929,4 +969,4 @@ ..() #undef DAMAGE -#undef FIRE +#undef FIRE \ No newline at end of file diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index 82cda80e494..88b2f42416c 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -23,7 +23,6 @@ name = "robotic cavity implant" steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/cavity/place_item,/datum/surgery_step/robotics/external/close_hatch) possible_locs = list("chest","head","groin") - allowed_mob = list(/mob/living/carbon/human/machine) /datum/surgery/cavity_implant/can_start(mob/user, mob/living/carbon/target) if(target.get_species() == "Machine") @@ -231,7 +230,6 @@ name = "implant removal" steps = list(/datum/surgery_step/robotics/external/unscrew_hatch,/datum/surgery_step/robotics/external/open_hatch,/datum/surgery_step/cavity/implant_removal,/datum/surgery_step/robotics/external/close_hatch) possible_locs = list("chest")//head is for borers..i can put it elsewhere - allowed_mob = list(/mob/living/carbon/human/machine) /datum/surgery/cavity_implant_rem/can_start(mob/user, mob/living/carbon/target) if(target.get_species() == "Machine") diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm index 3386f4b9366..8c0d20224e9 100644 --- a/code/modules/surgery/limb_reattach.dm +++ b/code/modules/surgery/limb_reattach.dm @@ -40,7 +40,6 @@ name = "limb attachment" steps = list(/datum/surgery_step/limb/attach) possible_locs = list("head","l_arm", "l_hand","r_arm","r_hand","r_leg","r_foot","l_leg","l_foot","groin") - allowed_mob = list(/mob/living/carbon/human/machine) /datum/surgery/reattach_synth/can_start(mob/user, mob/living/carbon/target) if(ishuman(target)) @@ -97,10 +96,12 @@ E.forceMove(target) if(target.get_species() == "Machine")//as this is the only step needed for ipc put togethers if(target_zone == "head") - var/obj/item/organ/external/head/H = target.organs_by_name["head"] + var/obj/item/organ/external/head/H = target.get_organ("head") var/datum/robolimb/robohead = all_robolimbs[H.model] if(robohead.is_monitor) //Ensures that if an IPC gets a head that's got a human hair wig attached to their body, the hair won't wipe. - target.h_style = "" + H.h_style = "" + H.f_style = "" + target.m_style = "" E.status &= ~ORGAN_DESTROYED if(E.children) for(var/obj/item/organ/external/C in E.children) diff --git a/code/modules/surgery/organs/augments_internal.dm b/code/modules/surgery/organs/augments_internal.dm index a5af2caca3d..b753bcf71a5 100644 --- a/code/modules/surgery/organs/augments_internal.dm +++ b/code/modules/surgery/organs/augments_internal.dm @@ -144,6 +144,13 @@ spawn(90 / severity) crit_fail = 0 +/obj/item/organ/internal/cyberimp/brain/clown_voice + name = "Comical implant" + desc = "Uh oh." + implant_color = "#DEDE00" + slot = "brain_clownvoice" + origin_tech = "materials=2;biotech=2" + //[[[[CHEST]]]] /obj/item/organ/internal/cyberimp/chest name = "cybernetic torso implant" @@ -315,7 +322,7 @@ organ_action_name = "Toggle Arm Cannon Taser" /obj/item/organ/internal/cyberimp/chest/arm_mod/tase/New()//when the implant is created... - holder = new /obj/item/weapon/gun/energy/advtaser/mounted(src)//assign a brand new item to it. (in this case, a gun) + holder = new /obj/item/weapon/gun/energy/gun/advtaser/mounted(src)//assign a brand new item to it. (in this case, a gun) /obj/item/organ/internal/cyberimp/chest/arm_mod/lase//mounted, self-charging laser! name = "Arm-cannon laser implant" @@ -351,4 +358,4 @@ var/implant while(contents.len <= amount + 1) // +1 for the autoimplanter. implant = pick(boxed) - new implant(src) \ No newline at end of file + new implant(src) diff --git a/code/modules/surgery/organs/blood.dm b/code/modules/surgery/organs/blood.dm index f2dd4c3c778..c1a1c7562a9 100644 --- a/code/modules/surgery/organs/blood.dm +++ b/code/modules/surgery/organs/blood.dm @@ -190,7 +190,9 @@ var/const/BLOOD_VOLUME_SURVIVE = 122 if(src.species.exotic_blood) vessel.remove_reagent(species.exotic_blood,amm) - vessel.reaction(T, TOUCH, amm) + if(vessel.total_volume) + var/fraction = amm / vessel.total_volume + vessel.reaction(T, TOUCH, fraction) return else diff --git a/code/modules/surgery/organs/helpers.dm b/code/modules/surgery/organs/helpers.dm index 29bd9801b26..a61537f1985 100644 --- a/code/modules/surgery/organs/helpers.dm +++ b/code/modules/surgery/organs/helpers.dm @@ -40,4 +40,9 @@ return O /proc/is_int_organ(atom/A) - return istype(A, /obj/item/organ/internal) \ No newline at end of file + return istype(A, /obj/item/organ/internal) + +/mob/living/carbon/human/proc/get_limb_by_name(limb_name) //Look for a limb with the given limb name in the source mob, and return it if found. + for(var/obj/item/organ/external/O in organs) + if(limb_name == O.limb_name) + return O diff --git a/code/modules/surgery/organs/organ.dm b/code/modules/surgery/organs/organ.dm index 3bce602694a..9c1398c6405 100644 --- a/code/modules/surgery/organs/organ.dm +++ b/code/modules/surgery/organs/organ.dm @@ -176,7 +176,12 @@ var/list/organ_cache = list() /obj/item/organ/proc/rejuvenate() damage = 0 germ_level = 0 - status &= ~ORGAN_DEAD + if(status & ORGAN_ROBOT) //Robotic organs stay robotic. + status = ORGAN_ROBOT + else if (status & ORGAN_ASSISTED) //Assisted organs stay assisted. + status = ORGAN_ASSISTED + else + status = 0 if(!owner) processing_objects |= src diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm index ac96bd0f775..d0245c224d9 100644 --- a/code/modules/surgery/organs/organ_external.dm +++ b/code/modules/surgery/organs/organ_external.dm @@ -308,14 +308,20 @@ This function completely restores a damaged organ to perfect condition. */ /obj/item/organ/external/rejuvenate() damage_state = "00" - if(status & 128) //Robotic organs stay robotic. Fix because right click rejuvinate makes IPC's organs organic. - status = 128 + if(status & ORGAN_ROBOT) //Robotic organs stay robotic. + status = ORGAN_ROBOT + else if (status & ORGAN_ASSISTED) //Assisted organs stay assisted. + status = ORGAN_ASSISTED else status = 0 germ_level = 0 perma_injury = 0 brute_dam = 0 burn_dam = 0 + open = 0 //Closing all wounds. + wounds.Cut() //Clears all wounds! Good as new. + if(istype(src, /obj/item/organ/external/head) && disfigured) //If their head's disfigured, refigure it. + disfigured = 0 // handle internal organs for(var/obj/item/organ/internal/current_organ in internal_organs) diff --git a/code/modules/surgery/organs/organ_icon.dm b/code/modules/surgery/organs/organ_icon.dm index db6ffd81a2a..0488d768adf 100644 --- a/code/modules/surgery/organs/organ_icon.dm +++ b/code/modules/surgery/organs/organ_icon.dm @@ -54,6 +54,7 @@ var/global/list/limb_icon_cache = list() overlays.Cut() if(!owner) return + var/obj/item/organ/external/head/H = owner.get_organ("head") if(species.has_organ["eyes"]) var/obj/item/organ/internal/eyes/eyes = owner.get_int_organ(/obj/item/organ/internal/eyes)//owner.internal_organs_by_name["eyes"] @@ -79,32 +80,32 @@ var/global/list/limb_icon_cache = list() markings_s.Blend(rgb(owner.r_markings, owner.g_markings, owner.b_markings), ICON_ADD) overlays |= markings_s - if(owner.ha_style) - var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[owner.ha_style] - if(head_accessory_style && head_accessory_style.species_allowed && (species.name in head_accessory_style.species_allowed)) + if(H.ha_style) + var/datum/sprite_accessory/head_accessory_style = head_accessory_styles_list[H.ha_style] + if(head_accessory_style && head_accessory_style.species_allowed && (H.species.name in head_accessory_style.species_allowed)) var/icon/head_accessory_s = new/icon("icon" = head_accessory_style.icon, "icon_state" = "[head_accessory_style.icon_state]_s") if(head_accessory_style.do_colouration) - head_accessory_s.Blend(rgb(owner.r_headacc, owner.g_headacc, owner.b_headacc), ICON_ADD) + head_accessory_s.Blend(rgb(H.r_headacc, H.g_headacc, H.b_headacc), ICON_ADD) overlays |= head_accessory_s - if(owner.f_style) - var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[owner.f_style] - if(facial_hair_style && ((facial_hair_style.species_allowed && (species.name in facial_hair_style.species_allowed)) || (src.species.flags & ALL_RPARTS))) + if(H.f_style) + var/datum/sprite_accessory/facial_hair_style = facial_hair_styles_list[H.f_style] + if(facial_hair_style && ((facial_hair_style.species_allowed && (H.species.name in facial_hair_style.species_allowed)) || (src.species.flags & ALL_RPARTS))) var/icon/facial_s = new/icon("icon" = facial_hair_style.icon, "icon_state" = "[facial_hair_style.icon_state]_s") - if(species.name == "Slime People") // I am el worstos + if(H.species.name == "Slime People") // I am el worstos facial_s.Blend(rgb(owner.r_skin, owner.g_skin, owner.b_skin, 160), ICON_AND) else if(facial_hair_style.do_colouration) - facial_s.Blend(rgb(owner.r_facial, owner.g_facial, owner.b_facial), ICON_ADD) + facial_s.Blend(rgb(H.r_facial, H.g_facial, H.b_facial), ICON_ADD) overlays |= facial_s - if(owner.h_style && !(owner.head && (owner.head.flags & BLOCKHEADHAIR))) - var/datum/sprite_accessory/hair_style = hair_styles_list[owner.h_style] - if(hair_style && ((species.name in hair_style.species_allowed) || (src.species.flags & ALL_RPARTS))) + if(H.h_style && !(owner.head && (owner.head.flags & BLOCKHEADHAIR))) + var/datum/sprite_accessory/hair_style = hair_styles_list[H.h_style] + if(hair_style && ((H.species.name in hair_style.species_allowed) || (src.species.flags & ALL_RPARTS))) var/icon/hair_s = new/icon("icon" = hair_style.icon, "icon_state" = "[hair_style.icon_state]_s") - if(species.name == "Slime People") // I am el worstos + if(H.species.name == "Slime People") // I am el worstos hair_s.Blend(rgb(owner.r_skin, owner.g_skin, owner.b_skin, 160), ICON_AND) else if(hair_style.do_colouration) - hair_s.Blend(rgb(owner.r_hair, owner.g_hair, owner.b_hair), ICON_ADD) + hair_s.Blend(rgb(H.r_hair, H.g_hair, H.b_hair), ICON_ADD) overlays |= hair_s return mob_icon diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 248da9d1154..57e2934dbb4 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -10,6 +10,7 @@ vital = 0 var/organ_action_name = null var/non_primary = 0 + action_button_custom_type = /datum/action/item_action/organ_action /obj/item/organ/internal/New(var/mob/living/carbon/holder) if(istype(holder)) @@ -292,6 +293,7 @@ organ_tag = "liver" parent_organ = "groin" slot = "liver" + var/alcohol_intensity = 1 /obj/item/organ/internal/liver/process() @@ -499,18 +501,19 @@ if(istype(owner, /mob/living/carbon/human)) var/mob/living/carbon/human/H = owner - if(!(H.h_style == "Very Long Hair" || H.h_style == "Mowhawk")) + var/obj/item/organ/external/head/head_organ = H.get_organ("head") + if(!(head_organ.h_style == "Very Long Hair" || head_organ.h_style == "Mohawk")) if(prob(10)) - H.h_style = "Mohawk" + head_organ.h_style = "Mohawk" else - H.h_style = "Very Long Hair" - H.r_hair = 216 - H.g_hair = 192 - H.b_hair = 120 + head_organ.h_style = "Very Long Hair" + head_organ.r_hair = 216 + head_organ.g_hair = 192 + head_organ.b_hair = 120 H.update_hair() - if(!(H.f_style == "Very Long Beard")) - H.f_style = "Very Long Beard" - H.r_facial = 216 - H.g_facial = 192 - H.b_facial = 120 + if(!(head_organ.f_style == "Very Long Beard")) + head_organ.f_style = "Very Long Beard" + head_organ.r_facial = 216 + head_organ.g_facial = 192 + head_organ.b_facial = 120 H.update_fhair() \ No newline at end of file diff --git a/code/modules/surgery/organs/subtypes/diona.dm b/code/modules/surgery/organs/subtypes/diona.dm index 407f2187842..5d2bf63035b 100644 --- a/code/modules/surgery/organs/subtypes/diona.dm +++ b/code/modules/surgery/organs/subtypes/diona.dm @@ -17,125 +17,81 @@ D.death() return 1 */ -/obj/item/organ/external/diona - name = "tendril" +/obj/item/organ/external/chest/diona + name = "core trunk" + max_damage = 200 + min_broken_damage = 50 + cannot_break = 1 + amputation_point = "trunk" + encased = null + gendered_icon = 0 + +/obj/item/organ/external/groin/diona + name = "fork" + min_broken_damage = 50 + cannot_break = 1 + amputation_point = "lower trunk" + gendered_icon = 0 + +/obj/item/organ/external/arm/diona + name = "left upper tendril" + max_damage = 35 + min_broken_damage = 20 + cannot_break = 1 + amputation_point = "upper left trunk" + +/obj/item/organ/external/arm/right/diona + name = "right upper tendril" + max_damage = 35 + min_broken_damage = 20 + cannot_break = 1 + amputation_point = "upper right trunk" + +/obj/item/organ/external/leg/diona + name = "left lower tendril" + max_damage = 35 + min_broken_damage = 20 + cannot_break = 1 + amputation_point = "lower left fork" + +/obj/item/organ/external/leg/right/diona + name = "right lower tendril" + max_damage = 35 + min_broken_damage = 20 + cannot_break = 1 + amputation_point = "lower right fork" + +/obj/item/organ/external/foot/diona + name = "left foot" + max_damage = 20 + min_broken_damage = 10 cannot_break = 1 amputation_point = "branch" -/obj/item/organ/external/diona/chest - name = "core trunk" - limb_name = "chest" - icon_name = "torso" - max_damage = 200 - min_broken_damage = 50 - w_class = 5 - body_part = UPPER_TORSO - vital = 1 - cannot_amputate = 1 - parent_organ = null - -/obj/item/organ/external/diona/groin - name = "fork" - limb_name = "groin" - icon_name = "groin" - max_damage = 100 - min_broken_damage = 50 - w_class = 4 - body_part = LOWER_TORSO - parent_organ = "chest" - -/obj/item/organ/external/diona/arm - name = "left upper tendril" - limb_name = "l_arm" - icon_name = "l_arm" - max_damage = 35 - min_broken_damage = 20 - w_class = 3 - body_part = ARM_LEFT - parent_organ = "chest" - can_grasp = 1 - -/obj/item/organ/external/diona/arm/right - name = "right upper tendril" - limb_name = "r_arm" - icon_name = "r_arm" - body_part = ARM_RIGHT - -/obj/item/organ/external/diona/leg - name = "left lower tendril" - limb_name = "l_leg" - icon_name = "l_leg" - max_damage = 35 - min_broken_damage = 20 - w_class = 3 - body_part = LEG_LEFT - icon_position = LEFT - parent_organ = "groin" - can_stand = 1 - -/obj/item/organ/external/diona/leg/right - name = "right lower tendril" - limb_name = "r_leg" - icon_name = "r_leg" - body_part = LEG_RIGHT - icon_position = RIGHT - -/obj/item/organ/external/diona/foot - name = "left foot" - limb_name = "l_foot" - icon_name = "l_foot" +/obj/item/organ/external/foot/right/diona + name = "right foot" max_damage = 20 min_broken_damage = 10 - w_class = 2 - body_part = FOOT_LEFT - icon_position = LEFT - parent_organ = "l_leg" - can_stand = 1 + cannot_break = 1 + amputation_point = "branch" -/obj/item/organ/external/diona/foot/right - name = "right foot" - limb_name = "r_foot" - icon_name = "r_foot" - body_part = FOOT_RIGHT - icon_position = RIGHT - parent_organ = "r_leg" - amputation_point = "right ankle" - -/obj/item/organ/external/diona/hand +/obj/item/organ/external/hand/diona name = "left grasper" - limb_name = "l_hand" - icon_name = "l_hand" - max_damage = 30 - min_broken_damage = 15 - w_class = 2 - body_part = HAND_LEFT - parent_organ = "l_arm" - can_grasp = 1 + cannot_break = 1 + amputation_point = "branch" -/obj/item/organ/external/diona/hand/right +/obj/item/organ/external/hand/right/diona name = "right grasper" - limb_name = "r_hand" - icon_name = "r_hand" - body_part = HAND_RIGHT - parent_organ = "r_arm" + cannot_break = 1 + amputation_point = "branch" -/obj/item/organ/external/diona/head - limb_name = "head" - icon_name = "head" - name = "head" +/obj/item/organ/external/head/diona max_damage = 50 min_broken_damage = 25 - vital = 1 - w_class = 3 - body_part = HEAD - parent_organ = "chest" - var/can_intake_reagents = 1 - -/obj/item/organ/external/diona/head/remove() - if(owner) - owner.unEquip(owner.head) - owner.unEquip(owner.l_ear) - ..() + cannot_break = 1 + encased = null + amputation_point = "upper trunk" + gendered_icon = 0 //DIONA ORGANS. /* /obj/item/organ/external/diona/removed() diff --git a/code/modules/surgery/organs/subtypes/drask.dm b/code/modules/surgery/organs/subtypes/drask.dm index 5ecfa67e054..3e9b37cebe8 100644 --- a/code/modules/surgery/organs/subtypes/drask.dm +++ b/code/modules/surgery/organs/subtypes/drask.dm @@ -38,6 +38,8 @@ icon_state = "brain2" organ_tag = "brain" slot = "brain" + mmi_icon = 'icons/obj/surgery_drask.dmi' + mmi_icon_state = "mmi_full" /obj/item/organ/internal/eyes/drask name = "eyes" diff --git a/code/modules/surgery/organs/subtypes/skrell.dm b/code/modules/surgery/organs/subtypes/skrell.dm new file mode 100644 index 00000000000..faf58b7a3ef --- /dev/null +++ b/code/modules/surgery/organs/subtypes/skrell.dm @@ -0,0 +1,2 @@ +/obj/item/organ/internal/liver/skrell + alcohol_intensity = 5 \ No newline at end of file diff --git a/code/modules/surgery/organs/subtypes/standard.dm b/code/modules/surgery/organs/subtypes/standard.dm index c9cbbb17906..d481ba1b7ae 100644 --- a/code/modules/surgery/organs/subtypes/standard.dm +++ b/code/modules/surgery/organs/subtypes/standard.dm @@ -141,6 +141,24 @@ encased = "skull" var/can_intake_reagents = 1 + //Hair colour and style + var/r_hair = 0 + var/g_hair = 0 + var/b_hair = 0 + var/h_style = "Bald" + + //Head accessory colour and style + var/r_headacc = 0 + var/g_headacc = 0 + var/b_headacc = 0 + var/ha_style = "None" + + //Facial hair colour and style + var/r_facial = 0 + var/g_facial = 0 + var/b_facial = 0 + var/f_style = "Shaved" + /obj/item/organ/external/head/remove() if(owner) if(!istype(dna)) diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index e5c6292fa56..8f7ed0e6d67 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -31,7 +31,7 @@ return 0 if(target.get_species() == "Machine")//i know organ robot might be enough but i am not taking chances... return 0 - if(!affected.encased)//no bone, problem. + if(affected && !affected.encased) //no bone, problem. return 0 return 1 @@ -43,9 +43,9 @@ if(affected && (affected.status & ORGAN_ROBOT)) return 0//no operating on robotic limbs in an organic surgery - if(!affected.encased)//no bones no problem. - return 1 - return 0 + if(affected && affected.encased) //no bones no problem. + return 0 + return 1 /datum/surgery/organ_manipulation/alien/can_start(mob/user, mob/living/carbon/target) if(istype(target,/mob/living/carbon/alien/humanoid)) diff --git a/code/modules/vehicle/ambulance.dm b/code/modules/vehicle/ambulance.dm index 526b1e2c0a9..7d3f9084f5f 100644 --- a/code/modules/vehicle/ambulance.dm +++ b/code/modules/vehicle/ambulance.dm @@ -35,7 +35,8 @@ if(bed && get_dist(oldloc, loc) <= 2) bed.Move(oldloc) bed.dir = Dir - bed.buckled_mob.dir = Dir + if(bed.buckled_mob) + bed.buckled_mob.dir = Dir /obj/structure/stool/bed/amb_trolley name = "ambulance train trolley" diff --git a/code/world.dm b/code/world.dm index f5cfdee0401..b28a0c2d0de 100644 --- a/code/world.dm +++ b/code/world.dm @@ -18,7 +18,7 @@ var/global/datum/global_init/init = new () cache_lifespan = 0 //stops player uploaded stuff from being kept in the rsc past the current session -#define RECOMMENDED_VERSION 508 +#define RECOMMENDED_VERSION 510 /world/New() //logs @@ -115,6 +115,7 @@ var/world_topic_spam_protect_time = world.timeofday else if ("status" in input) var/list/s = list() + var/list/admins = list() s["version"] = game_version s["mode"] = master_mode s["respawn"] = config ? abandon_allowed : 0 @@ -132,6 +133,7 @@ var/world_topic_spam_protect_time = world.timeofday if(C.holder.fakekey) continue //so stealthmins aren't revealed by the hub admin_count++ + admins += list(list(C.key, C.holder.rank)) s["player[player_count]"] = C.key player_count++ s["players"] = player_count @@ -150,6 +152,11 @@ var/world_topic_spam_protect_time = world.timeofday // Shuttle timer, in seconds s["shuttle_timer"] = shuttle_master.emergency.timeLeft() + for(var/i in 1 to admins.len) + var/list/A = admins[i] + s["admin[i - 1]"] = A[1] + s["adminrank[i - 1]"] = A[2] + return list2params(s) else if("adminmsg" in input) diff --git a/dm.sh b/dm.sh index 3d04531b3f4..d77cabc637a 100644 --- a/dm.sh +++ b/dm.sh @@ -79,7 +79,7 @@ else then DreamMaker $dmepath.mdme 2>&1 | tee result.log retval=$? - if ! grep '0 errors, 0 warnings' result.log + if ! grep '\- 0 errors, 0 warnings' result.log then retval=1 #hard fail, due to warnings or errors fi @@ -94,4 +94,4 @@ mv $dmepath.mdme.rsc $dmepath.rsc rm $dmepath.mdme -exit $retval \ No newline at end of file +exit $retval diff --git a/html/changelog.html b/html/changelog.html index 102d0b0136d..56ad627eb86 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,317 @@ -->
    +

    12 June 2016

    +

    CrAzYPiLoT updated:

    +
      +
    • Fixed the long-lasting bug of handcuffed people keeping their chainsaws.
    • +
    +

    Crazylemon64 updated:

    +
      +
    • No more language message-spam on roundstart
    • +
    +

    DaveTheHeadcrab updated:

    +
      +
    • Adds a new icon for the detective's scanner.
    • +
    • Detectives scanner now has access to DNA and fingerprint records.
    • +
    +

    Fox McCloud updated:

    +
      +
    • Adds three new chaplain weapons: pirate saber, multiverse sword, and possessed/talking sword
    • +
    • Fixes not being able to sheath the claymore in the Crusader Armor
    • +
    • Adds in a mocha drink
    • +
    • Fixes ice being unobtainable for the jobs that use it most
    • +
    • Fixes laser armor losing its reflecting ability
    • +
    • Fixes the lack of progress bars for more stack-based construction
    • +
    • Fixes Experimentor producing coffee machines instead of cups
    • +
    • Can deconvert mindslaves by removing their mindslave implant
    • +
    • Can deconvert Vampire thralls by feeding them holy water
    • +
    • Fixes mindslaves not having a HUD for the master and mindslave
    • +
    • Fixes being able to duplicate just about anything in the Experimentor
    • +
    • Fixes not being able to use tank transfer valves or one tank bombs in the Experimentor.
    • +
    • Fixes infinite-throw spam
    • +
    • Fixes being able to resist out of grabs by moving (that is to say, it'll actually work now)
    • +
    • Fixes passive grabs using the wrong HUD icon
    • +
    • Tabling duration reduced from 5 to 2
    • +
    • Can no longer wield double-bladed energy swords as a hulk
    • +
    • Fixes on map stools having the wrong offsets, making it look like you're not sitting on them
    • +
    +

    FreeStylaLT updated:

    +
      +
    • Added (Enabled) Mind Batterer for Traitors
    • +
    • Fixed uplink implant description (Said 5 when actually gave you 10 TCs)
    • +
    +

    Glorken updated:

    +
      +
    • Shifts Zeng-Hu left leg over in order to regain thigh gap.
    • +
    • Chops off a pixel on Bishop feet so that they fit into shoes.
    • +
    +

    KasparoVy updated:

    +
      +
    • Old placeholder IPC butt sprite replaced with the finished QR-code sprite.
    • +
    +

    Krausus updated:

    +
      +
    • Fixes ghosts failing to follow mobs that move in unusual ways
    • +
    • Fixed tape allowing mobs with sufficient access to move through solid objects.
    • +
    +

    Many -tg-station Coders, TheDZD updated:

    +
      +
    • Old gun code is now gone.
    • +
    • Ports the vast majority of TG's gun code and their guns (any previously unavailable guns, and newly-added guns will remain unavailable to players). Expect some changes that might not be listed here due to the sheer scope of this refactor.
    • +
    • Probably some new bugs.
    • +
    • A lot of old gun bugs.
    • +
    • Mouth suiciding with a gun no longer instantly kills you, you fire the gun at yourself at 5x damage (assuming it even did damage to begin with).
    • +
    • Mouth suicide shooting does not work on harm intent.
    • +
    • You can now bash people with guns while on harm intent instead of shooting them point-blank.
    • +
    • You can now mouth suicide other people, doing so still takes the full 12 seconds to mouth suicide, but has the same 5x damage multiplier.
    • +
    • Vox spike throwers are real guns that fire spike bullets now, instead of just being fake guns that threw spikes. They do 25 damage per hit, have 30 armor piercing, cause a 1 second stun (not the kind that drops you to the floor), and cause some bleeding. They have 2 round burst fire as well, and have 10 shots per clip. A new should should recharge every 20 or so seconds.
    • +
    • Xray lasers now have a maximum range of 15 tiles.
    • +
    • Zoomed guns now actually fire accurately while zoomed.
    • +
    • Using Suicide with guns now actually does gun-like things.
    • +
    • The clown no longer deletes guns if he fucks up with them due to being clumsy.
    • +
    • Emitters no longer become inaccurate over long ranges.
    • +
    • Power gloves now override middle-click and alt-click when worn.
    • +
    • Power gloves give a notification when worn.
    • +
    • Power gloves now have special examine text when examined by an antagonist.
    • +
    • Proto SMGs now only have a 21 shot clip.
    • +
    +

    Spacemanspark updated:

    +
      +
    • Adds the ability to make a more irritated buzz noise at people as a synthetic. The original buzz is still there.
    • +
    +

    Tauka Usanake updated:

    +
      +
    • Adds more belt icon overlays
    • +
    +

    Twinmold updated:

    +
      +
    • Nar'Sie AI Hologram and Error Sprite
    • +
    • Fixes space pod equipment variable. Can now properly install/uninstall equipment.
    • +
    • Check Seat verb no longer pulls out installed equipment.
    • +
    • You can now have a passenger in your pod if you have a passenger seat.
    • +
    +

    monster860 updated:

    +
      +
    • Adds comical implant. It is an implant that causes you to have a comic sans voice. It can be made in the protolathe using bananium.
    • +
    • The comical implant now spawns by default inside IPC clowns
    • +
    • Fixes the window getting stuck when you try to drag or resize a NanoUI window too fast with Fancy NanoUI enabled
    • +
    • Fixes a small quirk with the resize handle.
    • +
    • Fix javascript error in cargo UI
    • +
    +

    pinatacolada updated:

    +
      +
    • removes atmos tech SOP from supply SOP
    • +
    • Fixes defibing people without a heart
    • +
    • Fixes defib saying it didn't work stopping a heart attack when they do
    • +
    + +

    02 June 2016

    +

    CrAzYPiLoT updated:

    +
      +
    • Fixed a text problem in virtual gameboard description.
    • +
    • Made gameboards deconstructable and movable.
    • +
    • Added a light to gameboards. Pretty!
    • +
    +

    Crazylemon64 updated:

    +
      +
    • There will no longer be a mountain of startup runtimes when people have custom languages.
    • +
    +

    DaveTheHeadcrab updated:

    +
      +
    • Removes xenobio golem rune creation sound
    • +
    • Added overlays for sec belts that reflect the items stored therein.
    • +
    +

    Fox McCloud updated:

    +
      +
    • Fixes Chapel and Chaplain's office not having a light switch
    • +
    • Fixes mass driver only being usable once due to weird pressure
    • +
    • Fixes chapel being overly dark near coffins
    • +
    • Fixes not being able to sheath the claymore in the Crusader Armor
    • +
    +

    IK3I updated:

    +
      +
    • crate cargo system
    • +
    • passenger seat system
    • +
    • loot box secondary cargo system (install it and your pod has a standard inventory)
    • +
    • lock busters for the CE and Armory
    • +
    • incappacitated people can't operate the door controls anymore
    • +
    • Items dropped in a pod can now be scrounged up
    • +
    • security can rip you out of an unlocked pod
    • +
    • The pod code isn't full of tumors any more
    • +
    +

    Tastyfish updated:

    +
      +
    • Holsters now have an action button while on your suit again.
    • +
    +

    monster860 updated:

    +
      +
    • Adds the following words to the AI announcer: active, airlock, alcohol, arrival, arrivals, becoming, between, blob, briefing, camp, chair, chapel, closet, cyberiad, declared, detective, diona, dock, docked, docking, docks, drask, drunk, emag, equipment, evacuation, experimentor, gateway, hail, hallway, holoparasite, honk, hull, ian, imminent, interested, intruders, kida, kidan, labor, library, mime, mimes, miner, miners, mining, n2o, nuke, office, op, operational, ops, pod, pods, poly, pun, renault, representative, runtime, scrubbers, sequencer, skree, skrek, skrell, space, spider, spiders, still, stupid, swarmer, swarmers, sword, technology, teleport, teleported, teleporter, teleporting, tesla, tool, unathi, vacant, vault, vents, vulpkanin, weld, window, windows, yet
    • +
    + +

    31 May 2016

    +

    CrAzYPiLoT updated:

    +
      +
    • Fixes potential exploits involving door remotes.
    • +
    • Adds another type of remote door control.
    • +
    +

    Fox McCloud updated:

    +
      +
    • Allows Chaplain to select a wide new range of null rod customizations
    • +
    • Slightly increases null rod damage (15->18)
    • +
    • Fixes abductors speaking other languages
    • +
    • Fixes traitors getting less TC on some game modes
    • +
    +

    QuinnAggeler updated:

    +
      +
    • All lazarus revived mobs become valid for pet collaring
    • +
    +

    Tastyfish updated:

    +
      +
    • Adds a suicide for light tubes.
    • +
    • Progress bars, buttons, and several of the values in UI's are now animated.
    • +
    • Deconstructing glass tables now gives a stack of 2 sheets of glass.
    • +
    +

    monster860 updated:

    +
      +
    • Upgrading the experimentor will no longer reduce the chance of upgrading an item's tech
    • +
    • Guest passes can now be attached to an ID card.
    • +
    • Adds a HoP guest pass computer, which is like a normal guest pass computer, but using an ID with ID computer access will allow it to issue guest passes with any access.
    • +
    • Adds the HoP guest pass computer to the HoP office.
    • +
    • Moves the guest pass computer in robotics to RnD.
    • +
    + +

    25 May 2016

    +

    CrAzYPiLoT updated:

    +
      +
    • Adds an unread change notification.
    • +
    +

    Fox McCloud updated:

    +
      +
    • Removes Dragon's Breath Recipe
    • +
    • Removes Ghost Chilli Juice
    • +
    • Fixes buckled flipping over someone
    • +
    +

    IK3I updated:

    +
      +
    • Sleepers, scanners, and borg chargers no longer remove you from existence when destroyed
    • +
    • Hostile mobs are no longer fooled by your clever scanner and recharger tricks
    • +
    + +

    24 May 2016

    +

    CrAzYPiLoT updated:

    +
      +
    • Adds the ability to attach signalers to bear traps. Stealthy hunting!
    • +
    +

    Crazylemon64 updated:

    +
      +
    • You can now fasten the circulators in the TEG kit with a wrench - no adminbus needed to set it up, now
    • +
    • You can now rename cassette tapes with a pen.
    • +
    • You can now wipe data from a tape from its right-click menu.
    • +
    +

    FalseIncarnate updated:

    +
      +
    • Adds 4 new types of fudge for the chef to make: Peanut, Chocolate Cherry, Cookies 'n' Cream, and Turtle Fudge.
    • +
    • Normal fudge recipe now uses milk instead of cream.
    • +
    • Mutant/Modified/Enhanced plants will no longer infinitely increase their name length, and instead will be simply "mutant", "modified", or "enhanced" plant as determined by the last type of modification they were subject to.
    • +
    • Bees can no longer phase through hydroponics lids, giving botanists a way to finally stem the tide of pollination.
    • +
    • Premade beeboxes now spawn with the right type of bees, specifically of the worker caste.
    • +
    +

    Fox McCloud updated:

    +
      +
    • Donk pockets have more omnizine, but only upon fully consuming the donk pocket
    • +
    • swarmers will drop an artificial bluespace crystal on death
    • +
    • Orion Trail guards now drop an energy shield and C20R on death
    • +
    • Reviving simple animals with strange reagent will prevent them from dropping any further loot
    • +
    +

    KasparoVy updated:

    +
      +
    • Rejuvenating a mob now unbuckles them correctly (if they're buckled to something).
    • +
    • Rejuvenating a mob will no longer remove their hair.
    • +
    • Rejuvenating a mob will no longer permanently blacken their eyes.
    • +
    • Rejuvenating a mob will no longer remove their prostheses with fleshy limbs, it will just fix the prostheses.
    • +
    • Rejuvenating a mob will not remove organs/limbs belonging to other species if said organs/limbs are in the same place(s) as the mob's default organs/limbs would be.
    • +
    • Fixes a runtime when trying to flip with an object other than a grab in your hand.
    • +
    • Doing a 'cybernetic repair' procedure on the head of a disfigured IPC will re-figure them.
    • +
    • Rejuvenating a mob will only regrow organs/limbs that are missing (by comparison to the standard organs for their species).
    • +
    • The regenerate_icons proc will now update skin tone and body accessories properly.
    • +
    • Organ rejuvenation now clears disfigurement and closes open wounds.
    • +
    • Rejuvenating a mob will end all in-progress surgeries.
    • +
    • Vox get their cortical stacks back, since the non-implant ones don't interfere with the Heist game-mode.
    • +
    • Rejuvenating a long-dead or husked mob will now clear the appropriate mutations.
    • +
    +

    QuinnAggeler updated:

    +
      +
    • Species disguise variable for clothing items
    • +
    • Species disguise string, "High-tech robot," for cardborg suit and helmet
    • +
    • ABSTRACT flagged clothing items will not be displayed on examination
    • +
    +

    Tastyfish updated:

    +
      +
    • Removes n2 pills healing vox oxyloss, and o2 pills poisoning vox.
    • +
    +

    monster860 updated:

    +
      +
    • Adds the floor painter. Sprite by FlattestGuitar
    • +
    + +

    20 May 2016

    +

    Fox McCloud updated:

    +
      +
    • Fixes Chaplains being able to be vampires
    • +
    • Cryopods will now always display the occupant's name
    • +
    +

    KasparoVy updated:

    +
      +
    • Fixes a runtime with Dioneae by repathing their limbs.
    • +
    +

    QuinnAggeler updated:

    +
      +
    • Makes dehydrated space carp description more accurate and informative
    • +
    +

    monster860 updated:

    +
      +
    • Adds the permanent teleporter. Use the circuitboard on a teleporter hub to set the target before constructing it.
    • +
    + +

    17 May 2016

    +

    AugRob updated:

    +
      +
    • Add screwdriver sound when opening/closing panels on airlocks
    • +
    +

    Fox MCCloud updated:

    +
      +
    • Removes "harm" traitor objective
    • +
    • Increases non-escape/hijack/die objectives from 1 to 2
    • +
    • Tweaks available objectives to traitors a bit
    • +
    +

    Fox McCloud updated:

    +
      +
    • Players can no longer see how many players have readied up or who has readied up
    • +
    • Hulks, Shadowlings, and Golems can no longer use laserpointers
    • +
    • Adds in the ability to flip over someone with *flip
    • +
    • Fixes and improves foam to better interact with reagents
    • +
    +

    KasparoVy updated:

    +
      +
    • Refactors hair so it's on the head (organ).
    • +
    • Adjusts some Vox hair style names so they're consistent with all others.
    • +
    • Refactors Morph and the order by which options are presented.
    • +
    • Players with heads of a different species than the body will now only be able to access the head accessories, hair/facial hair styles of the head's species.
    • +
    • Fixes some typos.
    • +
    • Fixes a bug where hairgrownium made you bald and super hairgrownium only changed the hair/facial hair styles of Humans.
    • +
    • Fixes a bug where Morph wouldn't correctly set eye colour or skin tone.
    • +
    • Fixes a typo that didn't really have any negative effect on the beard organ to begin with.
    • +
    • Fixes bugs where Alopecia and Facial Hypertrichosis disease symptoms wouldn't update player sprite correctly.
    • +
    • Adds a new Vox hairstyle.
    • +
    • You can now change your head accessory (and its colour), body markings (and their colour), and body accessory if you're a species that has such things via the Morph genetic power and C.M.A. (the bathroom SalonPro Nano-Mirrors and admin verbs).
    • +
    +

    monster860 updated:

    +
      +
    • Fixes sleep() in telecomms
    • +
    • Windows can now be constructed and deconstructed using RCD's.
    • +
    +

    10 May 2016

    Crazylemon64 updated:

      diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 747be21ca7d..0c1163ec003 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -1483,3 +1483,280 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. tigercat2000: - rscadd: The station blueprints can now show you where wires/pipes/disposal pipes are supposed to go. +2016-05-17: + AugRob: + - rscadd: Add screwdriver sound when opening/closing panels on airlocks + Fox MCCloud: + - tweak: Removes "harm" traitor objective + - tweak: Increases non-escape/hijack/die objectives from 1 to 2 + - tweak: Tweaks available objectives to traitors a bit + Fox McCloud: + - tweak: Players can no longer see how many players have readied up or who has readied + up + - tweak: Hulks, Shadowlings, and Golems can no longer use laserpointers + - rscadd: Adds in the ability to flip over someone with *flip + - tweak: Fixes and improves foam to better interact with reagents + KasparoVy: + - tweak: Refactors hair so it's on the head (organ). + - tweak: Adjusts some Vox hair style names so they're consistent with all others. + - tweak: Refactors Morph and the order by which options are presented. + - tweak: Players with heads of a different species than the body will now only be + able to access the head accessories, hair/facial hair styles of the head's species. + - bugfix: Fixes some typos. + - bugfix: Fixes a bug where hairgrownium made you bald and super hairgrownium only + changed the hair/facial hair styles of Humans. + - bugfix: Fixes a bug where Morph wouldn't correctly set eye colour or skin tone. + - bugfix: Fixes a typo that didn't really have any negative effect on the beard + organ to begin with. + - bugfix: Fixes bugs where Alopecia and Facial Hypertrichosis disease symptoms wouldn't + update player sprite correctly. + - rscadd: Adds a new Vox hairstyle. + - rscadd: You can now change your head accessory (and its colour), body markings + (and their colour), and body accessory if you're a species that has such things + via the Morph genetic power and C.M.A. (the bathroom SalonPro Nano-Mirrors and + admin verbs). + monster860: + - bugfix: Fixes sleep() in telecomms + - rscadd: Windows can now be constructed and deconstructed using RCD's. +2016-05-20: + Fox McCloud: + - bugfix: Fixes Chaplains being able to be vampires + - bugfix: Cryopods will now always display the occupant's name + KasparoVy: + - bugfix: Fixes a runtime with Dioneae by repathing their limbs. + QuinnAggeler: + - bugfix: Makes dehydrated space carp description more accurate and informative + monster860: + - rscadd: Adds the permanent teleporter. Use the circuitboard on a teleporter hub + to set the target before constructing it. +2016-05-24: + CrAzYPiLoT: + - rscadd: Adds the ability to attach signalers to bear traps. Stealthy hunting! + Crazylemon64: + - rscadd: You can now fasten the circulators in the TEG kit with a wrench - no adminbus + needed to set it up, now + - rscadd: You can now rename cassette tapes with a pen. + - rscadd: You can now wipe data from a tape from its right-click menu. + FalseIncarnate: + - rscadd: 'Adds 4 new types of fudge for the chef to make: Peanut, Chocolate Cherry, + Cookies ''n'' Cream, and Turtle Fudge.' + - tweak: Normal fudge recipe now uses milk instead of cream. + - tweak: Mutant/Modified/Enhanced plants will no longer infinitely increase their + name length, and instead will be simply "mutant", "modified", or "enhanced" + plant as determined by the last type of modification they were subject to. + - tweak: Bees can no longer phase through hydroponics lids, giving botanists a way + to finally stem the tide of pollination. + - bugfix: Premade beeboxes now spawn with the right type of bees, specifically of + the worker caste. + Fox McCloud: + - tweak: Donk pockets have more omnizine, but only upon fully consuming the donk + pocket + - tweak: swarmers will drop an artificial bluespace crystal on death + - tweak: Orion Trail guards now drop an energy shield and C20R on death + - tweak: Reviving simple animals with strange reagent will prevent them from dropping + any further loot + KasparoVy: + - bugfix: Rejuvenating a mob now unbuckles them correctly (if they're buckled to + something). + - bugfix: Rejuvenating a mob will no longer remove their hair. + - bugfix: Rejuvenating a mob will no longer permanently blacken their eyes. + - bugfix: Rejuvenating a mob will no longer remove their prostheses with fleshy + limbs, it will just fix the prostheses. + - bugfix: Rejuvenating a mob will not remove organs/limbs belonging to other species + if said organs/limbs are in the same place(s) as the mob's default organs/limbs + would be. + - bugfix: Fixes a runtime when trying to flip with an object other than a grab in + your hand. + - bugfix: Doing a 'cybernetic repair' procedure on the head of a disfigured IPC + will re-figure them. + - tweak: Rejuvenating a mob will only regrow organs/limbs that are missing (by comparison + to the standard organs for their species). + - tweak: The regenerate_icons proc will now update skin tone and body accessories + properly. + - rscadd: Organ rejuvenation now clears disfigurement and closes open wounds. + - rscadd: Rejuvenating a mob will end all in-progress surgeries. + - rscadd: Vox get their cortical stacks back, since the non-implant ones don't interfere + with the Heist game-mode. + - rscadd: Rejuvenating a long-dead or husked mob will now clear the appropriate + mutations. + QuinnAggeler: + - rscadd: Species disguise variable for clothing items + - rscadd: Species disguise string, "High-tech robot," for cardborg suit and helmet + - tweak: ABSTRACT flagged clothing items will not be displayed on examination + Tastyfish: + - rscdel: Removes n2 pills healing vox oxyloss, and o2 pills poisoning vox. + monster860: + - rscadd: Adds the floor painter. Sprite by FlattestGuitar +2016-05-25: + CrAzYPiLoT: + - rscadd: Adds an unread change notification. + Fox McCloud: + - tweak: Removes Dragon's Breath Recipe + - tweak: Removes Ghost Chilli Juice + - bugfix: Fixes buckled flipping over someone + IK3I: + - bugfix: Sleepers, scanners, and borg chargers no longer remove you from existence + when destroyed + - bugfix: Hostile mobs are no longer fooled by your clever scanner and recharger + tricks +2016-05-31: + CrAzYPiLoT: + - bugfix: Fixes potential exploits involving door remotes. + - rscadd: Adds another type of remote door control. + Fox McCloud: + - rscadd: Allows Chaplain to select a wide new range of null rod customizations + - tweak: Slightly increases null rod damage (15->18) + - bugfix: Fixes abductors speaking other languages + - bugfix: Fixes traitors getting less TC on some game modes + QuinnAggeler: + - tweak: All lazarus revived mobs become valid for pet collaring + Tastyfish: + - rscadd: Adds a suicide for light tubes. + - experiment: Progress bars, buttons, and several of the values in UI's are now + animated. + - tweak: Deconstructing glass tables now gives a stack of 2 sheets of glass. + monster860: + - tweak: Upgrading the experimentor will no longer reduce the chance of upgrading + an item's tech + - rscadd: Guest passes can now be attached to an ID card. + - rscadd: Adds a HoP guest pass computer, which is like a normal guest pass computer, + but using an ID with ID computer access will allow it to issue guest passes + with any access. + - rscadd: Adds the HoP guest pass computer to the HoP office. + - rscadd: Moves the guest pass computer in robotics to RnD. +2016-06-02: + CrAzYPiLoT: + - bugfix: Fixed a text problem in virtual gameboard description. + - rscadd: Made gameboards deconstructable and movable. + - tweak: Added a light to gameboards. Pretty! + Crazylemon64: + - bugfix: There will no longer be a mountain of startup runtimes when people have + custom languages. + DaveTheHeadcrab: + - tweak: Removes xenobio golem rune creation sound + - rscadd: Added overlays for sec belts that reflect the items stored therein. + Fox McCloud: + - bugfix: Fixes Chapel and Chaplain's office not having a light switch + - bugfix: Fixes mass driver only being usable once due to weird pressure + - bugfix: Fixes chapel being overly dark near coffins + - bugfix: Fixes not being able to sheath the claymore in the Crusader Armor + IK3I: + - rscadd: crate cargo system + - rscadd: passenger seat system + - rscadd: loot box secondary cargo system (install it and your pod has a standard + inventory) + - rscadd: lock busters for the CE and Armory + - bugfix: incappacitated people can't operate the door controls anymore + - bugfix: Items dropped in a pod can now be scrounged up + - bugfix: security can rip you out of an unlocked pod + - bugfix: The pod code isn't full of tumors any more + Tastyfish: + - bugfix: Holsters now have an action button while on your suit again. + monster860: + - rscadd: 'Adds the following words to the AI announcer: active, airlock, alcohol, + arrival, arrivals, becoming, between, blob, briefing, camp, chair, chapel, closet, + cyberiad, declared, detective, diona, dock, docked, docking, docks, drask, drunk, + emag, equipment, evacuation, experimentor, gateway, hail, hallway, holoparasite, + honk, hull, ian, imminent, interested, intruders, kida, kidan, labor, library, + mime, mimes, miner, miners, mining, n2o, nuke, office, op, operational, ops, + pod, pods, poly, pun, renault, representative, runtime, scrubbers, sequencer, + skree, skrek, skrell, space, spider, spiders, still, stupid, swarmer, swarmers, + sword, technology, teleport, teleported, teleporter, teleporting, tesla, tool, + unathi, vacant, vault, vents, vulpkanin, weld, window, windows, yet' +2016-06-12: + CrAzYPiLoT: + - bugfix: Fixed the long-lasting bug of handcuffed people keeping their chainsaws. + Crazylemon64: + - bugfix: No more language message-spam on roundstart + DaveTheHeadcrab: + - rscadd: Adds a new icon for the detective's scanner. + - tweak: Detectives scanner now has access to DNA and fingerprint records. + Fox McCloud: + - rscadd: 'Adds three new chaplain weapons: pirate saber, multiverse sword, and + possessed/talking sword' + - bugfix: Fixes not being able to sheath the claymore in the Crusader Armor + - rscadd: Adds in a mocha drink + - bugfix: Fixes ice being unobtainable for the jobs that use it most + - bugfix: Fixes laser armor losing its reflecting ability + - bugfix: Fixes the lack of progress bars for more stack-based construction + - bugfix: Fixes Experimentor producing coffee machines instead of cups + - tweak: Can deconvert mindslaves by removing their mindslave implant + - tweak: Can deconvert Vampire thralls by feeding them holy water + - bugfix: Fixes mindslaves not having a HUD for the master and mindslave + - bugfix: Fixes being able to duplicate just about anything in the Experimentor + - bugfix: Fixes not being able to use tank transfer valves or one tank bombs in + the Experimentor. + - bugfix: Fixes infinite-throw spam + - bugfix: Fixes being able to resist out of grabs by moving (that is to say, it'll + actually work now) + - bugfix: Fixes passive grabs using the wrong HUD icon + - tweak: Tabling duration reduced from 5 to 2 + - tweak: Can no longer wield double-bladed energy swords as a hulk + - bugfix: Fixes on map stools having the wrong offsets, making it look like you're + not sitting on them + FreeStylaLT: + - rscadd: Added (Enabled) Mind Batterer for Traitors + - spellcheck: Fixed uplink implant description (Said 5 when actually gave you 10 + TCs) + Glorken: + - bugfix: Shifts Zeng-Hu left leg over in order to regain thigh gap. + - bugfix: Chops off a pixel on Bishop feet so that they fit into shoes. + KasparoVy: + - tweak: Old placeholder IPC butt sprite replaced with the finished QR-code sprite. + Krausus: + - bugfix: Fixes ghosts failing to follow mobs that move in unusual ways + - bugfix: Fixed tape allowing mobs with sufficient access to move through solid + objects. + Many -tg-station Coders, TheDZD: + - rscdel: Old gun code is now gone. + - rscadd: Ports the vast majority of TG's gun code and their guns (any previously + unavailable guns, and newly-added guns will remain unavailable to players). + Expect some changes that might not be listed here due to the sheer scope of + this refactor. + - rscadd: Probably some new bugs. + - bugfix: A lot of old gun bugs. + - rscadd: Mouth suiciding with a gun no longer instantly kills you, you fire the + gun at yourself at 5x damage (assuming it even did damage to begin with). + - tweak: Mouth suicide shooting does not work on harm intent. + - tweak: You can now bash people with guns while on harm intent instead of shooting + them point-blank. + - rscadd: You can now mouth suicide other people, doing so still takes the full + 12 seconds to mouth suicide, but has the same 5x damage multiplier. + - tweak: Vox spike throwers are real guns that fire spike bullets now, instead of + just being fake guns that threw spikes. They do 25 damage per hit, have 30 armor + piercing, cause a 1 second stun (not the kind that drops you to the floor), + and cause some bleeding. They have 2 round burst fire as well, and have 10 shots + per clip. A new should should recharge every 20 or so seconds. + - tweak: Xray lasers now have a maximum range of 15 tiles. + - bugfix: Zoomed guns now actually fire accurately while zoomed. + - rscadd: Using Suicide with guns now actually does gun-like things. + - tweak: The clown no longer deletes guns if he fucks up with them due to being + clumsy. + - bugfix: Emitters no longer become inaccurate over long ranges. + - tweak: Power gloves now override middle-click and alt-click when worn. + - tweak: Power gloves give a notification when worn. + - tweak: Power gloves now have special examine text when examined by an antagonist. + - tweak: Proto SMGs now only have a 21 shot clip. + Spacemanspark: + - rscadd: Adds the ability to make a more irritated buzz noise at people as a synthetic. + The original buzz is still there. + Tauka Usanake: + - rscadd: Adds more belt icon overlays + Twinmold: + - rscadd: Nar'Sie AI Hologram and Error Sprite + - bugfix: Fixes space pod equipment variable. Can now properly install/uninstall + equipment. + - bugfix: Check Seat verb no longer pulls out installed equipment. + - bugfix: You can now have a passenger in your pod if you have a passenger seat. + monster860: + - rscadd: Adds comical implant. It is an implant that causes you to have a comic + sans voice. It can be made in the protolathe using bananium. + - rscadd: The comical implant now spawns by default inside IPC clowns + - bugfix: Fixes the window getting stuck when you try to drag or resize a NanoUI + window too fast with Fancy NanoUI enabled + - bugfix: Fixes a small quirk with the resize handle. + - bugfix: Fix javascript error in cargo UI + pinatacolada: + - bugfix: removes atmos tech SOP from supply SOP + - bugfix: Fixes defibing people without a heart + - bugfix: Fixes defib saying it didn't work stopping a heart attack when they do diff --git a/html/changelogs/AutoChangeLog-pr-4391.yml b/html/changelogs/AutoChangeLog-pr-4391.yml deleted file mode 100644 index 8567b77dbee..00000000000 --- a/html/changelogs/AutoChangeLog-pr-4391.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: Fox MCCloud -delete-after: True -changes: - - tweak: "Removes \"harm\" traitor objective" - - tweak: "Increases non-escape/hijack/die objectives from 1 to 2" - - tweak: "Tweaks available objectives to traitors a bit" diff --git a/html/changelogs/AutoChangeLog-pr-4407.yml b/html/changelogs/AutoChangeLog-pr-4407.yml deleted file mode 100644 index 936843c7952..00000000000 --- a/html/changelogs/AutoChangeLog-pr-4407.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: Fox McCloud -delete-after: True -changes: - - tweak: "Hulks, Shadowlings, and Golems can no longer use laserpointers" diff --git a/html/changelogs/AutoChangeLog-pr-4654.yml b/html/changelogs/AutoChangeLog-pr-4654.yml new file mode 100644 index 00000000000..26232f3d166 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4654.yml @@ -0,0 +1,5 @@ +author: TheDZD +delete-after: True +changes: + - bugfix: "Teaches camera assemblies the meaning of the word \"respect\" (for NODROP items)." + - bugfix: "Sates the insatiable hunger that orange shoes once had for secborg cuffs." diff --git a/icons/goonstation/objects/objects.dmi b/icons/goonstation/objects/objects.dmi index 41523d18541..8dadb400668 100644 Binary files a/icons/goonstation/objects/objects.dmi and b/icons/goonstation/objects/objects.dmi differ diff --git a/icons/goonstation/objects/syringe.dmi b/icons/goonstation/objects/syringe.dmi new file mode 100644 index 00000000000..4bde6be96bd Binary files /dev/null and b/icons/goonstation/objects/syringe.dmi differ diff --git a/icons/mob/AI.dmi b/icons/mob/AI.dmi index 1170fd94edb..4c879d066b1 100644 Binary files a/icons/mob/AI.dmi and b/icons/mob/AI.dmi differ diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi index 877f91de1f4..a4cd1d997a8 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi index eeb5ecbbee3..c5115b3cbc5 100644 Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index f036d7e3111..a53d468804d 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi b/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi index 3bf83ae98cd..819b01edafe 100644 Binary files a/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi and b/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi differ diff --git a/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi b/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi index 0d74250a3ea..0cb76d89420 100644 Binary files a/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi and b/icons/mob/human_races/cyberlimbs/zenghu/zenghu_main.dmi differ diff --git a/icons/mob/inhands/guns_lefthand.dmi b/icons/mob/inhands/guns_lefthand.dmi index 63fbda7a4bd..1064c55f48b 100644 Binary files a/icons/mob/inhands/guns_lefthand.dmi and b/icons/mob/inhands/guns_lefthand.dmi differ diff --git a/icons/mob/inhands/guns_righthand.dmi b/icons/mob/inhands/guns_righthand.dmi index d8fada37744..93e30e4e812 100644 Binary files a/icons/mob/inhands/guns_righthand.dmi and b/icons/mob/inhands/guns_righthand.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index c649cee3ec2..61c176bd08a 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index c0b8af3b551..652996f8d8c 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/mob/robots.dmi b/icons/mob/robots.dmi index 6bad482e8e4..062fb83e28b 100644 Binary files a/icons/mob/robots.dmi and b/icons/mob/robots.dmi differ diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi index 4936936afde..c3843c0c967 100644 Binary files a/icons/mob/screen_gen.dmi and b/icons/mob/screen_gen.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index 61a53ab5541..589b2654211 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/mob/uniform.dmi b/icons/mob/uniform.dmi index 09203887784..28096d4e1a4 100644 Binary files a/icons/mob/uniform.dmi and b/icons/mob/uniform.dmi differ diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi index 7e588ec2210..b6bbd8ab349 100644 Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ diff --git a/icons/obj/assemblies.dmi b/icons/obj/assemblies.dmi index 362ce9b00d4..a8d8e668828 100644 Binary files a/icons/obj/assemblies.dmi and b/icons/obj/assemblies.dmi differ diff --git a/icons/obj/butts.dmi b/icons/obj/butts.dmi index 9a71d519a19..104906120d4 100644 Binary files a/icons/obj/butts.dmi and b/icons/obj/butts.dmi differ diff --git a/icons/obj/chemical.dmi b/icons/obj/chemical.dmi index afe27ae192d..54ed8f57927 100644 Binary files a/icons/obj/chemical.dmi and b/icons/obj/chemical.dmi differ diff --git a/icons/obj/clothing/belts.dmi b/icons/obj/clothing/belts.dmi index 7427f32fd3e..f747338a5a7 100644 Binary files a/icons/obj/clothing/belts.dmi and b/icons/obj/clothing/belts.dmi differ diff --git a/icons/obj/custom_items.dmi b/icons/obj/custom_items.dmi index 5e7c8e43981..a2c5117d204 100644 Binary files a/icons/obj/custom_items.dmi and b/icons/obj/custom_items.dmi differ diff --git a/icons/obj/device.dmi b/icons/obj/device.dmi index 46a4a974316..6e749fc11ec 100644 Binary files a/icons/obj/device.dmi and b/icons/obj/device.dmi differ diff --git a/icons/obj/food/candy.dmi b/icons/obj/food/candy.dmi index ed86db2b0bd..4bf2f9b9862 100644 Binary files a/icons/obj/food/candy.dmi and b/icons/obj/food/candy.dmi differ diff --git a/icons/obj/gun.dmi b/icons/obj/gun.dmi deleted file mode 100644 index 45e4265c292..00000000000 Binary files a/icons/obj/gun.dmi and /dev/null differ diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi new file mode 100644 index 00000000000..39b73d8052b Binary files /dev/null and b/icons/obj/guns/energy.dmi differ diff --git a/icons/obj/gun_temperature.dmi b/icons/obj/guns/gun_temperature.dmi similarity index 100% rename from icons/obj/gun_temperature.dmi rename to icons/obj/guns/gun_temperature.dmi diff --git a/icons/obj/guns/magic.dmi b/icons/obj/guns/magic.dmi new file mode 100644 index 00000000000..2f3fc52957a Binary files /dev/null and b/icons/obj/guns/magic.dmi differ diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi new file mode 100644 index 00000000000..cd1eed09f02 Binary files /dev/null and b/icons/obj/guns/projectile.dmi differ diff --git a/icons/obj/toyguns.dmi b/icons/obj/guns/toy.dmi similarity index 81% rename from icons/obj/toyguns.dmi rename to icons/obj/guns/toy.dmi index bd2ff273a40..d05231e7718 100644 Binary files a/icons/obj/toyguns.dmi and b/icons/obj/guns/toy.dmi differ diff --git a/icons/obj/hypo.dmi b/icons/obj/hypo.dmi new file mode 100644 index 00000000000..fe42acbe4d2 Binary files /dev/null and b/icons/obj/hypo.dmi differ diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi index db105c191d2..a22bb625198 100644 Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index 23ee204e96a..5a780217109 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/icons/obj/reagentfillings.dmi b/icons/obj/reagentfillings.dmi index 94e2f2e7d27..42ba9cf7f29 100644 Binary files a/icons/obj/reagentfillings.dmi and b/icons/obj/reagentfillings.dmi differ diff --git a/icons/obj/surgery_drask.dmi b/icons/obj/surgery_drask.dmi index df2fd75a360..082d3e0f4f2 100644 Binary files a/icons/obj/surgery_drask.dmi and b/icons/obj/surgery_drask.dmi differ diff --git a/icons/obj/syringe.dmi b/icons/obj/syringe.dmi deleted file mode 100644 index 1621a9d8f2d..00000000000 Binary files a/icons/obj/syringe.dmi and /dev/null differ diff --git a/icons/obj/syringefilling.dmi b/icons/obj/syringefilling.dmi index 74f72313b91..7bb9d675437 100644 Binary files a/icons/obj/syringefilling.dmi and b/icons/obj/syringefilling.dmi differ diff --git a/icons/obj/toy.dmi b/icons/obj/toy.dmi index 6e6d268c9bd..b7f40b4cdbb 100644 Binary files a/icons/obj/toy.dmi and b/icons/obj/toy.dmi differ diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi index 728bfaba198..01609b50824 100644 Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ diff --git a/icons/vehicles/spacepod.dmi b/icons/vehicles/spacepod.dmi index e55085622c9..54edb864aba 100644 Binary files a/icons/vehicles/spacepod.dmi and b/icons/vehicles/spacepod.dmi differ diff --git a/interface/interface.dm b/interface/interface.dm index 44f74a20e59..81fe75b269b 100644 --- a/interface/interface.dm +++ b/interface/interface.dm @@ -39,6 +39,9 @@ ) src << browse('html/changelog.html', "window=changes;size=675x650") + if(prefs.lastchangelog != changelog_hash) //if it's already opened, no need to tell them they have unread changes + prefs.SetChangelog(src,changelog_hash) + /client/verb/forum() set name = "forum" set desc = "Visit the forum." @@ -221,7 +224,10 @@ Any-Mode: (hotkey doesn't need to be on) set name = "Set Hotkey Mode" set category = "Preferences" - hotkeytype = input("Choose hotkey mode", "Hotkey mode") as null|anything in hotkeylist//ask the user for the hotkey type + var/hkt = input("Choose hotkey mode", "Hotkey mode") as null|anything in hotkeylist//ask the user for the hotkey type + if(!hkt) + return + hotkeytype = hkt var/hotkeys = hotkeylist[hotkeytype]//get the list containing the hotkey names var/hotkeyname = hotkeys[hotkeyon ? "on" : "off"]//get the name of the hotkey, to not clutter winset() to much diff --git a/nano/assets/libraries.min.js b/nano/assets/libraries.min.js index ba3441604d1..6e3405a7be4 100644 --- a/nano/assets/libraries.min.js +++ b/nano/assets/libraries.min.js @@ -1,5 +1,5 @@ -!function(e,t){"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(e,t){function n(e){var t="length"in e&&e.length,n=oe.type(e);return"function"===n||oe.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e}function i(e,t,n){if(oe.isFunction(t))return oe.grep(e,function(e,i){return!!t.call(e,i,e)!==n});if(t.nodeType)return oe.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(de.test(t))return oe.filter(t,e,n);t=oe.filter(t,e)}return oe.grep(e,function(e){return oe.inArray(e,t)>=0!==n})}function o(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function r(e){var t=xe[e]={};return oe.each(e.match(be)||[],function(e,n){t[n]=!0}),t}function s(){he.addEventListener?(he.removeEventListener("DOMContentLoaded",a,!1),e.removeEventListener("load",a,!1)):(he.detachEvent("onreadystatechange",a),e.detachEvent("onload",a))}function a(){(he.addEventListener||"load"===event.type||"complete"===he.readyState)&&(s(),oe.ready())}function l(e,t,n){if(void 0===n&&1===e.nodeType){var i="data-"+t.replace(Ne,"-$1").toLowerCase();if(n=e.getAttribute(i),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:Ce.test(n)?oe.parseJSON(n):n}catch(o){}oe.data(e,t,n)}else n=void 0}return n}function u(e){var t;for(t in e)if(("data"!==t||!oe.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function c(e,t,n,i){if(oe.acceptData(e)){var o,r,s=oe.expando,a=e.nodeType,l=a?oe.cache:e,u=a?e[s]:e[s]&&s;if(u&&l[u]&&(i||l[u].data)||void 0!==n||"string"!=typeof t)return u||(u=a?e[s]=Y.pop()||oe.guid++:s),l[u]||(l[u]=a?{}:{toJSON:oe.noop}),"object"!=typeof t&&"function"!=typeof t||(i?l[u]=oe.extend(l[u],t):l[u].data=oe.extend(l[u].data,t)),r=l[u],i||(r.data||(r.data={}),r=r.data),void 0!==n&&(r[oe.camelCase(t)]=n),"string"==typeof t?(o=r[t],null==o&&(o=r[oe.camelCase(t)])):o=r,o}}function f(e,t,n){if(oe.acceptData(e)){var i,o,r=e.nodeType,s=r?oe.cache:e,a=r?e[oe.expando]:oe.expando;if(s[a]){if(t&&(i=n?s[a]:s[a].data)){oe.isArray(t)?t=t.concat(oe.map(t,oe.camelCase)):t in i?t=[t]:(t=oe.camelCase(t),t=t in i?[t]:t.split(" ")),o=t.length;for(;o--;)delete i[t[o]];if(n?!u(i):!oe.isEmptyObject(i))return}(n||(delete s[a].data,u(s[a])))&&(r?oe.cleanData([e],!0):ne.deleteExpando||s!=s.window?delete s[a]:s[a]=null)}}}function d(){return!0}function p(){return!1}function h(){try{return he.activeElement}catch(e){}}function g(e){var t=We.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function m(e,t){var n,i,o=0,r=typeof e.getElementsByTagName!==_e?e.getElementsByTagName(t||"*"):typeof e.querySelectorAll!==_e?e.querySelectorAll(t||"*"):void 0;if(!r)for(r=[],n=e.childNodes||e;null!=(i=n[o]);o++)!t||oe.nodeName(i,t)?r.push(i):oe.merge(r,m(i,t));return void 0===t||t&&oe.nodeName(e,t)?oe.merge([e],r):r}function v(e){Pe.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t){return oe.nodeName(e,"table")&&oe.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function b(e){return e.type=(null!==oe.find.attr(e,"type"))+"/"+e.type,e}function x(e){var t=Qe.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function w(e,t){for(var n,i=0;null!=(n=e[i]);i++)oe._data(n,"globalEval",!t||oe._data(t[i],"globalEval"))}function T(e,t){if(1===t.nodeType&&oe.hasData(e)){var n,i,o,r=oe._data(e),s=oe._data(t,r),a=r.events;if(a){delete s.handle,s.events={};for(n in a)for(i=0,o=a[n].length;o>i;i++)oe.event.add(t,n,a[n][i])}s.data&&(s.data=oe.extend({},s.data))}}function _(e,t){var n,i,o;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!ne.noCloneEvent&&t[oe.expando]){o=oe._data(t);for(i in o.events)oe.removeEvent(t,i,o.handle);t.removeAttribute(oe.expando)}"script"===n&&t.text!==e.text?(b(t).text=e.text,x(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),ne.html5Clone&&e.innerHTML&&!oe.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Pe.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:"input"!==n&&"textarea"!==n||(t.defaultValue=e.defaultValue)}}function C(t,n){var i,o=oe(n.createElement(t)).appendTo(n.body),r=e.getDefaultComputedStyle&&(i=e.getDefaultComputedStyle(o[0]))?i.display:oe.css(o[0],"display");return o.detach(),r}function N(e){var t=he,n=Ze[e];return n||(n=C(e,t),"none"!==n&&n||(Ke=(Ke||oe("