diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 0b450df9848..ed0845ed33f 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -274,6 +274,7 @@ CREATE TABLE `player` ( `nanoui_fancy` smallint(4) DEFAULT '1', `show_ghostitem_attack` smallint(4) DEFAULT '1', `lastchangelog` varchar(32) NOT NULL DEFAULT '0', + `windowflashing` smallint(4) DEFAULT '1', `exp` mediumtext, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index 2489e6cb325..216082157d4 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -273,6 +273,7 @@ CREATE TABLE `SS13_player` ( `nanoui_fancy` smallint(4) DEFAULT '1', `show_ghostitem_attack` smallint(4) DEFAULT '1', `lastchangelog` varchar(32) NOT NULL DEFAULT '0', + `windowflashing` smallint(4) DEFAULT '1', `exp` mediumtext, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) diff --git a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm index c8a092e9f22..aa3a13962a9 100644 --- a/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm +++ b/_maps/map_files/MetaStation/MetaStation.v41A.II.dmm @@ -1,11 +1,11 @@ "aaa" = (/turf/space,/area/space) "aab" = (/obj/docking_port/stationary{dheight = 9; dir = 2; dwidth = 5; height = 22; id = "syndicate_n"; name = "north of station"; width = 18},/turf/space,/area/space) -"aac" = (/turf/space,/obj/machinery/gun_turret,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/syndicate) +"aac" = (/turf/space,/obj/machinery/porta_turret/syndicate,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/syndicate) "aad" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/shuttle/syndicate) "aae" = (/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "syndieshutters"; name = "Blast Shutters"; opacity = 0},/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,/area/shuttle/syndicate) "aaf" = (/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "syndieshutters"; name = "Blast Shutters"; opacity = 0},/obj/structure/grille,/obj/structure/shuttle/window{tag = "icon-window5_mid"; icon = 'icons/turf/shuttle.dmi'; icon_state = "window5_mid"; dir = 2},/turf/simulated/shuttle/plating,/area/shuttle/syndicate) "aag" = (/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "syndieshutters"; name = "Blast Shutters"; opacity = 0},/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,/area/shuttle/syndicate) -"aah" = (/turf/space,/obj/machinery/gun_turret,/turf/simulated/shuttle/wall{dir = 1; icon_state = "diagonalWall3"},/area/shuttle/syndicate) +"aah" = (/turf/space,/obj/machinery/porta_turret/syndicate,/turf/simulated/shuttle/wall{dir = 1; icon_state = "diagonalWall3"},/area/shuttle/syndicate) "aai" = (/turf/simulated/shuttle/wall{dir = 4; icon_state = "wall3"},/area/shuttle/syndicate) "aaj" = (/obj/structure/table,/obj/machinery/kitchen_machine/microwave,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "aak" = (/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) @@ -29,7 +29,7 @@ "aaC" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "aaD" = (/obj/effect/landmark{name = "carpspawn"},/turf/space,/area/space) "aaE" = (/turf/space,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/syndicate) -"aaF" = (/obj/machinery/gun_turret,/turf/simulated/shuttle/wall{dir = 4; icon_state = "wall3"},/area/shuttle/syndicate) +"aaF" = (/obj/machinery/porta_turret/syndicate,/turf/simulated/shuttle/wall{dir = 4; icon_state = "wall3"},/area/shuttle/syndicate) "aaG" = (/obj/structure/closet/syndicate/suits,/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "aaH" = (/obj/effect/landmark{name = "Syndicate-Uplink"; tag = ""},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) "aaI" = (/obj/structure/stool{pixel_y = 8},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/syndicate) diff --git a/_maps/map_files/MetaStation/z2.dmm b/_maps/map_files/MetaStation/z2.dmm index 59ab53037cc..51558afd164 100644 --- a/_maps/map_files/MetaStation/z2.dmm +++ b/_maps/map_files/MetaStation/z2.dmm @@ -372,10 +372,10 @@ "hh" = (/obj/structure/stool/bed/chair/office/dark,/turf/unsimulated/floor{icon_state = "dark"},/area/centcom/evac) "hi" = (/obj/effect/decal/warning_stripes/southeast,/turf/simulated/floor/plating/airless,/area/syndicate_mothership) "hj" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/shuttle/assault_pod) -"hk" = (/turf/space,/obj/machinery/gun_turret/assault_pod,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) +"hk" = (/turf/space,/obj/machinery/porta_turret/syndicate/pod,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) "hl" = (/obj/machinery/door/airlock/centcom{aiControlDisabled = 1; name = "Assault Pod"; opacity = 1; req_one_access_txt = "150"},/turf/simulated/floor/plating,/area/shuttle/assault_pod) "hm" = (/obj/effect/decal/warning_stripes/southwest,/turf/simulated/floor/plating/airless,/area/syndicate_mothership) -"hn" = (/turf/space,/obj/machinery/gun_turret/assault_pod,/turf/simulated/shuttle/wall{dir = 1; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) +"hn" = (/turf/space,/obj/machinery/porta_turret/syndicate/pod,/turf/simulated/shuttle/wall{dir = 1; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) "ho" = (/obj/effect/decal/warning_stripes/east,/turf/simulated/floor/plating/airless,/area/syndicate_mothership) "hp" = (/obj/structure/table/woodentable,/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/area/centcom/ferry) "hq" = (/obj/structure/stool/bed/chair/comfy/black{dir = 8},/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/area/centcom/ferry) @@ -396,7 +396,7 @@ "hF" = (/obj/structure/stool/bed/chair{dir = 4},/obj/machinery/light/small{tag = "icon-bulb1 (WEST)"; icon_state = "bulb1"; dir = 8},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/assault_pod) "hG" = (/obj/machinery/computer/shuttle/syndicate/drop_pod,/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/shuttle/assault_pod) "hH" = (/obj/structure/stool/bed/chair,/obj/machinery/light/small{dir = 1},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/assault_pod) -"hI" = (/turf/space,/obj/machinery/gun_turret/assault_pod,/turf/simulated/shuttle/wall{tag = "icon-diagonalWall3"; icon_state = "diagonalWall3"; dir = 2},/area/shuttle/assault_pod) +"hI" = (/turf/space,/obj/machinery/porta_turret/syndicate/pod,/turf/simulated/shuttle/wall{tag = "icon-diagonalWall3"; icon_state = "diagonalWall3"; dir = 2},/area/shuttle/assault_pod) "hJ" = (/obj/machinery/vending/clothing,/turf/unsimulated/floor{dir = 8; icon_state = "wood"},/area/centcom/ferry) "hK" = (/turf/unsimulated/floor/grass,/area/centcom/control) "hL" = (/turf/unsimulated/floor{icon_state = "greencorner"; dir = 8},/area/centcom/control) @@ -407,7 +407,7 @@ "hQ" = (/obj/structure/rack,/turf/unsimulated/floor{dir = 1; icon_state = "green"},/area/centcom/evac) "hR" = (/obj/structure/rack,/obj/item/weapon/storage/fancy/crayons,/obj/item/toy/sword,/turf/unsimulated/floor{dir = 1; icon_state = "green"},/area/centcom/evac) "hS" = (/turf/unsimulated/wall/fakeglass{icon_state = "fakewindows"; dir = 1},/area/centcom/evac) -"hT" = (/turf/space,/obj/machinery/gun_turret/assault_pod,/turf/simulated/shuttle/wall{dir = 4; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) +"hT" = (/turf/space,/obj/machinery/porta_turret/syndicate/pod,/turf/simulated/shuttle/wall{dir = 4; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) "hU" = (/obj/effect/decal/warning_stripes/northeast,/turf/simulated/floor/plating/airless,/area/syndicate_mothership) "hV" = (/obj/effect/decal/warning_stripes/northeastcorner,/turf/simulated/floor/plating/airless,/area/syndicate_mothership) "hW" = (/obj/machinery/door/airlock/centcom{aiControlDisabled = 1; name = "Assault Pod"; opacity = 1; req_one_access_txt = "150"},/obj/docking_port/mobile/assault_pod,/turf/simulated/floor/plating,/area/shuttle/assault_pod) diff --git a/_maps/map_files/RandomZLevels/evil_santa.dmm b/_maps/map_files/RandomZLevels/evil_santa.dmm index 7d56e430210..0fc16a7eaa7 100644 --- a/_maps/map_files/RandomZLevels/evil_santa.dmm +++ b/_maps/map_files/RandomZLevels/evil_santa.dmm @@ -20,7 +20,7 @@ "at" = (/obj/structure/table/woodentable,/obj/item/weapon/newton,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) "au" = (/obj/structure/grille,/obj/structure/window/full/basic,/turf/simulated/floor/plating,/area/awaymission/challenge/main) "av" = (/mob/living/simple_animal/hostile/winter/reindeer,/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main) -"aw" = (/obj/machinery/gun_turret/grenade{desc = "Winterized 40mm grenade launcher defense turret. If you've had this much time to look at it, you're probably already dead."; faction = "winter"; name = "winterized mounted grenade launcher (40mm)"},/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main) +"aw" = (/obj/machinery/porta_turret/syndicate/grenade{desc = "Winterized 40mm grenade launcher defense turret. If you've had this much time to look at it, you're probably already dead."; faction = "winter"; name = "winterized mounted grenade launcher (40mm)"},/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main) "ax" = (/obj/structure/stool,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) "ay" = (/obj/structure/table/woodentable,/obj/structure/safe/floor,/obj/item/weapon/gun/projectile/shotgun/automatic/combat,/obj/item/weapon/gun/projectile/automatic/mini_uzi,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) "az" = (/obj/machinery/recharge_station,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) @@ -30,7 +30,7 @@ "aD" = (/obj/structure/table,/obj/machinery/recharger,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) "aE" = (/obj/machinery/floodlight,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) "aF" = (/obj/structure/table,/obj/machinery/cell_charger,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) -"aG" = (/obj/machinery/gun_turret/exterior{desc = "Winterized exterior defense turret chambered for 7.62 rounds. Designed to down intruders with heavy calliber bullets."; faction = "winter"; name = "winterized machine gun turret (7.62)"},/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main) +"aG" = (/obj/machinery/porta_turret/syndicate/exterior{desc = "Winterized exterior defense turret chambered for 7.62 rounds. Designed to down intruders with heavy calliber bullets."; faction = "winter"; name = "winterized machine gun turret (7.62)"},/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main) "aH" = (/mob/living/simple_animal/hostile/winter/snowman,/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main) "aI" = (/obj/structure/flora/bush,/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main) "aJ" = (/obj/item/weapon/pickaxe/gold,/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main) @@ -73,7 +73,7 @@ "bu" = (/obj/machinery/vending/cola,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) "bv" = (/obj/structure/reagent_dispensers/fueltank,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) "bw" = (/obj/machinery/autolathe,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) -"bx" = (/obj/machinery/gun_turret/interior{density = 0; desc = "Winterized interior defense turret chambered for .45 rounds and mounted on a wall. Designed to down intruders without damaging the hull."; faction = "winter"; name = "wall mounted machine gun turret (.45)"; pixel_y = 27},/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) +"bx" = (/obj/machinery/porta_turret/syndicate/interior{density = 0; desc = "Winterized interior defense turret chambered for .45 rounds and mounted on a wall. Designed to down intruders without damaging the hull."; faction = "winter"; name = "wall mounted machine gun turret (.45)"; pixel_y = 27},/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) "by" = (/obj/structure/table,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/rcd_ammo,/obj/item/weapon/storage/toolbox/mechanical,/turf/simulated/floor/plasteel,/area/awaymission/challenge/main) "bz" = (/obj/item/clothing/head/cone,/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main) "bA" = (/mob/living/simple_animal/walrus,/turf/simulated/floor/snow{carbon_dioxide = 21.8366; nitrogen = 0; oxygen = 82.1472; temperature = 73},/area/awaymission/challenge/main) diff --git a/_maps/map_files/RandomZLevels/wildwest.dmm b/_maps/map_files/RandomZLevels/wildwest.dmm index 0d5e512241b..07acec7105d 100644 --- a/_maps/map_files/RandomZLevels/wildwest.dmm +++ b/_maps/map_files/RandomZLevels/wildwest.dmm @@ -125,7 +125,7 @@ "cu" = (/obj/item/weapon/moneybag,/turf/simulated/floor/carpet,/area/awaymission/wwgov) "cv" = (/obj/structure/stool/bed/chair/wood/wings,/turf/simulated/floor/wood,/area/awaymission/wwgov) "cw" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/wood,/area/awaymission/wwmines) -"cx" = (/obj/effect/mine/plasma,/obj/item/ammo_box/c10mm,/turf/simulated/floor/plating/ironsand{tag = "icon-ironsand1"; icon_state = "ironsand1"},/area/awaymission/wwmines) +"cx" = (/obj/effect/mine/gas/plasma,/obj/item/ammo_box/c10mm,/turf/simulated/floor/plating/ironsand{tag = "icon-ironsand1"; icon_state = "ironsand1"},/area/awaymission/wwmines) "cy" = (/obj/item/weapon/storage/toolbox/electrical,/turf/simulated/floor/wood,/area/awaymission/wwgov) "cz" = (/obj/item/clothing/gloves/color/yellow,/obj/item/device/multitool,/turf/simulated/floor/wood,/area/awaymission/wwgov) "cA" = (/obj/structure/stool/bed/chair/wood/normal{dir = 4},/turf/simulated/floor/wood,/area/awaymission/wwgov) @@ -166,7 +166,7 @@ "dj" = (/obj/item/weapon/reagent_containers/food/drinks/bottle/patron,/turf/simulated/floor/plasteel{tag = "icon-stage_bleft"; icon_state = "stage_bleft"},/area/awaymission/wwgov) "dk" = (/obj/effect/decal/cleanable/blood/tracks,/turf/simulated/floor/plating/ironsand{tag = "icon-ironsand1"; icon_state = "ironsand1"},/area/awaymission/wwmines) "dl" = (/obj/effect/decal/cleanable/blood/tracks,/turf/simulated/floor/wood,/area/awaymission/wwmines) -"dm" = (/obj/effect/mine/plasma,/obj/item/ammo_box/c10mm,/turf/simulated/floor/wood,/area/awaymission/wwmines) +"dm" = (/obj/effect/mine/gas/plasma,/obj/item/ammo_box/c10mm,/turf/simulated/floor/wood,/area/awaymission/wwmines) "dn" = (/obj/effect/decal/cleanable/blood/splatter,/turf/simulated/floor/plating/ironsand{tag = "icon-ironsand1"; icon_state = "ironsand1"},/area/awaymission/wwmines) "do" = (/turf/simulated/floor/plating/ironsand{tag = "icon-ironsand4"; icon_state = "ironsand4"},/area/awaymission/wwgov) "dp" = (/obj/effect/landmark/corpse/miner/rig,/turf/simulated/floor/wood,/area/awaymission/wwmines) @@ -207,7 +207,7 @@ "dY" = (/obj/structure/window/reinforced{dir = 4},/turf/simulated/floor/plating/ironsand{tag = "icon-ironsand1"; icon_state = "ironsand1"},/area/awaymission/wwgov) "dZ" = (/obj/structure/window/reinforced{tag = "icon-fwindow (NORTH)"; icon_state = "fwindow"; dir = 1},/obj/structure/window/reinforced{tag = "icon-fwindow (WEST)"; icon_state = "fwindow"; dir = 8},/turf/space,/area/space) "ea" = (/obj/effect/decal/cleanable/blood,/turf/simulated/floor/plating/ironsand{tag = "icon-ironsand1"; icon_state = "ironsand1"},/area/awaymission/wwmines) -"eb" = (/obj/effect/mine/plasma,/turf/simulated/floor/plasteel{tag = "icon-cafeteria (NORTHEAST)"; icon_state = "cafeteria"; dir = 5},/area/awaymission/wwmines) +"eb" = (/obj/effect/mine/gas/plasma,/turf/simulated/floor/plasteel{tag = "icon-cafeteria (NORTHEAST)"; icon_state = "cafeteria"; dir = 5},/area/awaymission/wwmines) "ec" = (/obj/effect/decal/cleanable/blood,/obj/machinery/washing_machine,/turf/simulated/floor/plasteel{tag = "icon-cafeteria (NORTHEAST)"; icon_state = "cafeteria"; dir = 5},/area/awaymission/wwmines) "ed" = (/obj/structure/stool/bed,/obj/item/weapon/bedsheet/blue,/obj/item/ammo_box/a357,/turf/simulated/floor/wood,/area/awaymission/wwmines) "ee" = (/obj/structure/stool/bed/chair/comfy/brown{tag = "icon-comfychair_brown (EAST)"; icon_state = "comfychair_brown"; dir = 4},/turf/simulated/floor/carpet,/area/awaymission/wwmines) @@ -238,7 +238,7 @@ "eE" = (/obj/structure/window/reinforced,/obj/structure/window/reinforced{tag = "icon-fwindow (NORTH)"; icon_state = "fwindow"; dir = 1},/obj/structure/grille,/turf/simulated/floor/plasteel,/area/awaymission/wwrefine) "eF" = (/obj/structure/window/reinforced{tag = "icon-fwindow (NORTH)"; icon_state = "fwindow"; dir = 1},/obj/structure/window/reinforced{tag = "icon-fwindow"; icon_state = "fwindow"},/obj/structure/grille,/turf/simulated/floor/plasteel,/area/awaymission/wwrefine) "eG" = (/obj/structure/window/reinforced{tag = "icon-fwindow (EAST)"; icon_state = "fwindow"; dir = 4},/obj/structure/window/reinforced{tag = "icon-fwindow (NORTH)"; icon_state = "fwindow"; dir = 1},/obj/structure/window/reinforced{tag = "icon-fwindow"; icon_state = "fwindow"},/obj/structure/grille,/turf/simulated/floor/plasteel,/area/awaymission/wwrefine) -"eH" = (/obj/effect/mine/plasma,/turf/simulated/floor/wood,/area/awaymission/wwmines) +"eH" = (/obj/effect/mine/gas/plasma,/turf/simulated/floor/wood,/area/awaymission/wwmines) "eI" = (/obj/structure/stool/bed/chair/comfy/beige{dir = 1; icon_state = "comfychair_beige"; tag = ""},/turf/simulated/floor/carpet,/area/awaymission/wwmines) "eJ" = (/obj/structure/stool/bed/chair/comfy/brown{dir = 1},/turf/simulated/floor/carpet,/area/awaymission/wwmines) "eK" = (/obj/effect/decal/cleanable/blood/gibs/body{tag = "icon-gibup1"; icon_state = "gibup1"},/turf/simulated/floor/carpet,/area/awaymission/wwmines) @@ -267,7 +267,7 @@ "fh" = (/obj/structure/window/reinforced{dir = 4},/obj/structure/window/reinforced{tag = "icon-fwindow"; icon_state = "fwindow"},/turf/space,/area/space) "fi" = (/obj/structure/window/reinforced{tag = "icon-fwindow (WEST)"; icon_state = "fwindow"; dir = 8},/obj/structure/window/reinforced{tag = "icon-fwindow"; icon_state = "fwindow"},/turf/space,/area/space) "fj" = (/obj/structure/window/reinforced{tag = "icon-fwindow (WEST)"; icon_state = "fwindow"; dir = 8},/obj/structure/window/reinforced{tag = "icon-fwindow (EAST)"; icon_state = "fwindow"; dir = 4},/obj/structure/grille,/obj/structure/window/reinforced,/turf/simulated/floor/plasteel,/area/awaymission/wwrefine) -"fk" = (/obj/effect/mine/plasma,/turf/simulated/floor/plating/ironsand{tag = "icon-ironsand1"; icon_state = "ironsand1"},/area/awaymission/wwmines) +"fk" = (/obj/effect/mine/gas/plasma,/turf/simulated/floor/plating/ironsand{tag = "icon-ironsand1"; icon_state = "ironsand1"},/area/awaymission/wwmines) "fl" = (/obj/effect/decal/cleanable/blood/gibs/body{tag = "icon-gibdown1"; icon_state = "gibdown1"},/turf/simulated/floor/plating/ironsand{tag = "icon-ironsand1"; icon_state = "ironsand1"},/area/awaymission/wwmines) "fm" = (/obj/structure/stool/bed/chair/office/dark{dir = 8},/turf/simulated/floor/wood,/area/awaymission/wwmines) "fn" = (/obj/structure/stool/bed/chair/office/dark{dir = 4},/turf/simulated/floor/wood,/area/awaymission/wwmines) diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm index 42b742533dc..e04b5939ff2 100644 --- a/_maps/map_files/cyberiad/cyberiad.dmm +++ b/_maps/map_files/cyberiad/cyberiad.dmm @@ -83,12 +83,12 @@ "abE" = (/obj/effect/decal/remains/human,/turf/simulated/shuttle/plating,/area/shuttle/abandoned) "abF" = (/obj/structure/spacepoddoor,/obj/machinery/door/poddoor/multi_tile/two_tile_ver{id_tag = "whiteshippoddoor"; layer = 3.1},/turf/simulated/shuttle/plating,/area/shuttle/abandoned) "abG" = (/obj/machinery/door_control{id = "whiteshippoddoor"; name = "Pod Door Control"; pixel_y = -24},/turf/simulated/shuttle/floor{icon_state = "floor3"},/area/shuttle/abandoned) -"abH" = (/turf/space,/obj/machinery/gun_turret,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/syndicate) +"abH" = (/turf/space,/obj/machinery/porta_turret/syndicate,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/syndicate) "abI" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/shuttle/syndicate) "abJ" = (/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "syndieshutters"; name = "Blast Shutters"; opacity = 0},/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,/area/shuttle/syndicate) "abK" = (/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "syndieshutters"; name = "Blast Shutters"; opacity = 0},/obj/structure/grille,/obj/structure/shuttle/window{tag = "icon-window5_mid"; icon = 'icons/turf/shuttle.dmi'; icon_state = "window5_mid"; dir = 2},/turf/simulated/shuttle/plating,/area/shuttle/syndicate) "abL" = (/obj/machinery/door/poddoor/shutters{density = 0; dir = 2; icon_state = "shutter0"; id_tag = "syndieshutters"; name = "Blast Shutters"; opacity = 0},/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,/area/shuttle/syndicate) -"abM" = (/turf/space,/obj/machinery/gun_turret,/turf/simulated/shuttle/wall{dir = 1; icon_state = "diagonalWall3"},/area/shuttle/syndicate) +"abM" = (/turf/space,/obj/machinery/porta_turret/syndicate,/turf/simulated/shuttle/wall{dir = 1; icon_state = "diagonalWall3"},/area/shuttle/syndicate) "abN" = (/turf/simulated/wall/r_wall,/area/security/permabrig) "abO" = (/obj/effect/spawner/window/reinforced,/obj/machinery/door/poddoor{density = 0; icon_state = "pdoor0"; id_tag = "Prison Gate"; name = "Prison Blast Doors"; opacity = 0},/obj/structure/cable{d2 = 4; icon_state = "0-4"},/turf/simulated/floor/plating,/area/security/permabrig) "abP" = (/obj/structure/cable{d1 = 2; d2 = 4; icon_state = "2-4"; tag = ""},/obj/structure/cable{d1 = 2; d2 = 8; icon_state = "2-8"; tag = ""},/turf/simulated/wall/r_wall,/area/security/permabrig) @@ -148,7 +148,7 @@ "acR" = (/obj/machinery/door/airlock{name = "Toilet"; req_access_txt = "0"},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/security/permabrig) "acS" = (/obj/structure/toilet{dir = 8},/obj/machinery/light/small{dir = 1},/turf/simulated/floor/plasteel{icon_state = "freezerfloor"},/area/security/permabrig) "acT" = (/turf/space,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/syndicate) -"acU" = (/obj/machinery/gun_turret,/turf/simulated/shuttle/wall{dir = 4; icon_state = "wall3"},/area/shuttle/syndicate) +"acU" = (/obj/machinery/porta_turret/syndicate,/turf/simulated/shuttle/wall{dir = 4; icon_state = "wall3"},/area/shuttle/syndicate) "acV" = (/obj/machinery/atmospherics/pipe/simple/hidden,/turf/simulated/wall,/area/security/permabrig) "acW" = (/turf/simulated/wall,/area/security/permabrig) "acX" = (/obj/structure/cable{d1 = 1; d2 = 2; icon_state = "1-2"; pixel_y = 0; tag = ""},/obj/machinery/door/airlock/glass{name = "Prison Garden"},/obj/machinery/atmospherics/pipe/simple/hidden/supply,/turf/simulated/floor/plasteel{icon_state = "floorgrime"},/area/security/permabrig) diff --git a/_maps/map_files/cyberiad/z2.dmm b/_maps/map_files/cyberiad/z2.dmm index 3c125b87eed..6295ccde4e3 100644 --- a/_maps/map_files/cyberiad/z2.dmm +++ b/_maps/map_files/cyberiad/z2.dmm @@ -436,7 +436,7 @@ "it" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/syndicate_mothership) "iu" = (/obj/effect/decal/warning_stripes/southeast,/turf/simulated/floor/plating/airless,/area/syndicate_mothership) "iv" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/shuttle/assault_pod) -"iw" = (/turf/space,/obj/machinery/gun_turret/assault_pod,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) +"iw" = (/turf/space,/obj/machinery/porta_turret/syndicate/pod,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) "ix" = (/turf/unsimulated/floor{dir = 8; icon_state = "carpetside"},/area/wizard_station) "iy" = (/obj/effect/landmark/start{name = "wizard"},/turf/unsimulated/floor{icon_state = "carpet"; dir = 2},/area/wizard_station) "iz" = (/turf/unsimulated/floor{dir = 4; icon_state = "carpetside"},/area/wizard_station) @@ -447,7 +447,7 @@ "iE" = (/turf/space,/turf/unsimulated/wall{dir = 1; icon = 'icons/turf/shuttle.dmi'; icon_state = "diagonalWall3"},/area/space) "iF" = (/obj/machinery/door/airlock/centcom{aiControlDisabled = 1; name = "Assault Pod"; opacity = 1; req_one_access_txt = "150"},/turf/simulated/floor/plating,/area/shuttle/assault_pod) "iG" = (/obj/effect/decal/warning_stripes/southwest,/turf/simulated/floor/plating/airless,/area/syndicate_mothership) -"iH" = (/turf/space,/obj/machinery/gun_turret/assault_pod,/turf/simulated/shuttle/wall{dir = 1; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) +"iH" = (/turf/space,/obj/machinery/porta_turret/syndicate/pod,/turf/simulated/shuttle/wall{dir = 1; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) "iI" = (/obj/effect/decal/warning_stripes/east,/turf/simulated/floor/plating/airless,/area/syndicate_mothership) "iJ" = (/obj/structure/stool/bed/chair{dir = 4},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/assault_pod) "iK" = (/obj/structure/stool/bed/chair{dir = 8},/turf/simulated/shuttle/floor{icon_state = "floor4"},/area/shuttle/assault_pod) @@ -484,8 +484,8 @@ "jp" = (/turf/simulated/floor/plasteel,/area/tdome/arena_source) "jq" = (/turf/simulated/floor/plasteel{icon_state = "green"; dir = 4},/area/tdome/arena_source) "jr" = (/obj/structure/rack,/obj/item/clothing/under/color/green,/obj/item/clothing/shoes/brown,/obj/item/clothing/suit/armor/tdome/green,/obj/item/clothing/head/helmet/thunderdome,/obj/item/weapon/melee/energy/sword/saber/green,/turf/unsimulated/floor{icon_state = "dark"},/area/tdome/arena_source) -"js" = (/turf/space,/obj/machinery/gun_turret/assault_pod,/turf/simulated/shuttle/wall{tag = "icon-diagonalWall3"; icon_state = "diagonalWall3"; dir = 2},/area/shuttle/assault_pod) -"jt" = (/turf/space,/obj/machinery/gun_turret/assault_pod,/turf/simulated/shuttle/wall{dir = 4; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) +"js" = (/turf/space,/obj/machinery/porta_turret/syndicate/pod,/turf/simulated/shuttle/wall{tag = "icon-diagonalWall3"; icon_state = "diagonalWall3"; dir = 2},/area/shuttle/assault_pod) +"jt" = (/turf/space,/obj/machinery/porta_turret/syndicate/pod,/turf/simulated/shuttle/wall{dir = 4; icon_state = "diagonalWall3"},/area/shuttle/assault_pod) "ju" = (/obj/effect/decal/warning_stripes/northeast,/turf/simulated/floor/plating/airless,/area/syndicate_mothership) "jv" = (/obj/effect/decal/warning_stripes/northeastcorner,/turf/simulated/floor/plating/airless,/area/syndicate_mothership) "jw" = (/obj/machinery/door/airlock/centcom{aiControlDisabled = 1; name = "Assault Pod"; opacity = 1; req_one_access_txt = "150"},/obj/docking_port/mobile/assault_pod,/turf/simulated/floor/plating,/area/shuttle/assault_pod) diff --git a/_maps/map_files/cyberiad/z6.dmm b/_maps/map_files/cyberiad/z6.dmm index 5a0231c9394..b94124d9e4b 100644 --- a/_maps/map_files/cyberiad/z6.dmm +++ b/_maps/map_files/cyberiad/z6.dmm @@ -620,7 +620,7 @@ "lW" = (/obj/machinery/power/apc/noalarm{dir = 0; name = "Worn-out APC"; pixel_y = -24},/turf/simulated/floor/plasteel/airless,/area/derelict/teleporter) "lX" = (/turf/simulated/floor/plating/airless/asteroid,/area/syndicate_depot) "lY" = (/turf/simulated/mineral,/area/syndicate_depot) -"lZ" = (/obj/structure/lattice,/obj/machinery/gun_turret/exterior,/turf/simulated/floor/plating/airless/asteroid,/area/syndicate_depot) +"lZ" = (/obj/structure/lattice,/obj/machinery/porta_turret/syndicate/exterior,/turf/simulated/floor/plating/airless/asteroid,/area/syndicate_depot) "ma" = (/turf/simulated/mineral/random,/turf/simulated/shuttle/wall{dir = 8; icon_state = "diagonalWall3"},/area/syndicate_depot) "mb" = (/turf/simulated/shuttle/wall{icon_state = "wall3"},/area/syndicate_depot) "mc" = (/turf/simulated/floor/plasteel{icon_state = "dark"},/turf/simulated/shuttle/wall{desc = "This window appears to be reinforced, it looks nearly impossible to break."; icon_state = "window5"; name = "window"; opacity = 0},/area/syndicate_depot) @@ -633,16 +633,16 @@ "mj" = (/obj/structure/stool/bed,/obj/item/weapon/bedsheet/red,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) "mk" = (/obj/structure/closet/crate{name = "foot locker"},/obj/item/ammo_box/magazine/smgm45{pixel_x = 3},/obj/item/weapon/storage/fancy/cigarettes/cigpack_syndicate{pixel_x = -3; pixel_y = -2},/obj/item/weapon/lighter/zippo/gonzofist,/obj/item/clothing/under/syndicate{pixel_x = 3; pixel_y = 3},/obj/item/clothing/suit/armor/vest/combat{pixel_x = -3; pixel_y = -3},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) "ml" = (/turf/simulated/floor/plasteel{icon_state = "dark"},/turf/unsimulated/wall{desc = "This window appears to be reinforced, it looks nearly impossible to break."; dir = 8; icon = 'icons/turf/shuttle.dmi'; icon_state = "window5_end"; name = "window"; opacity = 0; tag = "icon-window5_end (WEST)"},/area/syndicate_depot) -"mm" = (/obj/machinery/gun_turret/interior,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) +"mm" = (/obj/machinery/porta_turret/syndicate/interior,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) "mn" = (/obj/item/device/radio/intercom/syndicate{pixel_x = -28},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) "mo" = (/obj/machinery/space_heater,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) "mp" = (/turf/simulated/floor/plasteel{icon_state = "dark"},/turf/unsimulated/wall{desc = "This window appears to be reinforced, it looks nearly impossible to break."; dir = 4; icon = 'icons/turf/shuttle.dmi'; icon_state = "window5_end"; name = "window"; opacity = 0; tag = "icon-window5 (EAST)"},/area/syndicate_depot) "mq" = (/turf/simulated/mineral,/turf/simulated/shuttle/wall{icon_state = "diagonalWall3"},/area/syndicate_depot) "mr" = (/turf/simulated/floor/plasteel{icon_state = "dark"},/turf/simulated/shuttle/wall{dir = 4; icon_state = "diagonalWall3"},/area/syndicate_depot) -"ms" = (/obj/machinery/gun_turret/interior{density = 0; desc = "Syndicate interior defense turret chambered for .45 rounds and mounted on a wall. Designed to down intruders without damaging the hull."; name = "wall mounted machine gun turret (.45)"; pixel_y = -27},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) +"ms" = (/obj/machinery/porta_turret/syndicate/interior{density = 0; desc = "Syndicate interior defense turret chambered for .45 rounds and mounted on a wall. Designed to down intruders without damaging the hull."; name = "wall mounted machine gun turret (.45)"; pixel_y = -27},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) "mt" = (/obj/structure/table,/obj/item/weapon/reagent_containers/food/snacks/syndicake,/obj/item/weapon/reagent_containers/food/drinks/cans/beer,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) -"mu" = (/obj/machinery/gun_turret/grenade,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) -"mv" = (/obj/machinery/gun_turret/interior{density = 0; desc = "Syndicate interior defense turret chambered for .45 rounds and mounted on a wall. Designed to down intruders without damaging the hull."; name = "wall mounted machine gun turret (.45)"; pixel_y = 27},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) +"mu" = (/obj/machinery/porta_turret/syndicate/grenade,/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) +"mv" = (/obj/machinery/porta_turret/syndicate/interior{density = 0; desc = "Syndicate interior defense turret chambered for .45 rounds and mounted on a wall. Designed to down intruders without damaging the hull."; name = "wall mounted machine gun turret (.45)"; pixel_y = 27},/turf/simulated/floor/plasteel{icon_state = "dark"},/area/syndicate_depot) "mw" = (/turf/simulated/floor/plasteel{icon_state = "dark"},/turf/simulated/shuttle/wall{icon_state = "diagonalWall3"},/area/syndicate_depot) "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) diff --git a/code/__DEFINES/clothing.dm b/code/__DEFINES/clothing.dm index ec9ad2f2128..6e1934a77ae 100644 --- a/code/__DEFINES/clothing.dm +++ b/code/__DEFINES/clothing.dm @@ -32,7 +32,8 @@ #define slot_r_ear 20 #define slot_wear_pda 21 #define slot_tie 22 -#define slots_amt 22 +#define slot_collar 23 +#define slots_amt 23 //Cant seem to find a mob bitflags area other than the powers one diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm index 1d89eea87a1..6fe2d302e7b 100644 --- a/code/__DEFINES/hud.dm +++ b/code/__DEFINES/hud.dm @@ -47,3 +47,8 @@ #define ANTAG_HUD_CHANGELING 15 #define ANTAG_HUD_VAMPIRE 16 #define ANTAG_HUD_ABDUCTOR 17 //For Fox + +// Notification action types +#define NOTIFY_JUMP "jump" +#define NOTIFY_ATTACK "attack" +#define NOTIFY_FOLLOW "orbit" \ No newline at end of file diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 3448fa11626..a27e3f8e96a 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -1,6 +1,27 @@ +// Atoms #define isatom(A) istype(A, /atom) #define ismovableatom(A) istype(A, /atom/movable) -#define isclient(A) istype(A, /client) +// Mobs +#define ismegafauna(A) istype(A, /mob/living/simple_animal/hostile/megafauna) + +//Turfs +#define issimulatedturf(A) istype(A, /turf/simulated) + +#define isspaceturf(A) istype(A, /turf/space) + +#define isfloorturf(A) istype(A, /turf/simulated/floor) + +#define isunsimulatedturf(A) istype(A, /turf/unsimulated) + +#define iswallturf(A) istype(A, /turf/simulated/wall) + +#define isreinforcedwallturf(A) istype(A, /turf/simulated/wall/r_wall) + +#define ismineralturf(A) istype(A, /turf/simulated/mineral) + +// Misc +#define isclient(A) istype(A, /client) #define isradio(A) istype(A, /obj/item/device/radio) #define ispill(A) istype(A, /obj/item/weapon/reagent_containers/food/pill) + diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index bcc4487be0b..64e38bba06d 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -17,6 +17,8 @@ #define CLICK_CD_TKSTRANGLE 10 #define CLICK_CD_POINT 10 #define CLICK_CD_RESIST 20 +#define CLICK_CD_CLICK_ABILITY 6 +#define CLICK_CD_RAPID 2 //Sizes of mobs, used by mob/living/var/mob_size #define MOB_SIZE_TINY 0 @@ -286,7 +288,6 @@ #define SOUND_MINIMUM_PRESSURE 10 #define FALLOFF_SOUNDS 0.5 - // Bluespace shelter deploy checks #define SHELTER_DEPLOY_ALLOWED "allowed" #define SHELTER_DEPLOY_BAD_TURFS "bad turfs" @@ -300,3 +301,16 @@ // The cooldown on OOC messages such as OOC, LOOC, praying and adminhelps #define OOC_COOLDOWN 5 + +// Medal names +#define BOSS_KILL_MEDAL "Killer" +#define ALL_KILL_MEDAL "Exterminator" //Killing all of x type + +// Score names +#define LEGION_SCORE "Legion Killed" +#define COLOSSUS_SCORE "Colossus Killed" +#define BUBBLEGUM_SCORE "Bubblegum Killed" +#define DRAKE_SCORE "Drakes Killed" +#define BIRD_SCORE "Hierophants Killed" +#define BOSS_SCORE "Bosses Killed" +#define TENDRIL_CLEAR_SCORE "Tendrils Killed" \ No newline at end of file diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 69ea87f8fda..1ada9f5100d 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -151,7 +151,7 @@ // The old system would loop through lists for a total of 5000 per function call, in an empty server. // This new system will loop at around 1000 in an empty server. -/proc/get_mobs_in_view(var/R, var/atom/source) +/proc/get_mobs_in_view(var/R, var/atom/source, var/include_clientless = FALSE) // Returns a list of mobs in range of R from source. Used in radio and say code. var/turf/T = get_turf(source) @@ -165,7 +165,7 @@ for(var/atom/A in range) if(ismob(A)) var/mob/M = A - if(M.client) + if(M.client || include_clientless) hear += M //log_to_dd("Start = [M] - [get_turf(M)] - ([M.x], [M.y], [M.z])") else if(istype(A, /obj/item/device/radio)) @@ -418,7 +418,7 @@ /proc/SecondsToTicks(var/seconds) return seconds * 10 -proc/pollCandidates(var/Question, var/be_special_type, var/antag_age_check = 0, var/poll_time = 300, var/ignore_respawnability = 0, var/min_hours = 0) +proc/pollCandidates(Question, be_special_type, antag_age_check = 0, poll_time = 300, ignore_respawnability = 0, min_hours = 0, flashwindow = TRUE) var/roletext = be_special_type ? get_roletext(be_special_type) : null var/list/mob/dead/observer/candidates = list() var/time_passed = world.time @@ -444,7 +444,8 @@ proc/pollCandidates(var/Question, var/be_special_type, var/antag_age_check = 0, continue spawn(0) G << 'sound/misc/notice2.ogg'//Alerting them to their consideration - + if(flashwindow) + window_flash(G.client) switch(alert(G,Question,"Please answer in [poll_time/10] seconds!","Yes","No","Not This Round")) if("Yes") to_chat(G, "Choice registered: Yes.") @@ -471,3 +472,12 @@ proc/pollCandidates(var/Question, var/be_special_type, var/antag_age_check = 0, candidates.Remove(G) return candidates + +/proc/window_flash(client/C) + if(ismob(C)) + var/mob/M = C + if(M.client) + C = M.client + if(!C || !C.prefs.windowflashing) + return + winset(C, "mainwindow", "flash=5") \ No newline at end of file diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index f54726c4161..9fa27c93356 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -72,6 +72,14 @@ return 0 return L[A.type] +//returns a new list with only atoms that are in typecache L +/proc/typecache_filter_list(list/atoms, list/typecache) + . = list() + for (var/thing in atoms) + var/atom/A = thing + if(typecache[A.type]) + . += A + //Like typesof() or subtypesof(), but returns a typecache instead of a list /proc/typecacheof(path, ignore_root_path) if(ispath(path)) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index d5b75eb4c7c..4c6abbd7d0b 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -431,3 +431,17 @@ proc/checkhtml(var/t) text = copytext(text, 1, index) + repl_chars[char] + copytext(text, index+keylength) index = findtext(text, char) return text + +//Checks if any of a given list of needles is in the haystack +/proc/text_in_list(haystack, list/needle_list, start=1, end=0) + for(var/needle in needle_list) + if(findtext(haystack, needle, start, end)) + return 1 + return 0 + +//Like above, but case sensitive +/proc/text_in_list_case(haystack, list/needle_list, start=1, end=0) + for(var/needle in needle_list) + if(findtextEx(haystack, needle, start, end)) + return 1 + return 0 diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index a2af5d5f4c6..9644b4348b3 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1,4 +1,3 @@ - //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 /* @@ -326,7 +325,7 @@ Turf and target are seperate in case you want to teleport some distance from a t var/mob/M = old_list[named] if(issilicon(M)) AI_list |= M - else if(isobserver(M) || M.stat == 2) + else if(isobserver(M) || M.stat == DEAD) Dead_list |= M else if(M.key && M.client) keyclient_list |= M @@ -360,7 +359,7 @@ Turf and target are seperate in case you want to teleport some distance from a t namecounts[name] = 1 if(M.real_name && M.real_name != M.name) name += " \[[M.real_name]\]" - if(M.stat == 2) + if(M.stat == DEAD) if(istype(M, /mob/dead/observer/)) name += " \[ghost\]" else @@ -550,15 +549,21 @@ proc/anim(turf/location as turf,target as mob|obj,a_icon,a_icon_state as text,fl /proc/can_see(var/atom/source, var/atom/target, var/length=5) // I couldnt be arsed to do actual raycasting :I This is horribly inaccurate. var/turf/current = get_turf(source) var/turf/target_turf = get_turf(target) - var/steps = 0 - - while(current != target_turf) - if(steps > length) return 0 - if(current.opacity) return 0 - for(var/atom/A in current) - if(A.opacity) return 0 - current = get_step_towards(current, target_turf) - steps++ + var/steps = 1 + + if(current != target_turf) + current = get_step_towards(current, target_turf) + while(current != target_turf) + if(steps > length) + return 0 + if(current.opacity) + return 0 + for(var/thing in current) + var/atom/A = thing + if(A.opacity) + return 0 + current = get_step_towards(current, target_turf) + steps++ return 1 @@ -1812,6 +1817,70 @@ var/global/list/g_fancy_list_of_types = null //you might be thinking of adding more steps to this, or making it use a loop and a counter var // not worth it. +// This proc gets a list of all "points of interest" (poi's) that can be used by admins to track valuable mobs or atoms (such as the nuke disk). +/proc/getpois(mobs_only=0,skip_mindless=0) + var/list/mobs = sortmobs() + var/list/names = list() + var/list/pois = list() + var/list/namecounts = list() + + for(var/mob/M in mobs) + if(skip_mindless && (!M.mind && !M.ckey)) + if(!isbot(M) && !istype(M, /mob/camera/)) + continue + if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins + continue + var/name = M.name + if(name in names) + namecounts[name]++ + name = "[name] ([namecounts[name]])" + else + names.Add(name) + namecounts[name] = 1 + if(M.real_name && M.real_name != M.name) + name += " \[[M.real_name]\]" + if(M.stat == DEAD) + if(istype(M, /mob/dead/observer/)) + name += " \[ghost\]" + else + name += " \[dead\]" + pois[name] = M + + if(!mobs_only) + for(var/atom/A in poi_list) + if(!A || !A.loc) + continue + var/name = A.name + if(names.Find(name)) + namecounts[name]++ + name = "[name] ([namecounts[name]])" + else + names.Add(name) + namecounts[name] = 1 + pois[name] = A + + return pois + +/proc/flash_color(mob_or_client, flash_color="#960000", flash_time=20) + var/client/C + if(istype(mob_or_client, /mob)) + var/mob/M = mob_or_client + if(M.client) + C = M.client + else + return + else if(istype(mob_or_client, /client)) + C = mob_or_client + + if(!istype(C)) + return + + C.color = flash_color + spawn(0) + animate(C, color = initial(C.color), time = flash_time) + +#define RANDOM_COLOUR (rgb(rand(0,255),rand(0,255),rand(0,255))) + /proc/make_bit_triplet() var/list/num_sample = list(1, 2, 3, 4, 5, 6, 7, 8, 9) var/result = 0 diff --git a/code/_globalvars/configuration.dm b/code/_globalvars/configuration.dm index 5b41171d557..3e2d7d995d6 100644 --- a/code/_globalvars/configuration.dm +++ b/code/_globalvars/configuration.dm @@ -36,3 +36,8 @@ var/eventchance = 10 //% per 5 mins var/event = 0 var/hadevent = 0 var/blobevent = 0 + +//Medals hub related variables +var/global/medal_hub = null +var/global/medal_pass = " " +var/global/medals_enabled = TRUE //will be auto set to false if the game fails contacting the medal hub to prevent unneeded calls. \ No newline at end of file diff --git a/code/_globalvars/lists/misc.dm b/code/_globalvars/lists/misc.dm index 4cdc0bef33d..eb5c500573b 100644 --- a/code/_globalvars/lists/misc.dm +++ b/code/_globalvars/lists/misc.dm @@ -19,3 +19,5 @@ var/list/restricted_camera_networks = list( //Those networks can only be accesse ) var/list/mineral_turfs = list() + +var/list/ruin_landmarks = list() \ No newline at end of file diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 5a929ebeb30..8018fae5681 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -33,5 +33,9 @@ var/global/list/shuttle_caller_list = list() //list of all communication cons var/global/list/tracked_implants = list() //list of all current implants that are tracked to work out what sort of trek everyone is on. Sadly not on lavaworld not implemented... var/global/list/pinpointer_list = list() //list of all pinpointers. Used to change stuff they are pointing to all at once. var/global/list/abductor_equipment = list() //list of all abductor equipment + + var/global/list/global_intercoms = list() //list of all intercomms, across all z-levels -var/global/list/global_radios = list() //list of all radios, across all z-levels \ No newline at end of file +var/global/list/global_radios = list() //list of all radios, across all z-levels + +var/global/list/poi_list = list() //list of points of interest for observe/follow \ No newline at end of file diff --git a/code/_globalvars/mapping.dm b/code/_globalvars/mapping.dm index dfecea02531..841fbced3f7 100644 --- a/code/_globalvars/mapping.dm +++ b/code/_globalvars/mapping.dm @@ -49,6 +49,6 @@ var/list/datum/map_template/map_templates = list() var/list/datum/map_template/ruins_templates = list() var/list/datum/map_template/space_ruins_templates = list() -//var/list/datum/map_template/lava_ruins_templates = list() +var/list/datum/map_template/lava_ruins_templates = list() var/list/datum/map_template/shelter_templates = list() var/list/datum/map_template/shuttle_templates = list() \ No newline at end of file diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 66377ec3fcd..58928da83e0 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -95,9 +95,9 @@ update_inv_r_hand(0) return - // operate two STORAGE levels deep here (item in backpack in src; NOT item in box in backpack in src) + // operate three levels deep here (item in backpack in src; item in box in backpack in src, not any deeper) var/sdepth = A.storage_depth(src) - if(A == loc || (A in loc) || (sdepth != -1 && sdepth <= 1)) + if(A == loc || (A in loc) || (sdepth != -1 && sdepth <= 2)) // No adjacency needed if(W) var/resolved = A.attackby(W,src) @@ -323,16 +323,6 @@ // 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) - -/* // Snowflake for space vines. //Are you fucking kidding me? - var/is_buckled = 0 - if(buckled) - if(istype(buckled)) - if(!buckled.movable) - is_buckled = 1 - else - is_buckled = 0*/ - if( stat || buckled || !A || !x || !y || !A.x || !A.y ) return var/dx = A.x - x var/dy = A.y - y @@ -345,11 +335,7 @@ else if(dx > 0) direction = EAST else direction = WEST - usr.dir = direction - -/* if(buckled && buckled.movable) - buckled.dir = direction - buckled.handle_rotation()*/ + dir = direction /obj/screen/click_catcher icon = 'icons/mob/screen_full.dmi' diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm index cb77112deb3..a20efc98a06 100644 --- a/code/_onclick/hud/alert.dm +++ b/code/_onclick/hud/alert.dm @@ -197,6 +197,16 @@ The box in your backpack has an oxygen tank and gas mask in it." name = "High Pressure" desc = "The air around you is hazardously thick. A fire suit would protect you." icon_state = "highpressure" + +/obj/screen/alert/lightexposure + name = "Light Exposure" + desc = "You're exposed to light." + icon_state = "lightexposure" + +/obj/screen/alert/nolight + name = "No Light" + desc = "You're not exposed to any light." + icon_state = "nolight" /obj/screen/alert/blind name = "Blind" @@ -349,25 +359,28 @@ so as to remain in compliance with the most up-to-date laws." var/mob/dead/observer/G = usr G.reenter_corpse() -/obj/screen/alert/notify_jump +/obj/screen/alert/notify_action name = "Body created" desc = "A body was created. You can enter it." icon_state = "template" timeout = 300 - var/atom/jump_target = null - var/attack_not_jump = null + var/atom/target = null + var/action = NOTIFY_JUMP -/obj/screen/alert/notify_jump/Click() +/obj/screen/alert/notify_action/Click() if(!usr || !usr.client) return - if(!jump_target) return + if(!target) return var/mob/dead/observer/G = usr if(!istype(G)) return - if(attack_not_jump) - jump_target.attack_ghost(G) - else - var/turf/T = get_turf(jump_target) - if(T && isturf(T)) - G.loc = T + switch(action) + if(NOTIFY_ATTACK) + target.attack_ghost(G) + if(NOTIFY_JUMP) + var/turf/T = get_turf(target) + if(T && isturf(T)) + G.loc = T + if(NOTIFY_FOLLOW) + G.ManualFollow(target) //OBJECT-BASED diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 20a04b5278e..46368def984 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -74,7 +74,9 @@ ///////////////////////// - if(istype(M, /mob/living/simple_animal)) + if(isanimal(M)) + var/mob/living/simple_animal/S = M + S.attacked_by(src, user) return 0 // No sanic-speed double-attacks for you - simple mobs will handle being attacked on their own var/power = force diff --git a/code/controllers/Processes/weather.dm b/code/controllers/Processes/weather.dm index 6cdcce750b6..d2149371649 100644 --- a/code/controllers/Processes/weather.dm +++ b/code/controllers/Processes/weather.dm @@ -33,7 +33,7 @@ var/global/datum/controller/process/weather/weather_master var/list/possible_weather_for_this_z = list() for(var/V in existing_weather) var/datum/weather/WE = V - if(WE.target_level == Z && WE.probability) //Another check so that it doesn't run extra weather + if(WE.target_z == Z && WE.probability) //Another check so that it doesn't run extra weather possible_weather_for_this_z[WE] = WE.probability var/datum/weather/W = pickweight(possible_weather_for_this_z) run_weather(W.name) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index f1c081f1df6..5e1701aacb8 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -575,6 +575,12 @@ if("round_abandon_penalty_period") config.round_abandon_penalty_period = MinutesToTicks(text2num(value)) + + if("medal_hub_address") + global.medal_hub = value + + if("medal_hub_password") + global.medal_pass = value if("disable_ooc_emoji") config.disable_ooc_emoji = 1 diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index a7678e1d261..027101df146 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -17,8 +17,7 @@ message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.") return - -/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Lighting","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote","Mob Hunt Server")) +/client/proc/debug_controller(controller in list("Master","failsafe","Ticker","Air","Lighting","Jobs","Sun","Radio","Configuration","pAI", "Cameras","Garbage", "Transfer Controller","Event","Alarm","Scheduler","Nano","Vote","Diseases","Fires","Mob","NPC AI","Shuttle","Timer","Weather","Space","Mob Hunt Server")) set category = "Debug" set name = "Debug Controller" set desc = "Debug the various periodic loop controllers for the game (be careful!)" @@ -76,6 +75,30 @@ if("Vote") debug_variables(vote) feedback_add_details("admin_verb","DVote") + if("Diseases") + debug_variables(disease_master) + feedback_add_details("admin_verb","DDiseases") + if("Fires") + debug_variables(fire_master) + feedback_add_details("admin_verb","DFires") + if("Mob") + debug_variables(mob_master) + feedback_add_details("admin_verb","DMob") + if("NPC AI") + debug_variables(npcai_master) + feedback_add_details("admin_verb","DNPCAI") + if("Shuttle") + debug_variables(shuttle_master) + feedback_add_details("admin_verb","DShuttle") + if("Timer") + debug_variables(timer_master) + feedback_add_details("admin_verb","DTimer") + if("Weather") + debug_variables(weather_master) + feedback_add_details("admin_verb","DWeather") + if("Space") + debug_variables(space_manager) + feedback_add_details("admin_verb","DSpace") if("Mob Hunt Server") debug_variables(mob_hunt_server) feedback_add_details("admin_verb","DMobHuntServer") diff --git a/code/datums/action.dm b/code/datums/action.dm index 446b50243ae..f1826c334c5 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -187,6 +187,40 @@ /datum/action/item_action/toggle_hardsuit_mode name = "Toggle Hardsuit Mode" + +/datum/action/item_action/toggle_unfriendly_fire + name = "Toggle Friendly Fire \[ON\]" + desc = "Toggles if the staff causes friendly fire." + button_icon_state = "vortex_ff_on" + +/datum/action/item_action/toggle_unfriendly_fire/Trigger() + if(..()) + UpdateButtonIcon() + +/datum/action/item_action/toggle_unfriendly_fire/UpdateButtonIcon() + if(istype(target, /obj/item/weapon/hierophant_staff)) + var/obj/item/weapon/hierophant_staff/H = target + if(H.friendly_fire_check) + button_icon_state = "vortex_ff_off" + name = "Toggle Friendly Fire \[OFF\]" + button.name = name + else + button_icon_state = "vortex_ff_on" + name = "Toggle Friendly Fire \[ON\]" + button.name = name + ..() + +/datum/action/item_action/vortex_recall + name = "Vortex Recall" + desc = "Recall yourself, and anyone nearby, to an attuned hierophant rune at any time.
If no such rune exists, will produce a rune at your location." + button_icon_state = "vortex_recall" + +/datum/action/item_action/vortex_recall/IsAvailable() + if(istype(target, /obj/item/weapon/hierophant_staff)) + var/obj/item/weapon/hierophant_staff/H = target + if(H.teleporting) + return 0 + return ..() /datum/action/item_action/toggle @@ -323,6 +357,11 @@ ..() name = "Toggle [target.name]" button.name = name + +/datum/action/item_action/organ_action/use/New(Target) + ..() + name = "Use [target.name]" + button.name = name // for clothing accessories like holsters /datum/action/item_action/accessory diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 7e54565c4f0..31b789844be 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -1,5 +1,11 @@ // reference: /client/proc/modify_variables(var/atom/O, var/param_var_name = null, var/autodetect_class = 0) +/datum + var/var_edited = 0 //Warrenty void if seal is broken + +/datum/proc/on_varedit(modified_var) //called whenever a var is edited + var_edited = 1 + /client/proc/debug_variables(datum/D in world) set category = "Debug" set name = "View Variables" diff --git a/code/datums/spell.dm b/code/datums/spell.dm index a7bf2b7c0ba..f48f6ca3fc7 100644 --- a/code/datums/spell.dm +++ b/code/datums/spell.dm @@ -3,9 +3,53 @@ /obj/effect/proc_holder var/panel = "Debug"//What panel the proc holder needs to go on. + var/active = FALSE //Used by toggle based abilities. + var/ranged_mousepointer var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin verb for now +/obj/effect/proc_holder/proc/InterceptClickOn(mob/living/user, params, atom/A) + if(user.ranged_ability != src) + to_chat(user, "[user.ranged_ability.name] has been disabled.") + user.ranged_ability.remove_ranged_ability(user) + return TRUE //TRUE for failed, FALSE for passed. + user.next_click = world.time + CLICK_CD_CLICK_ABILITY + user.face_atom(A) + return FALSE + +/obj/effect/proc_holder/proc/add_ranged_ability(mob/living/user, var/msg) + if(!user || !user.client) + return + if(user.ranged_ability && user.ranged_ability != src) + to_chat(user, "[user.ranged_ability.name] has been replaced by [name].") + user.ranged_ability.remove_ranged_ability(user) + user.ranged_ability = src + user.client.click_intercept = user.ranged_ability + add_mousepointer(user.client) + active = TRUE + if(msg) + to_chat(user, msg) + update_icon() + +/obj/effect/proc_holder/proc/add_mousepointer(client/C) + if(C && ranged_mousepointer && C.mouse_pointer_icon == initial(C.mouse_pointer_icon)) + C.mouse_pointer_icon = ranged_mousepointer + +/obj/effect/proc_holder/proc/remove_mousepointer(client/C) + if(C && ranged_mousepointer && C.mouse_pointer_icon == ranged_mousepointer) + C.mouse_pointer_icon = initial(C.mouse_pointer_icon) + +/obj/effect/proc_holder/proc/remove_ranged_ability(mob/living/user, var/msg) + if(!user || !user.client || (user.ranged_ability && user.ranged_ability != src)) //To avoid removing the wrong ability + return + user.ranged_ability = null + user.client.click_intercept = null + remove_mousepointer(user.client) + active = FALSE + if(msg) + to_chat(user, msg) + update_icon() + /obj/effect/proc_holder/spell name = "Spell" desc = "A wizard spell" @@ -26,6 +70,8 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin var/ghost = 0 // Skip life check. var/clothes_req = 1 //see if it requires clothes + var/human_req = 0 //spell can only be cast by humans + var/nonabstract_req = 0 //spell can only be cast by mobs that are physical entities var/stat_allowed = 0 //see if it requires being conscious/alive, need to set to 1 for ghostpells var/invocation = "HURP DURP" //what is uttered when the wizard casts the spell var/invocation_emote_self = null @@ -54,13 +100,15 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin var/action_icon = 'icons/mob/actions.dmi' var/action_icon_state = "spell_default" var/action_background_icon_state = "bg_spell" + + var/sound = null //The sound the spell makes when it is cast /obj/effect/proc_holder/spell/proc/cast_check(skipcharge = 0, mob/living/user = usr) //checks if the spell can be cast based on its settings; skipcharge is used when an additional cast_check is called inside the spell - if(((!user.mind) || !(src in user.mind.spell_list)) && !(src in user.mob_spell_list)) to_chat(user, "You shouldn't have this spell! Something's wrong.") return 0 - if(istype(user, /mob/living/carbon/human)) + + if(ishuman(user)) var/mob/living/carbon/human/caster = user if(caster.remoteview_target) caster.remoteview_target = null @@ -83,26 +131,31 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin if(!ghost) if(user.stat && !stat_allowed) - to_chat(user, "Not when you're incapacitated.") + to_chat(user, "You can't cast this spell while incapacitated.") return 0 - if(ishuman(user) && (invocation_type == "whisper" || invocation_type == "shout") && user.is_muzzled()) to_chat(user, "Mmmf mrrfff!") return 0 - var/obj/effect/proc_holder/spell/noclothes/spell = locate() in (user.mob_spell_list | (user.mind ? user.mind.spell_list : list())) - if(clothes_req && !(spell && istype(spell)))//clothes check - if(!istype(user, /mob/living/carbon/human)) - to_chat(user, "You aren't a human, Why are you trying to cast a human spell, silly non-human? Casting human spells is for humans.") + + var/obj/effect/proc_holder/spell/noclothes/clothes_spell = locate() in (user.mob_spell_list | (user.mind ? user.mind.spell_list : list())) + if((ishuman(user) && clothes_req) && !istype(clothes_spell))//clothes check + var/mob/living/carbon/human/H = user + if(!istype(H.wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(H.wear_suit, /obj/item/clothing/suit/space/rig/wizard)) + to_chat(user, "I don't feel strong enough without my robe.") return 0 - if(!istype(user:wear_suit, /obj/item/clothing/suit/wizrobe) && !istype(user:wear_suit, /obj/item/clothing/suit/space/rig/wizard)) - to_chat(user, "I don't feel strong enough without my robe.") + if(!istype(H.shoes, /obj/item/clothing/shoes/sandal)) + to_chat(user, "I don't feel strong enough without my sandals.") return 0 - if(!istype(user:shoes, /obj/item/clothing/shoes/sandal)) - to_chat(user, "I don't feel strong enough without my sandals.") - return 0 - if(!istype(user:head, /obj/item/clothing/head/wizard) && !istype(user:head, /obj/item/clothing/head/helmet/space/rig/wizard)) + if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/rig/wizard)) to_chat(user, "I don't feel strong enough without my hat.") return 0 + else if(!ishuman(user)) + if(clothes_req || human_req) + to_chat(user, "This spell can only be cast by humans!") + return 0 + if(nonabstract_req && (isbrain(user) || ispAI(user))) + to_chat(user, "This spell can only be cast by physical beings!") + return 0 if(!skipcharge) switch(charge_type) @@ -130,6 +183,9 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin if("emote") user.visible_message(invocation, invocation_emote_self) //same style as in mob/living/emote.dm +/obj/effect/proc_holder/spell/proc/playMagSound() + playsound(get_turf(usr), sound,50,1) + /obj/effect/proc_holder/spell/New() ..() action = new(src) @@ -167,10 +223,14 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin spawn(0) if(charge_type == "recharge" && recharge) start_recharge() + + if(sound) + playMagSound() + if(prob(critfailchance)) critfail(targets) else - cast(targets) + cast(targets, user = user) after_cast(targets) /obj/effect/proc_holder/spell/proc/before_cast(list/targets) @@ -216,7 +276,7 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin smoke.set_up(smoke_amt, 0, location) // same here smoke.start() -/obj/effect/proc_holder/spell/proc/cast(list/targets) +/obj/effect/proc_holder/spell/proc/cast(list/targets, mob/user = usr) return /obj/effect/proc_holder/spell/proc/critfail(list/targets) @@ -270,9 +330,6 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin switch(max_targets) if(0) //unlimited for(var/mob/living/target in view_or_range(range, user, selection_type)) - for(var/F in user.faction) - if(F in target.faction) - continue targets += target if(1) //single target can be picked if(range < 0) @@ -326,7 +383,7 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin revert_cast(user) return - perform(targets) + perform(targets, user=user) return @@ -341,7 +398,7 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin revert_cast() return - perform(targets) + perform(targets, user=user) return @@ -377,7 +434,6 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin return 0 if(ishuman(user)) - var/mob/living/carbon/human/H = user if((invocation_type == "whisper" || invocation_type == "shout") && H.is_muzzled()) @@ -393,8 +449,8 @@ var/list/spells = typesof(/obj/effect/proc_holder/spell) //needed for the badmin if(!istype(H.head, /obj/item/clothing/head/wizard) && !istype(H.head, /obj/item/clothing/head/helmet/space/rig/wizard)) return 0 else - if(clothes_req) + if(clothes_req || human_req) return 0 - if(isbrain(user) || ispAI(user)) + if(nonabstract_req && (isbrain(user) || ispAI(user))) return 0 return 1 diff --git a/code/datums/spells/area_teleport.dm b/code/datums/spells/area_teleport.dm index ad0b6fa61de..46def2b5a9c 100644 --- a/code/datums/spells/area_teleport.dm +++ b/code/datums/spells/area_teleport.dm @@ -1,10 +1,15 @@ /obj/effect/proc_holder/spell/targeted/area_teleport name = "Area teleport" desc = "This spell teleports you to a type of area of your selection." - + nonabstract_req = 1 + var/randomise_selection = 0 //if it lets the usr choose the teleport loc or picks it from the list var/invocation_area = 1 //if the invocation appends the selected area -/obj/effect/proc_holder/spell/targeted/area_teleport/perform(list/targets, recharge = 1) + + var/sound1 = 'sound/weapons/ZapBang.ogg' + var/sound2 = 'sound/weapons/ZapBang.ogg' + +/obj/effect/proc_holder/spell/targeted/area_teleport/perform(list/targets, recharge = 1, mob/living/user = usr) var/thearea = before_cast(targets) if(!thearea || !cast_check(1)) revert_cast() @@ -32,7 +37,8 @@ return thearea -/obj/effect/proc_holder/spell/targeted/area_teleport/cast(list/targets,area/thearea) +/obj/effect/proc_holder/spell/targeted/area_teleport/cast(list/targets,area/thearea,mob/living/user = usr) + playsound(get_turf(user), sound1, 50,1) for(var/mob/living/target in targets) var/list/L = list() for(var/turf/T in get_area_turfs(thearea.type)) @@ -64,7 +70,8 @@ break if(!success) - target.loc = pick(L) + target.forceMove(pick(L)) + playsound(get_turf(user), sound2, 50,1) return diff --git a/code/datums/spells/bloodcrawl.dm b/code/datums/spells/bloodcrawl.dm index 7f6f4d4fb2a..0b23b12b9f2 100644 --- a/code/datums/spells/bloodcrawl.dm +++ b/code/datums/spells/bloodcrawl.dm @@ -14,8 +14,8 @@ /obj/effect/proc_holder/spell/bloodcrawl/choose_targets(mob/user = usr) for(var/obj/effect/decal/cleanable/target in range(range, get_turf(user))) - if(istype(target,/obj/effect/decal/cleanable/blood) && !(istype(target,/obj/effect/decal/cleanable/blood/oil) || istype(target,/obj/effect/decal/cleanable/blood/gibs/robot))) - perform(target) + if(target.can_bloodcrawl_in()) + perform(target, user = user) return revert_cast() to_chat(user, "There must be a nearby source of blood!") diff --git a/code/datums/spells/conjure.dm b/code/datums/spells/conjure.dm index bdd15eb34fe..fe0ffd9c1c0 100644 --- a/code/datums/spells/conjure.dm +++ b/code/datums/spells/conjure.dm @@ -13,15 +13,17 @@ var/list/newVars = list() //vars of the summoned objects will be replaced with those where they meet //should have format of list("emagged" = 1,"name" = "Wizard's Justicebot"), for example var/delay = 1//Go Go Gadget Inheritance + + var/cast_sound = 'sound/items/welder.ogg' -/obj/effect/proc_holder/spell/aoe_turf/conjure/cast(list/targets) - +/obj/effect/proc_holder/spell/aoe_turf/conjure/cast(list/targets,mob/living/user = usr) + playsound(get_turf(user), cast_sound, 50,1) for(var/turf/T in targets) if(T.density && !summon_ignore_density) targets -= T - playsound(get_turf(src), 'sound/items/welder.ogg', 50, 1) + playsound(get_turf(src), cast_sound, 50, 1) - if(do_after(usr,delay, target = usr)) + if(do_after(user,delay, target = user)) for(var/i=0,iYou are somehow too bound to your current location to abandon it.") diff --git a/code/datums/spells/explosion.dm b/code/datums/spells/explosion.dm index 7bb7195c2dd..4beeae1206a 100644 --- a/code/datums/spells/explosion.dm +++ b/code/datums/spells/explosion.dm @@ -7,7 +7,7 @@ var/ex_light = 3 var/ex_flash = 4 -/obj/effect/proc_holder/spell/targeted/explosion/cast(list/targets) +/obj/effect/proc_holder/spell/targeted/explosion/cast(list/targets, mob/user = usr) for(var/mob/living/target in targets) explosion(target.loc,ex_severe,ex_heavy,ex_light,ex_flash) diff --git a/code/datums/spells/genetic.dm b/code/datums/spells/genetic.dm index e61819dc183..697337d85e0 100644 --- a/code/datums/spells/genetic.dm +++ b/code/datums/spells/genetic.dm @@ -15,7 +15,7 @@ 6th bit - ? */ -/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets) +/obj/effect/proc_holder/spell/targeted/genetic/cast(list/targets, mob/user = usr) for(var/mob/living/target in targets) for(var/x in mutations) diff --git a/code/datums/spells/horsemask.dm b/code/datums/spells/horsemask.dm index 3d2ab9d4718..b3ca73fe367 100644 --- a/code/datums/spells/horsemask.dm +++ b/code/datums/spells/horsemask.dm @@ -14,6 +14,7 @@ selection_type = "range" action_icon_state = "barn" + sound = 'sound/magic/HorseHead_curse.ogg' /obj/effect/proc_holder/spell/targeted/horsemask/cast(list/targets, mob/user = usr) if(!targets.len) diff --git a/code/datums/spells/inflict_handler.dm b/code/datums/spells/inflict_handler.dm index 1eed65bbed4..cfda930afd2 100644 --- a/code/datums/spells/inflict_handler.dm +++ b/code/datums/spells/inflict_handler.dm @@ -19,7 +19,7 @@ var/summon_type = null //this will put an obj at the target's location -/obj/effect/proc_holder/spell/targeted/inflict_handler/cast(list/targets) +/obj/effect/proc_holder/spell/targeted/inflict_handler/cast(list/targets, mob/user = usr) for(var/mob/living/target in targets) switch(destroys) diff --git a/code/datums/spells/knock.dm b/code/datums/spells/knock.dm index e2be52fb7db..1d296c26d41 100644 --- a/code/datums/spells/knock.dm +++ b/code/datums/spells/knock.dm @@ -11,8 +11,9 @@ cooldown_min = 20 //20 deciseconds reduction per rank action_icon_state = "knock" + sound = 'sound/magic/Knock.ogg' -/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets) +/obj/effect/proc_holder/spell/aoe_turf/knock/cast(list/targets, mob/user = usr) for(var/turf/T in targets) for(var/obj/machinery/door/door in T.contents) spawn(1) diff --git a/code/datums/spells/lightning.dm b/code/datums/spells/lightning.dm index 00c04e5a792..bb2bb133d71 100644 --- a/code/datums/spells/lightning.dm +++ b/code/datums/spells/lightning.dm @@ -14,6 +14,7 @@ var/ready = 0 var/image/halo = null action_icon_state = "lightning" + var/sound/Snd // so far only way i can think of to stop a sound, thank MSO for the idea. /obj/effect/proc_holder/spell/targeted/lightning/lightnian clothes_req = 0 @@ -31,8 +32,10 @@ /obj/effect/proc_holder/spell/targeted/lightning/proc/StartChargeup(mob/user = usr) ready = 1 to_chat(user, "You start gathering the power.") + Snd = new/sound('sound/magic/lightning_chargeup.ogg',channel = 7) halo = image("icon"='icons/effects/effects.dmi',"icon_state" ="electricity","layer" = EFFECTS_LAYER) user.overlays.Add(halo) + playsound(get_turf(user), Snd, 50, 0) start_time = world.time if(do_mob(user,user,100,uninterruptible=1)) if(ready) @@ -59,11 +62,14 @@ obj/effect/proc_holder/spell/targeted/lightning/proc/Reset(mob/user = usr) /obj/effect/proc_holder/spell/targeted/lightning/cast(list/targets, mob/user = usr) ready = 0 var/mob/living/carbon/target = targets[1] + Snd=sound(null, repeat = 0, wait = 1, channel = Snd.channel) //byond, why you suck? + playsound(get_turf(user),Snd,50,0)// Sorry MrPerson, but the other ways just didn't do it the way i needed to work, this is the only way. if(get_dist(user,target)>range) to_chat(user, "They are too far away!") Reset(user) return + playsound(get_turf(user), 'sound/magic/lightningbolt.ogg', 50, 1) user.Beam(target,icon_state="lightning[rand(1,12)]",icon='icons/effects/effects.dmi',time=5) var/energy = min(world.time - start_time,100) @@ -75,10 +81,10 @@ obj/effect/proc_holder/spell/targeted/lightning/proc/Reset(mob/user = usr) var/mob/living/carbon/current = target if(bounces < 1) current.electrocute_act(bolt_energy,"Lightning Bolt",safety=1) - playsound(get_turf(current), 'sound/machines/defib_zap.ogg', 50, 1, -1) + playsound(get_turf(current), 'sound/magic/LightningShock.ogg', 50, 1, -1) else current.electrocute_act(bolt_energy,"Lightning Bolt",safety=1) - playsound(get_turf(current), 'sound/machines/defib_zap.ogg', 50, 1, -1) + playsound(get_turf(current), 'sound/magic/LightningShock.ogg', 50, 1, -1) var/list/possible_targets = new for(var/mob/living/M in view_or_range(range,target,"view")) if(user == M || target == M && los_check(current,M)) // || origin == M ? Not sure double shockings is good or not diff --git a/code/datums/spells/mime.dm b/code/datums/spells/mime.dm index fb996bc84ee..296521405a0 100644 --- a/code/datums/spells/mime.dm +++ b/code/datums/spells/mime.dm @@ -10,7 +10,9 @@ charge_max = 300 clothes_req = 0 range = 0 - + cast_sound = null + human_req = 1 + action_icon_state = "mime" action_background_icon_state = "bg_mime" @@ -34,6 +36,7 @@ charge_max = 3000 range = -1 include_user = 1 + human_req = 1 action_icon_state = "mime" action_background_icon_state = "bg_mime" diff --git a/code/datums/spells/projectile.dm b/code/datums/spells/projectile.dm index 611c45b1595..258925653d8 100644 --- a/code/datums/spells/projectile.dm +++ b/code/datums/spells/projectile.dm @@ -37,7 +37,7 @@ projectile.dir = get_dir(target,projectile) projectile.name = proj_name - var/current_loc = usr.loc + var/current_loc = user.loc projectile.loc = current_loc @@ -75,7 +75,7 @@ qdel(trail) if(projectile.loc in range(target.loc,proj_trigger_range)) - projectile.perform(list(target)) + projectile.perform(list(target), user = user) break current_loc = projectile.loc diff --git a/code/datums/spells/shapeshift.dm b/code/datums/spells/shapeshift.dm new file mode 100644 index 00000000000..a814c84fa59 --- /dev/null +++ b/code/datums/spells/shapeshift.dm @@ -0,0 +1,82 @@ +/obj/effect/proc_holder/spell/targeted/shapeshift + name = "Shapechange" + desc = "Take on the shape of another for a time to use their natural abilities. Once you've made your choice it cannot be changed." + clothes_req = 0 + human_req = 0 + charge_max = 200 + cooldown_min = 50 + range = -1 + include_user = 1 + invocation = "RAC'WA NO!" + invocation_type = "shout" + action_icon_state = "shapeshift" + + var/shapeshift_type + var/list/current_shapes = list() + var/list/current_casters = list() + var/list/possible_shapes = list(/mob/living/simple_animal/mouse, + /mob/living/simple_animal/pet/corgi, + /mob/living/simple_animal/bot/ed209, + /mob/living/simple_animal/hostile/construct/armoured) + +/obj/effect/proc_holder/spell/targeted/shapeshift/cast(list/targets, mob/user = usr) + for(var/mob/living/M in targets) + if(!shapeshift_type) + var/list/animal_list = list() + for(var/path in possible_shapes) + var/mob/living/simple_animal/A = path + animal_list[initial(A.name)] = path + shapeshift_type = input(M, "Choose Your Animal Form!", "It's Morphing Time!", null) as anything in animal_list + if(!shapeshift_type) //If you aren't gonna decide I am! + shapeshift_type = pick(animal_list) + shapeshift_type = animal_list[shapeshift_type] + if(M in current_shapes) + Restore(M) + else + Shapeshift(M) + +/obj/effect/proc_holder/spell/targeted/shapeshift/proc/Shapeshift(mob/living/caster) + for(var/mob/living/M in caster) + if(M.status_flags & GODMODE) + to_chat(caster, "You're already shapeshifted!") + return + + var/mob/living/shape = new shapeshift_type(caster.loc) + caster.loc = shape + caster.status_flags |= GODMODE + + current_shapes |= shape + current_casters |= caster + clothes_req = 0 + human_req = 0 + + caster.mind.transfer_to(shape) + +/obj/effect/proc_holder/spell/targeted/shapeshift/proc/Restore(mob/living/shape) + var/mob/living/caster + for(var/mob/living/M in shape) + if(M in current_casters) + caster = M + break + if(!caster) + return + caster.loc = shape.loc + caster.status_flags &= ~GODMODE + + clothes_req = initial(clothes_req) + human_req = initial(human_req) + current_casters.Remove(caster) + current_shapes.Remove(shape) + + shape.mind.transfer_to(caster) + qdel(shape) //Gib it maybe ? + +/obj/effect/proc_holder/spell/targeted/shapeshift/dragon + name = "Dragon Form" + desc = "Take on the shape a lesser ash drake." + invocation = "RAAAAAAAAWR!" + + shapeshift_type = /mob/living/simple_animal/hostile/megafauna/dragon/lesser + list/current_shapes = list(/mob/living/simple_animal/hostile/megafauna/dragon/lesser) + list/current_casters = list() + list/possible_shapes = list(/mob/living/simple_animal/hostile/megafauna/dragon/lesser) \ No newline at end of file diff --git a/code/datums/spells/summonitem.dm b/code/datums/spells/summonitem.dm index ce68e7370dd..8ad20486041 100644 --- a/code/datums/spells/summonitem.dm +++ b/code/datums/spells/summonitem.dm @@ -15,9 +15,9 @@ action_icon_state = "summons" -/obj/effect/proc_holder/spell/targeted/summonitem/cast(list/targets) - for(var/mob/living/user in targets) - var/list/hand_items = list(user.get_active_hand(),user.get_inactive_hand()) +/obj/effect/proc_holder/spell/targeted/summonitem/cast(list/targets, mob/user = usr) + for(var/mob/living/target in targets) + var/list/hand_items = list(target.get_active_hand(),target.get_inactive_hand()) var/butterfingers = 0 var/message @@ -56,7 +56,7 @@ if(issilicon(M)) //Items in silicons warp the whole silicon M.loc.visible_message("[M] suddenly disappears!") - M.loc = user.loc + M.loc = target.loc M.loc.visible_message("[M] suddenly appears!") item_to_retrive = null break @@ -68,10 +68,10 @@ /*if(C.internal_organs_by_name && item_to_retrive in C.internal_organs_by_name ) //This won't work, as we use organ datums instead of objects. --DZD C.internal_organs_by_name -= item_to_retrive if(istype(marked_item, /obj/item/brain)) //If this code ever runs I will be happy - var/obj/item/brain/B = new /obj/item/brain(user.loc) + var/obj/item/brain/B = new /obj/item/brain(target.loc) B.transfer_identity(C) C.death() - add_logs(user, C, "magically debrained", addition="INTENT: [uppertext(user.a_intent)]")*/ + add_logs(target, C, "magically debrained", addition="INTENT: [uppertext(target.a_intent)]")*/ if(C.stomach_contents && item_to_retrive in C.stomach_contents) C.stomach_contents -= item_to_retrive @@ -91,19 +91,21 @@ item_to_retrive.loc.visible_message("The [item_to_retrive.name] suddenly disappears!") - if(user.hand) //left active hand - if(!user.equip_to_slot_if_possible(item_to_retrive, slot_l_hand, 0, 1, 1)) - if(!user.equip_to_slot_if_possible(item_to_retrive, slot_r_hand, 0, 1, 1)) + if(target.hand) //left active hand + if(!target.equip_to_slot_if_possible(item_to_retrive, slot_l_hand, 0, 1, 1)) + if(!target.equip_to_slot_if_possible(item_to_retrive, slot_r_hand, 0, 1, 1)) butterfingers = 1 else //right active hand - if(!user.equip_to_slot_if_possible(item_to_retrive, slot_r_hand, 0, 1, 1)) - if(!user.equip_to_slot_if_possible(item_to_retrive, slot_l_hand, 0, 1, 1)) + if(!target.equip_to_slot_if_possible(item_to_retrive, slot_r_hand, 0, 1, 1)) + if(!target.equip_to_slot_if_possible(item_to_retrive, slot_l_hand, 0, 1, 1)) butterfingers = 1 if(butterfingers) - item_to_retrive.loc = user.loc + item_to_retrive.loc = target.loc item_to_retrive.loc.visible_message("The [item_to_retrive.name] suddenly appears!") + playsound(get_turf(target),'sound/magic/SummonItems_generic.ogg',50,1) else - item_to_retrive.loc.visible_message("The [item_to_retrive.name] suddenly appears in [user]'s hand!") + item_to_retrive.loc.visible_message("The [item_to_retrive.name] suddenly appears in [target]'s hand!") + playsound(get_turf(target),'sound/magic/SummonItems_generic.ogg',50,1) if(message) - to_chat(user, message) + to_chat(target, message) diff --git a/code/datums/spells/touch_attacks.dm b/code/datums/spells/touch_attacks.dm index 6f659e5e98d..44993cb69b2 100644 --- a/code/datums/spells/touch_attacks.dm +++ b/code/datums/spells/touch_attacks.dm @@ -14,10 +14,10 @@ return 0 ..() -/obj/effect/proc_holder/spell/targeted/touch/cast(list/targets) - for(var/mob/living/carbon/user in targets) +/obj/effect/proc_holder/spell/targeted/touch/cast(list/targets, mob/user = usr) + for(var/mob/living/carbon/target in targets) if(!attached_hand) - if(!ChargeHand(user)) + if(!ChargeHand(target)) return 0 while(attached_hand) //hibernate untill the spell is actually used charge_counter = 0 diff --git a/code/datums/spells/trigger.dm b/code/datums/spells/trigger.dm index 0db9ae7d9a0..bba1f22cb1a 100644 --- a/code/datums/spells/trigger.dm +++ b/code/datums/spells/trigger.dm @@ -19,11 +19,11 @@ starting_spells = null return ..() -/obj/effect/proc_holder/spell/targeted/trigger/cast(list/targets) +/obj/effect/proc_holder/spell/targeted/trigger/cast(list/targets, mob/user = usr) for(var/mob/living/target in targets) for(var/obj/effect/proc_holder/spell/spell in contents) - spell.perform(list(target),0) + spell.perform(list(target), 0, user = user) for(var/obj/effect/proc_holder/spell/spell in linked_spells) - spell.perform(list(target),0) + spell.perform(list(target), 0, user = user) return \ No newline at end of file diff --git a/code/datums/spells/turf_teleport.dm b/code/datums/spells/turf_teleport.dm index 02dd5f71b49..8d4562aa1dc 100644 --- a/code/datums/spells/turf_teleport.dm +++ b/code/datums/spells/turf_teleport.dm @@ -1,14 +1,19 @@ /obj/effect/proc_holder/spell/targeted/turf_teleport name = "Turf Teleport" desc = "This spell teleports the target to the turf in range." + nonabstract_req = 1 var/inner_tele_radius = 1 var/outer_tele_radius = 2 var/include_space = 0 //whether it includes space tiles in possible teleport locations var/include_dense = 0 //whether it includes dense tiles in possible teleport locations + + var/sound1 = 'sound/weapons/ZapBang.ogg' + var/sound2 = 'sound/weapons/ZapBang.ogg' -/obj/effect/proc_holder/spell/targeted/turf_teleport/cast(list/targets) +/obj/effect/proc_holder/spell/targeted/turf_teleport/cast(list/targets,mob/living/user = usr) + playsound(get_turf(user), sound1, 50,1) for(var/mob/living/target in targets) var/list/turfs = new/list() for(var/turf/T in range(target,outer_tele_radius)) @@ -31,4 +36,5 @@ if(!picked || !isturf(picked)) return - target.loc = picked + target.forceMove(picked) + playsound(get_turf(user), sound2, 50,1) diff --git a/code/datums/spells/wizard.dm b/code/datums/spells/wizard.dm index 33cc6b8d574..e3892baac2f 100644 --- a/code/datums/spells/wizard.dm +++ b/code/datums/spells/wizard.dm @@ -25,9 +25,12 @@ proj_trail_icon_state = "magicmd" action_icon_state = "magicm" + + sound = 'sound/magic/MAGIC_MISSILE.ogg' /obj/effect/proc_holder/spell/targeted/inflict_handler/magic_missile amt_weakened = 3 + sound = 'sound/magic/MM_Hit.ogg' /obj/effect/proc_holder/spell/noclothes name = "No Clothes" @@ -52,8 +55,9 @@ cooldown_min = 300 //25 deciseconds reduction per rank action_icon_state = "mutate" + sound = 'sound/magic/Mutate.ogg' -/obj/effect/proc_holder/spell/targeted/genetic/mutate/cast(list/targets) +/obj/effect/proc_holder/spell/targeted/genetic/mutate/cast(list/targets, mob/user = usr) for(var/mob/living/target in targets) target.dna.SetSEState(HULKBLOCK, 1) genemutcheck(target, HULKBLOCK, null, MUTCHK_FORCED) @@ -93,6 +97,8 @@ emp_heavy = 6 emp_light = 10 + + sound = 'sound/magic/Disable_Tech.ogg' /obj/effect/proc_holder/spell/targeted/turf_teleport/blink name = "Blink" @@ -117,6 +123,9 @@ centcom_cancast = 0 //prevent people from getting to centcom action_icon_state = "blink" + + sound1 = 'sound/magic/blink.ogg' + sound2 = 'sound/magic/blink.ogg' /obj/effect/proc_holder/spell/targeted/area_teleport/teleport name = "Teleport" @@ -135,6 +144,9 @@ smoke_amt = 5 action_icon_state = "spell_teleport" + + sound1 = 'sound/magic/Teleport_diss.ogg' + sound2 = 'sound/magic/Teleport_app.ogg' /obj/effect/proc_holder/spell/aoe_turf/conjure/forcewall name = "Forcewall" @@ -152,6 +164,7 @@ summon_lifespan = 300 action_icon_state = "shield" + cast_sound = 'sound/magic/ForceWall.ogg' /obj/effect/proc_holder/spell/aoe_turf/conjure/timestop name = "Stop Time" @@ -180,7 +193,8 @@ summon_type = list(/mob/living/simple_animal/hostile/carp) - + cast_sound = 'sound/magic/Summon_Karp.ogg' + /obj/effect/proc_holder/spell/aoe_turf/conjure/construct name = "Artificer" desc = "This spell conjures a construct which may be controlled by Shades" @@ -195,6 +209,7 @@ summon_type = list(/obj/structure/constructshell) action_icon_state = "artificer" + cast_sound = 'sound/magic/SummonItems_generic.ogg' /obj/effect/proc_holder/spell/aoe_turf/conjure/creature name = "Summon Creature Swarm" @@ -209,6 +224,7 @@ range = 3 summon_type = list(/mob/living/simple_animal/hostile/creature) + cast_sound = 'sound/magic/SummonItems_generic.ogg' /obj/effect/proc_holder/spell/targeted/trigger/blind name = "Blind" @@ -229,12 +245,14 @@ /obj/effect/proc_holder/spell/targeted/inflict_handler/blind amt_eye_blind = 10 amt_eye_blurry = 20 + sound = 'sound/magic/Blind.ogg' /obj/effect/proc_holder/spell/targeted/genetic/blind disabilities = BLIND duration = 300 + sound = 'sound/magic/Blind.ogg' -/obj/effect/proc_holder/spell/dumbfire/fireball +/obj/effect/proc_holder/spell/fireball name = "Fireball" desc = "This spell fires a fireball at a target and does not require wizard garb." @@ -245,29 +263,65 @@ invocation_type = "shout" range = 20 cooldown_min = 20 //10 deciseconds reduction per rank + var/fireball_type = /obj/item/projectile/magic/fireball + action_icon_state = "fireball0" + sound = 'sound/magic/Fireball.ogg' - proj_icon_state = "fireball" - proj_name = "a fireball" - proj_type = "/obj/effect/proc_holder/spell/turf/fireball" + active = FALSE - proj_lifespan = 200 - proj_step_delay = 1 +/obj/effect/proc_holder/spell/fireball/Click() + var/mob/living/user = usr + if(!istype(user)) + return - action_icon_state = "fireball" + var/msg -/obj/effect/proc_holder/spell/turf/fireball/cast(var/turf/T) - explosion(T, -1, 0, 2, 3, 0, flame_range = 2) + if(!can_cast(user)) + msg = "You can no longer cast Fireball." + remove_ranged_ability(user, msg) + return + if(active) + msg = "You extinguish your fireball...for now." + remove_ranged_ability(user, msg) + else + msg = "Your prepare to cast your fireball spell! Left-click to cast at a target!" + add_ranged_ability(user, msg) -/obj/effect/proc_holder/spell/targeted/inflict_handler/fireball - amt_dam_brute = 20 - amt_dam_fire = 25 +/obj/effect/proc_holder/spell/fireball/update_icon() + if(!action) + return + action.button_icon_state = "fireball[active]" + action.UpdateButtonIcon() -/obj/effect/proc_holder/spell/targeted/explosion/fireball - ex_severe = -1 - ex_heavy = -1 - ex_light = 2 - ex_flash = 5 +/obj/effect/proc_holder/spell/fireball/InterceptClickOn(mob/living/user, params, atom/target) + if(..()) + return FALSE + + if(!cast_check(0, user)) + remove_ranged_ability(user) + return FALSE + + var/list/targets = list(target) + perform(targets, user = user) + + return TRUE + +/obj/effect/proc_holder/spell/fireball/cast(list/targets, mob/living/user = usr) + var/target = targets[1] //There is only ever one target for fireball + var/turf/T = user.loc + var/turf/U = get_step(user, user.dir) // Get the tile infront of the move, based on their direction + if(!isturf(U) || !isturf(T)) + return 0 + + var/obj/item/projectile/magic/fireball/FB = new fireball_type(user.loc) + FB.current = get_turf(user) + FB.preparePixelProjectile(target, get_turf(target), user) + FB.fire() + user.newtonian_move(get_dir(U, T)) + remove_ranged_ability(user) + + return 1 /obj/effect/proc_holder/spell/aoe_turf/repulse name = "Repulse" @@ -282,12 +336,13 @@ var/maxthrow = 5 action_icon_state = "repulse" + sound = 'sound/magic/Repulse.ogg' -/obj/effect/proc_holder/spell/aoe_turf/repulse/cast(list/targets) - var/mob/user = usr +/obj/effect/proc_holder/spell/aoe_turf/repulse/cast(list/targets, mob/user = usr) var/list/thrownatoms = list() var/atom/throwtarget var/distfromcaster + playMagSound() for(var/turf/T in targets) //Done this way so things don't get thrown all around hilariously. for(var/atom/movable/AM in T) thrownatoms += AM @@ -314,3 +369,24 @@ M.Weaken(2) to_chat(M, "You're thrown back by a mystical force!") spawn(0) AM.throw_at(throwtarget, ((Clamp((maxthrow - (Clamp(distfromcaster - 2, 0, distfromcaster))), 3, maxthrow))), 1)//So stuff gets tossed around at the same time. + +/obj/effect/proc_holder/spell/targeted/sacred_flame + name = "Sacred Flame" + desc = "Makes everyone around you more flammable, and lights yourself on fire." + charge_max = 60 + clothes_req = 0 + invocation = "FI'RAN DADISKO" + invocation_type = "shout" + max_targets = 0 + range = 6 + include_user = 1 + selection_type = "view" + action_icon_state = "sacredflame" + sound = 'sound/magic/Fireball.ogg' + +/obj/effect/proc_holder/spell/targeted/sacred_flame/cast(list/targets, mob/user = usr) + for(var/mob/living/L in targets) + L.adjust_fire_stacks(20) + if(isliving(user)) + var/mob/living/U = user + U.IgniteMob() \ No newline at end of file diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index fdd0d447634..641dcfd1bb5 100644 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -1575,6 +1575,14 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine cost = 15 containername = "snacks supply crate" +/datum/supply_packs/vending/chinese + name = "Chinese Supply Crate" + contains = list(/obj/item/weapon/vending_refill/chinese, + /obj/item/weapon/vending_refill/chinese, + /obj/item/weapon/vending_refill/chinese) + cost = 15 + containername = "chinese supply crate" + /datum/supply_packs/vending/cola name = "Softdrinks Supply Crate" contains = list(/obj/item/weapon/vending_refill/cola, diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm index 7002f92061b..c87b2b455e7 100644 --- a/code/datums/weather/weather.dm +++ b/code/datums/weather/weather.dm @@ -20,6 +20,7 @@ var/weather_duration_upper = 1500 //See above - this is the highest possible duration var/weather_sound var/weather_overlay + var/weather_color = null var/end_message = "The wind relents its assault." //Displayed once the wather is over var/end_duration = 300 //In deciseconds, how long the "wind-down" graphic will appear before vanishing entirely @@ -28,8 +29,9 @@ var/area_type = /area/space //Types of area to affect var/list/impacted_areas = list() //Areas to be affected by the weather, calculated when the weather begins - var/target_level = MAIN_STATION //The z-level to affect - + var/target_z = MAIN_STATION //The z-level to affect + var/list/protected_areas = list()//Areas that are protected and excluded from the affected areas. + var/overlay_layer = 10 //Since it's above everything else, this is the layer used by default. 2 is below mobs and walls if you need to use that. var/aesthetic = FALSE //If the weather has no purpose other than looks var/immunity_type = "storm" //Used by mobs to prevent them from being affected by the weather @@ -50,15 +52,20 @@ if(stage == STARTUP_STAGE) return stage = STARTUP_STAGE + var/list/affectareas = list() for(var/V in get_areas(area_type)) + affectareas += V + for(var/V in protected_areas) + affectareas -= get_areas(V) + for(var/V in affectareas) var/area/A = V - if(is_on_level_name(A,target_level)) + if(is_on_level_name(A,target_z)) impacted_areas |= A weather_duration = rand(weather_duration_lower, weather_duration_upper) update_areas() for(var/V in player_list) var/mob/M = V - if(is_on_level_name(M,target_level)) + if(is_on_level_name(M,target_z)) if(telegraph_message) to_chat(M, telegraph_message) if(telegraph_sound) @@ -72,7 +79,7 @@ update_areas() for(var/V in player_list) var/mob/M = V - if(is_on_level_name(M,target_level)) + if(is_on_level_name(M,target_z)) if(weather_message) to_chat(M, weather_message) if(weather_sound) @@ -87,7 +94,7 @@ update_areas() for(var/V in player_list) var/mob/M = V - if(is_on_level_name(M,target_level)) + if(is_on_level_name(M,target_z)) if(end_message) to_chat(M, end_message) if(end_sound) @@ -102,7 +109,7 @@ update_areas() /datum/weather/proc/can_impact(mob/living/L) //Can this weather impact a mob? - if(!is_on_level_name(L,target_level)) + if(!is_on_level_name(L,target_z)) return if(immunity_type in L.weather_immunities) return @@ -119,6 +126,7 @@ N.layer = overlay_layer N.icon = 'icons/effects/weather_effects.dmi' N.invisibility = 0 + N.color = weather_color switch(stage) if(STARTUP_STAGE) N.icon_state = telegraph_overlay @@ -127,6 +135,7 @@ if(WIND_DOWN_STAGE) N.icon_state = end_overlay if(END_STAGE) + N.color = null N.icon_state = initial(N.icon_state) N.icon = 'icons/turf/areas.dmi' N.layer = 10 //Just default back to normal area stuff since I assume setting a var is faster than initial diff --git a/code/datums/weather/weather_types.dm b/code/datums/weather/weather_types.dm index 90615896e6d..1581938bd96 100644 --- a/code/datums/weather/weather_types.dm +++ b/code/datums/weather/weather_types.dm @@ -16,7 +16,7 @@ end_duration = 0 area_type = /area - target_level = MAIN_STATION + target_z = MAIN_STATION overlay_layer = 2 //Covers floors only immunity_type = "lava" @@ -50,7 +50,7 @@ end_duration = 0 area_type = /area - target_level = MAIN_STATION + target_z = MAIN_STATION /datum/weather/advanced_darkness/update_areas() for(var/V in impacted_areas) @@ -87,7 +87,7 @@ end_overlay = "light_ash" area_type = /area/mine/dangerous - target_level = MINING + target_z = MINING immunity_type = "ash" diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 1bcc5bad5ef..e1077773daa 100644 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -58,6 +58,8 @@ NOTE: there are two lists of areas in the end of this file: centcom and station var/tele_proof = 0 var/no_teleportlocs = 0 + + var/outdoors = 0 //For space, the asteroid, lavaland, etc. Used with blueprints to determine if we are adding a new area (vs editing a station room) /*Adding a wizard area teleport list because motherfucking lag -- Urist*/ /*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/ @@ -121,6 +123,7 @@ var/list/ghostteleportlocs = list() power_light = 0 power_equip = 0 power_environ = 0 + outdoors = 1 ambientsounds = list('sound/ambience/ambispace.ogg','sound/music/title2.ogg','sound/music/space.ogg','sound/music/traitor.ogg') /area/space/atmosalert() @@ -551,6 +554,7 @@ var/list/ghostteleportlocs = list() name = "\improper Asteroid - Underground" icon_state = "cave" requires_power = 0 + outdoors = 1 /area/asteroid/artifactroom name = "\improper Asteroid - Artifact" diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 663d6c5a8f9..0df047cdca3 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -36,6 +36,8 @@ var/list/original_atom var/allow_spin = 1 //Set this to 1 for a _target_ that is being thrown at; if an atom has this set to 1 then atoms thrown AT it will not spin; currently used for the singularity. -Fox + + var/admin_spawned = 0 //was this spawned by an admin? used for stat tracking stuff. /atom/proc/onCentcom() var/turf/T = get_turf(src) @@ -464,3 +466,7 @@ /atom/proc/speech_bubble(var/bubble_state = "",var/bubble_loc = src, var/list/bubble_recipients = list()) return + +/atom/on_varedit(modified_var) + if(!Debug2) + admin_spawned = TRUE \ No newline at end of file diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 107e8aee518..f64b914f3eb 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -225,6 +225,10 @@ if(isobj(A)) if(A.density && !A.throwpass) // **TODO: Better behaviour for windows which are dense, but shouldn't always stop movement src.throw_impact(A,speed) + +/atom/movable/proc/throw_at_fast(atom/target, range, speed, thrower, no_spin) + set waitfor = 0 + throw_at(target, range, speed, thrower, no_spin) /atom/movable/proc/throw_at(atom/target, range, speed, thrower, no_spin) if(!target || !src || (flags & NODROP)) diff --git a/code/game/dna/genes/goon_disabilities.dm b/code/game/dna/genes/goon_disabilities.dm index f2489a2490a..a2ad15e797b 100644 --- a/code/game/dna/genes/goon_disabilities.dm +++ b/code/game/dna/genes/goon_disabilities.dm @@ -259,8 +259,8 @@ action_icon_state = "genetic_incendiary" -/obj/effect/proc_holder/spell/targeted/immolate/cast(list/targets) - var/mob/living/carbon/L = usr +/obj/effect/proc_holder/spell/targeted/immolate/cast(list/targets,mob/living/user = usr) + var/mob/living/carbon/L = user L.adjust_fire_stacks(0.5) L.visible_message("[L.name] suddenly bursts into flames!") L.IgniteMob() diff --git a/code/game/dna/genes/vg_powers.dm b/code/game/dna/genes/vg_powers.dm index c42ac3e43e3..e159aa44247 100644 --- a/code/game/dna/genes/vg_powers.dm +++ b/code/game/dna/genes/vg_powers.dm @@ -28,17 +28,17 @@ action_icon_state = "genetic_morph" -/obj/effect/proc_holder/spell/targeted/morph/cast(list/targets) - if(!ishuman(usr)) return +/obj/effect/proc_holder/spell/targeted/morph/cast(list/targets, mob/user = usr) + if(!ishuman(user)) return - if(istype(usr.loc,/mob/)) - to_chat(usr, "You can't change your appearance right now!") + if(istype(user.loc,/mob/)) + to_chat(user, "You can't change your appearance right now!") return - var/mob/living/carbon/human/M=usr + var/mob/living/carbon/human/M = user var/obj/item/organ/external/head/head_organ = M.get_organ("head") var/obj/item/organ/internal/eyes/eyes_organ = M.get_int_organ(/obj/item/organ/internal/eyes) - var/new_gender = alert(usr, "Please select gender.", "Character Generation", "Male", "Female") + var/new_gender = alert(user, "Please select gender.", "Character Generation", "Male", "Female") if(new_gender) if(new_gender == "Male") M.change_gender(MALE) @@ -219,7 +219,7 @@ validtargets += M if(!validtargets.len) - to_chat(usr, "There are no valid targets!") + to_chat(user, "There are no valid targets!") start_recharge() return @@ -229,24 +229,24 @@ revert_cast(user) return - perform(targets) + perform(targets, user = user) -/obj/effect/proc_holder/spell/targeted/remotetalk/cast(list/targets) - if(!ishuman(usr)) return +/obj/effect/proc_holder/spell/targeted/remotetalk/cast(list/targets, mob/user = usr) + if(!ishuman(user)) return var/say = input("What do you wish to say") as text|null if(!say) return say = strip_html(say) for(var/mob/living/target in targets) - log_say("Project Mind: [key_name(usr)]->[key_name(target)]: [say]") + log_say("Project Mind: [key_name(user)]->[key_name(target)]: [say]") if(REMOTE_TALK in target.mutations) - target.show_message("You hear [usr.real_name]'s voice: [say]") + target.show_message("You hear [user.real_name]'s voice: [say]") else target.show_message("You hear a voice that seems to echo around the room: [say]") - usr.show_message("You project your mind into [target.real_name]: [say]") + user.show_message("You project your mind into [target.real_name]: [say]") for(var/mob/dead/observer/G in player_list) - G.show_message("Telepathic message from [usr] ([ghost_follow_link(usr, ghost=G)]) to [target] ([ghost_follow_link(target, ghost=G)]): [say]") + G.show_message("Telepathic message from [user] ([ghost_follow_link(user, ghost=G)]) to [target] ([ghost_follow_link(target, ghost=G)]): [say]") /datum/dna/gene/basic/grant_spell/remoteview name="Remote Viewing" @@ -283,39 +283,39 @@ if(REMOTE_VIEW in M.mutations) remoteviewers += M if(!remoteviewers.len || remoteviewers.len == 1) - to_chat(usr, "No valid targets with remote view were found!") + to_chat(user, "No valid targets with remote view were found!") start_recharge() return targets += input("Choose the target to spy on.", "Targeting") as mob in remoteviewers - perform(targets) + perform(targets, user = user) -/obj/effect/proc_holder/spell/targeted/remoteview/cast(list/targets) - var/mob/living/carbon/human/user - if(ishuman(usr)) - user = usr +/obj/effect/proc_holder/spell/targeted/remoteview/cast(list/targets, mob/user = usr) + var/mob/living/carbon/human/H + if(ishuman(user)) + H = user else return var/mob/target - if(istype(user.l_hand, /obj/item/tk_grab) || istype(user.r_hand, /obj/item/tk_grab/)) - to_chat(user, "Your mind is too busy with that telekinetic grab.") - user.remoteview_target = null - user.reset_perspective(0) + if(istype(H.l_hand, /obj/item/tk_grab) || istype(H.r_hand, /obj/item/tk_grab/)) + to_chat(H, "Your mind is too busy with that telekinetic grab.") + H.remoteview_target = null + H.reset_perspective(0) return - if(user.client.eye != user.client.mob) - user.remoteview_target = null - user.reset_perspective(0) + if(H.client.eye != user.client.mob) + H.remoteview_target = null + H.reset_perspective(0) return for(var/mob/living/L in targets) target = L if(target) - user.remoteview_target = target - user.reset_perspective(target) + H.remoteview_target = target + H.reset_perspective(target) else - user.remoteview_target = null - user.reset_perspective(0) + H.remoteview_target = null + H.reset_perspective(0) diff --git a/code/game/gamemodes/autotraitor/autotraitor.dm b/code/game/gamemodes/autotraitor/autotraitor.dm index 51820eaf5f4..7c307295dc7 100644 --- a/code/game/gamemodes/autotraitor/autotraitor.dm +++ b/code/game/gamemodes/autotraitor/autotraitor.dm @@ -58,7 +58,6 @@ // if(!traitors.len) // return 0 - ..() return 1 @@ -197,5 +196,3 @@ //message_admins("New traitor roll failed. No new traitor.") //else //message_admins("Late Joiner does not have Be Syndicate") - - diff --git a/code/game/gamemodes/blob/blobs/core.dm b/code/game/gamemodes/blob/blobs/core.dm index afbc4ec9236..0142d198cc3 100644 --- a/code/game/gamemodes/blob/blobs/core.dm +++ b/code/game/gamemodes/blob/blobs/core.dm @@ -14,6 +14,7 @@ /obj/effect/blob/core/New(loc, var/h = 200, var/client/new_overmind = null, var/new_rate = 2, offspring) blob_cores += src processing_objects.Add(src) + poi_list |= src adjustcolors(color) //so it atleast appears if(!overmind) create_overmind(new_overmind) @@ -41,6 +42,7 @@ overmind.blob_core = null overmind = null processing_objects.Remove(src) + poi_list.Remove(src) return ..() /obj/effect/blob/core/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume) diff --git a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm index 83c29ed9109..a9899b33462 100644 --- a/code/game/gamemodes/changeling/powers/augmented_eyesight.dm +++ b/code/game/gamemodes/changeling/powers/augmented_eyesight.dm @@ -7,7 +7,6 @@ helptext = "Grants us thermal vision or flash protection. We will become a lot more vulnerable to flash-based devices while thermal vision is active." chemical_cost = 0 dna_cost = 2 //Would be 1 without thermal vision - var/active = 0 //Whether or not vision is enhanced /obj/effect/proc_holder/changeling/augmented_eyesight/sting_action(mob/living/carbon/human/user) if(!istype(user)) diff --git a/code/game/gamemodes/changeling/powers/strained_muscles.dm b/code/game/gamemodes/changeling/powers/strained_muscles.dm index 92cf9ad7fdf..28884c2653a 100644 --- a/code/game/gamemodes/changeling/powers/strained_muscles.dm +++ b/code/game/gamemodes/changeling/powers/strained_muscles.dm @@ -9,11 +9,11 @@ dna_cost = 1 req_human = 1 var/stacks = 0 //Increments every 5 seconds; damage increases over time - var/active = 0 //Whether or not you are a hedgehog + var/enabled = 0 //Whether or not you are a hedgehog /obj/effect/proc_holder/changeling/strained_muscles/sting_action(var/mob/living/carbon/user) - active = !active - if(active) + enabled = !enabled + if(enabled) to_chat(user, "Our muscles tense and strengthen.") else user.status_flags &= ~GOTTAGOFAST @@ -23,10 +23,10 @@ user.Weaken(3) user.emote("gasp") - while(active) + while(enabled) user.status_flags |= GOTTAGOFAST if(user.stat || user.staminaloss >= 90) - active = 0 //Let's use something exact instead of !active where we can. + enabled = 0 //Let's use something exact instead of !enabled where we can. to_chat(user, "Our muscles relax without the energy to strengthen them.") user.status_flags &= ~GOTTAGOFAST user.Weaken(2) @@ -42,7 +42,7 @@ sleep(40) - while(!active) //Damage stacks decrease fairly rapidly while not in sanic mode + while(!enabled) //Damage stacks decrease fairly rapidly while not in sanic mode if(stacks >= 1) stacks-- sleep(20) diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm index 904b9ea23e7..752e8e353d0 100644 --- a/code/game/gamemodes/cult/ritual.dm +++ b/code/game/gamemodes/cult/ritual.dm @@ -12,7 +12,11 @@ return /obj/effect/rune/proc/check_icon() - icon = get_rune_cult(invocation) + if(!ticker.mode)//work around for maps with runes and cultdat is not loaded all the way + var/bits = make_bit_triplet() + icon = get_rune(bits) + else + icon = get_rune_cult(invocation) /obj/item/weapon/tome name = "arcane tome" diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index af488fdb028..d4e78501639 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -153,6 +153,16 @@ structure_check() searches for nearby cultist structures required for the invoca L.changeNext_move(CLICK_CD_MELEE)//THIS IS WHY WE CAN'T HAVE NICE THINGS do_invoke_glow() +/obj/effect/rune/proc/burn_invokers(var/list/mobstoburn) + for(var/M in mobstoburn) + var/mob/living/L = M + to_chat(L, "\"YOUR SOUL BURNS WITH YOUR ARROGANCE!!!\"") + if(L.reagents) + L.reagents.add_reagent("hell_water", 10) + L.Weaken(7) + L.Stun(7) + fail_invoke() + /obj/effect/rune/proc/do_invoke_glow() var/oldtransform = transform spawn(0) //animate is a delay, we want to avoid being delayed @@ -476,16 +486,13 @@ var/list/teleport_runes = list() return var/mob/living/user = invokers[1] var/datum/game_mode/cult/cult_mode = ticker.mode + if(!(CULT_ELDERGOD in cult_mode.objectives)) + message_admins("[key_name_admin(user)] tried to summonn an eldritch horror when the objective was wrong") + burn_invokers(invokers) + log_game("Summon Nar-Sie rune failed - improper objective") if(!is_station_level(user.z)) - message_admins("[user.real_name]([user.ckey]) tried to summon an eldritch horror off station") - for(var/M in invokers) - var/mob/living/L = M - to_chat(L, "\"YOUR SOUL BURNS WITH YOUR ARROGANCE!!!\"") - if(L.reagents) - L.reagents.add_reagent("hell_water", 10) - L.Weaken(7) - L.Stun(7) - fail_invoke() + message_admins("[key_name_admin(user)] tried to summon an eldritch horror off station") + burn_invokers(invokers) log_game("Summon Nar-Sie rune failed - off station Z level") return if(!cult_mode.eldergod) @@ -566,26 +573,12 @@ var/list/teleport_runes = list() var/datum/game_mode/cult/cult_mode = ticker.mode if(!(CULT_SLAUGHTER in cult_mode.objectives)) message_admins("[usr.real_name]([user.ckey]) tried to summon demons when the objective was wrong") - for(var/M in invokers) - var/mob/living/L = M - to_chat(L, "\"YOUR SOUL BURNS WITH YOUR ARROGANCE!!!\"") - if(L.reagents) - L.reagents.add_reagent("hell_water", 10) - L.Weaken(7) - L.Stun(7) - fail_invoke() + burn_invokers(invokers) log_game("Summon Demons rune failed - improper objective") return if(!is_station_level(user.z)) message_admins("[user.real_name]([user.ckey]) tried to summon demons off station") - for(var/M in invokers) - var/mob/living/L = M - to_chat(L, "\"YOUR SOUL BURNS WITH YOUR ARROGANCE!!!\"") - if(L.reagents) - L.reagents.add_reagent("hell_water", 10) - L.Weaken(7) - L.Stun(7) - fail_invoke() + burn_invokers(invokers) log_game("Summon demons rune failed - off station Z level") return if(cult_mode.demons_summoned) diff --git a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm index 56bb4dd14c5..70b5f82172f 100644 --- a/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm +++ b/code/game/gamemodes/miniantags/bot_swarm/swarmer.dm @@ -6,7 +6,7 @@ icon_state = "swarmer_unactivated" /obj/item/unactivated_swarmer/New() - notify_ghosts("An unactivated swarmer has been created in [get_area(src)]!", enter_link = "(Click to enter)", source = src, attack_not_jump = 1) + notify_ghosts("An unactivated swarmer has been created in [get_area(src)]!", enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK) ..() /obj/item/unactivated_swarmer/Topic(href, href_list) @@ -63,7 +63,7 @@ mob_size = MOB_SIZE_TINY ventcrawler = 2 ranged = 1 - ranged_cooldown_cap = 1 + ranged_cooldown_time = 20 universal_speak = 0 universal_understand = 0 projectilesound = 'sound/weapons/taser2.ogg' diff --git a/code/game/gamemodes/miniantags/guardian/guardian.dm b/code/game/gamemodes/miniantags/guardian/guardian.dm index b3319c34ecb..94a7895bf51 100644 --- a/code/game/gamemodes/miniantags/guardian/guardian.dm +++ b/code/game/gamemodes/miniantags/guardian/guardian.dm @@ -496,7 +496,7 @@ melee_damage_upper = 10 damage_transfer = 0.9 projectiletype = /obj/item/projectile/guardian - ranged_cooldown_cap = 1 + ranged_cooldown_time = 1 projectilesound = 'sound/effects/hit_on_shattered_glass.ogg' ranged = 1 rapid = 1 diff --git a/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm b/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm index 0454499f5ce..85560dda620 100644 --- a/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm +++ b/code/game/gamemodes/miniantags/revenant/revenant_abilities.dm @@ -126,12 +126,12 @@ /obj/effect/proc_holder/spell/targeted/revenant_transmit/cast(list/targets, mob/living/simple_animal/revenant/user = usr) for(var/mob/living/M in targets) spawn(0) - var/msg = stripped_input(usr, "What do you wish to tell [M]?", null, "") + var/msg = stripped_input(user, "What do you wish to tell [M]?", null, "") if(!msg) charge_counter = charge_max return log_say("RevenantTransmit: [key_name(user)]->[key_name(M)] : [msg]") - to_chat(usr, "You transmit to [M]: [msg]") + to_chat(user, "You transmit to [M]: [msg]") to_chat(M, "An alien voice resonates from all around... [msg]") diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 676d48fff8e..a7f3b36fc74 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -300,7 +300,7 @@ proc/issyndicate(mob/living/M as mob) /datum/game_mode/nuclear/declare_completion() var/disk_rescued = 1 - for(var/obj/item/weapon/disk/nuclear/D in world) + for(var/obj/item/weapon/disk/nuclear/D in poi_list) if(!D.onCentcom()) disk_rescued = 0 break diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index d58fb0487ed..6e50736e722 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -32,10 +32,12 @@ var/bomb_set r_code = "[rand(10000, 99999.0)]"//Creates a random code upon object spawn. wires = new/datum/wires/nuclearbomb(src) previous_level = get_security_level() + poi_list |= src /obj/machinery/nuclearbomb/Destroy() qdel(wires) wires = null + poi_list.Remove(src) return ..() /obj/machinery/nuclearbomb/process() diff --git a/code/game/gamemodes/shadowling/shadowling.dm b/code/game/gamemodes/shadowling/shadowling.dm index 528d9396e51..10dac6414d2 100644 --- a/code/game/gamemodes/shadowling/shadowling.dm +++ b/code/game/gamemodes/shadowling/shadowling.dm @@ -311,6 +311,7 @@ Made by Xhuis hot_env_multiplier = 1.5 silent_steps = 1 + grant_vision_toggle = 0 /datum/species/shadow/ling/handle_life(var/mob/living/carbon/human/H) if(!H.weakeyes) @@ -321,11 +322,13 @@ Made by Xhuis var/turf/T = H.loc light_amount = T.get_lumcount() * 10 if(light_amount > LIGHT_DAM_THRESHOLD && !H.incorporeal_move) //Can survive in very small light levels. Also doesn't take damage while incorporeal, for shadow walk purposes + H.throw_alert("lightexposure", /obj/screen/alert/lightexposure) H.take_overall_damage(0, LIGHT_DAMAGE_TAKEN) if(H.stat != DEAD) to_chat(H, "The light burns you!")//Message spam to say "GET THE FUCK OUT" H << 'sound/weapons/sear.ogg' else if(light_amount < LIGHT_HEAL_THRESHOLD) + H.clear_alert("lightexposure") H.heal_overall_damage(5, 5) H.adjustToxLoss(-5) H.adjustBrainLoss(-25) //Shad O. Ling gibbers, "CAN U BE MY THRALL?!!" @@ -357,8 +360,10 @@ Made by Xhuis var/turf/T = H.loc light_amount = T.get_lumcount() * 10 if(light_amount > LIGHT_DAM_THRESHOLD && !H.incorporeal_move) + H.throw_alert("lightexposure", /obj/screen/alert/lightexposure) H.take_overall_damage(0, LIGHT_DAMAGE_TAKEN/2) else if(light_amount < LIGHT_HEAL_THRESHOLD) + H.clear_alert("lightexposure") H.heal_overall_damage(2,2) H.adjustToxLoss(-5) H.adjustBrainLoss(-25) diff --git a/code/game/gamemodes/shadowling/shadowling_abilities.dm b/code/game/gamemodes/shadowling/shadowling_abilities.dm index b29f79fe481..fbfbbb12527 100644 --- a/code/game/gamemodes/shadowling/shadowling_abilities.dm +++ b/code/game/gamemodes/shadowling/shadowling_abilities.dm @@ -21,34 +21,33 @@ clothes_req = 0 action_icon_state = "glare" -/obj/effect/proc_holder/spell/targeted/glare/cast(list/targets) +/obj/effect/proc_holder/spell/targeted/glare/cast(list/targets, mob/user = usr) for(var/mob/living/carbon/human/target in targets) if(!ishuman(target)) - to_chat(usr, "You may only glare at humans!") + to_chat(user, "You may only glare at humans!") charge_counter = charge_max return - if(!shadowling_check(usr)) + if(!shadowling_check(user)) charge_counter = charge_max return if(target.stat) - to_chat(usr, "[target] must be conscious!") + to_chat(user, "[target] must be conscious!") charge_counter = charge_max return if(is_shadow_or_thrall(target)) - to_chat(usr, "You don't see why you would want to paralyze an ally.") + to_chat(user, "You don't see why you would want to paralyze an ally.") charge_counter = charge_max return var/mob/living/carbon/human/M = target - usr.visible_message("[usr]'s eyes flash a blinding red!") + user.visible_message("[user]'s eyes flash a blinding red!") target.visible_message("[target] freezes in place, their eyes glazing over...") - if(in_range(target, usr)) - to_chat(target, "Your gaze is forcibly drawn into [usr]'s eyes, and you are mesmerized by their heavenly beauty...") + if(in_range(target, user)) + to_chat(target, "Your gaze is forcibly drawn into [user]'s eyes, and you are mesmerized by their heavenly beauty...") else //Only alludes to the shadowling if the target is close by to_chat(target, "Red lights suddenly dance in your vision, and you are mesmerized by the heavenly lights...") target.Stun(10) M.AdjustSilence(10) - /obj/effect/proc_holder/spell/aoe_turf/veil name = "Veil" desc = "Extinguishes most nearby light sources." @@ -105,12 +104,12 @@ if(F.light_range > 0) extinguishItem(F) -/obj/effect/proc_holder/spell/aoe_turf/veil/cast(list/targets) - if(!shadowling_check(usr)) +/obj/effect/proc_holder/spell/aoe_turf/veil/cast(list/targets, mob/user = usr) + if(!shadowling_check(user)) charge_counter = charge_max return - to_chat(usr, "You silently disable all nearby lights.") - for(var/obj/effect/glowshroom/G in orange(2, usr)) //Why the fuck was this in the loop below? + to_chat(user, "You silently disable all nearby lights.") + for(var/obj/effect/glowshroom/G in orange(2, user)) //Why the fuck was this in the loop below? G.visible_message("\The [G] withers away!") qdel(G) for(var/turf/T in targets) @@ -142,30 +141,30 @@ include_user = 1 action_icon_state = "shadow_walk" -/obj/effect/proc_holder/spell/targeted/shadow_walk/cast(list/targets) - if(!shadowling_check(usr)) +/obj/effect/proc_holder/spell/targeted/shadow_walk/cast(list/targets, mob/user = usr) + if(!shadowling_check(user)) charge_counter = charge_max return - for(var/mob/living/user in targets) + for(var/mob/living/target in targets) playsound(user.loc, 'sound/effects/bamf.ogg', 50, 1) - user.visible_message("[user] vanishes in a puff of black mist!", "You enter the space between worlds as a passageway.") - user.SetStunned(0) - user.SetWeakened(0) - user.incorporeal_move = 1 - user.alpha = 0 - user.ExtinguishMob() - var/turf/T = get_turf(user) - user.forceMove(T) //to properly move the mob out of a potential container - if(user.buckled) - user.buckled.unbuckle_mob() - if(user.pulledby) - user.pulledby.stop_pulling() - user.stop_pulling() + target.visible_message("[target] vanishes in a puff of black mist!", "You enter the space between worlds as a passageway.") + target.SetStunned(0) + target.SetWeakened(0) + target.incorporeal_move = 1 + target.alpha = 0 + target.ExtinguishMob() + var/turf/T = get_turf(target) + target.forceMove(T) //to properly move the mob out of a potential container + if(target.buckled) + target.buckled.unbuckle_mob() + if(target.pulledby) + target.pulledby.stop_pulling() + target.stop_pulling() sleep(40) //4 seconds - user.visible_message("[user] suddenly manifests!", "The pressure becomes too much and you vacate the interdimensional darkness.") - user.incorporeal_move = 0 - user.alpha = 255 - user.forceMove(user.loc) + target.visible_message("[target] suddenly manifests!", "The pressure becomes too much and you vacate the interdimensional darkness.") + target.incorporeal_move = 0 + target.alpha = 255 + target.forceMove(user.loc) /obj/effect/proc_holder/spell/targeted/lesser_shadow_walk name = "Guise" @@ -177,13 +176,13 @@ include_user = 1 action_icon_state = "shadow_walk" -/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk/cast(list/targets) - for(var/mob/living/user in targets) - user.visible_message("[user] suddenly fades away!", "You veil yourself in darkness, making you harder to see.") - user.alpha = 10 +/obj/effect/proc_holder/spell/targeted/lesser_shadow_walk/cast(list/targets, mob/user = usr) + for(var/mob/living/target in targets) + target.visible_message("[target] suddenly fades away!", "You veil yourself in darkness, making you harder to see.") + target.alpha = 10 sleep(40) - user.visible_message("[user] appears from nowhere!", "Your shadowy guise slips away.") - user.alpha = initial(user.alpha) + target.visible_message("[target] appears from nowhere!", "Your shadowy guise slips away.") + target.alpha = initial(target.alpha) /obj/effect/proc_holder/spell/targeted/shadow_vision @@ -197,11 +196,11 @@ var/datum/vision_override/vision_path = /datum/vision_override/nightvision action_icon_state = "darksight" -/obj/effect/proc_holder/spell/targeted/shadow_vision/cast(list/targets) - for(var/mob/living/user in targets) - if(!istype(user) || !ishuman(user)) +/obj/effect/proc_holder/spell/targeted/shadow_vision/cast(list/targets, mob/user = usr) + for(var/mob/living/target in targets) + if(!istype(target) || !ishuman(target)) return - var/mob/living/carbon/human/H = user + var/mob/living/carbon/human/H = target if(!H.vision_type) to_chat(H, "You shift the nerves in your eyes, allowing you to see in the dark.") H.vision_type = new vision_path @@ -223,17 +222,17 @@ clothes_req = 0 action_icon_state = "icy_veins" -/obj/effect/proc_holder/spell/aoe_turf/flashfreeze/cast(list/targets) - if(!shadowling_check(usr)) +/obj/effect/proc_holder/spell/aoe_turf/flashfreeze/cast(list/targets, mob/user = usr) + if(!shadowling_check(user)) charge_counter = charge_max return - to_chat(usr, "You freeze the nearby air.") - playsound(usr.loc, 'sound/effects/ghost2.ogg', 50, 1) + to_chat(user, "You freeze the nearby air.") + playsound(user.loc, 'sound/effects/ghost2.ogg', 50, 1) for(var/turf/T in targets) for(var/mob/living/carbon/M in T.contents) if(is_shadow_or_thrall(M)) - if(M == usr) //No message for the user, of course + if(M == user) //No message for the user, of course continue else to_chat(M, "You feel a blast of paralyzingly cold air wrap around you and flow past, but you are unaffected!") @@ -257,80 +256,80 @@ var/enthralling = 0 action_icon_state = "enthrall" -/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets) - var/mob/living/carbon/human/user = usr +/obj/effect/proc_holder/spell/targeted/enthrall/cast(list/targets, mob/user = usr) + var/mob/living/carbon/human/ling = user listclearnulls(ticker.mode.shadowling_thralls) - if(!(user.mind in ticker.mode.shadows)) + if(!(ling.mind in ticker.mode.shadows)) return - if(user.get_species() != "Shadowling") + if(ling.get_species() != "Shadowling") if(ticker.mode.shadowling_thralls.len >= 5) charge_counter = charge_max return for(var/mob/living/carbon/human/target in targets) - if(!in_range(usr, target)) - to_chat(usr, "You need to be closer to enthrall [target].") + if(!in_range(user, target)) + to_chat(user, "You need to be closer to enthrall [target].") charge_counter = charge_max return if(!target.key || !target.mind) - to_chat(usr, "The target has no mind.") + to_chat(user, "The target has no mind.") charge_counter = charge_max return if(target.stat) - to_chat(usr, "The target must be conscious.") + to_chat(user, "The target must be conscious.") charge_counter = charge_max return if(is_shadow_or_thrall(target)) - to_chat(usr, "You can not enthrall allies.") + to_chat(user, "You can not enthrall allies.") charge_counter = charge_max return if(!ishuman(target)) - to_chat(usr, "You can only enthrall humans.") + to_chat(user, "You can only enthrall humans.") charge_counter = charge_max return if(enthralling) - to_chat(usr, "You are already enthralling!") + to_chat(user, "You are already enthralling!") charge_counter = charge_max return if(!target.client) - to_chat(usr, "[target]'s mind is vacant of activity.") + to_chat(user, "[target]'s mind is vacant of activity.") enthralling = 1 - to_chat(usr, "This target is valid. You begin the enthralling.") - to_chat(target, "[usr] stares at you. You feel your head begin to pulse.") + to_chat(user, "This target is valid. You begin the enthralling.") + to_chat(target, "[user] stares at you. You feel your head begin to pulse.") for(var/progress = 0, progress <= 3, progress++) switch(progress) if(1) - to_chat(usr, "You place your hands to [target]'s head...") - usr.visible_message("[usr] places their hands onto the sides of [target]'s head!") + to_chat(user, "You place your hands to [target]'s head...") + user.visible_message("[user] places their hands onto the sides of [target]'s head!") if(2) - to_chat(usr, "You begin preparing [target]'s mind as a blank slate...") - usr.visible_message("[usr]'s palms flare a bright red against [target]'s temples!") + to_chat(user, "You begin preparing [target]'s mind as a blank slate...") + user.visible_message("[user]'s palms flare a bright red against [target]'s temples!") to_chat(target, "A terrible red light floods your mind. You collapse as conscious thought is wiped away.") target.Weaken(12) sleep(20) if(isloyal(target)) - to_chat(usr, "They have a mindshield implant. You begin to deactivate it - this will take some time.") - usr.visible_message("[usr] pauses, then dips their head in concentration!") + to_chat(user, "They have a mindshield implant. You begin to deactivate it - this will take some time.") + user.visible_message("[user] pauses, then dips their head in concentration!") to_chat(target, "Your mindshield implant becomes hot as it comes under attack!") sleep(100) //10 seconds - not spawn() so the enthralling takes longer - to_chat(usr, "The nanobots composing the mindshield implant have been rendered inert. Now to continue.") - usr.visible_message("[usr] relaxes again.") + to_chat(user, "The nanobots composing the mindshield implant have been rendered inert. Now to continue.") + user.visible_message("[user] relaxes again.") for(var/obj/item/weapon/implant/loyalty/L in target) if(L && L.implanted) qdel(L) to_chat(target, "Your mental protection implant unexpectedly falters, dims, dies.") if(3) - to_chat(usr, "You begin planting the tumor that will control the new thrall...") - usr.visible_message("A strange energy passes from [usr]'s hands into [target]'s head!") + to_chat(user, "You begin planting the tumor that will control the new thrall...") + user.visible_message("A strange energy passes from [user]'s hands into [target]'s head!") to_chat(target, "You feel your memories twisting, morphing. A sense of horror dominates your mind.") - if(!do_mob(usr, target, 70)) //around 21 seconds total for enthralling, 31 for someone with a mindshield implant - to_chat(usr, "The enthralling has been interrupted - your target's mind returns to its previous state.") - to_chat(target, "You wrest yourself away from [usr]'s hands and compose yourself") + if(!do_mob(user, target, 70)) //around 21 seconds total for enthralling, 31 for someone with a mindshield implant + to_chat(user, "The enthralling has been interrupted - your target's mind returns to its previous state.") + to_chat(target, "You wrest yourself away from [user]'s hands and compose yourself") enthralling = 0 return enthralling = 0 - to_chat(usr, "You have enthralled [target]!") + to_chat(user, "You have enthralled [target]!") target.visible_message("[target] looks to have experienced a revelation!", \ "False faces all dark not real not real not--") target.setOxyLoss(0) //In case the shadowling was choking them out @@ -347,18 +346,18 @@ clothes_req = 0 action_icon_state = "regen_armor" -/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor/cast(list/targets) - if(!is_shadow(usr)) - to_chat(usr, "You must be a shadowling to do this!") +/obj/effect/proc_holder/spell/targeted/shadowling_regenarmor/cast(list/targets, mob/user = usr) + if(!is_shadow(user)) + to_chat(user, "You must be a shadowling to do this!") charge_counter = charge_max return - for(var/mob/living/user in targets) - if(!istype(user) || !ishuman(user)) + for(var/mob/living/target in targets) + if(!istype(target) || !ishuman(target)) return - var/mob/living/carbon/human/H = user + var/mob/living/carbon/human/H = target H.visible_message("[H]'s skin suddenly bubbles and shifts around their body!", \ "You regenerate your protective armor and cleanse your form of defects.") - H.adjustCloneLoss(user.getCloneLoss()) + H.adjustCloneLoss(target.getCloneLoss()) H.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(H), slot_w_uniform) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(H), slot_shoes) H.equip_to_slot_or_del(new /obj/item/clothing/suit/space/shadowling(H), slot_wear_suit) @@ -382,54 +381,54 @@ var/reviveThrallAcquired action_icon_state = "collective_mind" -/obj/effect/proc_holder/spell/targeted/collective_mind/cast(list/targets) - if(!shadowling_check(usr)) +/obj/effect/proc_holder/spell/targeted/collective_mind/cast(list/targets, mob/user = usr) + if(!shadowling_check(user)) charge_counter = charge_max return - for(var/mob/living/user in targets) + for(var/mob/living/target in targets) var/thralls = 0 var/victory_threshold = ticker.mode.required_thralls var/mob/M - to_chat(user, "You focus your telepathic energies abound, harnessing and drawing together the strength of your thralls.") + to_chat(target, "You focus your telepathic energies abound, harnessing and drawing together the strength of your thralls.") for(M in living_mob_list) if(is_thrall(M)) thralls++ to_chat(M, "You feel hooks sink into your mind and pull.") - if(!do_after(user, 30, target = user)) - to_chat(user, "Your concentration has been broken. The mental hooks you have sent out now retract into your mind.") + if(!do_after(target, 30, target = target)) + to_chat(target, "Your concentration has been broken. The mental hooks you have sent out now retract into your mind.") return if(thralls >= 3 && !screech_acquired) screech_acquired = 1 - to_chat(user, "The power of your thralls has granted you the Sonic Screech ability. This ability will shatter nearby windows and deafen enemies, plus stunning silicon lifeforms.") - user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/unearthly_screech(null)) + to_chat(target, "The power of your thralls has granted you the Sonic Screech ability. This ability will shatter nearby windows and deafen enemies, plus stunning silicon lifeforms.") + target.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/unearthly_screech(null)) if(thralls >= 5 && !blind_smoke_acquired) blind_smoke_acquired = 1 - to_chat(user, "The power of your thralls has granted you the Blinding Smoke ability. \ + to_chat(target, "The power of your thralls has granted you the Blinding Smoke ability. \ It will create a choking cloud that will blind any non-thralls who enter.") - user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/blindness_smoke(null)) + target.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/blindness_smoke(null)) if(thralls >= 7 && !drainLifeAcquired) drainLifeAcquired = 1 - to_chat(user, "The power of your thralls has granted you the Drain Life ability. You can now drain the health of nearby humans to heal yourself.") - user.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/drainLife(null)) + to_chat(target, "The power of your thralls has granted you the Drain Life ability. You can now drain the health of nearby humans to heal yourself.") + target.mind.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/drainLife(null)) if(thralls >= 9 && !reviveThrallAcquired) reviveThrallAcquired = 1 - to_chat(user, "The power of your thralls has granted you the Black Recuperation ability. \ + to_chat(target, "The power of your thralls has granted you the Black Recuperation ability. \ This will, after a short time, bring a dead thrall completely back to life with no bodily defects.") - user.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/reviveThrall(null)) + target.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/reviveThrall(null)) if(thralls < victory_threshold) - to_chat(user, "You do not have the power to ascend. You require [victory_threshold] thralls, but only [thralls] living thralls are present.") + to_chat(target, "You do not have the power to ascend. You require [victory_threshold] thralls, but only [thralls] living thralls are present.") else if(thralls >= victory_threshold) - to_chat(usr, "You are now powerful enough to ascend. Use the Ascendance ability when you are ready. This will kill all of your thralls.") - to_chat(usr, "You may find Ascendance in the Shadowling Evolution tab.") + to_chat(target, "You are now powerful enough to ascend. Use the Ascendance ability when you are ready. This will kill all of your thralls.") + to_chat(target, "You may find Ascendance in the Shadowling Evolution tab.") for(M in living_mob_list) if(is_shadow(M)) var/obj/effect/proc_holder/spell/targeted/collective_mind/CM @@ -438,10 +437,10 @@ qdel(CM) M.mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/shadowling_hatch) M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadowling_ascend(null)) - if(M == usr) + if(M == user) to_chat(M, "You project this power to the rest of the shadowlings.") else - to_chat(M, "[user.real_name] has coalesced the strength of the thralls. You can draw upon it at any time to ascend. (Shadowling Evolution Tab)")//Tells all the other shadowlings + to_chat(M, "[target.real_name] has coalesced the strength of the thralls. You can draw upon it at any time to ascend. (Shadowling Evolution Tab)")//Tells all the other shadowlings @@ -456,15 +455,15 @@ include_user = 1 action_icon_state = "black_smoke" -/obj/effect/proc_holder/spell/targeted/blindness_smoke/cast(list/targets) //Extremely hacky - if(!shadowling_check(usr)) +/obj/effect/proc_holder/spell/targeted/blindness_smoke/cast(list/targets, mob/user = usr) //Extremely hacky + if(!shadowling_check(user)) charge_counter = charge_max return - for(var/mob/living/user in targets) - user.visible_message("[user] suddenly bends over and coughs out a cloud of black smoke, which begins to spread rapidly!") - to_chat(user, "You regurgitate a vast cloud of blinding smoke.") - playsound(user, 'sound/effects/bamf.ogg', 50, 1) - var/obj/item/weapon/reagent_containers/glass/beaker/large/B = new /obj/item/weapon/reagent_containers/glass/beaker/large(user.loc) + for(var/mob/living/target in targets) + target.visible_message("[target] suddenly bends over and coughs out a cloud of black smoke, which begins to spread rapidly!") + to_chat(target, "You regurgitate a vast cloud of blinding smoke.") + playsound(target, 'sound/effects/bamf.ogg', 50, 1) + var/obj/item/weapon/reagent_containers/glass/beaker/large/B = new /obj/item/weapon/reagent_containers/glass/beaker/large(target.loc) B.reagents.clear_reagents() //Just in case! B.icon_state = null //Invisible B.reagents.add_reagent("blindness_smoke", 10) @@ -506,17 +505,17 @@ clothes_req = 0 action_icon_state = "screech" -/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech/cast(list/targets) - if(!shadowling_check(usr)) +/obj/effect/proc_holder/spell/aoe_turf/unearthly_screech/cast(list/targets, mob/user = usr) + if(!shadowling_check(user)) charge_counter = charge_max return - usr.audible_message("[usr] lets out a horrible scream!") - playsound(usr.loc, 'sound/effects/screech.ogg', 100, 1) + user.audible_message("[user] lets out a horrible scream!") + playsound(user.loc, 'sound/effects/screech.ogg', 100, 1) for(var/turf/T in targets) for(var/mob/target in T.contents) if(is_shadow_or_thrall(target)) - if(target == usr) //No message for the user, of course + if(target == user) //No message for the user, of course continue else continue @@ -550,10 +549,11 @@ var/list/nearbyTargets action_icon_state = "drain_life" -/obj/effect/proc_holder/spell/aoe_turf/drainLife/cast(list/targets, var/mob/living/carbon/human/U = usr) - if(!shadowling_check(usr)) +/obj/effect/proc_holder/spell/aoe_turf/drainLife/cast(list/targets, mob/user = usr) + if(!shadowling_check(user)) charge_counter = charge_max return + var/mob/living/carbon/human/U = usr targetsDrained = 0 nearbyTargets = list() for(var/turf/T in targets) @@ -564,7 +564,7 @@ nearbyTargets.Add(M) if(!targetsDrained) charge_counter = charge_max - to_chat(usr, "There were no nearby humans for you to drain.") + to_chat(U, "There were no nearby humans for you to drain.") return for(var/mob/living/carbon/M in nearbyTargets) U.heal_organ_damage(10, 10) @@ -575,8 +575,8 @@ U.AdjustStunned(-1) M.adjustOxyLoss(20) M.adjustStaminaLoss(20) - to_chat(M, "You feel a wave of exhaustion and a curious draining sensation directed towards [usr]!") - to_chat(usr, "You draw life from those around you to heal your wounds.") + to_chat(M, "You feel a wave of exhaustion and a curious draining sensation directed towards [U]!") + to_chat(U, "You draw life from those around you to heal your wounds.") @@ -590,24 +590,24 @@ include_user = 0 action_icon_state = "revive_thrall" -/obj/effect/proc_holder/spell/targeted/reviveThrall/cast(list/targets) - if(!shadowling_check(usr)) +/obj/effect/proc_holder/spell/targeted/reviveThrall/cast(list/targets, mob/user = usr) + if(!shadowling_check(user)) charge_counter = charge_max return for(var/mob/living/carbon/human/thrallToRevive in targets) - var/choice = alert(usr,"Empower a living thrall or revive a dead one?",,"Empower","Revive","Cancel") + var/choice = alert(user,"Empower a living thrall or revive a dead one?",,"Empower","Revive","Cancel") switch(choice) if("Empower") if(!is_thrall(thrallToRevive)) - to_chat(usr, "[thrallToRevive] is not a thrall.") + to_chat(user, "[thrallToRevive] is not a thrall.") charge_counter = charge_max return if(thrallToRevive.stat != CONSCIOUS) - to_chat(usr, "[thrallToRevive] must be conscious to become empowered.") + to_chat(user, "[thrallToRevive] must be conscious to become empowered.") charge_counter = charge_max return if(thrallToRevive.get_species() == "Lesser Shadowling") - to_chat(usr, "[thrallToRevive] is already empowered.") + to_chat(user, "[thrallToRevive] is already empowered.") charge_counter = charge_max return var/empowered_thralls = 0 @@ -618,21 +618,21 @@ if(H.get_species() == "Lesser Shadowling") empowered_thralls++ if(empowered_thralls >= EMPOWERED_THRALL_LIMIT) - to_chat(usr, "You cannot spare this much energy. There are too many empowered thralls.") + to_chat(user, "You cannot spare this much energy. There are too many empowered thralls.") charge_counter = charge_max return - usr.visible_message("[usr] places their hands over [thrallToRevive]'s face, red light shining from beneath.", \ + user.visible_message("[user] places their hands over [thrallToRevive]'s face, red light shining from beneath.", \ "You place your hands on [thrallToRevive]'s face and begin gathering energy...") - to_chat(thrallToRevive, "[usr] places their hands over your face. You feel energy gathering. Stand still...") - if(!do_mob(usr, thrallToRevive, 80)) - to_chat(usr, "Your concentration snaps. The flow of energy ebbs.") + to_chat(thrallToRevive, "[user] places their hands over your face. You feel energy gathering. Stand still...") + if(!do_mob(user, thrallToRevive, 80)) + to_chat(user, "Your concentration snaps. The flow of energy ebbs.") charge_counter = charge_max return - to_chat(usr, "You release a massive surge of power into [thrallToRevive]!") - usr.visible_message("Red lightning surges into [thrallToRevive]'s face!") + to_chat(user, "You release a massive surge of power into [thrallToRevive]!") + user.visible_message("Red lightning surges into [thrallToRevive]'s face!") playsound(thrallToRevive, 'sound/weapons/Egloves.ogg', 50, 1) playsound(thrallToRevive, 'sound/machines/defib_zap.ogg', 50, 1) - usr.Beam(thrallToRevive,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1) + user.Beam(thrallToRevive,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1) thrallToRevive.Weaken(5) thrallToRevive.visible_message("[thrallToRevive] collapses, their skin and face distorting!", \ "AAAAAAAAAAAAAAAAAAAGH-") @@ -646,25 +646,25 @@ thrallToRevive.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/shadow_walk(null)) if("Revive") if(!is_thrall(thrallToRevive)) - to_chat(usr, "[thrallToRevive] is not a thrall.") + to_chat(user, "[thrallToRevive] is not a thrall.") charge_counter = charge_max return if(thrallToRevive.stat != DEAD) - to_chat(usr, "[thrallToRevive] is not dead.") + to_chat(user, "[thrallToRevive] is not dead.") charge_counter = charge_max return - usr.visible_message("[usr] kneels over [thrallToRevive], placing their hands on \his chest.", \ + user.visible_message("[user] kneels over [thrallToRevive], placing their hands on \his chest.", \ "You crouch over the body of your thrall and begin gathering energy...") thrallToRevive.notify_ghost_cloning("Your masters are resuscitating you! Re-enter your corpse if you wish to be brought to life.", source = thrallToRevive) - if(!do_mob(usr, thrallToRevive, 30)) - to_chat(usr, "Your concentration snaps. The flow of energy ebbs.") + if(!do_mob(user, thrallToRevive, 30)) + to_chat(user, "Your concentration snaps. The flow of energy ebbs.") charge_counter = charge_max return - to_chat(usr, "You release a massive surge of power into [thrallToRevive]!") - usr.visible_message("Red lightning surges from [usr]'s hands into [thrallToRevive]'s chest!") + to_chat(user, "You release a massive surge of power into [thrallToRevive]!") + user.visible_message("Red lightning surges from [user]'s hands into [thrallToRevive]'s chest!") playsound(thrallToRevive, 'sound/weapons/Egloves.ogg', 50, 1) playsound(thrallToRevive, 'sound/machines/defib_zap.ogg', 50, 1) - usr.Beam(thrallToRevive,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1) + user.Beam(thrallToRevive,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1) sleep(10) if(thrallToRevive.revive()) thrallToRevive.visible_message("[thrallToRevive] heaves in breath, dim red light shining in their eyes.", \ @@ -685,8 +685,8 @@ charge_max = 600 action_icon_state = "extend_shuttle" -/obj/effect/proc_holder/spell/targeted/shadowling_extend_shuttle/cast(list/targets) - if(!shadowling_check(usr)) +/obj/effect/proc_holder/spell/targeted/shadowling_extend_shuttle/cast(list/targets, mob/user = usr) + if(!shadowling_check(user)) charge_counter = charge_max return for(var/mob/living/carbon/human/target in targets) @@ -694,23 +694,23 @@ charge_counter = charge_max return if(!is_thrall(target)) - to_chat(usr, "[target] must be a thrall.") + to_chat(user, "[target] must be a thrall.") charge_counter = charge_max return if(shuttle_master.emergency.mode != SHUTTLE_CALL) - to_chat(usr, "The shuttle must be inbound only to the station.") + to_chat(user, "The shuttle must be inbound only to the station.") charge_counter = charge_max return var/mob/living/carbon/human/M = target - usr.visible_message("[usr]'s eyes flash a bright red!", \ + user.visible_message("[user]'s eyes flash a bright red!", \ "You begin to draw [M]'s life force.") M.visible_message("[M]'s face falls slack, their jaw slightly distending.", \ "You are suddenly transported... far, far away...") - if(!do_after(usr, 50, target = M)) + if(!do_after(user, 50, target = M)) to_chat(M, "You are snapped back to reality, your haze dissipating!") - to_chat(usr, "You have been interrupted. The draw has failed.") + to_chat(user, "You have been interrupted. The draw has failed.") return - to_chat(usr, "You project [M]'s life force toward the approaching shuttle, extending its arrival duration!") + to_chat(user, "You project [M]'s life force toward the approaching shuttle, extending its arrival duration!") M.visible_message("[M]'s eyes suddenly flare red. They proceed to collapse on the floor, not breathing.", \ "...speeding by... ...pretty blue glow... ...touch it... ...no glow now... ...no light... ...nothing at all...") M.death() @@ -720,7 +720,7 @@ timer += more_minutes event_announcement.Announce("Major system failure aboard the emergency shuttle. This will extend its arrival time by approximately 15 minutes..", "System Failure", 'sound/misc/notice1.ogg') shuttle_master.emergency.setTimer(timer) - usr.mind.spell_list.Remove(src) //Can only be used once! + user.mind.spell_list.Remove(src) //Can only be used once! qdel(src) // ASCENDANT ABILITIES BEYOND THIS POINT // @@ -734,20 +734,20 @@ clothes_req = 0 action_icon_state = "annihilate" -/obj/effect/proc_holder/spell/targeted/annihilate/cast(list/targets) - var/mob/living/simple_animal/ascendant_shadowling/SHA = usr +/obj/effect/proc_holder/spell/targeted/annihilate/cast(list/targets, mob/user = usr) + var/mob/living/simple_animal/ascendant_shadowling/SHA = user if(SHA.phasing) - to_chat(usr, "You are not in the same plane of existence. Unphase first.") + to_chat(user, "You are not in the same plane of existence. Unphase first.") charge_counter = charge_max return - playsound(usr.loc, 'sound/magic/Staff_Chaos.ogg', 100, 1) + playsound(user.loc, 'sound/magic/Staff_Chaos.ogg', 100, 1) for(var/mob/living/boom in targets) if(is_shadow(boom)) //Used to not work on thralls. Now it does so you can PUNISH THEM LIKE THE WRATHFUL GOD YOU ARE. - to_chat(usr, "Making an ally explode seems unwise.") + to_chat(user, "Making an ally explode seems unwise.") charge_counter = charge_max return - usr.visible_message("[usr]'s markings flare as they gesture at [boom]!", \ + user.visible_message("[user]'s markings flare as they gesture at [boom]!", \ "You direct a lance of telekinetic energy at [boom].") sleep(4) if(iscarbon(boom)) @@ -766,32 +766,32 @@ clothes_req = 0 action_icon_state = "enthrall" -/obj/effect/proc_holder/spell/targeted/hypnosis/cast(list/targets) - var/mob/living/simple_animal/ascendant_shadowling/SHA = usr +/obj/effect/proc_holder/spell/targeted/hypnosis/cast(list/targets, mob/user = usr) + var/mob/living/simple_animal/ascendant_shadowling/SHA = user if(SHA.phasing) charge_counter = charge_max - to_chat(usr, "You are not in the same plane of existence. Unphase first.") + to_chat(user, "You are not in the same plane of existence. Unphase first.") return for(var/mob/living/carbon/human/target in targets) if(is_shadow_or_thrall(target)) - to_chat(usr, "You cannot enthrall an ally.") + to_chat(user, "You cannot enthrall an ally.") charge_counter = charge_max return if(!target.ckey || !target.mind) - to_chat(usr, "The target has no mind.") + to_chat(user, "The target has no mind.") charge_counter = charge_max return if(target.stat) - to_chat(usr, "The target must be conscious.") + to_chat(user, "The target must be conscious.") charge_counter = charge_max return if(!ishuman(target)) - to_chat(usr, "You can only enthrall humans.") + to_chat(user, "You can only enthrall humans.") charge_counter = charge_max return - to_chat(usr, "You instantly rearrange [target]'s memories, hyptonitizing them into a thrall.") + to_chat(user, "You instantly rearrange [target]'s memories, hyptonitizing them into a thrall.") to_chat(target, "An agonizing spike of pain drives into your mind, and--") ticker.mode.add_thrall(target.mind) target.mind.special_role = SPECIAL_ROLE_SHADOWLING_THRALL @@ -809,8 +809,8 @@ clothes_req = 0 action_icon_state = "shadow_walk" -/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift/cast(list/targets) - var/mob/living/simple_animal/ascendant_shadowling/SHA = usr +/obj/effect/proc_holder/spell/targeted/shadowling_phase_shift/cast(list/targets, mob/user = usr) + var/mob/living/simple_animal/ascendant_shadowling/SHA = user for(SHA in targets) SHA.phasing = !SHA.phasing if(SHA.phasing) @@ -835,16 +835,16 @@ clothes_req = 0 action_icon_state = "lightning_storm" -/obj/effect/proc_holder/spell/aoe_turf/ascendant_storm/cast(list/targets) - var/mob/living/simple_animal/ascendant_shadowling/SHA = usr +/obj/effect/proc_holder/spell/aoe_turf/ascendant_storm/cast(list/targets, mob/user = usr) + var/mob/living/simple_animal/ascendant_shadowling/SHA = user if(SHA.phasing) - to_chat(usr, "You are not in the same plane of existence. Unphase first.") + to_chat(user, "You are not in the same plane of existence. Unphase first.") charge_counter = charge_max return - usr.visible_message("A massive ball of lightning appears in [usr]'s hands and flares out!", \ + user.visible_message("A massive ball of lightning appears in [user]'s hands and flares out!", \ "You conjure a ball of lightning and release it.") - playsound(usr.loc, 'sound/magic/lightningbolt.ogg', 100, 1) + playsound(user.loc, 'sound/magic/lightningbolt.ogg', 100, 1) for(var/turf/T in targets) for(var/mob/living/carbon/human/target in T.contents) if(is_shadow_or_thrall(target)) @@ -853,7 +853,7 @@ playsound(target, 'sound/magic/LightningShock.ogg', 50, 1) target.Weaken(8) target.take_organ_damage(0,50) - usr.Beam(target,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1) + user.Beam(target,icon_state="red_lightning",icon='icons/effects/effects.dmi',time=1) /obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit name = "Ascendant Broadcast" @@ -865,9 +865,9 @@ include_user = 1 action_icon_state = "transmit" -/obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit/cast(list/targets) - for(var/mob/living/user in targets) - var/text = stripped_input(user, "What do you want to say to everything on and near [station_name()]?.", "Transmit to World", "") +/obj/effect/proc_holder/spell/targeted/shadowlingAscendantTransmit/cast(list/targets, mob/user = usr) + for(var/mob/living/target in targets) + var/text = stripped_input(target, "What do you want to say to everything on and near [station_name()]?.", "Transmit to World", "") if(!text) return to_chat(world, "\"[text]\"") diff --git a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm index 2fac272afd5..1ebf944173d 100644 --- a/code/game/gamemodes/shadowling/special_shadowling_abilities.dm +++ b/code/game/gamemodes/shadowling/special_shadowling_abilities.dm @@ -10,11 +10,11 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N include_user = 1 action_icon_state = "hatch" -/obj/effect/proc_holder/spell/targeted/shadowling_hatch/cast(list/targets) - if(usr.stat || !ishuman(usr) || !usr || !is_shadow(usr || isinspace(usr))) +/obj/effect/proc_holder/spell/targeted/shadowling_hatch/cast(list/targets, mob/user = usr) + if(user.stat || !ishuman(user) || !user || !is_shadow(user || isinspace(user))) return - if(!isturf(usr.loc)) - to_chat(usr, "You can't hatch here!") + if(!isturf(user.loc)) + to_chat(user, "You can't hatch here!") return for(var/mob/living/carbon/human/H in targets) var/hatch_or_no = alert(H,"Are you sure you want to hatch? You cannot undo this!",,"Yes","No") @@ -33,8 +33,8 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N sleep(50) var/turf/simulated/floor/F - var/turf/shadowturf = get_turf(usr) - for(F in orange(1, usr)) + var/turf/shadowturf = get_turf(user) + for(F in orange(1, user)) new /obj/structure/alien/resin/wall/shadowling(F) for(var/obj/structure/alien/resin/wall/shadowling/R in shadowturf) //extremely hacky qdel(R) @@ -68,7 +68,7 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N var/newNameId = pick(possibleShadowlingNames) possibleShadowlingNames.Remove(newNameId) H.real_name = newNameId - H.name = usr.real_name + H.name = user.real_name H.SetStunned(0) to_chat(H, "YOU LIVE!!!") @@ -83,13 +83,13 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N H.socks = "None" H.faction |= "faithless" - H.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(usr), slot_w_uniform) - H.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(usr), slot_shoes) - H.equip_to_slot_or_del(new /obj/item/clothing/suit/space/shadowling(usr), slot_wear_suit) - H.equip_to_slot_or_del(new /obj/item/clothing/head/shadowling(usr), slot_head) - H.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(usr), slot_gloves) - H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(usr), slot_wear_mask) - H.equip_to_slot_or_del(new /obj/item/clothing/glasses/shadowling(usr), slot_glasses) + H.equip_to_slot_or_del(new /obj/item/clothing/under/shadowling(user), slot_w_uniform) + H.equip_to_slot_or_del(new /obj/item/clothing/shoes/shadowling(user), slot_shoes) + H.equip_to_slot_or_del(new /obj/item/clothing/suit/space/shadowling(user), slot_wear_suit) + H.equip_to_slot_or_del(new /obj/item/clothing/head/shadowling(user), slot_head) + H.equip_to_slot_or_del(new /obj/item/clothing/gloves/shadowling(user), slot_gloves) + H.equip_to_slot_or_del(new /obj/item/clothing/mask/gas/shadowling(user), slot_wear_mask) + H.equip_to_slot_or_del(new /obj/item/clothing/glasses/shadowling(user), slot_glasses) H.set_species("Shadowling") //can't be a shadowling without being a shadowling H.mind.RemoveSpell(src) @@ -116,8 +116,8 @@ var/list/possibleShadowlingNames = list("U'ruan", "Y`shej", "Nex", "Hel-uae", "N include_user = 1 action_icon_state = "ascend" -/obj/effect/proc_holder/spell/targeted/shadowling_ascend/cast(list/targets) - var/mob/living/carbon/human/H = usr +/obj/effect/proc_holder/spell/targeted/shadowling_ascend/cast(list/targets, mob/user = usr) + var/mob/living/carbon/human/H = user if(!shadowling_check(H)) return for(H in targets) diff --git a/code/game/gamemodes/vampire/vampire_powers.dm b/code/game/gamemodes/vampire/vampire_powers.dm index 92a1a3dfa19..023fef59a7b 100644 --- a/code/game/gamemodes/vampire/vampire_powers.dm +++ b/code/game/gamemodes/vampire/vampire_powers.dm @@ -117,7 +117,7 @@ revert_cast(user) return - perform(list(T)) + perform(list(T), user = user) /obj/effect/proc_holder/spell/vampire/self/choose_targets(mob/user = usr) perform(list(user)) @@ -131,7 +131,7 @@ revert_cast(user) return - perform(targets) + perform(targets, user = user) /datum/vampire_passive var/gain_desc @@ -150,14 +150,14 @@ charge_max = 200 stat_allowed = 1 -/obj/effect/proc_holder/spell/vampire/self/rejuvenate/cast() - var/mob/living/U = usr +/obj/effect/proc_holder/spell/vampire/self/rejuvenate/cast(list/targets, mob/user = usr) + var/mob/living/U = user - usr.SetWeakened(0) - usr.SetStunned(0) - usr.SetParalysis(0) + user.SetWeakened(0) + user.SetStunned(0) + user.SetParalysis(0) U.adjustStaminaLoss(-75) - to_chat(usr, "You flush your system with clean blood and remove any incapacitating effects.") + to_chat(user, "You flush your system with clean blood and remove any incapacitating effects.") spawn(1) if(usr.mind.vampire.get_ability(/datum/vampire_passive/regen)) for(var/i = 1 to 5) @@ -173,15 +173,15 @@ action_icon_state = "vampire_hypnotise" required_blood = 20 -/obj/effect/proc_holder/spell/vampire/targetted/hypnotise/cast(list/targets) +/obj/effect/proc_holder/spell/vampire/targetted/hypnotise/cast(list/targets, mob/user = usr) for(var/mob/living/target in targets) - usr.visible_message("[usr]'s eyes flash briefly as he stares into [target]'s eyes") - if(do_mob(usr, target, 50)) + user.visible_message("[user]'s eyes flash briefly as he stares into [target]'s eyes") + if(do_mob(user, target, 50)) if(!affects(target)) - to_chat(usr, "Your piercing gaze fails to knock out [target].") - to_chat(target, "\blue [usr]'s feeble gaze is ineffective.") + to_chat(user, "Your piercing gaze fails to knock out [target].") + to_chat(target, "\blue [user]'s feeble gaze is ineffective.") else - to_chat(usr, "Your piercing gaze knocks out [target].") + to_chat(user, "Your piercing gaze knocks out [target].") to_chat(target, "You find yourself unable to move and barely able to speak.") target.Weaken(10) target.Stun(10) @@ -197,12 +197,12 @@ action_icon_state = "vampire_disease" required_blood = 100 -/obj/effect/proc_holder/spell/vampire/targetted/disease/cast(list/targets) +/obj/effect/proc_holder/spell/vampire/targetted/disease/cast(list/targets, mob/user = usr) for(var/mob/living/carbon/target in targets) - to_chat(usr, "You stealthily infect [target] with your diseased touch.") - target.help_shake_act(usr) + to_chat(user, "You stealthily infect [target] with your diseased touch.") + target.help_shake_act(user) if(!affects(target)) - to_chat(usr, "They seem to be unaffected.") + to_chat(user, "They seem to be unaffected.") continue var/datum/disease/D = new /datum/disease/vampire target.ForceContractDisease(D) @@ -214,10 +214,10 @@ charge_max = 300 stat_allowed = 1 -/obj/effect/proc_holder/spell/vampire/mob_aoe/glare/cast(list/targets) - usr.visible_message("[usr]'s eyes emit a blinding flash!") - if(istype(usr:glasses, /obj/item/clothing/glasses/sunglasses/blindfold)) - to_chat(usr, "You're blindfolded!") +/obj/effect/proc_holder/spell/vampire/mob_aoe/glare/cast(list/targets, mob/user = usr) + user.visible_message("[user]'s eyes emit a blinding flash!") + if(istype(user:glasses, /obj/item/clothing/glasses/sunglasses/blindfold)) + to_chat(user, "You're blindfolded!") return for(var/mob/living/target in targets) if(!affects(target)) @@ -225,7 +225,7 @@ target.Stun(5) target.Weaken(5) target.stuttering = 20 - to_chat(target, "You are blinded by [usr]'s glare.") + to_chat(target, "You are blinded by [user]'s glare.") /obj/effect/proc_holder/spell/vampire/self/shapeshift name = "Shapeshift (50)" @@ -234,12 +234,12 @@ action_icon_state = "genetic_poly" required_blood = 50 -/obj/effect/proc_holder/spell/vampire/self/shapeshift/cast() - usr.visible_message("[usr] transforms!") - usr.client.prefs.real_name = usr.generate_name() - usr.client.prefs.random_character() - usr.client.prefs.copy_to(usr) - usr.regenerate_icons() +/obj/effect/proc_holder/spell/vampire/self/shapeshift/cast(list/targets, mob/user = usr) + user.visible_message("[user] transforms!") + user.client.prefs.real_name = user.generate_name() + user.client.prefs.random_character() + user.client.prefs.copy_to(user) + user.regenerate_icons() /obj/effect/proc_holder/spell/vampire/self/screech name = "Chiroptean Screech (30)" @@ -248,10 +248,10 @@ action_icon_state = "vampire_screech" required_blood = 30 -/obj/effect/proc_holder/spell/vampire/self/screech/cast() - usr.visible_message("[usr] lets out an ear piercing shriek!", "You let out a loud shriek.", "You hear a loud painful shriek!") +/obj/effect/proc_holder/spell/vampire/self/screech/cast(list/targets, mob/user = usr) + user.visible_message("[user] lets out an ear piercing shriek!", "You let out a loud shriek.", "You hear a loud painful shriek!") for(var/mob/living/carbon/C in hearers(4)) - if(C == usr) + if(C == user) continue if(ishuman(C) && (C:l_ear || C:r_ear) && istype((C:l_ear || C:r_ear), /obj/item/clothing/ears/earmuffs)) continue @@ -265,7 +265,7 @@ C.Jitter(150) for(var/obj/structure/window/W in view(4)) W.destroy() - playsound(usr.loc, 'sound/effects/creepyshriek.ogg', 100, 1) + playsound(user.loc, 'sound/effects/creepyshriek.ogg', 100, 1) /proc/isvampirethrall(mob/living/M as mob) @@ -278,19 +278,19 @@ action_icon_state = "vampire_enthrall" required_blood = 300 -/obj/effect/proc_holder/spell/vampire/targetted/enthrall/cast(list/targets) +/obj/effect/proc_holder/spell/vampire/targetted/enthrall/cast(list/targets, mob/user = usr) for(var/mob/living/target in targets) - usr.visible_message("[usr] bites [target]'s neck!", "You bite [target]'s neck and begin the flow of power.") + user.visible_message("[user] bites [target]'s neck!", "You bite [target]'s neck and begin the flow of power.") to_chat(target, "You feel the tendrils of evil invade your mind.") if(!ishuman(target)) - to_chat(usr, "You can only enthrall humans.") + to_chat(user, "You can only enthrall humans.") break - if(do_mob(usr, target, 50)) - if(can_enthrall(usr, target)) - handle_enthrall(usr, target) + if(do_mob(user, target, 50)) + if(can_enthrall(user, target)) + handle_enthrall(user, target) else - revert_cast(usr) - to_chat(usr, "You or your target either moved or you dont have enough usable blood.") + revert_cast(user) + to_chat(user, "You or your target either moved or you dont have enough usable blood.") /obj/effect/proc_holder/spell/vampire/targetted/enthrall/proc/can_enthrall(mob/living/user, mob/living/carbon/C) var/enthrall_safe = 0 @@ -359,11 +359,11 @@ return name = "[initial(name)] ([user.mind.vampire.iscloaking ? "Deactivate" : "Activate"])" -/obj/effect/proc_holder/spell/vampire/self/cloak/cast() - var/datum/vampire/V = usr.mind.vampire +/obj/effect/proc_holder/spell/vampire/self/cloak/cast(list/targets, mob/user = usr) + var/datum/vampire/V = user.mind.vampire V.iscloaking = !V.iscloaking update_name() - to_chat(usr, "You will now be [V.iscloaking ? "hidden" : "seen"] in darkness.") + to_chat(user, "You will now be [V.iscloaking ? "hidden" : "seen"] in darkness.") /obj/effect/proc_holder/spell/vampire/bats name = "Summon Bats (75)" @@ -387,11 +387,11 @@ for(var/i = locs.len + 1 to num_bats) locs += user.loc - perform(locs) + perform(locs, user = user) -/obj/effect/proc_holder/spell/vampire/bats/cast(list/targets) +/obj/effect/proc_holder/spell/vampire/bats/cast(list/targets, mob/user = usr) for(var/T in targets) - new /mob/living/simple_animal/hostile/scarybat(T, usr) + new /mob/living/simple_animal/hostile/scarybat(T, user) /obj/effect/proc_holder/spell/vampire/self/jaunt name = "Mist Form (30)" @@ -402,12 +402,12 @@ required_blood = 30 var/jaunt_duration = 50 //in deciseconds -/obj/effect/proc_holder/spell/vampire/self/jaunt/cast() - if(usr.buckled) - usr.buckled.unbuckle_mob() +/obj/effect/proc_holder/spell/vampire/self/jaunt/cast(list/targets, mob/user = usr) + if(user.buckled) + user.buckled.unbuckle_mob() spawn(0) - var/mob/living/U = usr - var/originalloc = get_turf(usr.loc) + var/mob/living/U = user + var/originalloc = get_turf(user.loc) var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt(originalloc) var/atom/movable/overlay/animation = new /atom/movable/overlay(originalloc) animation.name = "water" @@ -418,34 +418,34 @@ animation.layer = 5 animation.master = holder U.ExtinguishMob() - if(usr.buckled) - usr.buckled.unbuckle_mob() + if(user.buckled) + user.buckled.unbuckle_mob() flick("liquify", animation) - usr.forceMove(holder) - usr.client.eye = holder + user.forceMove(holder) + user.client.eye = holder var/datum/effect/system/steam_spread/steam = new /datum/effect/system/steam_spread() steam.set_up(10, 0, originalloc) steam.start() sleep(jaunt_duration) - var/mobloc = get_turf(usr.loc) + var/mobloc = get_turf(user.loc) if(get_area(mobloc) == /area/security/armoury/gamma) - to_chat(usr, "A strange energy repels you!") + to_chat(user, "A strange energy repels you!") mobloc = originalloc animation.loc = mobloc steam.location = mobloc steam.start() - usr.canmove = 0 + user.canmove = 0 sleep(20) flick("reappear",animation) sleep(5) - if(!usr.Move(mobloc)) + if(!user.Move(mobloc)) for(var/direction in list(1,2,4,8,5,6,9,10)) var/turf/T = get_step(mobloc, direction) if(T) - if(usr.Move(T)) + if(user.Move(T)) break - usr.canmove = 1 - usr.client.eye = usr + user.canmove = 1 + user.client.eye = user qdel(animation) qdel(holder) @@ -492,29 +492,29 @@ to_chat(user, "\red You cannot find darkness to step to.") return - perform(turfs) + perform(turfs, user = user) -/obj/effect/proc_holder/spell/vampire/shadowstep/cast(list/targets) +/obj/effect/proc_holder/spell/vampire/shadowstep/cast(list/targets, mob/user = usr) if(usr.buckled) - usr.buckled.unbuckle_mob() + user.buckled.unbuckle_mob() spawn(0) var/turf/picked = pick(targets) if(!picked || !isturf(picked)) return - var/mob/living/U = usr + var/mob/living/U = user U.ExtinguishMob() - if(usr.buckled) - usr.buckled.unbuckle_mob() - var/atom/movable/overlay/animation = new /atom/movable/overlay(get_turf(usr)) - animation.name = usr.name + if(user.buckled) + user.buckled.unbuckle_mob() + var/atom/movable/overlay/animation = new /atom/movable/overlay(get_turf(user)) + animation.name = user.name animation.density = 0 animation.anchored = 1 - animation.icon = usr.icon + animation.icon = user.icon animation.alpha = 127 animation.layer = 5 //animation.master = src - usr.forceMove(picked) + user.forceMove(picked) spawn(10) qdel(animation) diff --git a/code/game/gamemodes/wizard/artefact.dm b/code/game/gamemodes/wizard/artefact.dm index 44565a6d157..18cc1d64b7d 100644 --- a/code/game/gamemodes/wizard/artefact.dm +++ b/code/game/gamemodes/wizard/artefact.dm @@ -60,7 +60,7 @@ switch(href_list["school"]) if("destruction") M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null)) - M.mind.AddSpell(new /obj/effect/proc_holder/spell/dumbfire/fireball(null)) + M.mind.AddSpell(new /obj/effect/proc_holder/spell/fireball(null)) to_chat(M, "Your service has not gone unrewarded, however. Studying under [H.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball.") if("bluespace") M.mind.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null)) diff --git a/code/game/gamemodes/wizard/rightandwrong.dm b/code/game/gamemodes/wizard/rightandwrong.dm index 3899d10d23c..a8e449e1175 100644 --- a/code/game/gamemodes/wizard/rightandwrong.dm +++ b/code/game/gamemodes/wizard/rightandwrong.dm @@ -88,6 +88,8 @@ new /obj/item/weapon/gun/projectile/revolver/grenadelauncher(get_turf(H)) if("medibeam") new /obj/item/weapon/gun/medbeam(get_turf(H)) + + playsound(get_turf(H), 'sound/magic/Summon_guns.ogg', 50, 1) else switch(randomizemagic) if("fireball") @@ -155,3 +157,5 @@ if("necromantic") new /obj/item/device/necromantic_stone(get_turf(H)) to_chat(H, "You suddenly feel lucky.") + + playsound(get_turf(H), 'sound/magic/Summon_Magic.ogg', 50, 1) diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index 0f280b6b4a2..5cc190f267b 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -103,7 +103,7 @@ /datum/spellbook_entry/fireball name = "Fireball" - spell_type = /obj/effect/proc_holder/spell/dumbfire/fireball + spell_type = /obj/effect/proc_holder/spell/fireball log_name = "FB" /datum/spellbook_entry/magicm @@ -714,7 +714,7 @@ return /obj/item/weapon/spellbook/oneuse/fireball - spell = /obj/effect/proc_holder/spell/dumbfire/fireball + spell = /obj/effect/proc_holder/spell/fireball spellname = "fireball" icon_state ="bookfireball" desc = "This book feels warm to the touch." @@ -854,3 +854,9 @@ spellname = "disintegrate" icon_state ="bookfireball" desc = "This book feels like it will rip stuff apart." + +/obj/item/weapon/spellbook/oneuse/sacredflame + spell = /obj/effect/proc_holder/spell/targeted/sacred_flame + spellname = "sacred flame" + icon_state ="booksacredflame" + desc = "Become one with the flames that burn within... and invite others to do so as well." \ No newline at end of file diff --git a/code/game/machinery/computer/card.dm b/code/game/machinery/computer/card.dm index ebba68ec570..66e2ec25779 100644 --- a/code/game/machinery/computer/card.dm +++ b/code/game/machinery/computer/card.dm @@ -439,3 +439,5 @@ var/time_last_changed_position = 0 name = "\improper CentComm identification computer" circuit = /obj/item/weapon/circuitboard/card/centcom req_access = list(access_cent_commander) + change_position_cooldown = -1 + blacklisted = list() \ No newline at end of file diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm index 1634ebdc4a0..2a11b4a8836 100644 --- a/code/game/machinery/computer/security.dm +++ b/code/game/machinery/computer/security.dm @@ -369,7 +369,7 @@ What a mess.*/ var/counter = 1 while(active2.fields[text("com_[]", counter)]) counter++ - active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], 2557
[t1]") + active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [worldtime2text()]
[t1]") if("Delete Record (ALL)") if(active1) diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index e0466bc7637..9b03727495a 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -230,6 +230,7 @@ to destroy them and players will be able to make replacements. var/list/names_paths = list("Booze-O-Mat" = /obj/machinery/vending/boozeomat, "Solar's Best Hot Drinks" = /obj/machinery/vending/coffee, "Getmore Chocolate Corp" = /obj/machinery/vending/snack, + "Mr. Chang" = /obj/machinery/vending/chinese, "Robust Softdrinks" = /obj/machinery/vending/cola, "ShadyCigs Deluxe" = /obj/machinery/vending/cigarette, "AutoDrobe" = /obj/machinery/vending/autodrobe, diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm index 17fe32f39ec..28b3cfe7132 100644 --- a/code/game/machinery/portable_turret.dm +++ b/code/game/machinery/portable_turret.dm @@ -20,7 +20,7 @@ var/health = 80 //the turret's health var/locked = 1 //if the turret's behaviour control access is locked var/controllock = 0 //if the turret responds to control panels - + var/installation = /obj/item/weapon/gun/energy/gun/turret //the type of weapon installed var/gun_charge = 0 //the charge of the gun inserted var/projectile = null //holder for bullettype @@ -56,6 +56,13 @@ var/screen = 0 // Screen 0: main control, screen 1: access levels var/one_access = 0 // Determines if access control is set to req_one_access or req_access + + var/syndicate = 0 //is the turret a syndicate turret? + var/faction = "" + var/emp_vulnerable = 1 // Can be empd + var/scan_range = 7 + var/always_up = 0 //Will stay active + var/has_cover = 1 //Hides the cover /obj/machinery/porta_turret/centcom enabled = 0 @@ -99,7 +106,7 @@ one_access = 0 /obj/machinery/porta_turret/proc/setup() - var/obj/item/weapon/gun/energy/E= new installation //All energy-based weapons are applicable + 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 = shottype.projectile_type @@ -206,10 +213,10 @@ var/list/turret_icons data["screen"] = screen data["locked"] = locked data["enabled"] = enabled - data["is_lethal"] = 1 + data["lethal_control"] = !syndicate ? 1 : 0 data["lethal"] = lethal - if(data["access"]) + if(data["access"] && !syndicate) var/settings[0] settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth) settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons) @@ -219,18 +226,19 @@ var/list/turret_icons settings[++settings.len] = list("category" = "Check Misc. Lifeforms", "setting" = "check_anomalies", "value" = check_anomalies) data["settings"] = settings - data["one_access"] = one_access - var/accesses[0] - var/list/access_list = get_all_accesses() - for(var/access in access_list) - var/name = get_access_desc(access) - var/active - if(one_access) - active = (access in req_one_access) - else - active = (access in req_access) - accesses[++accesses.len] = list("name" = name, "active" = active, "number" = access) - data["accesses"] = accesses + if(!syndicate) + data["one_access"] = one_access + var/accesses[0] + var/list/access_list = get_all_accesses() + for(var/access in access_list) + var/name = get_access_desc(access) + var/active + if(one_access) + active = (access in req_one_access) + else + active = (access in req_access) + accesses[++accesses.len] = list("name" = name, "active" = active, "number" = access) + data["accesses"] = accesses return data /obj/machinery/porta_turret/proc/HasController() @@ -259,6 +267,8 @@ var/list/turret_icons var/value = text2num(href_list["value"]) if(href_list["command"] == "enable") enabled = value + else if(syndicate) + return 1 else if(href_list["command"] == "screen") screen = value else if(href_list["command"] == "lethal") @@ -276,11 +286,12 @@ var/list/turret_icons else if(href_list["command"] == "check_anomalies") check_anomalies = value - if(href_list["one_access"]) - toggle_one_access(href_list["one_access"]) + if(!syndicate) + if(href_list["one_access"]) + toggle_one_access(href_list["one_access"]) - if(href_list["access"]) - toggle_access(href_list["access"]) + if(href_list["access"]) + toggle_access(href_list["access"]) return 1 @@ -311,7 +322,7 @@ var/list/turret_icons req_access += required /obj/machinery/porta_turret/power_change() - if(powered()) + if(powered() || !use_power) stat &= ~NOPOWER update_icon() else @@ -321,7 +332,7 @@ var/list/turret_icons /obj/machinery/porta_turret/attackby(obj/item/I, mob/user) - if(stat & BROKEN) + if((stat & BROKEN) && !syndicate) if(istype(I, /obj/item/weapon/crowbar)) //If the turret is destroyed, you can remove it with a crowbar to //try and salvage its components @@ -438,13 +449,12 @@ var/list/turret_icons return health -= force - if(force > 5 && prob(45)) + if(force > 5 && prob(45) && spark_system) spark_system.start() if(health <= 0) die() //the death process :( /obj/machinery/porta_turret/bullet_act(obj/item/projectile/Proj) - if(Proj.damage_type == STAMINA) return @@ -461,7 +471,7 @@ var/list/turret_icons take_damage(Proj.damage) /obj/machinery/porta_turret/emp_act(severity) - if(enabled) + if(enabled && emp_vulnerable) //if the turret is on, the EMP no matter how severe disables the turret for a while //and scrambles its settings, with a slight chance of having an emag effect check_arrest = prob(50) @@ -494,7 +504,8 @@ var/list/turret_icons /obj/machinery/porta_turret/proc/die() //called when the turret dies, ie, health <= 0 health = 0 stat |= BROKEN //enables the BROKEN bit - spark_system.start() //creates some sparks because they look cool + if(spark_system) + spark_system.start() //creates some sparks because they look cool update_icon() /obj/machinery/porta_turret/process() @@ -503,35 +514,43 @@ var/list/turret_icons set background = BACKGROUND_ENABLED if(stat & (NOPOWER|BROKEN)) - //if the turret has no power or is broken, make the turret pop down if it hasn't already - popDown() + if(!always_up) + //if the turret has no power or is broken, make the turret pop down if it hasn't already + popDown() return if(!enabled) - //if the turret is off, make it pop down - popDown() + if(!always_up) + //if the turret is off, make it pop down + popDown() return var/list/targets = list() //list of primary targets var/list/secondarytargets = list() //targets that are least important - for(var/obj/mecha/ME in view(7,src)) + for(var/obj/mecha/ME in view(scan_range,src)) assess_and_assign(ME.occupant, targets, secondarytargets) - for(var/obj/spacepod/SP in view(7,src)) + for(var/obj/spacepod/SP in view(scan_range,src)) assess_and_assign(SP.pilot, targets, secondarytargets) - for(var/obj/vehicle/T in view(7,src)) + for(var/obj/vehicle/T in view(scan_range,src)) assess_and_assign(T.buckled_mob, targets, secondarytargets) - for(var/mob/living/C in view(7,src)) //loops through all living lifeforms in view + for(var/mob/living/C in view(scan_range,src)) //loops through all living lifeforms in view assess_and_assign(C, targets, secondarytargets) if(!tryToShootAt(targets)) if(!tryToShootAt(secondarytargets)) // if no valid targets, go for secondary targets - spawn() - popDown() // no valid targets, close the cover + if(!always_up) + spawn() + popDown() // no valid targets, close the cover +/obj/machinery/porta_turret/proc/in_faction(mob/living/target) + if(!(faction in target.faction)) + return 0 + return 1 + /obj/machinery/porta_turret/proc/assess_and_assign(var/mob/living/L, var/list/targets, var/list/secondarytargets) switch(assess_living(L)) if(TURRET_PRIORITY_TARGET) @@ -552,17 +571,20 @@ var/list/turret_icons if(!L) return TURRET_NOT_TARGET - if(!emagged && (issilicon(L) || isbot(L))) // Don't target silica + if(!emagged && !syndicate && (issilicon(L) || isbot(L))) // Don't target silica return TURRET_NOT_TARGET if(L.stat && !emagged) //if the perp is dead/dying, no need to bother really return TURRET_NOT_TARGET //move onto next potential victim! - if(get_dist(src, L) > 7) //if it's too far away, why bother? + if(get_dist(src, L) > scan_range) //if it's too far away, why bother? return TURRET_NOT_TARGET if(emagged) // If emagged not even the dead get a rest return L.stat ? TURRET_SECONDARY_TARGET : TURRET_PRIORITY_TARGET + + if(in_faction(L)) + return TURRET_NOT_TARGET if(lethal && locate(/mob/living/silicon/ai) in get_turf(L)) //don't accidentally kill the AI! return TURRET_NOT_TARGET @@ -648,18 +670,19 @@ var/list/turret_icons return ..() -/obj/machinery/porta_turret/proc/set_raised_raising(var/raised, var/raising) - src.raised = raised - src.raising = raising - density = raised || raising +/obj/machinery/porta_turret/proc/set_raised_raising(var/is_raised, var/is_raising) + raised = is_raised + raising = is_raising + density = is_raised || is_raising /obj/machinery/porta_turret/proc/target(var/mob/living/target) if(disabled) return if(target) last_target = target - spawn() - popUp() //pop the turret up if it's not already up. + if(has_cover) + spawn() + popUp() //pop the turret up if it's not already up. dir = get_dir(src, target) //even if you can't shoot, follow the target spawn() shootAt(target) @@ -667,7 +690,7 @@ 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? + if(!raised && has_cover) //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 @@ -719,9 +742,9 @@ var/list/turret_icons /obj/machinery/porta_turret/proc/setState(var/datum/turret_checks/TC) if(controllock) return - src.enabled = TC.enabled - src.lethal = TC.lethal - src.iconholder = TC.lethal + enabled = TC.enabled + lethal = TC.lethal + iconholder = TC.lethal check_synth = TC.check_synth check_access = TC.check_access @@ -731,7 +754,7 @@ var/list/turret_icons check_anomalies = TC.check_anomalies ailock = TC.ailock - src.power_change() + power_change() /* Portable turret constructions @@ -944,3 +967,87 @@ var/list/turret_icons /atom/movable/porta_turret_cover icon = 'icons/obj/turrets.dmi' + +// Syndicate turrets +/obj/machinery/porta_turret/syndicate + projectile = /obj/item/projectile/bullet + eprojectile = /obj/item/projectile/bullet + shot_sound = 'sound/weapons/Gunshot.ogg' + eshot_sound = 'sound/weapons/Gunshot.ogg' + + icon_state = "syndieturret0" + var/icon_state_initial = "syndieturret0" + var/icon_state_active = "syndieturret1" + var/icon_state_destroyed = "syndieturret2" + + syndicate = 1 + installation = null + always_up = 1 + use_power = 0 + has_cover = 0 + raised = 1 + scan_range = 9 + + faction = "syndicate" + emp_vulnerable = 0 + + lethal = 1 + check_arrest = 0 + check_records = 0 + check_weapons = 0 + check_access = 0 + check_anomalies = 1 + check_synth = 1 + ailock = 1 + +/obj/machinery/porta_turret/syndicate/New() + ..() + if(req_one_access && req_one_access.len) + req_one_access.Cut() + req_access = list(access_syndicate) + one_access = 0 + +/obj/machinery/porta_turret/syndicate/update_icon() + if(stat & BROKEN) + icon_state = icon_state_destroyed + else if(enabled) + icon_state = icon_state_active + else + icon_state = icon_state_initial + +/obj/machinery/porta_turret/syndicate/setup() + return + +/obj/machinery/porta_turret/syndicate/assess_perp(mob/living/carbon/human/perp) + return 10 //Syndicate turrets shoot everything not in their faction + +/obj/machinery/porta_turret/syndicate/pod + health = 40 + projectile = /obj/item/projectile/bullet/weakbullet3 + eprojectile = /obj/item/projectile/bullet/weakbullet3 + +/obj/machinery/porta_turret/syndicate/interior + name = "machine gun turret (.45)" + desc = "Syndicate interior defense turret chambered for .45 rounds. Designed to down intruders without damaging the hull." + projectile = /obj/item/projectile/bullet/midbullet + eprojectile = /obj/item/projectile/bullet/midbullet + +/obj/machinery/porta_turret/syndicate/exterior + name = "machine gun turret (7.62)" + desc = "Syndicate exterior defense turret chambered for 7.62 rounds. Designed to down intruders with heavy calliber bullets." + projectile = /obj/item/projectile/bullet + eprojectile = /obj/item/projectile/bullet/midbullet + +/obj/machinery/porta_turret/syndicate/grenade + name = "mounted grenade launcher (40mm)" + desc = "Syndicate 40mm grenade launcher defense turret. If you've had this much time to look at it, you're probably already dead." + projectile = /obj/item/projectile/bullet/a40mm + eprojectile = /obj/item/projectile/bullet/midbullet + +/obj/machinery/porta_turret/syndicate/assault_pod + name = "machine gun turret (4.6x30mm)" + desc = "Syndicate exterior defense turret chambered for 4.6x30mm rounds. Designed to be fitted to assault pods, it uses low calliber bullets to save space." + health = 100 + projectile = /obj/item/projectile/bullet/weakbullet3 + eprojectile = /obj/item/projectile/bullet/midbullet + diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index 704da886685..936b18f35c5 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -8,14 +8,16 @@ //Request Console Screens #define RCS_MAINMENU 0 // Main menu -#define RCS_RQASSIST 1 // Request supplies -#define RCS_RQSUPPLY 2 // Request assistance +#define RCS_RQSUPPLY 1 // Request supplies +#define RCS_RQASSIST 2 // Request assistance #define RCS_SENDINFO 3 // Relay information #define RCS_SENTPASS 4 // Message sent successfully #define RCS_SENTFAIL 5 // Message sent unsuccessfully #define RCS_VIEWMSGS 6 // View messages #define RCS_MESSAUTH 7 // Authentication before sending #define RCS_ANNOUNCE 8 // Send announcement +#define RCS_SHIPPING 9 // Print Shipping Labels/Packages +#define RCS_SHIP_LOG 10 // View Shipping Label Log var/req_console_assistance = list() var/req_console_supplies = list() @@ -52,6 +54,10 @@ var/list/obj/machinery/requests_console/allConsoles = list() var/priority = -1 ; //Priority of the message being sent light_range = 0 var/datum/announcement/announcement = new + var/list/shipping_log = list() + var/ship_tag_name = "" + var/ship_tag_index = 0 + var/print_cooldown = 0 //cooldown on shipping label printer, stores the in-game time of when the printer will next be ready /obj/machinery/requests_console/power_change() ..() @@ -128,6 +134,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() data["assist_dept"] = req_console_assistance data["supply_dept"] = req_console_supplies data["info_dept"] = req_console_information + data["ship_dept"] = TAGGERLOCATIONS data["message"] = message data["recipient"] = recipient @@ -135,6 +142,8 @@ var/list/obj/machinery/requests_console/allConsoles = list() data["msgStamped"] = msgStamped data["msgVerified"] = msgVerified data["announceAuth"] = announceAuth + data["shipDest"] = ship_tag_name + data["shipping_log"] = shipping_log return data @@ -182,7 +191,7 @@ var/list/obj/machinery/requests_console/allConsoles = list() screen = RCS_SENTPASS message_log += "Message sent to [recipient]
[message]" else - audible_message(text("[bicon(src)] *The Requests Console beeps: 'NOTICE: No server detected!'"),,4) + audible_message(text("[bicon(src)] *The Requests Console beeps: 'NOTICE: No server detected!'"),,4) //Handle screen switching if(href_list["setScreen"]) @@ -199,6 +208,26 @@ var/list/obj/machinery/requests_console/allConsoles = list() reset_message() screen = tempScreen + if(href_list["shipSelect"]) + ship_tag_name = href_list["shipSelect"] + ship_tag_index = TAGGERLOCATIONS.Find(ship_tag_name) + + //Handle Shipping Label Printing + if(href_list["printLabel"]) + var/error_message = "" + if(!ship_tag_index) + error_message = "Please select a destination." + else if(!msgVerified) + error_message = "Please verify shipper ID." + else if(world.time < print_cooldown) + error_message = "Please allow the printer time to prepare the next shipping label." + if(error_message) + audible_message(text("[bicon(src)] *The Requests Console beeps: 'NOTICE: [error_message]'"),,4) + return + print_label(ship_tag_name, ship_tag_index) + shipping_log += "Shipping Label printed for [ship_tag_name]
[msgVerified]" + reset_message(1) + //Handle silencing the console if(href_list["toggleSilent"]) silent = !silent @@ -245,6 +274,10 @@ var/list/obj/machinery/requests_console/allConsoles = list() reset_message() to_chat(user, "You are not authorized to send announcements.") updateUsrDialog() + if(screen == RCS_SHIPPING) + var/obj/item/weapon/card/id/T = O + msgVerified = text("Sender verified as [T.registered_name] ([T.assignment])") + updateUsrDialog() if(istype(O, /obj/item/weapon/stamp)) if(inoperable(MAINT)) return if(screen == RCS_MESSAUTH) @@ -261,6 +294,8 @@ var/list/obj/machinery/requests_console/allConsoles = list() msgStamped = "" announceAuth = 0 announcement.announcer = "" + ship_tag_name = "" + ship_tag_index = 0 if(mainmenu) screen = RCS_MAINMENU @@ -286,3 +321,9 @@ var/list/obj/machinery/requests_console/allConsoles = list() else // Normal src.message_log += "From: [linkedSender]
[message]" set_light(2) + +/obj/machinery/requests_console/proc/print_label(tag_name, tag_index) + var/obj/item/shippingPackage/sp = new /obj/item/shippingPackage(get_turf(src)) + sp.sortTag = tag_index + sp.update_desc() + print_cooldown = world.time + 600 //1 minute cooldown before you can print another label, but you can still configure the next one during this time diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index bf4300351fa..f9355a98d37 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -257,6 +257,7 @@ var/obj/machinery/syndicatebomb/B = src.loc for(var/i = 0; i < amt_summon; i++) var/atom/movable/X = new summon_path + X.admin_spawned = TRUE X.loc = get_turf(src) if(prob(50)) for(var/j = 1, j <= rand(1, 3), j++) diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm index 21da8c4159c..ad5aeb5fc61 100644 --- a/code/game/machinery/turret_control.dm +++ b/code/game/machinery/turret_control.dm @@ -25,6 +25,9 @@ var/check_anomalies = 1 //checks if it can shoot at unidentified lifeforms (ie xenos) var/check_synth = 0 //if active, will shoot at anything not an AI or cyborg var/ailock = 0 //Silicons cannot use this + + var/syndicate = 0 + var/faction = "" // Turret controls can only access turrets that are in the same faction req_access = list(access_ai_upload) @@ -36,6 +39,23 @@ enabled = 1 lethal = 1 icon_state = "control_kill" + +/obj/machinery/turretid/syndicate + enabled = 1 + lethal = 1 + icon_state = "control_kill" + + lethal = 1 + check_arrest = 0 + check_records = 0 + check_weapons = 0 + check_access = 0 + check_anomalies = 1 + check_synth = 1 + ailock = 1 + + syndicate = 1 + faction = "syndicate" /obj/machinery/turretid/Destroy() if(control_area) @@ -50,7 +70,7 @@ control_area = get_area(src) else if(istext(control_area)) for(var/area/A in world) - if(A.name && A.name==control_area) + if(A.name && A.name == control_area) control_area = A break @@ -130,10 +150,10 @@ data["access"] = !isLocked(user) data["locked"] = locked data["enabled"] = enabled - data["is_lethal"] = 1 + data["lethal_control"] = !syndicate ? 1 : 0 data["lethal"] = lethal - if(data["access"]) + if(data["access"] && !syndicate) var/settings[0] settings[++settings.len] = list("category" = "Neutralize All Non-Synthetics", "setting" = "check_synth", "value" = check_synth) settings[++settings.len] = list("category" = "Check Weapon Authorization", "setting" = "check_weapons", "value" = check_weapons) @@ -156,6 +176,8 @@ var/value = text2num(href_list["value"]) if(href_list["command"] == "enable") enabled = value + else if(syndicate) + return 1 else if(href_list["command"] == "lethal") lethal = value else if(href_list["command"] == "check_synth") @@ -188,7 +210,8 @@ if(istype(control_area)) for(var/obj/machinery/porta_turret/aTurret in control_area) - aTurret.setState(TC) + if(faction == aTurret.faction) + aTurret.setState(TC) update_icon() diff --git a/code/game/machinery/turrets.dm b/code/game/machinery/turrets.dm deleted file mode 100644 index b8a8eddb79d..00000000000 --- a/code/game/machinery/turrets.dm +++ /dev/null @@ -1,580 +0,0 @@ -/area/turret_protected - name = "Turret Protected Area" - var/list/turretTargets = list() - -/area/turret_protected/proc/subjectDied(target) - if( isliving(target) ) - if( !issilicon(target) ) - var/mob/living/L = target - if( L.stat ) - if( L in turretTargets ) - src.Exited(L) - - -/area/turret_protected/Entered(O) - ..() - if( iscarbon(O) ) - turretTargets |= O - else if( istype(O, /obj/mecha) ) - var/obj/mecha/Mech = O - if( Mech.occupant ) - turretTargets |= Mech - else if( istype(O, /obj/spacepod) ) - var/obj/spacepod/Pod = O - if( Pod.pilot ) - turretTargets |= Pod - else if(istype(O,/mob/living/simple_animal)) - turretTargets |= O - return 1 - -/area/turret_protected/Exited(O) - if( ismob(O) && !issilicon(O) ) - turretTargets -= O - else if( istype(O, /obj/mecha) ) - turretTargets -= O - else if( istype(O, /obj/spacepod) ) - turretTargets -= O - ..() - return 1 - - -/obj/machinery/turret - name = "turret" - icon = 'icons/obj/turrets.dmi' - icon_state = "grey_target_prism" - var/raised = 0 - var/enabled = 1 - anchored = 1 - layer = 3 - invisibility = INVISIBILITY_LEVEL_TWO - density = 1 - var/lasers = 0 - var/lasertype = 1 - // 1 = lasers - // 2 = cannons - // 3 = pulse - // 4 = change (HONK) - // 5 = bluetag - // 6 = redtag - var/health = 80 - var/obj/machinery/turretcover/cover = null - var/popping = 0 - var/wasvalid = 0 - var/lastfired = 0 - var/shot_delay = 30 //3 seconds between shots - var/datum/effect/system/spark_spread/spark_system - use_power = 1 - idle_power_usage = 50 - active_power_usage = 300 -// var/list/targets - var/atom/movable/cur_target - var/targeting_active = 0 - var/area/turret_protected/protected_area - - -/obj/machinery/turret/New() - spark_system = new /datum/effect/system/spark_spread - spark_system.set_up(5, 0, src) - spark_system.attach(src) -// targets = new - ..() - return - -/obj/machinery/turretcover - name = "pop-up turret cover" - icon = 'icons/obj/turrets.dmi' - icon_state = "turretCover" - anchored = 1 - layer = 3.5 - density = 0 - var/obj/machinery/turret/host = null - -/obj/machinery/turret/proc/isPopping() - return (popping!=0) - -/obj/machinery/turret/power_change() - if(stat & BROKEN) - icon_state = "grey_target_prism" - else - if( powered() ) - if(src.enabled) - if(src.lasers) - icon_state = "orange_target_prism" - else - icon_state = "target_prism" - else - icon_state = "grey_target_prism" - stat &= ~NOPOWER - else - spawn(rand(0, 15)) - src.icon_state = "grey_target_prism" - stat |= NOPOWER - -/obj/machinery/turret/proc/setState(var/enabled, var/lethal) - src.enabled = enabled - src.lasers = lethal - src.power_change() - - -/obj/machinery/turret/proc/get_protected_area() - var/area/turret_protected/TP = get_area(src) - if(istype(TP)) - return TP - return - -/obj/machinery/turret/proc/check_target(var/atom/movable/T as mob|obj) - if( T && T in protected_area.turretTargets ) - var/area/area_T = get_area(T) - if( !area_T || (area_T.type != protected_area.type) ) - protected_area.Exited(T) - return 0 //If the guy is somehow not in the turret's area (teleportation), get them out the damn list. --NEO - if( iscarbon(T) ) - var/mob/living/carbon/MC = T - if( !MC.stat ) - if( !MC.lying || lasers ) - return 1 - else if( istype(T, /obj/mecha) ) - var/obj/mecha/ME = T - if( ME.occupant ) - return 1 - else if( istype(T, /obj/spacepod) ) - var/obj/spacepod/SP = T - if( SP.pilot ) - return 1 - else if(istype(T,/mob/living/simple_animal)) - var/mob/living/simple_animal/A = T - if( !A.stat ) - if(lasers) - return 1 - return 0 - -/obj/machinery/turret/proc/get_new_target() - var/list/new_targets = new - var/new_target - for(var/mob/living/carbon/M in protected_area.turretTargets) - if(!M.stat) - if(!M.lying || lasers) - new_targets += M - for(var/obj/mecha/M in protected_area.turretTargets) - if(M.occupant) - new_targets += M - for(var/obj/spacepod/M in protected_area.turretTargets) - if(M.pilot) - new_targets += M.pilot - for(var/mob/living/simple_animal/M in protected_area.turretTargets) - if(!M.stat) - new_targets += M - if(new_targets.len) - new_target = pick(new_targets) - return new_target - - -/obj/machinery/turret/process() - if(stat & (NOPOWER|BROKEN)) - return - if(src.cover==null) - src.cover = new /obj/machinery/turretcover(src.loc) - src.cover.host = src - protected_area = get_protected_area() - if(!enabled || !protected_area || protected_area.turretTargets.len<=0) - if(!isDown() && !isPopping()) - popDown() - return - if(!check_target(cur_target)) //if current target fails target check - cur_target = get_new_target() //get new target - - if(cur_target) //if it's found, proceed -// to_chat(world, "[cur_target]") - if(!isPopping()) - if(isDown()) - popUp() - use_power = 2 - else - spawn() - if(!targeting_active) - targeting_active = 1 - target() - targeting_active = 0 - - if(prob(15)) - if(prob(50)) - playsound(get_turf(src), 'sound/effects/turret/move1.wav', 60, 1) - else - playsound(get_turf(src), 'sound/effects/turret/move2.wav', 60, 1) - - else if(!isPopping())//else, pop down - if(!isDown()) - popDown() - use_power = 1 - return - - -/obj/machinery/turret/proc/target() - while(src && enabled && !stat && check_target(cur_target)) - src.dir = get_dir(src, cur_target) - shootAt(cur_target) - sleep(shot_delay) - return - -/obj/machinery/turret/proc/shootAt(var/atom/movable/target) - var/turf/T = get_turf(src) - var/turf/U = get_turf(target) - if(!T || !U) - return - var/obj/item/projectile/A - if(src.lasers) - switch(lasertype) - if(1) - A = new /obj/item/projectile/beam(loc) - if(2) - 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/beam/lasertag/bluetag(loc) - if(6) - A = new /obj/item/projectile/beam/lasertag/redtag(loc) - use_power(500) - else - A = new /obj/item/projectile/energy/electrode( loc ) - use_power(200) - if(src.lasers) - playsound(get_turf(src), 'sound/weapons/Laser.ogg', 60, 1) - else - playsound(get_turf(src), 'sound/weapons/Taser.ogg', 60, 1) - A.original = target - A.current = T - A.yo = U.y - T.y - A.xo = U.x - T.x - A.fire() - return A - - -/obj/machinery/turret/proc/isDown() - return (invisibility!=0) - -/obj/machinery/turret/proc/popUp() - if((!isPopping()) || src.popping==-1) - invisibility = 0 - popping = 1 - playsound(get_turf(src), 'sound/effects/turret/open.wav', 60, 1) - if(src.cover!=null) - flick("popup", src.cover) - src.cover.icon_state = "openTurretCover" - spawn(10) - if(popping==1) popping = 0 - -/obj/machinery/turret/proc/popDown() - if((!isPopping()) || src.popping==1) - popping = -1 - playsound(get_turf(src), 'sound/effects/turret/open.wav', 60, 1) - if(src.cover!=null) - flick("popdown", src.cover) - src.cover.icon_state = "turretCover" - spawn(10) - if(popping==-1) - invisibility = INVISIBILITY_LEVEL_TWO - popping = 0 - -/obj/machinery/turret/bullet_act(var/obj/item/projectile/Proj) - if((Proj.damage_type == BRUTE || Proj.damage_type == BURN)) - src.health -= Proj.damage - ..() - if(prob(45) && Proj.damage > 0) src.spark_system.start() - qdel(Proj) - if(src.health <= 0) - src.die() - return - -/obj/machinery/turret/attackby(obj/item/weapon/W, mob/user)//I can't believe no one added this before/N - ..() - user.changeNext_move(CLICK_CD_MELEE) - playsound(src.loc, 'sound/weapons/smash.ogg', 60, 1) - src.spark_system.start() - src.health -= W.force * 0.5 - if(src.health <= 0) - src.die() - return - -/obj/machinery/turret/emp_act(severity) - switch(severity) - if(1) - enabled = 0 - lasers = 0 - power_change() - ..() - -/obj/machinery/turret/ex_act(severity) - if(severity < 3) - src.die() - -/obj/machinery/turret/proc/die() - src.health = 0 - src.density = 0 - src.stat |= BROKEN - src.icon_state = "destroyed_target_prism" - if(cover!=null) - qdel(cover) - sleep(3) - flick("explosion", src) - spawn(13) - qdel(src) - - -/obj/machinery/turret/attack_animal(mob/living/simple_animal/M as mob) - M.changeNext_move(CLICK_CD_MELEE) - M.do_attack_animation(src) - if(M.melee_damage_upper == 0) return - if(!(stat & BROKEN)) - visible_message("[M] [M.attacktext] [src]!") - add_logs(src, M, "attacked", admin=0, print_attack_log = 0) - //src.create_attack_log("was attacked by [M.name] ([M.ckey])") - src.health -= M.melee_damage_upper - if(src.health <= 0) - src.die() - else - to_chat(M, "That object is useless to you.") - return - - - - -/obj/machinery/turret/attack_alien(mob/living/carbon/alien/humanoid/M as mob) - M.changeNext_move(CLICK_CD_MELEE) - M.do_attack_animation(src) - if(!(stat & BROKEN)) - playsound(src.loc, 'sound/weapons/slash.ogg', 25, 1, -1) - visible_message("[M] has slashed at [src]!") - src.health -= 15 - if(src.health <= 0) - src.die() - else - to_chat(M, "\green That object is useless to you.") - return - - - -/obj/machinery/turretid/Topic(href, href_list, var/nowindow = 0) - if(..(href, href_list)) - return 1 - if(src.locked) - if(!istype(usr, /mob/living/silicon)) - to_chat(usr, "Control panel is locked!") - return - if(href_list["toggleOn"]) - src.enabled = !src.enabled - src.updateTurrets() - else if(href_list["toggleLethal"]) - src.lethal = !src.lethal - src.updateTurrets() - if(!nowindow) - src.attack_hand(usr) - -/obj/machinery/turretid/proc/update_icons() - if(src.enabled) - if(src.lethal) - icon_state = "control_kill" - else - icon_state = "control_stun" - else - icon_state = "control_standby" - //CODE FIXED BUT REMOVED -// if(control_area) //USE: updates other controls in the area -// for(var/obj/machinery/turretid/Turret_Control in world) //I'm not sure if this is what it was -// if( Turret_Control.control_area != src.control_area ) continue //supposed to do. Or whether the person -// Turret_Control.icon_state = icon_state //who coded it originally was just tired -// Turret_Control.enabled = enabled //or something. I don't see any situation -// Turret_Control.lethal = lethal //in which this would be used on the current map. - //If he wants it back he can uncomment it - - -/obj/machinery/gun_turret //related to turrets but work way differentely because of being mounted on a moving ship. - name = "machine gun turret" - desc = "Syndicate heavy defense turret. It really packs a bunch." - density = 1 - anchored = 1 - var/state = 0 //Like stat on mobs, 0 is alive, 1 is damaged, 2 is dead - var/faction = "syndicate" - var/atom/cur_target = null - var/scan_range = 9 //You will never see them coming - var/health = 200 //Because it lacks a cover, and is mostly to keep people from touching the syndie shuttle. - var/bullet_type = /obj/item/projectile/bullet - var/firing_sound = 'sound/weapons/Gunshot3.ogg' - var/base_icon = "syndieturret" - icon = 'icons/obj/turrets.dmi' - icon_state = "syndieturret0" - -/obj/machinery/gun_turret/New() - ..() - take_damage(0) //check your health - -/obj/machinery/gun_turret/ex_act(severity) - switch(severity) - if(1) - die() - if(2) - take_damage(100) - if(3) - take_damage(50) - return - -/obj/machinery/gun_turret/emp_act() //Can't emp an mechanical turret. - return - -/obj/machinery/gun_turret/update_icon() - if(state > 2 || state < 0) //someone fucked up the vars so fix them - take_damage(0) - icon_state = "[base_icon]" + "[state]" - return - - -/obj/machinery/gun_turret/proc/take_damage(damage) - health -= damage - var/orig_health = initial(health) - var/health_percent = (health/orig_health) * 100 - - if(health_percent > 50) - state = 0 - else - state = 1 - if(health_percent <= 0) - if(state != 2) - die() - return - state = 2 - - update_icon() - - - - -/obj/machinery/gun_turret/bullet_act(var/obj/item/projectile/Proj) - if((Proj.damage_type == BRUTE || Proj.damage_type == BURN)) - take_damage(Proj.damage) - return - -/obj/machinery/gun_turret/proc/die() - state = 2 - update_icon() - -/obj/machinery/gun_turret/attack_hand(mob/user) - return - -/obj/machinery/gun_turret/attack_ai(mob/user) - return attack_hand(user) - - -/obj/machinery/gun_turret/attack_alien(mob/living/user as mob) - user.changeNext_move(CLICK_CD_MELEE) - user.do_attack_animation(src) - playsound(src.loc, 'sound/weapons/slash.ogg', 25, 1, -1) - user.visible_message("[user] slashes at [src]", "You slash at [src]") - take_damage(15) - return - -/obj/machinery/gun_turret/proc/validate_target(atom/target) - if(get_dist(target, src)>scan_range) - return 0 - if(istype(target, /mob)) - var/mob/M = target - if(!M.stat) - return 1 - else if(istype(target, /obj/mecha)) - var/obj/mecha/M = target - if(M.occupant) - return 1 - else if(istype(target, /obj/spacepod)) - var/obj/spacepod/S = target - if(S.pilot) - return 1 - return 0 - - -/obj/machinery/gun_turret/process() - if(state == 2) - return - if(cur_target && !validate_target(cur_target)) - cur_target = null - if(!cur_target) - cur_target = get_target() - if(cur_target) - fire(cur_target) - return - - -/obj/machinery/gun_turret/proc/get_target() - var/list/pos_targets = list() - var/target = null - for(var/mob/living/M in view(scan_range,src)) - if(M.stat) - continue - if(faction in M.faction) - continue - if(ispAI(M)) - continue - pos_targets += M - for(var/obj/mecha/M in oview(scan_range, src)) - if(M.occupant) - if(faction in M.occupant.faction) - continue - if(!M.occupant) - continue //Don't shoot at empty mechs. - pos_targets += M - for(var/obj/spacepod/M in oview(scan_range, src)) - if(M.pilot) - var/mob/P = M.pilot - if(faction in P.faction) - continue - if(!M.pilot) - continue //Don't shoot at empty pods. - pos_targets += M - if(pos_targets.len) - target = pick(pos_targets) - return target - - -/obj/machinery/gun_turret/proc/fire(atom/target) - if(!target) - cur_target = null - return - src.dir = get_dir(src,target) - var/turf/targloc = get_turf(target) - if(!src) - return - var/turf/curloc = get_turf(src) - if(!targloc || !curloc) - return - if(targloc == curloc) - return - playsound(get_turf(src), firing_sound, 60, 1) - var/obj/item/projectile/A = new bullet_type(curloc) - A.original = target - A.current = curloc - A.yo = targloc.y - curloc.y - A.xo = targloc.x - curloc.x - A.fire() - return - - -/obj/machinery/gun_turret/interior - name = "machine gun turret (.45)" - desc = "Syndicate interior defense turret chambered for .45 rounds. Designed to down intruders without damaging the hull." - bullet_type = /obj/item/projectile/bullet/midbullet - -/obj/machinery/gun_turret/exterior - name = "machine gun turret (7.62)" - desc = "Syndicate exterior defense turret chambered for 7.62 rounds. Designed to down intruders with heavy calliber bullets." - bullet_type = /obj/item/projectile/bullet - -/obj/machinery/gun_turret/grenade - name = "mounted grenade launcher (40mm)" - desc = "Syndicate 40mm grenade launcher defense turret. If you've had this much time to look at it, you're probably already dead." - bullet_type = /obj/item/projectile/bullet/a40mm - -/obj/machinery/gun_turret/assault_pod - name = "machine gun turret (4.6x30mm)" - desc = "Syndicate exterior defense turret chambered for 4.6x30mm rounds. Designed to be fitted to assault pods, it uses low calliber bullets to save space." - health = 100 - bullet_type = /obj/item/projectile/bullet/weakbullet3 diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index 89ce884a80f..0992f8bb509 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -800,6 +800,17 @@ /obj/item/weapon/reagent_containers/food/snacks/chinese/rice = 6) prices = list(/obj/item/weapon/reagent_containers/food/snacks/chinese/chowmein = 50, /obj/item/weapon/reagent_containers/food/snacks/chinese/tao = 50, /obj/item/weapon/reagent_containers/food/snacks/chinese/newdles = 50, /obj/item/weapon/reagent_containers/food/snacks/chinese/rice = 50) + refill_canister = /obj/item/weapon/vending_refill/chinese + +/obj/machinery/vending/chinese/New() + ..() + component_parts = list() + var/obj/item/weapon/circuitboard/vendor/V = new(null) + V.set_type(type) + component_parts += V + component_parts += new /obj/item/weapon/vending_refill/chinese(0) + component_parts += new /obj/item/weapon/vending_refill/chinese(0) + component_parts += new /obj/item/weapon/vending_refill/chinese(0) /obj/machinery/vending/cola name = "\improper Robust Softdrinks" diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index b5fcb46b39c..6e155779aa5 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -93,6 +93,7 @@ processing_objects.Add(src) removeVerb(/obj/mecha/verb/disconnect_from_port) + poi_list |= src log_message("[src] created.") mechas_list += src //global mech list prepare_huds() @@ -616,6 +617,7 @@ qdel(internal_tank) processing_objects.Remove(src) + poi_list.Remove(src) equipment.Cut() cell = null internal_tank = null @@ -831,6 +833,8 @@ /obj/mecha/proc/attacked_by(obj/item/I, mob/user) log_message("Attacked by [I]. Attacker - [user]") + user.changeNext_move(CLICK_CD_MELEE) + user.do_attack_animation(src) var/deflection = deflect_chance var/dam_coeff = 1 for(var/obj/item/mecha_parts/mecha_equipment/anticcw_armor_booster/B in equipment) diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index 090a7437a5b..434fec620b8 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -18,6 +18,11 @@ var/new_frequency = sanitize_frequency(rand(PUBLIC_LOW_FREQ, PUBLIC_HIGH_FREQ)) aSignal.set_frequency(new_frequency) + poi_list |= src + +/obj/effect/anomaly/Destroy() + poi_list.Remove(src) + return ..() /obj/effect/anomaly/proc/anomalyEffect() if(prob(50)) diff --git a/code/game/objects/effects/decals/Cleanable/fuel.dm b/code/game/objects/effects/decals/Cleanable/fuel.dm index aad9f5ab4bf..3d6a47a00b9 100644 --- a/code/game/objects/effects/decals/Cleanable/fuel.dm +++ b/code/game/objects/effects/decals/Cleanable/fuel.dm @@ -1,4 +1,4 @@ -obj/effect/decal/cleanable/liquid_fuel +/obj/effect/decal/cleanable/liquid_fuel //Liquid fuel is used for things that used to rely on volatile fuels or plasma being contained to a couple tiles. icon = 'icons/effects/effects.dmi' icon_state = "fuel" @@ -6,52 +6,53 @@ obj/effect/decal/cleanable/liquid_fuel anchored = 1 var/amount = 1 //Basically moles. - New(newLoc,amt=1) - src.amount = amt +/obj/effect/decal/cleanable/liquid_fuel/New(newLoc,amt=1) + amount = amt - //Be absorbed by any other liquid fuel in the tile. - for(var/obj/effect/decal/cleanable/liquid_fuel/other in newLoc) - if(other != src) - other.amount += src.amount - spawn other.Spread() - qdel(src) + //Be absorbed by any other liquid fuel in the tile. + for(var/obj/effect/decal/cleanable/liquid_fuel/other in newLoc) + if(other != src) + other.amount += amount + spawn other.Spread() + qdel(src) - Spread() - . = ..() + Spread() + . = ..() - proc/Spread() - //Allows liquid fuels to sometimes flow into other tiles. - if(amount < 0.5) return - var/turf/simulated/S = loc - if(!istype(S)) return - for(var/d in cardinal) - if(rand(25)) - var/turf/simulated/target = get_step(src,d) - var/turf/simulated/origin = get_turf(src) - if(origin.CanPass(null, target, 0, 0) && target.CanPass(null, origin, 0, 0)) - if(!locate(/obj/effect/decal/cleanable/liquid_fuel) in target) - new/obj/effect/decal/cleanable/liquid_fuel(target, amount*0.25) - amount *= 0.75 +/obj/effect/decal/cleanable/liquid_fuel/proc/Spread() + //Allows liquid fuels to sometimes flow into other tiles. + if(amount < 0.5) return + var/turf/simulated/S = loc + if(!istype(S)) return + for(var/d in cardinal) + if(rand(25)) + var/turf/simulated/target = get_step(src, d) + var/turf/simulated/origin = get_turf(src) + if(origin.CanPass(null, target, 0, 0) && target.CanPass(null, origin, 0, 0)) + if(!locate(/obj/effect/decal/cleanable/liquid_fuel) in target) + new/obj/effect/decal/cleanable/liquid_fuel(target, amount*0.25) + amount *= 0.75 - flamethrower_fuel - icon_state = "mustard" - anchored = 0 - New(newLoc, amt = 1, d = 0) - dir = d //Setting this direction means you won't get torched by your own flamethrower. - . = ..() +/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel + icon_state = "mustard" + anchored = 0 - Spread() - //The spread for flamethrower fuel is much more precise, to create a wide fire pattern. - if(amount < 0.1) return - var/turf/simulated/S = loc - if(!istype(S)) return +/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel/New(newLoc, amt = 1, d = 0) + dir = d //Setting this direction means you won't get torched by your own flamethrower. + . = ..() - for(var/d in list(turn(dir,90),turn(dir,-90), dir)) - var/turf/simulated/O = get_step(S,d) - if(locate(/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel) in O) - continue - if(O.CanPass(null, S, 0, 0) && S.CanPass(null, O, 0, 0)) - new/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(O,amount*0.25,d) - O.hotspot_expose((T20C*2) + 380,500) //Light flamethrower fuel on fire immediately. +/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel/Spread() + //The spread for flamethrower fuel is much more precise, to create a wide fire pattern. + if(amount < 0.1) return + var/turf/simulated/S = loc + if(!istype(S)) return - amount *= 0.25 + for(var/d in list(turn(dir,90),turn(dir,-90), dir)) + var/turf/simulated/O = get_step(S,d) + if(locate(/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel) in O) + continue + if(O.CanPass(null, S, 0, 0) && S.CanPass(null, O, 0, 0)) + new/obj/effect/decal/cleanable/liquid_fuel/flamethrower_fuel(O,amount*0.25,d) + O.hotspot_expose((T20C*2) + 380,500) //Light flamethrower fuel on fire immediately. + + amount *= 0.25 diff --git a/code/game/objects/effects/decals/Cleanable/humans.dm b/code/game/objects/effects/decals/Cleanable/humans.dm index 0c0f7cbdf91..26344ec96f1 100644 --- a/code/game/objects/effects/decals/Cleanable/humans.dm +++ b/code/game/objects/effects/decals/Cleanable/humans.dm @@ -117,10 +117,13 @@ var/global/list/image/splatter_cache=list() user.hand_blood_color = basecolor user.update_inv_gloves(1) user.verbs += /mob/living/carbon/human/proc/bloody_doodle + +/obj/effect/decal/cleanable/blood/can_bloodcrawl_in() + return amount /obj/effect/decal/cleanable/blood/splatter - random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5") - amount = 2 + random_icon_states = list("mgibbl1", "mgibbl2", "mgibbl3", "mgibbl4", "mgibbl5") + amount = 2 /obj/effect/decal/cleanable/blood/drip name = "drips of blood" diff --git a/code/game/objects/effects/decals/Cleanable/robots.dm b/code/game/objects/effects/decals/Cleanable/robots.dm index 16688932b9c..5fc09b6ec34 100644 --- a/code/game/objects/effects/decals/Cleanable/robots.dm +++ b/code/game/objects/effects/decals/Cleanable/robots.dm @@ -11,6 +11,9 @@ /obj/effect/decal/cleanable/blood/gibs/robot/dry() //pieces of robots do not dry up like return + +/obj/effect/decal/cleanable/blood/gibs/robot/can_bloodcrawl_in() + return FALSE /obj/effect/decal/cleanable/blood/gibs/robot/streak(var/list/directions) spawn (0) @@ -42,6 +45,9 @@ desc = "It's black and greasy. Looks like Beepsky made another mess." basecolor="#030303" +/obj/effect/decal/cleanable/blood/oil/can_bloodcrawl_in() + return FALSE + /obj/effect/decal/cleanable/blood/oil/dry() return diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm index 0d6bf3255a5..48a85e7e704 100644 --- a/code/game/objects/effects/decals/cleanable.dm +++ b/code/game/objects/effects/decals/cleanable.dm @@ -3,6 +3,9 @@ var/targeted_by = null // Used so cleanbots can't claim a mess. var/noscoop = 0 //if it has this, don't let it be scooped up var/noclear = 0 //if it has this, don't delete it when its' scooped up + +/obj/effect/decal/cleanable/proc/can_bloodcrawl_in() + return FALSE /obj/effect/decal/cleanable/New() if(random_icon_states && length(src.random_icon_states) > 0) diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm index f46810486ca..7ff80f248da 100644 --- a/code/game/objects/effects/landmarks.dm +++ b/code/game/objects/effects/landmarks.dm @@ -1,252 +1,267 @@ -/obj/effect/landmark - name = "landmark" - icon = 'icons/mob/screen_gen.dmi' - icon_state = "x2" - anchored = 1.0 - unacidable = 1 - -/obj/effect/landmark/New() - - ..() - set_tag() - invisibility = 101 - - switch(name) //some of these are probably obsolete - if("start") - newplayer_start += loc - qdel(src) - - if("wizard") - wizardstart += loc - qdel(src) - - if("JoinLate") - latejoin += loc - qdel(src) - - if("JoinLateGateway") - latejoin_gateway += loc - qdel(src) - - if("JoinLateCryo") - latejoin_cryo += loc - qdel(src) - - if("JoinLateCyborg") - latejoin_cyborg += loc - qdel(src) - - if("prisonwarp") - prisonwarp += loc - qdel(src) +/obj/effect/landmark + name = "landmark" + icon = 'icons/mob/screen_gen.dmi' + icon_state = "x2" + anchored = 1.0 + unacidable = 1 - if("prisonsecuritywarp") - prisonsecuritywarp += loc - qdel(src) +/obj/effect/landmark/New() - if("tdome1") - tdome1 += loc + ..() + set_tag() + invisibility = 101 - if("tdome2") - tdome2 += loc + switch(name) //some of these are probably obsolete + if("start") + newplayer_start += loc + qdel(src) - if("tdomeadmin") - tdomeadmin += loc + if("wizard") + wizardstart += loc + qdel(src) - if("tdomeobserve") - tdomeobserve += loc + if("JoinLate") + latejoin += loc + qdel(src) - if("aroomwarp") - aroomwarp += loc - - if("blobstart") - blobstart += loc - qdel(src) - - if("xeno_spawn") - xeno_spawn += loc - qdel(src) - - if("ninjastart") - ninjastart += loc - qdel(src) - - if("carpspawn") - carplist += loc - - if("voxstart") - raider_spawn += loc - - if("ERT Director") - ertdirector += loc - qdel(src) + if("JoinLateGateway") + latejoin_gateway += loc + qdel(src) - if("Response Team") - emergencyresponseteamspawn += loc - qdel(src) - - landmarks_list += src - return 1 - -/obj/effect/landmark/Destroy() - landmarks_list -= src - ..() - return QDEL_HINT_HARDDEL_NOW - -/obj/effect/landmark/proc/set_tag() - tag = text("landmark*[]", name) - - -/obj/effect/landmark/start - name = "start" - icon = 'icons/mob/screen_gen.dmi' - icon_state = "x" - anchored = 1.0 - -/obj/effect/landmark/start/set_tag() - tag = "start*[name]" - - -//Costume spawner landmarks - -/obj/effect/landmark/costume/New() //costume spawner, selects a random subclass and disappears - - var/list/options = typesof(/obj/effect/landmark/costume) - var/PICK= options[rand(1,options.len)] - new PICK(src.loc) - qdel(src) - -//SUBCLASSES. Spawn a bunch of items and disappear likewise -/obj/effect/landmark/costume/chicken/New() - new /obj/item/clothing/suit/chickensuit(src.loc) - new /obj/item/clothing/head/chicken(src.loc) - new /obj/item/weapon/reagent_containers/food/snacks/egg(src.loc) - qdel(src) - -/obj/effect/landmark/costume/gladiator/New() - new /obj/item/clothing/under/gladiator(src.loc) - new /obj/item/clothing/head/helmet/gladiator(src.loc) - qdel(src) - -/obj/effect/landmark/costume/madscientist/New() - new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc) - new /obj/item/clothing/head/flatcap(src.loc) - new /obj/item/clothing/suit/storage/labcoat/mad(src.loc) - new /obj/item/clothing/glasses/gglasses(src.loc) - qdel(src) - -/obj/effect/landmark/costume/elpresidente/New() - new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc) - new /obj/item/clothing/head/flatcap(src.loc) - new /obj/item/clothing/mask/cigarette/cigar/havana(src.loc) - new /obj/item/clothing/shoes/jackboots(src.loc) - qdel(src) - -/obj/effect/landmark/costume/nyangirl/New() - new /obj/item/clothing/under/schoolgirl(src.loc) - new /obj/item/clothing/head/kitty(src.loc) - qdel(src) - -/obj/effect/landmark/costume/maid/New() - new /obj/item/clothing/under/blackskirt(src.loc) - var/CHOICE = pick( /obj/item/clothing/head/beret , /obj/item/clothing/head/rabbitears ) - new CHOICE(src.loc) - new /obj/item/clothing/glasses/sunglasses/blindfold(src.loc) - qdel(src) - -/obj/effect/landmark/costume/butler/New() - new /obj/item/clothing/suit/wcoat(src.loc) - new /obj/item/clothing/under/suit_jacket(src.loc) - new /obj/item/clothing/head/that(src.loc) - qdel(src) - -/obj/effect/landmark/costume/scratch/New() - new /obj/item/clothing/gloves/color/white(src.loc) - new /obj/item/clothing/shoes/white(src.loc) - new /obj/item/clothing/under/scratch(src.loc) - if(prob(30)) - new /obj/item/clothing/head/cueball(src.loc) - qdel(src) - -/obj/effect/landmark/costume/highlander/New() - new /obj/item/clothing/under/kilt(src.loc) - new /obj/item/clothing/head/beret(src.loc) - qdel(src) - -/obj/effect/landmark/costume/prig/New() - new /obj/item/clothing/suit/wcoat(src.loc) - new /obj/item/clothing/glasses/monocle(src.loc) - var/CHOICE= pick( /obj/item/clothing/head/bowlerhat, /obj/item/clothing/head/that) - new CHOICE(src.loc) - new /obj/item/clothing/shoes/black(src.loc) - new /obj/item/weapon/cane(src.loc) - new /obj/item/clothing/under/sl_suit(src.loc) - new /obj/item/clothing/mask/fakemoustache(src.loc) - qdel(src) - -/obj/effect/landmark/costume/plaguedoctor/New() - new /obj/item/clothing/suit/bio_suit/plaguedoctorsuit(src.loc) - new /obj/item/clothing/head/plaguedoctorhat(src.loc) - qdel(src) - -/obj/effect/landmark/costume/nightowl/New() - new /obj/item/clothing/under/owl(src.loc) - new /obj/item/clothing/mask/gas/owl_mask(src.loc) - qdel(src) - -/obj/effect/landmark/costume/waiter/New() - new /obj/item/clothing/under/waiter(src.loc) - var/CHOICE= pick( /obj/item/clothing/head/kitty, /obj/item/clothing/head/rabbitears) - new CHOICE(src.loc) - new /obj/item/clothing/suit/apron(src.loc) - qdel(src) - -/obj/effect/landmark/costume/pirate/New() - new /obj/item/clothing/under/pirate(src.loc) - new /obj/item/clothing/suit/pirate_black(src.loc) - var/CHOICE = pick( /obj/item/clothing/head/pirate , /obj/item/clothing/head/bandana ) - new CHOICE(src.loc) - new /obj/item/clothing/glasses/eyepatch(src.loc) - qdel(src) - -/obj/effect/landmark/costume/commie/New() - new /obj/item/clothing/under/soviet(src.loc) - new /obj/item/clothing/head/ushanka(src.loc) - qdel(src) - -/obj/effect/landmark/costume/imperium_monk/New() - new /obj/item/clothing/suit/imperium_monk(src.loc) - if(prob(25)) - new /obj/item/clothing/mask/gas/cyborg(src.loc) - qdel(src) - -/obj/effect/landmark/costume/holiday_priest/New() - new /obj/item/clothing/suit/holidaypriest(src.loc) - qdel(src) - -/obj/effect/landmark/costume/marisawizard/fake/New() - new /obj/item/clothing/head/wizard/marisa/fake(src.loc) - new/obj/item/clothing/suit/wizrobe/marisa/fake(src.loc) - qdel(src) - -/obj/effect/landmark/costume/cutewitch/New() - new /obj/item/clothing/under/sundress(src.loc) - new /obj/item/clothing/head/witchwig(src.loc) - new /obj/item/weapon/twohanded/staff/broom(src.loc) - qdel(src) - -/obj/effect/landmark/costume/fakewizard/New() - new /obj/item/clothing/suit/wizrobe/fake(src.loc) - new /obj/item/clothing/head/wizard/fake(src.loc) - new /obj/item/weapon/twohanded/staff/(src.loc) - qdel(src) - -/obj/effect/landmark/costume/sexyclown/New() - new /obj/item/clothing/mask/gas/sexyclown(src.loc) - new /obj/item/clothing/under/sexyclown(src.loc) - qdel(src) - -/obj/effect/landmark/costume/sexymime/New() - new /obj/item/clothing/mask/gas/sexymime(src.loc) - new /obj/item/clothing/under/sexymime(src.loc) - qdel(src) + if("JoinLateCryo") + latejoin_cryo += loc + qdel(src) + + if("JoinLateCyborg") + latejoin_cyborg += loc + qdel(src) + + if("prisonwarp") + prisonwarp += loc + qdel(src) + + if("prisonsecuritywarp") + prisonsecuritywarp += loc + qdel(src) + + if("tdome1") + tdome1 += loc + + if("tdome2") + tdome2 += loc + + if("tdomeadmin") + tdomeadmin += loc + + if("tdomeobserve") + tdomeobserve += loc + + if("aroomwarp") + aroomwarp += loc + + if("blobstart") + blobstart += loc + qdel(src) + + if("xeno_spawn") + xeno_spawn += loc + qdel(src) + + if("ninjastart") + ninjastart += loc + qdel(src) + + if("carpspawn") + carplist += loc + + if("voxstart") + raider_spawn += loc + + if("ERT Director") + ertdirector += loc + qdel(src) + + if("Response Team") + emergencyresponseteamspawn += loc + qdel(src) + + landmarks_list += src + return 1 + +/obj/effect/landmark/Destroy() + landmarks_list -= src + ..() + return QDEL_HINT_HARDDEL_NOW + +/obj/effect/landmark/proc/set_tag() + tag = text("landmark*[]", name) + + +/obj/effect/landmark/start + name = "start" + icon = 'icons/mob/screen_gen.dmi' + icon_state = "x" + anchored = 1.0 + +/obj/effect/landmark/start/set_tag() + tag = "start*[name]" + + +//Costume spawner landmarks + +/obj/effect/landmark/costume/New() //costume spawner, selects a random subclass and disappears + + var/list/options = typesof(/obj/effect/landmark/costume) + var/PICK= options[rand(1,options.len)] + new PICK(src.loc) + qdel(src) + +//SUBCLASSES. Spawn a bunch of items and disappear likewise +/obj/effect/landmark/costume/chicken/New() + new /obj/item/clothing/suit/chickensuit(src.loc) + new /obj/item/clothing/head/chicken(src.loc) + new /obj/item/weapon/reagent_containers/food/snacks/egg(src.loc) + qdel(src) + +/obj/effect/landmark/costume/gladiator/New() + new /obj/item/clothing/under/gladiator(src.loc) + new /obj/item/clothing/head/helmet/gladiator(src.loc) + qdel(src) + +/obj/effect/landmark/costume/madscientist/New() + new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc) + new /obj/item/clothing/head/flatcap(src.loc) + new /obj/item/clothing/suit/storage/labcoat/mad(src.loc) + new /obj/item/clothing/glasses/gglasses(src.loc) + qdel(src) + +/obj/effect/landmark/costume/elpresidente/New() + new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc) + new /obj/item/clothing/head/flatcap(src.loc) + new /obj/item/clothing/mask/cigarette/cigar/havana(src.loc) + new /obj/item/clothing/shoes/jackboots(src.loc) + qdel(src) + +/obj/effect/landmark/costume/nyangirl/New() + new /obj/item/clothing/under/schoolgirl(src.loc) + new /obj/item/clothing/head/kitty(src.loc) + qdel(src) + +/obj/effect/landmark/costume/maid/New() + new /obj/item/clothing/under/blackskirt(src.loc) + var/CHOICE = pick( /obj/item/clothing/head/beret , /obj/item/clothing/head/rabbitears ) + new CHOICE(src.loc) + new /obj/item/clothing/glasses/sunglasses/blindfold(src.loc) + qdel(src) + +/obj/effect/landmark/costume/butler/New() + new /obj/item/clothing/suit/wcoat(src.loc) + new /obj/item/clothing/under/suit_jacket(src.loc) + new /obj/item/clothing/head/that(src.loc) + qdel(src) + +/obj/effect/landmark/costume/scratch/New() + new /obj/item/clothing/gloves/color/white(src.loc) + new /obj/item/clothing/shoes/white(src.loc) + new /obj/item/clothing/under/scratch(src.loc) + if(prob(30)) + new /obj/item/clothing/head/cueball(src.loc) + qdel(src) + +/obj/effect/landmark/costume/highlander/New() + new /obj/item/clothing/under/kilt(src.loc) + new /obj/item/clothing/head/beret(src.loc) + qdel(src) + +/obj/effect/landmark/costume/prig/New() + new /obj/item/clothing/suit/wcoat(src.loc) + new /obj/item/clothing/glasses/monocle(src.loc) + var/CHOICE= pick( /obj/item/clothing/head/bowlerhat, /obj/item/clothing/head/that) + new CHOICE(src.loc) + new /obj/item/clothing/shoes/black(src.loc) + new /obj/item/weapon/cane(src.loc) + new /obj/item/clothing/under/sl_suit(src.loc) + new /obj/item/clothing/mask/fakemoustache(src.loc) + qdel(src) + +/obj/effect/landmark/costume/plaguedoctor/New() + new /obj/item/clothing/suit/bio_suit/plaguedoctorsuit(src.loc) + new /obj/item/clothing/head/plaguedoctorhat(src.loc) + qdel(src) + +/obj/effect/landmark/costume/nightowl/New() + new /obj/item/clothing/under/owl(src.loc) + new /obj/item/clothing/mask/gas/owl_mask(src.loc) + qdel(src) + +/obj/effect/landmark/costume/waiter/New() + new /obj/item/clothing/under/waiter(src.loc) + var/CHOICE= pick( /obj/item/clothing/head/kitty, /obj/item/clothing/head/rabbitears) + new CHOICE(src.loc) + new /obj/item/clothing/suit/apron(src.loc) + qdel(src) + +/obj/effect/landmark/costume/pirate/New() + new /obj/item/clothing/under/pirate(src.loc) + new /obj/item/clothing/suit/pirate_black(src.loc) + var/CHOICE = pick( /obj/item/clothing/head/pirate , /obj/item/clothing/head/bandana ) + new CHOICE(src.loc) + new /obj/item/clothing/glasses/eyepatch(src.loc) + qdel(src) + +/obj/effect/landmark/costume/commie/New() + new /obj/item/clothing/under/soviet(src.loc) + new /obj/item/clothing/head/ushanka(src.loc) + qdel(src) + + +/obj/effect/landmark/costume/imperium_monk/New() + new /obj/item/clothing/suit/imperium_monk(src.loc) + if(prob(25)) + new /obj/item/clothing/mask/gas/cyborg(src.loc) + qdel(src) + +/obj/effect/landmark/costume/holiday_priest/New() + new /obj/item/clothing/suit/holidaypriest(src.loc) + qdel(src) + +/obj/effect/landmark/costume/marisawizard/fake/New() + new /obj/item/clothing/head/wizard/marisa/fake(src.loc) + new/obj/item/clothing/suit/wizrobe/marisa/fake(src.loc) + qdel(src) + +/obj/effect/landmark/costume/cutewitch/New() + new /obj/item/clothing/under/sundress(src.loc) + new /obj/item/clothing/head/witchwig(src.loc) + new /obj/item/weapon/twohanded/staff/broom(src.loc) + qdel(src) + +/obj/effect/landmark/costume/fakewizard/New() + new /obj/item/clothing/suit/wizrobe/fake(src.loc) + new /obj/item/clothing/head/wizard/fake(src.loc) + new /obj/item/weapon/twohanded/staff/(src.loc) + qdel(src) + +/obj/effect/landmark/costume/sexyclown/New() + new /obj/item/clothing/mask/gas/sexyclown(src.loc) + new /obj/item/clothing/under/sexyclown(src.loc) + qdel(src) + +/obj/effect/landmark/costume/sexymime/New() + new /obj/item/clothing/mask/gas/sexymime(src.loc) + new /obj/item/clothing/under/sexymime(src.loc) + qdel(src) + +/obj/effect/landmark/ruin + var/datum/map_template/ruin/ruin_template + +/obj/effect/landmark/ruin/New(loc, my_ruin_template) + name = "ruin_[ruin_landmarks.len + 1]" + ..(loc) + ruin_template = my_ruin_template + ruin_landmarks |= src + +/obj/effect/landmark/ruin/Destroy() + ruin_landmarks -= src + ruin_template = null + . = ..() diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm index c9cb0c62eab..12e26827c56 100644 --- a/code/game/objects/effects/mines.dm +++ b/code/game/objects/effects/mines.dm @@ -1,94 +1,166 @@ /obj/effect/mine - name = "Mine" + name = "dummy mine" desc = "I Better stay away from that thing." - density = 1 + density = 0 anchored = 1 - layer = 3 icon = 'icons/obj/weapons.dmi' - icon_state = "uglymine" - var/triggerproc = "explode" //name of the proc thats called when the mine is triggered - var/triggered = 0 - -/obj/effect/mine/New() icon_state = "uglyminearmed" + var/triggered = 0 + +/obj/effect/mine/proc/mineEffect(mob/living/victim) + to_chat(victim, "*click*") /obj/effect/mine/Crossed(AM as mob|obj) - Bumped(AM) - -/obj/effect/mine/Bumped(mob/M as mob|obj) - - if(triggered) return - - if(istype(M, /mob/living/carbon/human)) - for(var/mob/O in viewers(world.view, src.loc)) - to_chat(O, "[M] triggered the [bicon(src)] [src]") - triggered = 1 - call(src,triggerproc)(M) - -/obj/effect/mine/proc/triggerrad(obj) + if(isanimal(AM)) + var/mob/living/simple_animal/SA = AM + if(!SA.flying) + triggermine(SA) + else + triggermine(AM) + +/obj/effect/mine/proc/triggermine(mob/living/victim) + if(triggered) + return + visible_message("[victim] sets off \icon[src] [src]!") var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread s.set_up(3, 1, src) s.start() - obj:radiation += 50 - randmutb(obj) - domutcheck(obj,null) - spawn(0) - qdel(src) - -/obj/effect/mine/proc/triggerstun(obj) - if(ismob(obj)) - var/mob/M = obj - M.Stun(30) - var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - spawn(0) - qdel(src) - -/obj/effect/mine/proc/triggern2o(obj) - atmos_spawn_air(SPAWN_N2O, 360) - spawn(0) - qdel(src) - -/obj/effect/mine/proc/triggerplasma(obj) - atmos_spawn_air(SPAWN_HEAT | SPAWN_TOXINS, 360) - spawn(0) - qdel(src) - -/obj/effect/mine/proc/triggerkick(obj) - var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread - s.set_up(3, 1, src) - s.start() - qdel(obj:client) - spawn(0) - qdel(src) - -/obj/effect/mine/proc/explode(obj) - explosion(loc, 0, 1, 2, 3) - spawn(0) - qdel(src) + mineEffect(victim) + triggered = 1 + qdel(src) + +/obj/effect/mine/explosive + name = "explosive mine" + var/range_devastation = 0 + var/range_heavy = 1 + var/range_light = 2 + var/range_flash = 3 + +/obj/effect/mine/explosive/mineEffect(mob/living/victim) + explosion(loc, range_devastation, range_heavy, range_light, range_flash) + +/obj/effect/mine/stun + name = "stun mine" + var/stun_time = 8 +/obj/effect/mine/stun/mineEffect(mob/living/victim) + if(isliving(victim)) + victim.Weaken(stun_time) + /obj/effect/mine/dnascramble name = "Radiation Mine" - icon_state = "uglymine" - triggerproc = "triggerrad" + var/radiation_amount + +/obj/effect/mine/dnascramble/mineEffect(mob/living/victim) + victim.apply_effect(radiation_amount, IRRADIATE, 0) + randmutb(victim) + domutcheck(victim ,null) -/obj/effect/mine/plasma - name = "Plasma Mine" - icon_state = "uglymine" - triggerproc = "triggerplasma" +/obj/effect/mine/gas + name = "oxygen mine" + var/gas_amount = 360 + var/gas_type = SPAWN_OXYGEN -/obj/effect/mine/kick - name = "Kick Mine" - icon_state = "uglymine" - triggerproc = "triggerkick" +/obj/effect/mine/gas/mineEffect(mob/living/victim) + atmos_spawn_air(gas_type, gas_amount) -/obj/effect/mine/n2o - name = "N2O Mine" - icon_state = "uglymine" - triggerproc = "triggern2o" +/obj/effect/mine/gas/plasma + name = "plasma mine" + gas_type = SPAWN_HEAT | SPAWN_TOXINS -/obj/effect/mine/stun - name = "Stun Mine" - icon_state = "uglymine" - triggerproc = "triggerstun" +/obj/effect/mine/gas/n2o + name = "\improper N2O mine" + gas_type = SPAWN_N2O + +/obj/effect/mine/sound + name = "honkblaster 1000" + var/sound = 'sound/items/bikehorn.ogg' + +/obj/effect/mine/sound/mineEffect(mob/living/victim) + playsound(loc, sound, 100, 1) + +/obj/effect/mine/sound/bwoink + name = "bwoink mine" + sound = 'sound/effects/adminhelp.ogg' + +/obj/effect/mine/pickup + name = "pickup" + desc = "pick me up" + icon = 'icons/effects/effects.dmi' + icon_state = "electricity2" + density = 0 + var/duration = 0 + +/obj/effect/mine/pickup/New() + ..() + animate(src, pixel_y = 4, time = 20, loop = -1) + +/obj/effect/mine/pickup/triggermine(mob/living/victim) + if(triggered) + return + triggered = 1 + invisibility = 101 + mineEffect(victim) + qdel(src) + +/obj/effect/mine/pickup/bloodbath + name = "Red Orb" + desc = "You feel angry just looking at it." + duration = 1200 //2min + color = "red" + +/obj/effect/mine/pickup/bloodbath/mineEffect(mob/living/carbon/victim) + if(!istype(victim) || !victim.client) + return + to_chat(victim, "RIP AND TEAR") + victim << 'sound/misc/e1m1.ogg' + var/old_color = victim.client.color + var/red_splash = list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0) + var/pure_red = list(0,0,0,0,0,0,0,0,0,1,0,0) + + spawn(0) + new /obj/effect/hallucination/delusion(victim.loc, victim, force_kind = "demon", duration = duration, skip_nearby = 0) + + var/obj/item/weapon/twohanded/required/chainsaw/doomslayer/chainsaw = new(victim.loc) + chainsaw.flags |= NODROP + victim.drop_l_hand() + victim.drop_r_hand() + victim.put_in_hands(chainsaw) + chainsaw.attack_self(victim) + chainsaw.wield(victim) + victim.reagents.add_reagent("adminordrazine", 25) + + victim.client.color = pure_red + animate(victim.client,color = red_splash, time = 10, easing = SINE_EASING|EASE_OUT) + spawn(10) + animate(victim.client,color = old_color, time = duration)//, easing = SINE_EASING|EASE_OUT) + spawn(duration) + to_chat(victim, "Your bloodlust seeps back into the bog of your subconscious and you regain self control.") + qdel(chainsaw) + qdel(src) + +/obj/effect/mine/pickup/healing + name = "Blue Orb" + desc = "You feel better just looking at it." + color = "blue" + +/obj/effect/mine/pickup/healing/mineEffect(mob/living/carbon/victim) + if(!victim.client || !istype(victim)) + return + to_chat(victim, "You feel great!") + victim.revive() + +/obj/effect/mine/pickup/speed + name = "Yellow Orb" + desc = "You feel faster just looking at it." + color = "yellow" + duration = 300 + +/obj/effect/mine/pickup/speed/mineEffect(mob/living/carbon/victim) + if(!victim.client || !istype(victim)) + return + to_chat(victim, "You feel fast!") + victim.status_flags |= GOTTAGOREALLYFAST + spawn(duration) + victim.status_flags &= ~GOTTAGOREALLYFAST + to_chat(victim, "You slow down.") \ No newline at end of file diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm index 94967f60c95..140c013b270 100644 --- a/code/game/objects/effects/overlays.dm +++ b/code/game/objects/effects/overlays.dm @@ -1,4 +1,3 @@ - /obj/effect/overlay name = "overlay" unacidable = 1 @@ -17,60 +16,9 @@ var/tmp/atom/BeamSource New() ..() - spawn(10) qdel(src) - - -/obj/effect/overlay/temp - anchored = 1 - layer = 4.1 - mouse_opacity = 0 - var/duration = 10 - var/randomdir = 1 - -/obj/effect/overlay/temp/New() - if(randomdir) - dir = pick(cardinal) - spawn(duration) - qdel(src) - -/obj/effect/overlay/temp/revenant - name = "spooky lights" - icon = 'icons/effects/effects.dmi' - icon_state = "purplesparkles" - -/obj/effect/overlay/temp/revenant/cracks - name = "glowing cracks" - icon_state = "purplecrack" - duration = 6 - -/obj/effect/overlay/temp/guardian - randomdir = 0 - -/obj/effect/overlay/temp/guardian/phase - duration = 5 - icon_state = "phasein" - -/obj/effect/overlay/temp/guardian/phase/out - icon_state = "phaseout" - -/obj/effect/overlay/temp/emp - name = "emp sparks" - icon = 'icons/effects/effects.dmi' - icon_state = "empdisable" - -/obj/effect/overlay/temp/emp/pulse - name = "emp pulse" - icon_state = "emp pulse" - duration = 8 - randomdir = 0 - -/obj/effect/overlay/temp/kinetic_blast - name = "kinetic explosion" - icon = 'icons/obj/projectiles.dmi' - icon_state = "kinetic_blast" - layer = 4.1 - duration = 4 - + spawn(10) + qdel(src) + /obj/effect/overlay/palmtree_r name = "Palm tree" icon = 'icons/misc/beach2.dmi' @@ -98,6 +46,152 @@ icon_state = "admin" layer = 4.1 +/obj/effect/overlay/temp + anchored = 1 + layer = 4.1 + mouse_opacity = 0 + var/duration = 10 + var/randomdir = 1 + +/obj/effect/overlay/temp/New() + if(randomdir) + dir = pick(cardinal) + + flick("[icon_state]", src) //Because we might be pulling it from a pool, flick whatever icon it uses so it starts at the start of the icon's animation. + + spawn(duration) + qdel(src) + +/obj/effect/overlay/temp/revenant + name = "spooky lights" + icon = 'icons/effects/effects.dmi' + icon_state = "purplesparkles" + +/obj/effect/overlay/temp/revenant/cracks + name = "glowing cracks" + icon_state = "purplecrack" + duration = 6 + +/obj/effect/overlay/temp/guardian + randomdir = 0 + +/obj/effect/overlay/temp/guardian/phase + duration = 5 + icon_state = "phasein" + +/obj/effect/overlay/temp/guardian/phase/out + icon_state = "phaseout" + +/obj/effect/overlay/temp/emp + name = "emp sparks" + icon = 'icons/effects/effects.dmi' + icon_state = "empdisable" + +/obj/effect/overlay/temp/emp/pulse + name = "emp pulse" + icon_state = "emppulse" + duration = 8 + randomdir = 0 + +/obj/effect/overlay/temp/heal //color is white by default, set to whatever is needed + name = "healing glow" + icon = 'icons/effects/effects.dmi' + icon_state = "heal" + duration = 15 + +/obj/effect/overlay/temp/heal/New(loc, colour) + ..() + pixel_x = rand(-12, 12) + pixel_y = rand(-9, 0) + if(colour) + color = colour + +/obj/effect/overlay/temp/kinetic_blast + name = "kinetic explosion" + icon = 'icons/obj/projectiles.dmi' + icon_state = "kinetic_blast" + layer = 4.1 + duration = 4 + +/obj/effect/overlay/temp/decoy + desc = "It's a decoy!" + duration = 15 + +/obj/effect/overlay/temp/decoy/New(loc, atom/mimiced_atom) + ..() + alpha = initial(alpha) + if(mimiced_atom) + name = mimiced_atom.name + appearance = mimiced_atom.appearance + dir = mimiced_atom.dir + mouse_opacity = 0 + +/obj/effect/overlay/temp/decoy/fading/New(loc, atom/mimiced_atom) + ..() + animate(src, alpha = 0, time = duration) + +/obj/effect/overlay/temp/cult + icon = 'icons/effects/effects.dmi' + randomdir = 0 + duration = 10 + +/obj/effect/overlay/temp/cult/sparks + randomdir = 1 + name = "blood sparks" + icon_state = "bloodsparkles" + +/obj/effect/overlay/temp/dir_setting + randomdir = FALSE + +/obj/effect/overlay/temp/dir_setting/New(loc, set_dir) + if(set_dir) + dir = set_dir + ..() + +/obj/effect/overlay/temp/dir_setting/bloodsplatter + icon = 'icons/effects/blood.dmi' + duration = 5 + randomdir = FALSE + layer = MOB_LAYER - 0.1 + var/splatter_type = "splatter" + +/obj/effect/overlay/temp/dir_setting/bloodsplatter/New(loc, set_dir) + if(set_dir in diagonals) + icon_state = "[splatter_type][pick(1, 2, 6)]" + else + icon_state = "[splatter_type][pick(3, 4, 5)]" + ..() + var/target_pixel_x = 0 + var/target_pixel_y = 0 + switch(set_dir) + if(NORTH) + target_pixel_y = 16 + if(SOUTH) + target_pixel_y = -16 + layer = MOB_LAYER + 0.1 + if(EAST) + target_pixel_x = 16 + if(WEST) + target_pixel_x = -16 + if(NORTHEAST) + target_pixel_x = 16 + target_pixel_y = 16 + if(NORTHWEST) + target_pixel_x = -16 + target_pixel_y = 16 + if(SOUTHEAST) + target_pixel_x = 16 + target_pixel_y = -16 + layer = MOB_LAYER + 0.1 + if(SOUTHWEST) + target_pixel_x = -16 + target_pixel_y = -16 + layer = MOB_LAYER + 0.1 + animate(src, pixel_x = target_pixel_x, pixel_y = target_pixel_y, alpha = 0, time = duration) + +/obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter + splatter_type = "xsplatter" + /obj/effect/overlay/wall_rot name = "Wallrot" desc = "Ick..." diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index 198c6ce45aa..3cc0f9b6023 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -53,7 +53,7 @@ By submitting this form, you accept any fines, fees, or personal injury/death that may occur during construction." w_class = 1 -/obj/item/areaeditor/permit/attack_self(mob/user as mob) +/obj/item/areaeditor/permit/attack_self(mob/user) . = ..() var/area/A = get_area() if(get_area_type() == AREA_STATION) @@ -85,7 +85,7 @@ return ..() -/obj/item/areaeditor/blueprints/attack_self(mob/user as mob) +/obj/item/areaeditor/blueprints/attack_self(mob/user) . = ..() var/area/A = get_area() if(get_area_type() == AREA_STATION) @@ -153,7 +153,7 @@ /obj/item/areaeditor/proc/get_area_type(var/area/A = get_area()) - if(istype(A,/area/space)) + if(A.outdoors) return AREA_SPACE var/list/SPECIALS = list( /area/shuttle, @@ -305,3 +305,10 @@ return ROOM_ERR_SPACE found+=T return found + +//Blueprint Subtypes + +/obj/item/areaeditor/blueprints/cyborg + name = "station schematics" + desc = "A digital copy of the station blueprints stored in your memory." + fluffnotice = "Intellectual Property of Nanotrasen. For use in engineering cyborgs only. Wipe from memory upon departure from the station." diff --git a/code/game/objects/items/stacks/sheets/leather.dm b/code/game/objects/items/stacks/sheets/leather.dm index 4678d18a2f3..46f7b3fb469 100644 --- a/code/game/objects/items/stacks/sheets/leather.dm +++ b/code/game/objects/items/stacks/sheets/leather.dm @@ -102,19 +102,49 @@ var/global/list/datum/stack_recipe/human_recipes = list( \ icon_state = "sheet-leather" origin_tech = "materials=2" +/obj/item/stack/sheet/sinew + name = "watcher sinew" + icon = 'icons/obj/mining.dmi' + desc = "Long stringy filaments which presumably came from a watcher's wings." + singular_name = "watcher sinew" + icon_state = "sinew" + origin_tech = "biotech=4" + +var/global/list/datum/stack_recipe/sinew_recipes = list ( \ + new/datum/stack_recipe("sinew restraints", /obj/item/weapon/restraints/handcuffs/sinew, 1, on_floor = 1), \ + ) +/obj/item/stack/sheet/sinew/New(var/loc, var/amount=null) + recipes = sinew_recipes + return ..() + +/obj/item/stack/sheet/animalhide/goliath_hide + name = "goliath hide plates" + desc = "Pieces of a goliath's rocky hide, these might be able to make your suit a bit more durable to attack from the local fauna." + icon = 'icons/obj/mining.dmi' + icon_state = "goliath_hide" + singular_name = "hide plate" + flags = NOBLUDGEON + w_class = 3 + layer = MOB_LAYER +/obj/item/stack/sheet/animalhide/ashdrake + name = "ash drake hide" + desc = "The strong, scaled hide of an ash drake." + icon = 'icons/obj/mining.dmi' + icon_state = "dragon_hide" + singular_name = "drake plate" + flags = NOBLUDGEON + w_class = 3 + layer = MOB_LAYER + //Step one - dehairing. /obj/item/stack/sheet/animalhide/attackby(obj/item/weapon/W as obj, mob/user as mob, params) - if( istype(W, /obj/item/weapon/kitchen/knife) || \ - istype(W, /obj/item/weapon/twohanded/fireaxe) || \ - istype(W, /obj/item/weapon/hatchet) ) - - //visible message on mobs is defined as visible_message(var/message, var/self_message, var/blind_message) - usr.visible_message("\blue \the [usr] starts cutting hair off \the [src]", "\blue You start cutting the hair off \the [src]", "You hear the sound of a knife rubbing against flesh") + if(W.sharp) + user.visible_message("[user] starts cutting hair off \the [src].", "You start cutting the hair off \the [src]...", "You hear the sound of a knife rubbing against flesh.") if(do_after(user,50, target = src)) - to_chat(usr, "\blue You cut the hair from this [src.singular_name]") + to_chat(user, "You cut the hair from this [src.singular_name].") //Try locating an exisitng stack on the tile and add to there if possible for(var/obj/item/stack/sheet/hairlesshide/HS in usr.loc) if(HS.amount < 50) @@ -128,7 +158,6 @@ var/global/list/datum/stack_recipe/human_recipes = list( \ else ..() - //Step two - washing..... it's actually in washing machine code. //Step three - drying diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 9a1bec9ecbb..4050a1ab7f3 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -270,3 +270,19 @@ var/global/list/datum/stack_recipe/runed_metal_recipes = list ( \ /obj/item/stack/sheet/runed_metal/New(var/loc, var/amount=null) recipes = runed_metal_recipes return ..() + +/* + * Bones + */ +/obj/item/stack/sheet/bone + name = "bones" + icon = 'icons/obj/mining.dmi' + icon_state = "bone" + singular_name = "bone" + desc = "Someone's been drinking their milk." + force = 7 + throwforce = 5 + w_class = 3 + throw_speed = 1 + throw_range = 3 + origin_tech = "materials=2;biotech=2" \ No newline at end of file diff --git a/code/game/objects/items/weapons/cards_ids.dm b/code/game/objects/items/weapons/cards_ids.dm index d1721c5c247..4a600fe188f 100644 --- a/code/game/objects/items/weapons/cards_ids.dm +++ b/code/game/objects/items/weapons/cards_ids.dm @@ -397,6 +397,7 @@ "medical", "HoS", "research", + "cargo", "engineering", "CMO", "RD", @@ -757,7 +758,7 @@ override_name = 1 /proc/get_station_card_skins() - return list("data","id","gold","silver","security","medical","research","engineering","HoS","CMO","RD","CE","clown","mime","rainbow","prisoner") + return list("data","id","gold","silver","security","medical","research","cargo","engineering","HoS","CMO","RD","CE","clown","mime","rainbow","prisoner") /proc/get_centcom_card_skins() return list("centcom","centcom_old","nanotrasen","ERT_leader","ERT_empty","ERT_security","ERT_engineering","ERT_medical","ERT_janitorial","deathsquad","commander","syndie","TDred","TDgreen") @@ -769,6 +770,8 @@ switch(skin) if("id") return "Standard" + if("cargo") + return "Supply" if("HoS") return "Head of Security" if("CMO") diff --git a/code/game/objects/items/weapons/defib.dm b/code/game/objects/items/weapons/defib.dm index eda6d74b296..924b5e3d590 100644 --- a/code/game/objects/items/weapons/defib.dm +++ b/code/game/objects/items/weapons/defib.dm @@ -424,6 +424,7 @@ else if(ghost) user.visible_message("[defib] buzzes: Resuscitation failed: Patient's brain is unresponsive. Further attempts may succeed.") to_chat(ghost, "Your heart is being defibrillated. Return to your body if you want to be revived! (Verbs -> Ghost -> Re-enter corpse)") + window_flash(ghost.client) ghost << sound('sound/effects/genetics.ogg') else user.visible_message("[defib] buzzes: Resuscitation failed.") @@ -546,6 +547,7 @@ else if(ghost) user.visible_message("[user] buzzes: Resuscitation failed: Patient's brain is unresponsive. Further attempts may succeed.") to_chat(ghost, "Your heart is being defibrillated. Return to your body if you want to be revived! (Verbs -> Ghost -> Re-enter corpse)") + window_flash(ghost.client) ghost << sound('sound/effects/genetics.ogg') else user.visible_message("[user] buzzes: Resuscitation failed.") diff --git a/code/game/objects/items/weapons/grenades/spawnergrenade.dm b/code/game/objects/items/weapons/grenades/spawnergrenade.dm index e93437fbe76..fe3cb3a0c12 100644 --- a/code/game/objects/items/weapons/grenades/spawnergrenade.dm +++ b/code/game/objects/items/weapons/grenades/spawnergrenade.dm @@ -20,6 +20,7 @@ for(var/i=1, i<=deliveryamt, i++) var/atom/movable/x = new spawner_type + x.admin_spawned = admin_spawned x.loc = T if(prob(50)) for(var/j = 1, j <= rand(1, 3), j++) diff --git a/code/game/objects/items/weapons/handcuffs.dm b/code/game/objects/items/weapons/handcuffs.dm index d7e4b3b7b23..7b1187bcc50 100644 --- a/code/game/objects/items/weapons/handcuffs.dm +++ b/code/game/objects/items/weapons/handcuffs.dm @@ -62,6 +62,15 @@ target.update_handcuffed() return +/obj/item/weapon/restraints/handcuffs/sinew + name = "sinew restraints" + desc = "A pair of restraints fashioned from long strands of flesh." + icon = 'icons/obj/mining.dmi' + icon_state = "sinewcuff" + item_state = "sinewcuff" + breakouttime = 300 //Deciseconds = 30s + cuffsound = 'sound/weapons/cablecuff.ogg' + /obj/item/weapon/restraints/handcuffs/cable name = "cable restraints" desc = "Looks like some cables tied together. Could be used to tie something up." diff --git a/code/game/objects/items/weapons/holy_weapons.dm b/code/game/objects/items/weapons/holy_weapons.dm index 78a88efdadb..d82ec9fdf00 100644 --- a/code/game/objects/items/weapons/holy_weapons.dm +++ b/code/game/objects/items/weapons/holy_weapons.dm @@ -189,7 +189,7 @@ sharp = 1 edge = 1 attack_verb = list("chopped", "sliced", "cut", "reaped") - hitsound = 'sound/weapons/bladeslice.ogg' + hitsound = 'sound/weapons/rapierhit.ogg' /obj/item/weapon/nullrod/scythe/vibro name = "high frequency blade" @@ -197,6 +197,14 @@ item_state = "hfrequency1" desc = "Bad references are the DNA of the soul." attack_verb = list("chopped", "sliced", "cut", "zandatsu'd") + +/obj/item/weapon/nullrod/scythe/spellblade + icon_state = "spellblade" + item_state = "spellblade" + icon = 'icons/obj/guns/magic.dmi' + name = "dormant spellblade" + desc = "The blade grants the wielder nearly limitless power...if they can figure out how to turn it on, that is." + hitsound = 'sound/weapons/rapierhit.ogg' /obj/item/weapon/nullrod/scythe/talking name = "possessed blade" @@ -204,7 +212,7 @@ item_state = "talking_sword" 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' + hitsound = 'sound/weapons/rapierhit.ogg' var/possessed = FALSE /obj/item/weapon/nullrod/scythe/talking/attack_self(mob/living/user) diff --git a/code/game/objects/items/weapons/melee/misc.dm b/code/game/objects/items/weapons/melee/misc.dm index f4b7946d0ca..7a05ca00cb6 100644 --- a/code/game/objects/items/weapons/melee/misc.dm +++ b/code/game/objects/items/weapons/melee/misc.dm @@ -35,7 +35,7 @@ edge = 1 origin_tech = "combat=5" attack_verb = list("lunged at", "stabbed") - hitsound = 'sound/weapons/slash.ogg' + hitsound = 'sound/weapons/rapierhit.ogg' materials = list(MAT_METAL = 1000) /obj/item/weapon/melee/rapier/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type) diff --git a/code/game/objects/items/weapons/twohanded.dm b/code/game/objects/items/weapons/twohanded.dm index 8e9424c4997..5c66759dc52 100644 --- a/code/game/objects/items/weapons/twohanded.dm +++ b/code/game/objects/items/weapons/twohanded.dm @@ -431,6 +431,7 @@ icon_state = "gchainsaw_off" flags = CONDUCT force = 13 + var/force_on = 21 w_class = 5 throwforce = 13 throw_speed = 2 @@ -449,8 +450,8 @@ to_chat(user, "As you pull the starting cord dangling from [src], [on ? "it begins to whirr." : "the chain stops moving."]") if(on) playsound(loc, 'sound/weapons/chainsawstart.ogg', 50, 1) - force = on ? 21 : 13 - throwforce = on ? 21 : 13 + force = on ? force_on : initial(force) + throwforce = on ? force_on : initial(force) icon_state = "gchainsaw_[on ? "on" : "off"]" if(hitsound == "swing_hit") @@ -469,6 +470,14 @@ name = "OOOH BABY" desc = "VRRRRRRR!!!" armour_penetration = 100 + force_on = 30 + +/obj/item/weapon/twohanded/required/chainsaw/doomslayer/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type) + if(attack_type == PROJECTILE_ATTACK) + owner.visible_message("Ranged attacks just make [owner] angrier!") + playsound(src, pick('sound/weapons/bulletflyby.ogg','sound/weapons/bulletflyby2.ogg','sound/weapons/bulletflyby3.ogg'), 75, 1) + return 1 + return 0 ///CHAINSAW/// diff --git a/code/game/objects/items/weapons/vending_items.dm b/code/game/objects/items/weapons/vending_items.dm index a6a53b03606..3fb54c16609 100644 --- a/code/game/objects/items/weapons/vending_items.dm +++ b/code/game/objects/items/weapons/vending_items.dm @@ -82,3 +82,8 @@ machine_name = "CritterCare" icon_state = "refill_pet" charges = 31// of 94 + +/obj/item/weapon/vending_refill/chinese + machine_name = "MrChangs" + charges = 8// of 24 + diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 26908f69180..e213c555c43 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -16,6 +16,7 @@ var/cutting_sound = 'sound/items/Welder.ogg' var/storage_capacity = 30 //This is so that someone can't pack hundreds of items in a locker/crate then open it in a populated area to crash clients. var/material_drop = /obj/item/stack/sheet/metal + var/material_drop_amount = 2 /obj/structure/closet/New() ..() @@ -49,28 +50,13 @@ return 1 /obj/structure/closet/proc/dump_contents() - //Cham Projector Exception - for(var/obj/effect/dummy/chameleon/AD in src) - AD.forceMove(loc) - - for(var/obj/I in src) - I.forceMove(loc) - - for(var/mob/M in src) - moveMob(M, loc) - -/obj/structure/closet/proc/moveMob(var/mob/M, var/atom/destination) - loc.Exited(M) - M.loc = destination - M.reset_perspective(destination) - if(isturf(loc)) - loc.Entered(M, src, ignoreRest = 1) - else - loc.Entered(M, src) - for(var/atom/movable/AM in loc) - if(istype(AM, /obj/item)) - continue - AM.Crossed(M) + var/turf/T = get_turf(src) + for(var/atom/movable/AM in src) + AM.forceMove(T) + if(throwing) // you keep some momentum when getting out of a thrown closet + step(AM, dir) + if(throwing) + throwing = 0 /obj/structure/closet/proc/open() if(src.opened) @@ -120,7 +106,7 @@ if(M.buckled) continue - moveMob(M, src) + M.forceMove(src) itemcount++ src.icon_state = src.icon_closed @@ -271,7 +257,7 @@ "You cut \the [src] apart with \the [WT].", "You hear welding.") var/turf/T = get_turf(src) - new material_drop(T) + new material_drop(T, material_drop_amount) qdel(src) return if(isrobot(user)) @@ -425,4 +411,4 @@ /obj/structure/closet/get_remote_view_fullscreens(mob/user) if(user.stat == DEAD || !(user.sight & (SEEOBJS|SEEMOBS))) - user.overlay_fullscreen("remote_view", /obj/screen/fullscreen/impaired, 1) + user.overlay_fullscreen("remote_view", /obj/screen/fullscreen/impaired, 1) \ No newline at end of file diff --git a/code/game/objects/structures/crates_lockers/closets/statue.dm b/code/game/objects/structures/crates_lockers/closets/statue.dm index c330ad11a01..3c198e4dd08 100644 --- a/code/game/objects/structures/crates_lockers/closets/statue.dm +++ b/code/game/objects/structures/crates_lockers/closets/statue.dm @@ -57,10 +57,9 @@ qdel(src) /obj/structure/closet/statue/dump_contents() - - if(istype(src.loc, /mob/living/simple_animal/hostile/statue)) - var/mob/living/simple_animal/hostile/statue/S = src.loc - src.loc = S.loc + if(istype(loc, /mob/living/simple_animal/hostile/statue)) + var/mob/living/simple_animal/hostile/statue/S = loc + forceMove(S.loc) if(S.mind) for(var/mob/M in contents) S.mind.transfer_to(M) @@ -68,21 +67,16 @@ break qdel(S) - - for(var/obj/O in src) - O.loc = src.loc - for(var/mob/living/M in src) M.forceMove(loc) M.disabilities -= MUTE M.take_overall_damage((M.health - health - 100),0) //any new damage the statue incurred is transfered to the mob - + + ..() /obj/structure/closet/statue/open() return - - /obj/structure/closet/statue/open() return @@ -158,4 +152,4 @@ obj/structure/statue/angel icon_state = "angelseen" obj/structure/statue/corgi - icon_state = "corgi" + icon_state = "corgi" \ No newline at end of file diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm index 11a0bae8849..4d03bfcdb27 100644 --- a/code/game/objects/structures/flora.dm +++ b/code/game/objects/structures/flora.dm @@ -36,6 +36,14 @@ ..() icon_state = "tree_[rand(1, 6)]" +/obj/structure/flora/tree/palm + icon = 'icons/misc/beach2.dmi' + icon_state = "palm1" + +/obj/structure/flora/tree/palm/New() + ..() + icon_state = pick("palm1","palm2") + pixel_x = 0 //grass /obj/structure/flora/grass diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index a328769d8dc..b09ef2c168e 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -43,7 +43,35 @@ new /obj/item/weapon/ore/glass(src) new /obj/item/weapon/ore/glass(src) //Make some sand if you shovel grass to_chat(user, "You shovel the grass.") + playsound(src, 'sound/effects/shovel_dig.ogg', 50, 1) make_plating() + +// NEEDS TO BE UPDATED +/turf/simulated/floor/basalt //By your powers combined, I am captain planet + name = "volcanic floor" + icon = 'icons/turf/floors.dmi' + icon_state = "basalt0" + oxygen = 14 + nitrogen = 23 + temperature = 300 + +/turf/simulated/floor/basalt/attackby(obj/item/W, mob/user, params) + if(..()) + return + if(istype(W, /obj/item/weapon/shovel)) + new /obj/item/weapon/ore/glass/basalt(src) + new /obj/item/weapon/ore/glass/basalt(src) + user.visible_message("[user] digs up [src].", "You uproot [src].") + playsound(src, 'sound/effects/shovel_dig.ogg', 50, 1) + make_plating() + +/turf/simulated/floor/basalt/New() + ..() + if(prob(15)) + icon_state = "basalt[rand(0, 12)]" + switch(icon_state) + if("basalt1", "basalt2", "basalt3") + set_light(1, 1) /turf/simulated/floor/carpet name = "Carpet" diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 8a664d184df..cb00562be9c 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -807,7 +807,8 @@ var/global/nologevent = 0 var/turf/T = get_turf(usr.loc) T.ChangeTurf(chosen) else - new chosen(usr.loc) + var/atom/A = new chosen(usr.loc) + A.admin_spawned = TRUE log_admin("[key_name(usr)] spawned [chosen] at ([usr.x],[usr.y],[usr.z])") feedback_add_details("admin_verb","SA") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 8678e3b6641..6b2224962f5 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -164,7 +164,9 @@ var/list/admin_verbs_debug = list( /client/proc/map_template_upload, /client/proc/view_runtimes, /client/proc/admin_serialize, - /client/proc/admin_deserialize + /client/proc/admin_deserialize, + /client/proc/jump_to_ruin, + /client/proc/toggle_medal_disable ) var/list/admin_verbs_possess = list( /proc/possess, diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 763ca6c3191..dc5754836d9 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -393,8 +393,11 @@ logout_status = " (snpc)" else logout_status = M.client ? "" : " (logged out)" + var/dname = M.real_name + if(!dname) + dname = M - return {"[M.real_name][caption][logout_status][M.stat == 2 ? " (DEAD)" : ""] + return {"[dname][caption][logout_status][M.stat == 2 ? " (DEAD)" : ""] PM[close ? "" : ""]"} /datum/admins/proc/check_antagonists() @@ -424,7 +427,7 @@ else dat += "Nuclear Operative not found!" dat += "
" - for(var/obj/item/weapon/disk/nuclear/N in world) + for(var/obj/item/weapon/disk/nuclear/N in poi_list) dat += "" if(can_collar) dat += "" - dat += "" + dat += "" dat += {"
Nuclear Disk(s)
[N.name], " var/atom/disk_loc = N.loc while(!istype(disk_loc, /turf)) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index bb8014037d0..4a01b1161e8 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2173,6 +2173,7 @@ else var/atom/O = new path(target) if(O) + O.admin_spawned = TRUE O.dir = obj_dir if(obj_name) O.name = obj_name diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index c17671995ff..73b481bbc6b 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -119,6 +119,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey"," for(var/client/X in modholders + adminholders) if(X.prefs.sound & SOUND_ADMINHELP) X << 'sound/effects/adminhelp.ogg' + window_flash(X) to_chat(X, msg) //show it to the person adminhelping too diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 989a7827e3d..5de3178e7ff 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -133,6 +133,7 @@ if(holder && !C.holder) recieve_message = "-- Click the [recieve_pm_type]'s name to reply --\n" if(C.adminhelped) + window_flash(C) to_chat(C, recieve_message) C.adminhelped = 0 diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index 862eed1b986..59ea8992889 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -1474,3 +1474,57 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that return error_cache.showTo(usr) + +/client/proc/jump_to_ruin() + set category = "Debug" + set name = "Jump to Ruin" + set desc = "Displays a list of all placed ruins to teleport to." + + if(!check_rights(R_DEBUG)) + return + + var/list/names = list() + for(var/i in ruin_landmarks) + var/obj/effect/landmark/ruin/ruin_landmark = i + var/datum/map_template/ruin/template = ruin_landmark.ruin_template + + var/count = 1 + var/name = template.name + var/original_name = name + + while(name in names) + count++ + name = "[original_name] ([count])" + + names[name] = ruin_landmark + + var/ruinname = input("Select ruin", "Jump to Ruin") as null|anything in names + + var/obj/effect/landmark/ruin/landmark = names[ruinname] + + if(istype(landmark)) + var/datum/map_template/ruin/template = landmark.ruin_template + admin_forcemove(usr, get_turf(landmark)) + + to_chat(usr, "[template.name]") + to_chat(usr, "[template.description]") + + log_admin("[key_name(usr)] jumped to ruin [ruinname]") + if(!isobserver(usr)) + message_admins("[key_name_admin(usr)] jumped to ruin [ruinname]", 1) + + feedback_add_details("admin_verb","JT") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! + +/client/proc/toggle_medal_disable() + set category = "Debug" + set name = "Toggle Medal Disable" + set desc = "Toggles the safety lock on trying to contact the medal hub." + + if(!check_rights(R_DEBUG)) + return + + global.medals_enabled = !global.medals_enabled + + message_admins("[key_name_admin(src)] [global.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.") + feedback_add_details("admin_verb","TMH") // If... + log_admin("[key_name(src)] [global.medals_enabled ? "disabled" : "enabled"] the medal hub lockout.") diff --git a/code/modules/admin/verbs/massmodvar.dm b/code/modules/admin/verbs/massmodvar.dm index c416f224cf9..c7b2d6d537e 100644 --- a/code/modules/admin/verbs/massmodvar.dm +++ b/code/modules/admin/verbs/massmodvar.dm @@ -137,32 +137,38 @@ for(var/mob/M in mob_list) if( istype(M , O.type) ) M.vars[variable] = O.vars[variable] + M.on_varedit(variable) else if(istype(O, /obj)) for(var/obj/A in world) if( istype(A , O.type) ) A.vars[variable] = O.vars[variable] + A.on_varedit(variable) else if(istype(O, /turf)) for(var/turf/A in world) if( istype(A , O.type) ) A.vars[variable] = O.vars[variable] + A.on_varedit(variable) else if(istype(O, /mob)) for(var/mob/M in mob_list) if(M.type == O.type) M.vars[variable] = O.vars[variable] + M.on_varedit(variable) else if(istype(O, /obj)) for(var/obj/A in world) if(A.type == O.type) A.vars[variable] = O.vars[variable] + A.on_varedit(variable) else if(istype(O, /turf)) for(var/turf/A in world) if(A.type == O.type) A.vars[variable] = O.vars[variable] + A.on_varedit(variable) if("edit referenced object") return .(O.vars[variable]) diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm index 0be55889bc2..8cce4c5a761 100644 --- a/code/modules/admin/verbs/modifyvariables.dm +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -131,7 +131,7 @@ var/list/forbidden_varedit_object_types = list( L[var_value] = mod_list_add_ass() //haha if("No") L += var_value - + /client/proc/mod_list(var/list/L) if(!check_rights(R_VAREDIT)) return @@ -440,6 +440,7 @@ var/list/forbidden_varedit_object_types = list( if(var_as_text == null) var_as_text = "[O.vars[variable]]" + O.on_varedit(variable) log_to_dd("### VarEdit by [src]: [O.type] [variable]=[html_encode("[var_as_text]")]") log_admin("[key_name(src)] modified [original_name]'s [variable] to [var_as_text]") message_admins("[key_name_admin(src)] modified [original_name]'s [variable] to [var_as_text]", 1) diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index b2864d1c7cc..4c050e0d4f3 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -26,6 +26,8 @@ var/corpseidicon = null //For setting it to be a gold, silver, centcomm etc ID var/timeofdeath = null var/coffin = 0 + var/brute_damage = 0 + var/oxy_damage = 0 /obj/effect/landmark/corpse/initialize() if(istype(src,/obj/effect/landmark/corpse/clown)) @@ -37,34 +39,36 @@ var/mob/living/carbon/human/human/M = new /mob/living/carbon/human/human (src.loc) M.real_name = src.name M.death(1) //Kills the new mob + M.adjustOxyLoss(oxy_damage) + M.adjustBruteLoss(brute_damage) M.timeofdeath = timeofdeath - if(src.mob_species) - M.set_species(src.mob_species) - if(src.corpseuniform) - M.equip_to_slot_or_del(new src.corpseuniform(M), slot_w_uniform) - if(src.corpsesuit) - M.equip_to_slot_or_del(new src.corpsesuit(M), slot_wear_suit) - if(src.corpseshoes) - M.equip_to_slot_or_del(new src.corpseshoes(M), slot_shoes) - if(src.corpsegloves) - M.equip_to_slot_or_del(new src.corpsegloves(M), slot_gloves) - if(src.corpseradio) - M.equip_to_slot_or_del(new src.corpseradio(M), slot_l_ear) - if(src.corpseglasses) - M.equip_to_slot_or_del(new src.corpseglasses(M), slot_glasses) - if(src.corpsemask) - M.equip_to_slot_or_del(new src.corpsemask(M), slot_wear_mask) - if(src.corpsehelmet) - M.equip_to_slot_or_del(new src.corpsehelmet(M), slot_head) - if(src.corpsebelt) - M.equip_to_slot_or_del(new src.corpsebelt(M), slot_belt) - if(src.corpsepocket1) - M.equip_to_slot_or_del(new src.corpsepocket1(M), slot_r_store) - if(src.corpsepocket2) - M.equip_to_slot_or_del(new src.corpsepocket2(M), slot_l_store) - if(src.corpseback) - M.equip_to_slot_or_del(new src.corpseback(M), slot_back) - if(src.corpseid == 1) + if(mob_species) + M.set_species(mob_species) + if(corpseuniform) + M.equip_to_slot_or_del(new corpseuniform(M), slot_w_uniform) + if(corpsesuit) + M.equip_to_slot_or_del(new corpsesuit(M), slot_wear_suit) + if(corpseshoes) + M.equip_to_slot_or_del(new corpseshoes(M), slot_shoes) + if(corpsegloves) + M.equip_to_slot_or_del(new corpsegloves(M), slot_gloves) + if(corpseradio) + M.equip_to_slot_or_del(new corpseradio(M), slot_l_ear) + if(corpseglasses) + M.equip_to_slot_or_del(new corpseglasses(M), slot_glasses) + if(corpsemask) + M.equip_to_slot_or_del(new corpsemask(M), slot_wear_mask) + if(corpsehelmet) + M.equip_to_slot_or_del(new corpsehelmet(M), slot_head) + if(corpsebelt) + M.equip_to_slot_or_del(new corpsebelt(M), slot_belt) + if(corpsepocket1) + M.equip_to_slot_or_del(new corpsepocket1(M), slot_r_store) + if(corpsepocket2) + M.equip_to_slot_or_del(new corpsepocket2(M), slot_l_store) + if(corpseback) + M.equip_to_slot_or_del(new corpseback(M), slot_back) + if(corpseid == 1) var/obj/item/weapon/card/id/W = new(M) W.name = "[M.real_name]'s ID Card" var/datum/job/jobdatum @@ -73,9 +77,9 @@ if(J.title == corpseidaccess) jobdatum = J break - if(src.corpseidicon) + if(corpseidicon) W.icon_state = corpseidicon - if(src.corpseidaccess) + if(corpseidaccess) if(jobdatum) W.access = jobdatum.get_access() else @@ -84,18 +88,14 @@ W.assignment = corpseidjob W.registered_name = M.real_name M.equip_to_slot_or_del(W, slot_wear_id) - if(src.coffin == 1) + if(coffin == 1) var/obj/structure/closet/coffin/sarcophagus/sarc = locate(/obj/structure/closet/coffin/sarcophagus) in loc if(sarc) M.loc = sarc qdel(src) - - // I'll work on making a list of corpses people request for maps, or that I think will be commonly used. Syndicate operatives for example. - - - - +/obj/effect/landmark/corpse/damaged + brute_damage = 1000 /obj/effect/landmark/corpse/syndicatesoldier name = "Syndicate Operative" diff --git a/code/modules/awaymissions/zlevel.dm b/code/modules/awaymissions/zlevel.dm index b12ee063f2d..f5b951eb627 100644 --- a/code/modules/awaymissions/zlevel.dm +++ b/code/modules/awaymissions/zlevel.dm @@ -205,7 +205,17 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away template = safepick(possible_ruins) if(!template) return 0 + var/turf/central_turf = get_turf(src) + for(var/i in template.get_affected_turfs(central_turf, 1)) + var/turf/T = i + for(var/mob/living/simple_animal/monster in T) + qdel(monster) + for(var/obj/structure/flora/ash/plant in T) + qdel(plant) template.load(get_turf(src),centered = 1) template.loaded++ + var/datum/map_template/ruin = template + if(istype(ruin)) + new /obj/effect/landmark/ruin(central_turf, ruin) qdel(src) return 1 diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index a558bad3dec..c9b3127094b 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -93,6 +93,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts var/show_ghostitem_attack = TRUE var/UI_style_color = "#ffffff" var/UI_style_alpha = 255 + var/windowflashing = TRUE //character preferences @@ -418,6 +419,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts dat += "

General Settings

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

" @@ -1935,6 +1937,9 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if("ghost_att_anim") show_ghostitem_attack = !show_ghostitem_attack + if("winflash") + windowflashing = !windowflashing + 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 diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm index 2713ae2dd7c..8f1b11b5ca6 100644 --- a/code/modules/client/preference/preferences_mysql.dm +++ b/code/modules/client/preference/preferences_mysql.dm @@ -14,7 +14,8 @@ nanoui_fancy, show_ghostitem_attack, lastchangelog, - exp + exp, + windowflashing FROM [format_table_name("player")] WHERE ckey='[C.ckey]'"} ) @@ -42,6 +43,7 @@ show_ghostitem_attack = text2num(query.item[12]) lastchangelog = query.item[13] exp = query.item[14] + windowflashing = text2num(query.item[15]) //Sanitize ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) @@ -57,6 +59,7 @@ show_ghostitem_attack = sanitize_integer(show_ghostitem_attack, 0, 1, initial(show_ghostitem_attack)) lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) exp = sanitize_text(exp, initial(exp)) + windowflashing = sanitize_integer(windowflashing, 0, 1, initial(windowflashing)) return 1 /datum/preferences/proc/save_preferences(client/C) diff --git a/code/modules/clothing/masks/miscellaneous.dm b/code/modules/clothing/masks/miscellaneous.dm index ee0c5ec0fb7..427cc071eda 100644 --- a/code/modules/clothing/masks/miscellaneous.dm +++ b/code/modules/clothing/masks/miscellaneous.dm @@ -340,7 +340,7 @@ icon_override = 'icons/goonstation/mob/clothing/mask.dmi' lefthand_file = 'icons/goonstation/mob/inhands/clothing_lefthand.dmi' righthand_file = 'icons/goonstation/mob/inhands/clothing_righthand.dmi' - flags = NODROP + flags = NODROP | AIRTIGHT | MASKCOVERSMOUTH /obj/item/clothing/mask/cursedclown/equipped(mob/user, slot) ..() diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/alien_infestation.dm index 5ce9d28be35..ed8b8d52ccd 100644 --- a/code/modules/events/alien_infestation.dm +++ b/code/modules/events/alien_infestation.dm @@ -29,6 +29,8 @@ respawnable_list -= C.client var/mob/living/carbon/alien/larva/new_xeno = new(vent.loc) new_xeno.key = C.key + if(ticker && ticker.mode) + ticker.mode.xenos += new_xeno.mind spawncount-- successSpawn = 1 diff --git a/code/modules/events/immovable_rod.dm b/code/modules/events/immovable_rod.dm index b1a5a0f054a..f7c48c88e23 100644 --- a/code/modules/events/immovable_rod.dm +++ b/code/modules/events/immovable_rod.dm @@ -34,8 +34,13 @@ In my current plan for it, 'solid' will be defined as anything with density == 1 loc = start z_original = z destination = end + poi_list |= src if(end && end.z==z_original) walk_towards(src, destination, 1) + +/obj/effect/immovablerod/Destroy() + poi_list.Remove(src) + return ..() /obj/effect/immovablerod/Move() if(z != z_original || loc == destination) diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index 0814bf988f4..eedae606007 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -331,4 +331,11 @@ name = "cup" desc = "A cup with the british flag emblazoned on it." icon_state = "britcup" - volume = 30 \ No newline at end of file + volume = 30 + +/obj/item/weapon/reagent_containers/food/drinks/mushroom_bowl + name = "mushroom bowl" + desc = "A bowl made out of mushrooms. Not food, though it might have contained some at some point." + icon = 'icons/obj/lavaland/ash_flora.dmi' + icon_state = "mushroom_bowl" + w_class = 2 \ No newline at end of file diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index 61ddaac84e3..3c694f993cf 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -193,14 +193,15 @@ * Item Adding ********************/ -/obj/machinery/smartfridge/attackby(obj/item/O, mob/user) - if(istype(O, /obj/item/weapon/screwdriver) && anchored) - playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) - panel_open = !panel_open - to_chat(user, "You [panel_open ? "open" : "close"] the maintenance panel.") - overlays.Cut() - if(panel_open) - overlays += image(icon, "[initial(icon_state)]-panel") +/obj/machinery/smartfridge/default_deconstruction_screwdriver(mob/user, obj/item/weapon/screwdriver/S) + . = ..(user, icon_state, icon_state, S) + + overlays.Cut() + if(panel_open) + overlays += image(icon, "[initial(icon_state)]-panel") + +/obj/machinery/smartfridge/attackby(obj/item/O, var/mob/user) + if(default_deconstruction_screwdriver(user, O)) return if(exchange_parts(user, O)) @@ -306,7 +307,7 @@ to_chat(user, "Some items are refused.") nanomanager.update_uis(src) -/obj/machinery/smartfridge/secure/emag_act(user) +/obj/machinery/smartfridge/secure/emag_act(mob/user) emagged = 1 locked = -1 to_chat(user, "You short out the product lock on [src].") @@ -535,4 +536,4 @@ to_chat(usr, "Access denied.") nanomanager.update_uis(src) return 0 - return ..() + return ..() \ No newline at end of file diff --git a/code/modules/garbage_collection/__gc_info.dm b/code/modules/garbage_collection/__gc_info.dm index be72097a8c9..e36b5fd2b1b 100644 --- a/code/modules/garbage_collection/__gc_info.dm +++ b/code/modules/garbage_collection/__gc_info.dm @@ -1,7 +1,7 @@ /* =============================================================================== - How Garbage Collection Works + How Garbage Collection Works =============================================================================== In BYOND, there are exactly two ways anything gets deleted: @@ -31,8 +31,8 @@ that can't be. There are two main procs involved in this process: /proc/qdel(datumToDelete) This is, effectively, a replacement for del that tells an object to prepare itself to be soft deleted by calling its Destroy() proc. Depending on the qdel hint returned by Destroy(), qdel will queue the object in the garbage collector - (to be hard deleted if it isn't soft deleted), directly delete the object, pool the object, or ignore the object and - assume it will handle deleting itself. An object passed into qdel will have its gcDestroyed var set, so + (to be hard deleted if it isn't soft deleted), directly delete the object, or ignore the object and + assume it will handle deleting itself. An object passed into qdel will have its gcDestroyed var set, so isnull(gcDestroyed) will be true if an object is not being destroyed, and false if it is (which means you should get rid of the reference you have to it). @@ -50,7 +50,7 @@ that can't be. There are two main procs involved in this process: should use a Del proc for any necessary cleanup, as a Destroy proc on them will not automatically get called. When called by qdel, Destroy is expected to return a qdel hint, which determines whether the object should be directly - deleted, queued for deletion, pooled, or ignored entirely; which of these are appropriate will vary, though objects + deleted, queued for deletion, or ignored entirely; which of these are appropriate will vary, though objects should be pooled or queued whenever possible. The full list of qdel hints are in the code for the qdel proc. As mentioned above, gcDestroyed can be used to tell whether an object is being destroyed. This is important, because if @@ -62,7 +62,4 @@ reference immediately. The inner workings of the GC itself and the stuff related to testing it probably don't need a detailed description - if you intend to work with them, it would be best to read the code to understand what they do. -Pooling is related to GC, in that it's meant to reduce deletion overhead, but it does so by re-using objects instead of -deleting them at all. Explaining pooling is outside the scope of this file. - */ \ No newline at end of file diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm index e573c20840e..712fca9592a 100644 --- a/code/modules/mining/equipment_locker.dm +++ b/code/modules/mining/equipment_locker.dm @@ -727,7 +727,7 @@ ranged = 1 sentience_type = SENTIENCE_MINEBOT ranged_message = "shoots" - ranged_cooldown_cap = 3 + ranged_cooldown_time = 30 projectiletype = /obj/item/projectile/kinetic projectilesound = 'sound/weapons/Gunshot4.ogg' speak_emote = list("states") @@ -978,10 +978,10 @@ name = "minebot cooldown upgrade" /obj/item/device/mine_bot_ugprade/cooldown/upgrade_bot(mob/living/simple_animal/hostile/mining_drone/M, mob/user) - if(M.ranged_cooldown_cap != initial(M.ranged_cooldown_cap)) + if(M.ranged_cooldown_time != initial(M.ranged_cooldown_time)) to_chat(user, "[M] already has a decreased weapon cooldown!") return - M.ranged_cooldown_cap = 1 + M.ranged_cooldown_time = 10 to_chat(user, "You upgrade [M]'s ranged weaponry, reducing its cooldown.") qdel(src) diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm new file mode 100644 index 00000000000..922dd34a166 --- /dev/null +++ b/code/modules/mining/lavaland/ash_flora.dm @@ -0,0 +1,205 @@ +/obj/structure/flora/ash + gender = PLURAL + icon = 'icons/obj/lavaland/ash_flora.dmi' + icon_state = "l_mushroom" + name = "large mushrooms" + desc = "A number of large mushrooms, covered in a faint layer of ash and what can only be spores." + var/harvested_name = "shortened mushrooms" + var/harvested_desc = "Some quickly regrowing mushrooms, formerly known to be quite large." + var/needs_sharp_harvest = TRUE + var/harvest = /obj/item/weapon/reagent_containers/food/snacks/ash_flora/shavings + var/harvest_amount_low = 1 + var/harvest_amount_high = 3 + var/harvest_time = 60 + var/harvest_message_low = "You pick a mushroom, but fail to collect many shavings from its cap." + var/harvest_message_med = "You pick a mushroom, carefully collecting the shavings from its cap." + var/harvest_message_high = "You harvest and collect shavings from several mushroom caps." + var/harvested = FALSE + var/base_icon + var/regrowth_time_low = 4800 + var/regrowth_time_high = 8400 + +/obj/structure/flora/ash/New() + ..() + base_icon = "[icon_state][rand(1, 4)]" + icon_state = base_icon + if(prob(15)) + harvest(null, TRUE) + +/obj/structure/flora/ash/proc/harvest(user, no_drop) + if(harvested) + return 0 + if(!no_drop) + var/rand_harvested = rand(harvest_amount_low, harvest_amount_high) + if(rand_harvested) + if(user) + var/msg = harvest_message_med + if(rand_harvested == harvest_amount_low) + msg = harvest_message_low + else if(rand_harvested == harvest_amount_high) + msg = harvest_message_high + to_chat(user, "[msg]") + for(var/i in 1 to rand_harvested) + new harvest(get_turf(src)) + icon_state = "[base_icon]p" + name = harvested_name + desc = harvested_desc + harvested = TRUE + addtimer(src, "regrow", rand(regrowth_time_low, regrowth_time_high)) + return 1 + +/obj/structure/flora/ash/proc/regrow() + icon_state = base_icon + name = initial(name) + desc = initial(desc) + harvested = FALSE + +/obj/structure/flora/ash/attackby(obj/item/weapon/W, mob/user, params) + if(!harvested && needs_sharp_harvest && W.sharp) + user.visible_message("[user] starts to harvest from [src] with [W].","You begin to harvest from [src] with [W].") + if(do_after(user, harvest_time, target = src)) + harvest(user) + else + return ..() + +/obj/structure/flora/ash/attack_hand(mob/user) + if(!harvested && !needs_sharp_harvest) + user.visible_message("[user] starts to harvest from [src].","You begin to harvest from [src].") + if(do_after(user, harvest_time, target = src)) + harvest(user) + else + ..() + +/obj/structure/flora/ash/tall_shroom //exists only so that the spawning check doesn't allow these spawning near other things + regrowth_time_low = 4200 + +/obj/structure/flora/ash/leaf_shroom + icon_state = "s_mushroom" + name = "leafy mushrooms" + desc = "A number of mushrooms, each of which surrounds a greenish sporangium with a number of leaf-like structures." + harvested_name = "leafless mushrooms" + harvested_desc = "A bunch of formerly-leafed mushrooms, with their sporangiums exposed. Scandalous?" + harvest = /obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_leaf + needs_sharp_harvest = FALSE + harvest_amount_high = 4 + harvest_time = 20 + harvest_message_low = "You pluck a single, suitable leaf." + harvest_message_med = "You pluck a number of leaves, leaving a few unsuitable ones." + harvest_message_high = "You pluck quite a lot of suitable leaves." + regrowth_time_low = 2400 + regrowth_time_high = 6000 + +/obj/structure/flora/ash/cap_shroom + icon_state = "r_mushroom" + name = "tall mushrooms" + desc = "Several mushrooms, the larger of which have a ring of conks at the midpoint of their stems." + harvested_name = "small mushrooms" + harvested_desc = "Several small mushrooms near the stumps of what likely were larger mushrooms." + harvest = /obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_cap + harvest_amount_high = 4 + harvest_time = 50 + harvest_message_low = "You slice the cap off of a mushroom." + harvest_message_med = "You slice off a few conks from the larger mushrooms." + harvest_message_high = "You slice off a number of caps and conks from these mushrooms." + regrowth_time_low = 3000 + regrowth_time_high = 5400 + +/obj/structure/flora/ash/stem_shroom + icon_state = "t_mushroom" + name = "numerous mushrooms" + desc = "A large number of mushrooms, some of which have long, fleshy stems. They're radiating light!" + luminosity = 1 + harvested_name = "tiny mushrooms" + harvested_desc = "A few tiny mushrooms around larger stumps. You can already see them growing back." + harvest = /obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_stem + harvest_amount_high = 4 + harvest_time = 40 + harvest_message_low = "You pick and slice the cap off of a mushroom, leaving the stem." + harvest_message_med = "You pick and decapitate several mushrooms for their stems." + harvest_message_high = "You acquire a number of stems from these mushrooms." + regrowth_time_low = 3000 + regrowth_time_high = 6000 + +/obj/structure/flora/ash/cacti + icon_state = "cactus" + name = "fruiting cacti" + desc = "Several prickly cacti, brimming with ripe fruit and covered in a thin layer of ash." + harvested_name = "cacti" + harvested_desc = "A bunch of prickly cacti. You can see fruits slowly growing beneath the covering of ash." + harvest = /obj/item/weapon/reagent_containers/food/snacks/ash_flora/cactus_fruit + needs_sharp_harvest = FALSE + harvest_amount_high = 2 + harvest_time = 10 + harvest_message_low = "You pick a cactus fruit." + harvest_message_med = "You pick several cactus fruit." //shouldn't show up, because you can't get more than two + harvest_message_high = "You pick a pair of cactus fruit." + regrowth_time_low = 4800 + regrowth_time_high = 7200 + +/obj/structure/flora/ash/cacti/Crossed(mob/AM) + if(ishuman(AM) && has_gravity(loc) && prob(70)) + var/mob/living/carbon/human/H = AM + if(!H.shoes && !H.lying) //ouch, my feet. + var/picked_def_zone = pick("l_leg", "r_leg") + var/obj/item/organ/external/affected = H.get_organ(picked_def_zone) + if(!istype(affected)) + return + H.apply_damage(rand(3, 6), BRUTE, picked_def_zone) + H.Weaken(2) + H.visible_message("[H] steps on a cactus!", \ + "You step on a cactus!") + +/obj/item/weapon/reagent_containers/food/snacks/ash_flora + name = "mushroom shavings" + desc = "Some shavings from a tall mushroom. With enough, might serve as a bowl." + icon = 'icons/obj/lavaland/ash_flora.dmi' + icon_state = "mushroom_shavings" + list_reagents = list("sugar" = 3, "ethanol" = 2, "stabilizing_agent" = 3, "minttoxin" = 2) + w_class = 1 + +/obj/item/weapon/reagent_containers/food/snacks/ash_flora/New() + ..() + pixel_x = rand(-4, 4) + pixel_y = rand(-4, 4) + +/obj/item/weapon/reagent_containers/food/snacks/ash_flora/shavings //for actual crafting + +/obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_leaf + name = "mushroom leaf" + desc = "A leaf, from a mushroom." + list_reagents = list("nutriment" = 3, "vitfro" = 2, "nicotine" = 2) + icon_state = "mushroom_leaf" + +/obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_cap + name = "mushroom cap" + desc = "The cap of a large mushroom." + list_reagents = list("lsd" = 2, "entpoly" = 4, "psilocybin" = 2) + icon_state = "mushroom_cap" + +/obj/item/weapon/reagent_containers/food/snacks/ash_flora/mushroom_stem + name = "mushroom stem" + desc = "A long mushroom stem. It's slightly glowing." + list_reagents = list("tinlux" = 2, "vitamin" = 1, "space_drugs" = 1) + icon_state = "mushroom_stem" + luminosity = 1 + +/obj/item/weapon/reagent_containers/food/snacks/ash_flora/cactus_fruit + name = "cactus fruit" + list_reagents = list("vitamin" = 2, "nutriment" = 2, "vitfro" = 4) + desc = "A cactus fruit covered in a thick, reddish skin. And some ash." + icon_state = "cactus_fruit" + +/obj/item/mushroom_bowl + name = "mushroom bowl" + desc = "A bowl made out of mushrooms. Not food, though it might have contained some at some point." + icon = 'icons/obj/lavaland/ash_flora.dmi' + icon_state = "mushroom_bowl" + w_class = 2 + +//what you can craft with these things +/datum/crafting_recipe/mushroom_bowl + name = "Mushroom Bowl" + result = /obj/item/weapon/reagent_containers/food/drinks/mushroom_bowl + reqs = list(/obj/item/weapon/reagent_containers/food/snacks/ash_flora/shavings = 5) + time = 30 + category = CAT_PRIMAL diff --git a/code/modules/mining/lavaland/colossus_loot.dm b/code/modules/mining/lavaland/colossus_loot.dm new file mode 100644 index 00000000000..1928ff0f342 --- /dev/null +++ b/code/modules/mining/lavaland/colossus_loot.dm @@ -0,0 +1,493 @@ +//Black Box + +/obj/machinery/smartfridge/black_box + name = "black box" + desc = "A completely indestructible chunk of crystal, rumoured to predate the start of this universe. It looks like you could store things inside it." + icon = 'icons/obj/lavaland/artefacts.dmi' + icon_state = "blackbox" + icon_on = "blackbox" + icon_off = "blackbox" + luminosity = 8 + max_n_of_items = INFINITY + unacidable = 1 + pixel_y = -4 + use_power = 0 + var/memory_saved = FALSE + var/list/stored_items = list() + var/static/list/blacklist = typecacheof(list(/obj/item/weapon/spellbook)) + +/obj/machinery/smartfridge/black_box/update_icon() + return + +/obj/machinery/smartfridge/black_box/accept_check(obj/item/O) + if(!istype(O)) + return FALSE + if(is_type_in_typecache(O, blacklist)) + return FALSE + return TRUE + +/obj/machinery/smartfridge/black_box/New() + var/static/obj/machinery/smartfridge/black_box/current + if(current && current != src) + qdel(src, force=TRUE) + return + current = src + ReadMemory() + . = ..() + +/obj/machinery/smartfridge/black_box/process() + ..() + if(!memory_saved && ticker.current_state == GAME_STATE_FINISHED) + WriteMemory() + +/obj/machinery/smartfridge/black_box/proc/WriteMemory() + var/savefile/S = new /savefile("data/npc_saves/Blackbox.sav") + stored_items = list() + + for(var/obj/O in (contents-component_parts)) + stored_items += O.type + + S["stored_items"] << stored_items + memory_saved = TRUE + +/obj/machinery/smartfridge/black_box/proc/ReadMemory() + var/savefile/S = new /savefile("data/npc_saves/Blackbox.sav") + S["stored_items"] >> stored_items + + if(isnull(stored_items)) + stored_items = list() + + for(var/item in stored_items) + create_item(item) + +//in it's own proc to avoid issues with items that nolonger exist in the code base. +//try catch doesn't always prevent byond runtimes from halting a proc, +/obj/machinery/smartfridge/black_box/proc/create_item(item_type) + new item_type(src) + +/obj/machinery/smartfridge/black_box/Destroy(force = FALSE) + if(force) + for(var/thing in src) + qdel(thing) + return ..() + else + return QDEL_HINT_LETMELIVE + + +//No taking it apart + +/obj/machinery/smartfridge/black_box/default_deconstruction_screwdriver() + return + +/obj/machinery/smartfridge/black_box/exchange_parts() + return + +/obj/machinery/smartfridge/black_box/default_unfasten_wrench() + return + +/obj/machinery/smartfridge/black_box/default_deconstruction_crowbar() + return + +///Anomolous Crystal/// + +/obj/machinery/anomalous_crystal + name = "anomalous crystal" + desc = "A strange chunk of crystal, being in the presence of it fills you with equal parts excitement and dread." + icon = 'icons/obj/lavaland/artefacts.dmi' + icon_state = "anomaly_crystal" + luminosity = 8 + use_power = 0 + density = 1 + unacidable = 1 + var/activation_method = "touch" + var/activation_damage_type = null + var/last_use_timer = 0 + var/cooldown_add = 30 + var/list/affected_targets = list() + var/activation_sound = 'sound/effects/break_stone.ogg' + +/obj/machinery/anomalous_crystal/New() + activation_method = pick("touch","laser","bullet","energy","bomb","mob_bump","weapon","speech") // "heat" removed due to lack of is_hot() + ..() + +/obj/machinery/anomalous_crystal/hear_talk(mob/speaker, message) + ..() + if(isliving(speaker) && message) + ActivationReaction(speaker, "speech") + +/obj/machinery/anomalous_crystal/attack_hand(mob/user) + ..() + ActivationReaction(user,"touch") + +/obj/machinery/anomalous_crystal/attackby(obj/item/I, mob/user, params) + ActivationReaction(user,"weapon") + ..() + +/obj/machinery/anomalous_crystal/bullet_act(obj/item/projectile/P, def_zone) + ..() + if(istype(P, /obj/item/projectile/magic)) + ActivationReaction(P.firer, "magic", P.damage_type) + return + ActivationReaction(P.firer, P.flag, P.damage_type) + +/obj/machinery/anomalous_crystal/proc/ActivationReaction(mob/user, method, damtype) + if(world.time < last_use_timer) + return 0 + if(activation_damage_type && activation_damage_type != damtype) + return 0 + if(method != activation_method) + return 0 + last_use_timer = (world.time + cooldown_add) + playsound(user, activation_sound, 100, 1) + return 1 + +/obj/machinery/anomalous_crystal/Bumped(atom/AM as mob|obj) + ..() + if(ismob(AM)) + ActivationReaction(AM,"mob_bump") + +/obj/machinery/anomalous_crystal/ex_act() + ActivationReaction(null,"bomb") + +/obj/machinery/anomalous_crystal/random/New()//Just a random crysal spawner for loot + var/random_crystal = pick(typesof(/obj/machinery/anomalous_crystal) - /obj/machinery/anomalous_crystal/random - /obj/machinery/anomalous_crystal) + new random_crystal(loc) + qdel(src) + +/obj/machinery/anomalous_crystal/honk //Strips and equips you as a clown. I apologize for nothing + activation_method = "mob_bump" + activation_sound = 'sound/items/bikehorn.ogg' + +/obj/machinery/anomalous_crystal/honk/ActivationReaction(mob/user) + if(..() && ishuman(user) && !(user in affected_targets)) + var/mob/living/carbon/human/H = user + for(var/obj/item/W in H) + H.unEquip(W) + var/datum/job/clown/C = job_master.GetJob("Clown") + C.equip(H) + affected_targets.Add(H) + +/obj/machinery/anomalous_crystal/honk/New() + ..() + activation_method = pick("mob_bump","speech") + +/obj/machinery/anomalous_crystal/theme_warp //Warps the area you're in to look like a new one + activation_method = "touch" + cooldown_add = 200 + var/terrain_theme = "winter" + var/NewTerrainFloors + var/NewTerrainWalls + var/NewTerrainChairs + var/NewTerrainTables + var/list/NewFlora = list() + var/florachance = 8 + +/obj/machinery/anomalous_crystal/theme_warp/New() + ..() + terrain_theme = pick("lavaland","winter","jungle","alien") + switch(terrain_theme) + if("lavaland")//Depressurizes the place... and free cult metal, I guess. + NewTerrainFloors = /turf/simulated/floor/basalt // Needs to be updated after turf update + NewTerrainWalls = /turf/simulated/wall/cult + NewFlora = list(/mob/living/simple_animal/hostile/asteroid/goldgrub) + florachance = 1 + if("winter") //Snow terrain is slow to move in and cold! Get the assistants to shovel your driveway. + NewTerrainFloors = /turf/simulated/floor/snow // Needs to be updated after turf update + NewTerrainWalls = /turf/simulated/wall/mineral/wood + NewTerrainChairs = /obj/structure/stool/bed/chair/wood/normal + NewTerrainTables = /obj/structure/table/glass + NewFlora = list(/obj/structure/flora/grass/green, /obj/structure/flora/grass/brown, /obj/structure/flora/grass/both) + if("jungle") //Beneficial due to actually having breathable air. Plus, monkeys and bows and arrows. + NewTerrainFloors = /turf/simulated/floor/grass + NewTerrainWalls = /turf/simulated/wall/mineral/sandstone + NewTerrainChairs = /obj/structure/stool/bed/chair/wood/normal + NewTerrainTables = /obj/structure/table/woodentable + NewFlora = list(/obj/structure/flora/ausbushes/sparsegrass, /obj/structure/flora/ausbushes/fernybush, /obj/structure/flora/ausbushes/leafybush, + /obj/structure/flora/ausbushes/grassybush, /obj/structure/flora/ausbushes/sunnybush, /obj/structure/flora/tree/palm, /mob/living/carbon/human/monkey, + /obj/item/weapon/gun/projectile/bow, /obj/item/weapon/storage/backpack/quiver/full) + florachance = 20 + if("alien") //Beneficial, turns stuff into alien alloy which is useful to cargo and research. Also repairs atmos. + NewTerrainFloors = /turf/simulated/floor/mineral/abductor + NewTerrainWalls = /turf/simulated/wall/mineral/abductor + NewTerrainChairs = /obj/structure/stool/bed/abductor //ayys apparently don't have chairs. An entire species of people who only recline. + NewTerrainTables = /obj/structure/table/abductor + +/obj/machinery/anomalous_crystal/theme_warp/ActivationReaction(mob/user, method) + if(..()) + var/area/A = get_area(src) + if(!A.outdoors && !(A in affected_targets)) + for(var/atom/Stuff in A) + if(isturf(Stuff)) + var/turf/T = Stuff + if((isspaceturf(T) || isfloorturf(T)) && NewTerrainFloors) + var/turf/simulated/O = T.ChangeTurf(NewTerrainFloors) + if(O.air) + var/datum/gas_mixture/G = O.air + G.copy_from(O.air) + if(prob(florachance) && NewFlora.len && !is_blocked_turf(O)) + var/atom/Picked = pick(NewFlora) + new Picked(O) + continue + if(iswallturf(T) && NewTerrainWalls) + T.ChangeTurf(NewTerrainWalls) + continue + if(istype(Stuff, /obj/structure/stool/bed/chair) && NewTerrainChairs) + var/obj/structure/stool/bed/chair/Original = Stuff + var/obj/structure/stool/bed/chair/C = new NewTerrainChairs(Original.loc) + C.dir = Original.dir + qdel(Stuff) + continue + if(istype(Stuff, /obj/structure/table) && NewTerrainTables) + var/obj/structure/table/Original = Stuff + var/obj/structure/table/T = new NewTerrainTables(Original.loc) + T.dir = Original.dir + qdel(Stuff) + continue + affected_targets += A + +/obj/machinery/anomalous_crystal/emitter //Generates a projectile when interacted with + activation_method = "touch" + cooldown_add = 50 + var/generated_projectile = /obj/item/projectile/beam/emitter + +/obj/machinery/anomalous_crystal/emitter/New() + ..() + generated_projectile = pick(/obj/item/projectile/magic/fireball/infernal,/obj/item/projectile/magic/spellblade, + /obj/item/projectile/bullet/meteorshot, /obj/item/projectile/beam/xray, /obj/item/projectile/colossus) + +/obj/machinery/anomalous_crystal/emitter/ActivationReaction(mob/user, method) + if(..()) + var/obj/item/projectile/P = new generated_projectile(get_turf(src)) + P.dir = dir + switch(dir) + if(NORTH) + P.yo = 20 + P.xo = 0 + if(EAST) + P.yo = 0 + P.xo = 20 + if(WEST) + P.yo = 0 + P.xo = -20 + else + P.yo = -20 + P.xo = 0 + P.fire() + +/obj/machinery/anomalous_crystal/dark_reprise //Revives anyone nearby, but turns them into shadowpeople and renders them uncloneable, so the crystal is your only hope of getting up again if you go down. + activation_method = "touch" + activation_sound = 'sound/hallucinations/growl1.ogg' + +/obj/machinery/anomalous_crystal/dark_reprise/ActivationReaction(mob/user, method) + if(..()) + for(var/i in range(1, src)) + if(isturf(i)) + new /obj/effect/overlay/temp/cult/sparks(i) + continue + if(ishuman(i)) + var/mob/living/carbon/human/H = i + if(H.stat == DEAD) + H.set_species("Shadow") + H.revive() + H.disabilities |= NOCLONE //Free revives, but significantly limits your options for reviving except via the crystal + H.grab_ghost(force = TRUE) + +/obj/machinery/anomalous_crystal/helpers //Lets ghost spawn as helpful creatures that can only heal people slightly. Incredibly fragile and they can't converse with humans + activation_method = "touch" + var/ready_to_deploy = 0 + +/obj/machinery/anomalous_crystal/helpers/ActivationReaction(mob/user, method) + if(..() && !ready_to_deploy) + ready_to_deploy = 1 + notify_ghosts("An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.", enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK) + +/obj/machinery/anomalous_crystal/helpers/attack_ghost(mob/dead/observer/user) + ..() + if(ready_to_deploy) + var/be_helper = alert("Become a Lightgeist? (Warning, You can no longer be cloned!)",,"Yes","No") + if(be_helper == "No") + return + var/mob/living/simple_animal/hostile/lightgeist/W = new /mob/living/simple_animal/hostile/lightgeist(get_turf(loc)) + W.key = user.key + +/obj/machinery/anomalous_crystal/helpers/Topic(href, href_list) + if(href_list["ghostjoin"]) + var/mob/dead/observer/ghost = usr + if(istype(ghost)) + attack_ghost(ghost) + +/mob/living/simple_animal/hostile/lightgeist + name = "lightgeist" + desc = "This small floating creature is a completely unknown form of life... being near it fills you with a sense of tranquility." + icon_state = "lightgeist" + icon_living = "lightgeist" + icon_dead = "butterfly_dead" + turns_per_move = 1 + response_help = "waves away" + response_disarm = "brushes aside" + response_harm = "disrupts" + speak_emote = list("oscillates") + maxHealth = 2 + health = 2 + harm_intent_damage = 1 + friendly = "mends" + density = 0 + flying = 1 + pass_flags = PASSTABLE | PASSGRILLE | PASSMOB + ventcrawler = 2 + mob_size = MOB_SIZE_TINY + gold_core_spawnable = 0 + speak_emote = list("warps") + damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) + luminosity = 4 + faction = list("neutral") + universal_understand = 1 + del_on_death = 1 + unsuitable_atmos_damage = 0 + flying = 1 + minbodytemp = 0 + maxbodytemp = 1500 + environment_smash = 0 + AIStatus = AI_OFF + stop_automated_movement = 1 + var/heal_power = 5 + +/mob/living/simple_animal/hostile/lightgeist/New() + ..() + verbs -= /mob/living/verb/pulled + verbs -= /mob/verb/me_verb + var/datum/atom_hud/medsensor = huds[DATA_HUD_MEDICAL_ADVANCED] + medsensor.add_hud_to(src) + +/mob/living/simple_animal/hostile/lightgeist/AttackingTarget() + ..() + if(isliving(target) && target != src) + var/mob/living/L = target + if(L.stat < DEAD) + L.heal_overall_damage(heal_power, heal_power) + new /obj/effect/overlay/temp/heal(get_turf(target), "#80F5FF") + +/mob/living/simple_animal/hostile/lightgeist/ghostize() + if(..()) + death() + +/obj/machinery/anomalous_crystal/refresher //Deletes and recreates a copy of the item, "refreshing" it. + activation_method = "touch" + cooldown_add = 50 + activation_sound = 'sound/magic/TIMEPARADOX2.ogg' + var/list/banned_items_typecache = list(/obj/item/weapon/storage, /obj/item/weapon/implant, /obj/item/weapon/implanter, /obj/item/weapon/disk/nuclear, /obj/item/projectile, /obj/item/weapon/spellbook) + +/obj/machinery/anomalous_crystal/refresher/New() + ..() + banned_items_typecache = typecacheof(banned_items_typecache) + + +/obj/machinery/anomalous_crystal/refresher/ActivationReaction(mob/user, method) + if(..()) + var/list/L = list() + var/turf/T = get_step(src, dir) + new /obj/effect/overlay/temp/emp/pulse(T) + for(var/i in T) + if(istype(i, /obj/item) && !is_type_in_typecache(i, banned_items_typecache)) + var/obj/item/W = i + if(!W.admin_spawned) + L += W + if(L.len) + var/obj/item/CHOSEN = pick(L) + new CHOSEN.type(T) + qdel(CHOSEN) + +/obj/machinery/anomalous_crystal/possessor //Allows you to bodyjack small animals, then exit them at your leisure, but you can only do this once per activation. Because they blow up. Also, if the bodyjacked animal dies, SO DO YOU. + activation_method = "touch" + +/obj/machinery/anomalous_crystal/possessor/ActivationReaction(mob/user, method) + if(..()) + if(ishuman(user)) + var/mobcheck = 0 + for(var/mob/living/simple_animal/A in range(1, src)) + if(A.melee_damage_upper > 5 || A.mob_size >= MOB_SIZE_LARGE || A.ckey || A.stat) + break + var/obj/structure/closet/stasis/S = new /obj/structure/closet/stasis(A) + user.forceMove(S) + mobcheck = 1 + break + if(!mobcheck) + new /mob/living/simple_animal/cockroach(get_step(src,dir)) //Just in case there aren't any animals on the station, this will leave you with a terrible option to possess if you feel like it + +/obj/structure/closet/stasis + name = "quantum entanglement stasis warp field" + desc = "You can hardly comprehend this thing... which is why you can't see it." + icon_state = null //This shouldn't even be visible, so if it DOES show up, at least nobody will notice + density = 1 + anchored = 1 + var/mob/living/simple_animal/holder_animal + +/obj/structure/closet/stasis/process() + if(holder_animal) + if(holder_animal.stat == DEAD && !qdeleted(holder_animal)) + dump_contents() + holder_animal.gib() + return + +/obj/structure/closet/stasis/New() + ..() + if(isanimal(loc)) + holder_animal = loc + processing_objects.Add(src) + +/obj/structure/closet/stasis/Entered(atom/A) + if(isliving(A) && holder_animal) + var/mob/living/L = A + L.notransform = 1 + L.disabilities |= MUTE + L.status_flags |= GODMODE + L.mind.transfer_to(holder_animal) + var/obj/effect/proc_holder/spell/targeted/exit_possession/P = new /obj/effect/proc_holder/spell/targeted/exit_possession + holder_animal.mind.AddSpell(P) + holder_animal.verbs -= /mob/living/verb/pulled + +/obj/structure/closet/stasis/dump_contents(var/kill = 1) + processing_objects.Remove(src) + for(var/mob/living/L in src) + L.disabilities &= ~MUTE + L.status_flags &= ~GODMODE + L.notransform = 0 + if(holder_animal && !qdeleted(holder_animal)) + holder_animal.mind.transfer_to(L) + L.mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/exit_possession) + if(kill || !isanimal(loc)) + L.death(0) + ..() + +/obj/structure/closet/stasis/emp_act() + return + +/obj/structure/closet/stasis/ex_act() + return + +/obj/effect/proc_holder/spell/targeted/exit_possession + name = "Exit Possession" + desc = "Exits the body you are possessing" + charge_max = 60 + clothes_req = 0 + invocation_type = "none" + max_targets = 1 + range = -1 + include_user = 1 + selection_type = "view" + action_icon_state = "exit_possession" + sound = null + +/obj/effect/proc_holder/spell/targeted/exit_possession/cast(list/targets, mob/user = usr) + if(!isfloorturf(user.loc)) + return + var/datum/mind/target_mind = user.mind + var/mob/living/current = user // Saving the current mob here to gib as usr seems to get confused after the mind's been transferred, due to delay in transfer_to + for(var/i in user) + if(istype(i, /obj/structure/closet/stasis)) + var/obj/structure/closet/stasis/S = i + S.dump_contents(0) + qdel(S) + break + current.gib() + target_mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/exit_possession) diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm new file mode 100644 index 00000000000..649a868077d --- /dev/null +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -0,0 +1,618 @@ +//The chests dropped by mob spawner tendrils. Also contains associated loot. + +/obj/structure/closet/crate/necropolis + name = "necropolis chest" + desc = "It's watching you closely." + icon_state = "necrocrate" + icon_opened = "necrocrateopen" + icon_closed = "necrocrate" + +/obj/structure/closet/crate/necropolis/tendril + desc = "It's watching you suspiciously." + +/obj/structure/closet/crate/necropolis/tendril/New() + ..() + // uncomment me once these items are being implemented + /*var/loot = rand(1,25) + switch(loot) + if(1) + new /obj/item/device/shared_storage/red(src) + if(2) + new /obj/item/clothing/suit/space/hardsuit/cult(src) + if(3) + new /obj/item/device/soulstone/anybody(src) + if(4) + new /obj/item/weapon/katana/cursed(src) + if(5) + new /obj/item/clothing/glasses/godeye(src) + if(6) + new /obj/item/weapon/reagent_containers/glass/bottle/potion/flight(src) + if(7) + new /obj/item/weapon/pickaxe/diamond(src) + if(8) + new /obj/item/clothing/head/culthood(src) + new /obj/item/clothing/suit/cultrobes(src) + new /obj/item/weapon/bedsheet/cult(src) + if(9) + new /obj/item/organ/brain/alien(src) + if(10) + new /obj/item/organ/heart/cursed(src) + if(11) + new /obj/item/ship_in_a_bottle(src) + if(12) + new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/beserker(src) + if(13) + new /obj/item/weapon/sord(src) + if(14) + new /obj/item/weapon/nullrod/scythe/talking(src) + if(15) + new /obj/item/weapon/nullrod/armblade(src) + if(16) + new /obj/item/weapon/guardiancreator(src) + if(17) + new /obj/item/borg/upgrade/modkit/aoe/turfs/andmobs(src) + if(18) + new /obj/item/device/warp_cube/red(src) + if(19) + new /obj/item/device/wisp_lantern(src) + if(20) + new /obj/item/device/immortality_talisman(src) + if(21) + new /obj/item/weapon/gun/magic/hook(src) + if(22) + new /obj/item/voodoo(src) + if(23) + new /obj/item/weapon/grenade/clusterbuster/inferno(src) + if(24) + new /obj/item/weapon/reagent_containers/food/drinks/bottle/holywater/hell(src) + new /obj/item/clothing/suit/space/hardsuit/ert/paranormal/inquisitor(src) + if(25) + new /obj/item/weapon/spellbook/oneuse/summonitem(src)*/ + +///Bosses + +//Dragon + +/obj/structure/closet/crate/necropolis/dragon + name = "dragon chest" + +/obj/structure/closet/crate/necropolis/dragon/New() + ..() + var/loot = rand(1,4) + switch(loot) + if(1) + new /obj/item/weapon/melee/ghost_sword(src) + if(2) + new /obj/item/weapon/lava_staff(src) + if(3) + new /obj/item/weapon/spellbook/oneuse/sacredflame(src) + new /obj/item/weapon/gun/magic/wand/fireball(src) + if(4) + new /obj/item/weapon/dragons_blood(src) + +/obj/item/weapon/melee/ghost_sword + name = "spectral blade" + desc = "A rusted and dulled blade. It doesn't look like it'd do much damage. It glows weakly." + icon_state = "spectral" + item_state = "spectral" + flags = CONDUCT + sharp = 1 + edge = 1 + w_class = 4 + force = 1 + throwforce = 1 + hitsound = 'sound/effects/ghost2.ogg' + attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "rended") + var/summon_cooldown = 0 + var/list/mob/dead/observer/spirits + +/obj/item/weapon/melee/ghost_sword/New() + ..() + spirits = list() + processing_objects.Add(src) + poi_list |= src + +/obj/item/weapon/melee/ghost_sword/Destroy() + for(var/mob/dead/observer/G in spirits) + G.invisibility = initial(G.invisibility) + spirits.Cut() + processing_objects.Remove(src) + poi_list -= src + . = ..() + +/obj/item/weapon/melee/ghost_sword/attack_self(mob/user) + if(summon_cooldown > world.time) + to_chat(user, "You just recently called out for aid. You don't want to annoy the spirits.") + return + to_chat(user, "You call out for aid, attempting to summon spirits to your side.") + + notify_ghosts("[user] is raising their [src], calling for your help!", enter_link="(Click to help)", source = user, action = NOTIFY_FOLLOW) + + summon_cooldown = world.time + 600 + +/obj/item/weapon/melee/ghost_sword/Topic(href, href_list) + if(href_list["follow"]) + var/mob/dead/observer/ghost = usr + if(istype(ghost)) + ghost.ManualFollow(src) + +/obj/item/weapon/melee/ghost_sword/process() + ghost_check() + +/obj/item/weapon/melee/ghost_sword/proc/ghost_check() + var/ghost_counter = 0 + var/turf/T = get_turf(src) + var/list/contents = T.GetAllContents() + var/mob/dead/observer/current_spirits = list() + + for(var/mob/dead/observer/O in player_list) + if(is_type_in_list(O.following, contents)) + ghost_counter++ + O.invisibility = 0 + current_spirits |= O + + for(var/mob/dead/observer/G in spirits - current_spirits) + G.invisibility = initial(G.invisibility) + + spirits = current_spirits + + return ghost_counter + +/obj/item/weapon/melee/ghost_sword/attack(mob/living/target, mob/living/carbon/human/user) + force = 0 + var/ghost_counter = ghost_check() + + force = Clamp((ghost_counter * 4), 0, 75) + user.visible_message("[user] strikes with the force of [ghost_counter] vengeful spirits!") + ..() + +/obj/item/weapon/melee/ghost_sword/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type) + var/ghost_counter = ghost_check() + final_block_chance += Clamp((ghost_counter * 5), 0, 75) + owner.visible_message("[owner] is protected by a ring of [ghost_counter] ghosts!") + return ..() + +// Blood + +/obj/item/weapon/dragons_blood + name = "bottle of dragons blood" + desc = "You're not actually going to drink this, are you?" + icon = 'icons/obj/wizard.dmi' + icon_state = "vial" + +/obj/item/weapon/dragons_blood/attack_self(mob/living/carbon/human/user) + if(!istype(user)) + return + + var/mob/living/carbon/human/H = user + var/random = rand(1,3) + + switch(random) + if(1) + to_chat(user, "Your flesh begins to melt! Miraculously, you seem fine otherwise.") + H.set_species("Skeleton") + if(2) + to_chat(user, "Power courses through you! You can now shift your form at will.") + if(user.mind) + var/obj/effect/proc_holder/spell/targeted/shapeshift/dragon/D = new + user.mind.AddSpell(D) + if(3) + to_chat(user, "You feel like you could walk straight through lava now.") + H.weather_immunities |= "lava" + + playsound(user.loc,'sound/items/drink.ogg', rand(10,50), 1) + qdel(src) + +/datum/disease/transformation/dragon + name = "dragon transformation" + cure_text = "nothing" + cures = list("adminordrazine") + agent = "dragon's blood" + desc = "What do dragons have to do with Space Station 13?" + stage_prob = 20 + severity = BIOHAZARD + visibility_flags = 0 + stage1 = list("Your bones ache.") + stage2 = list("Your skin feels scaley.") + stage3 = list("You have an overwhelming urge to terrorize some peasants.", "Your teeth feel sharper.") + stage4 = list("Your blood burns.") + stage5 = list("You're a fucking dragon. However, any previous allegiances you held still apply. It'd be incredibly rude to eat your still human friends for no reason.") + new_form = /mob/living/simple_animal/hostile/megafauna/dragon/lesser + +//Lava Staff + +/obj/item/weapon/lava_staff + name = "staff of lava" + desc = "The ability to fill the emergency shuttle with lava. What more could you want out of life?" + icon_state = "staffofstorms" + item_state = "staffofstorms" + icon = 'icons/obj/guns/magic.dmi' + slot_flags = SLOT_BACK + item_state = "staffofstorms" + w_class = 4 + force = 25 + damtype = BURN + hitsound = 'sound/weapons/sear.ogg' + var/turf_type = /turf/unsimulated/floor/lava // /turf/simulated/floor/plating/lava/smooth once Lavaland turfs are added + var/transform_string = "lava" + var/reset_turf_type = /turf/simulated/floor/plating/airless/asteroid // /turf/simulated/floor/plating/asteroid/basalt once Lavaland turfs are added + var/reset_string = "basalt" + var/create_cooldown = 100 + var/create_delay = 30 + var/reset_cooldown = 50 + var/timer = 0 + var/banned_turfs + +/obj/item/weapon/lava_staff/New() + . = ..() + banned_turfs = typecacheof(list(/turf/space/transit, /turf/unsimulated)) + +/obj/item/weapon/lava_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + ..() + if(timer > world.time) + return + + if(is_type_in_typecache(target, banned_turfs)) + return + + if(target in view(user.client.view, get_turf(user))) + + var/turf/simulated/T = get_turf(target) + if(!istype(T)) + return + if(!istype(T, turf_type)) + var/obj/effect/overlay/temp/lavastaff/L = new /obj/effect/overlay/temp/lavastaff(T) + L.alpha = 0 + animate(L, alpha = 255, time = create_delay) + user.visible_message("[user] points [src] at [T]!") + timer = world.time + create_delay + 1 + if(do_after(user, create_delay, target = T)) + user.visible_message("[user] turns \the [T] into [transform_string]!") + message_admins("[key_name_admin(user)] fired the lava staff at [get_area(target)] (JMP).") + log_game("[key_name(user)] fired the lava staff at [get_area(target)] ([T.x], [T.y], [T.z]).") + T.ChangeTurf(turf_type) + timer = world.time + create_cooldown + qdel(L) + else + timer = world.time + qdel(L) + return + else + user.visible_message("[user] turns \the [T] into [reset_string]!") + T.ChangeTurf(reset_turf_type) + timer = world.time + reset_cooldown + playsound(T,'sound/magic/Fireball.ogg', 200, 1) + +/obj/effect/overlay/temp/lavastaff + icon_state = "lavastaff_warn" + duration = 50 + +// Bubblegum + +/obj/structure/closet/crate/necropolis/bubblegum + name = "bubblegum chest" + +/obj/structure/closet/crate/necropolis/bubblegum/New() + ..() + var/loot = rand(1,3) + switch(loot) + if(1) + new /obj/item/mayhem(src) + if(2) + new /obj/item/blood_contract(src) + if(3) + new /obj/item/weapon/gun/magic/staff/spellblade(src) + +// Mayhem + +/obj/item/mayhem + name = "mayhem in a bottle" + desc = "A magically infused bottle of blood, the scent of which will drive anyone nearby into a murderous frenzy." + icon = 'icons/obj/wizard.dmi' + icon_state = "vial" + +/obj/item/mayhem/attack_self(mob/user) + for(var/mob/living/carbon/human/H in range(7,user)) + spawn() + var/obj/effect/mine/pickup/bloodbath/B = new(H) + B.mineEffect(H) + to_chat(user, "You shatter the bottle!") + playsound(user.loc, 'sound/effects/Glassbr1.ogg', 100, 1) + qdel(src) + +// Blood Contract + +/obj/item/blood_contract + name = "blood contract" + icon = 'icons/obj/wizard.dmi' + icon_state = "scroll2" + color = "#FF0000" + desc = "Mark your target for death." + var/used = FALSE + +/obj/item/blood_contract/attack_self(mob/user) + if(used) + return + + used = TRUE + var/choice = input(user,"Who do you want dead?","Choose Your Victim") as null|anything in player_list + + if(!choice) + used = FALSE + return + else if(!isliving(choice)) + to_chat(user, "[choice] is already dead!") + used = FALSE + return + else + var/mob/living/L = choice + + message_admins("[key_name_admin(L)] has been marked for death by [key_name_admin(user)].") + log_admin("[key_name(L)] has been marked for death by [key_name(user)].") + + var/datum/objective/survive/survive = new + survive.owner = L.mind + L.mind.objectives += survive + to_chat(L, "You've been marked for death! Don't let the demons get you!") + L.color = "#FF0000" + spawn() + var/obj/effect/mine/pickup/bloodbath/B = new(L) + B.mineEffect(L) + + for(var/mob/living/carbon/human/H in player_list) + if(H == L) + continue + to_chat(H, "You have an overwhelming desire to kill [L]. They have been marked red! Go kill them!") + H.put_in_hands(new /obj/item/weapon/kitchen/knife/butcher(H)) + + qdel(src) + +// Legion + +// Staff of Storms + +/obj/item/weapon/staff/storm + name = "staff of storms" + desc = "An ancient staff retrieved from the remains of Legion. The wind stirs as you move it." + icon_state = "staffofstorms" + item_state = "staffofstorms" + icon = 'icons/obj/guns/magic.dmi' + slot_flags = SLOT_BACK + item_state = "staffofstorms" + w_class = 4 + force = 25 + damtype = BURN + hitsound = 'sound/weapons/sear.ogg' + var/storm_type = /datum/weather/ash_storm + var/storm_cooldown = 0 + +/obj/item/weapon/staff/storm/attack_self(mob/user) + if(storm_cooldown > world.time) + to_chat(user, "The staff is still recharging!") + return + + var/area/user_area = get_area(user) + var/datum/weather/A + var/z_level_name = space_manager.levels_by_name[user.z] + for(var/V in weather_master.existing_weather) + var/datum/weather/W = V + if(W.target_z == z_level_name && W.area_type == user_area.type) + A = W + break + if(A) + + if(A.stage != END_STAGE) + if(A.stage == WIND_DOWN_STAGE) + to_chat(user, "The storm is already ending! It would be a waste to use the staff now.") + return + user.visible_message("[user] holds [src] skywards as an orange beam travels into the sky!", \ + "You hold [src] skyward, dispelling the storm!") + playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0) + A.wind_down() + return + else + A = new storm_type + A.name = "staff storm" + A.area_type = user_area.type + A.target_z = z_level_name + A.telegraph_duration = 100 + A.end_duration = 100 + + user.visible_message("[user] holds [src] skywards as red lightning crackles into the sky!", \ + "You hold [src] skyward, calling down a terrible storm!") + playsound(user, 'sound/magic/Staff_Change.ogg', 200, 0) + A.telegraph() + storm_cooldown = world.time + 200 + +// Hierophant + +//Hierophant + +/obj/item/weapon/hierophant_staff + name = "Hierophant's staff" + desc = "A large club with intense magic power infused into it." + icon_state = "hierophant_staff" + item_state = "hierophant_staff" + icon = 'icons/obj/guns/magic.dmi' + slot_flags = SLOT_BACK + w_class = 4 + force = 20 + hitsound = "swing_hit" + //hitsound = 'sound/weapons/sonic_jackhammer.ogg' + actions_types = list(/datum/action/item_action/vortex_recall, /datum/action/item_action/toggle_unfriendly_fire) + var/cooldown_time = 20 //how long the cooldown between non-melee ranged attacks is + var/chaser_cooldown = 101 //how long the cooldown between firing chasers at mobs is + var/chaser_timer = 0 //what our current chaser cooldown is + var/timer = 0 //what our current cooldown is + var/blast_range = 3 //how long the cardinal blast's walls are + var/obj/effect/hierophant/rune //the associated rune we teleport to + var/teleporting = FALSE //if we ARE teleporting + var/friendly_fire_check = FALSE //if the blasts we make will consider our faction against the faction of hit targets + +/obj/item/weapon/hierophant_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters) + ..() + var/turf/T = get_turf(target) + if(!T || timer > world.time) + return + timer = world.time + CLICK_CD_MELEE //by default, melee attacks only cause melee blasts, and have an accordingly short cooldown + if(proximity_flag) + spawn(0) + aoe_burst(T, user) + add_logs(user, target, "fired 3x3 blast at", src) + else + if(ismineralturf(target) && get_dist(user, target) < 6) //target is minerals, we can hit it(even if we can't see it) + spawn(0) + cardinal_blasts(T, user) + timer = world.time + cooldown_time + else if(target in view(5, get_turf(user))) //if the target is in view, hit it + timer = world.time + cooldown_time + if(isliving(target) && chaser_timer <= world.time) //living and chasers off cooldown? fire one! + chaser_timer = world.time + chaser_cooldown + new /obj/effect/overlay/temp/hierophant/chaser(get_turf(user), user, target, 1.5, friendly_fire_check) + add_logs(user, target, "fired a chaser at", src) + else + spawn(0) + cardinal_blasts(T, user) //otherwise, just do cardinal blast + add_logs(user, target, "fired cardinal blast at", src) + else + to_chat(user, "That target is out of range!") //too far away + +/obj/item/weapon/hierophant_staff/ui_action_click(mob/user, actiontype) + if(actiontype == /datum/action/item_action/toggle_unfriendly_fire) //toggle friendly fire... + friendly_fire_check = !friendly_fire_check + to_chat(user, "You toggle friendly fire [friendly_fire_check ? "off":"on"]!") + return + if(user.get_active_hand() != src && user.get_inactive_hand() != src) //you need to hold the staff to teleport + to_chat(user, "You need to hold the staff in your hands to [rune ? "teleport with it" : "create a rune"]!") + return + if(!rune) + if(isturf(user.loc)) + user.visible_message("[user] holds [src] carefully in front of them, moving it in a strange pattern...", \ + "You start creating a hierophant rune to teleport to...") + timer = world.time + 51 + if(do_after(user, 50, target = user)) + var/turf/T = get_turf(user) + playsound(T,'sound/magic/Blind.ogg', 200, 1, -4) + new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, user) + var/obj/effect/hierophant/H = new/obj/effect/hierophant(T) + rune = H + user.update_action_buttons_icon() + user.visible_message("[user] creates a strange rune beneath them!", \ + "You create a hierophant rune, which you can teleport yourself and any allies to at any time!\n\ + You can remove the rune to place a new one by striking it with the staff.") + else + timer = world.time + else + to_chat(user, "You need to be on solid ground to produce a rune!") + return + if(get_dist(user, rune) <= 2) //rune too close abort + to_chat(user, "You are too close to the rune to teleport to it!") + return + if(is_blocked_turf(get_turf(rune))) + to_chat(user, "The rune is blocked by something, preventing teleportation!") + return + teleporting = TRUE //start channel + user.update_action_buttons_icon() + user.visible_message("[user] starts to glow faintly...") + timer = world.time + 50 + if(do_after(user, 40, target = user) && rune) + var/turf/T = get_turf(rune) + var/turf/source = get_turf(user) + if(is_blocked_turf(T)) + teleporting = FALSE + to_chat(user, "The rune is blocked by something, preventing teleportation!") + user.update_action_buttons_icon() + return + new /obj/effect/overlay/temp/hierophant/telegraph(T, user) + new /obj/effect/overlay/temp/hierophant/telegraph(source, user) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/magic/Wand_Teleport.ogg', 200, 1) + playsound(source,'sound/magic/blink.ogg', 200, 1) + //playsound(source,'sound/machines/AirlockOpen.ogg', 200, 1) + if(!do_after(user, 3, target = user) || !rune) //no walking away shitlord + teleporting = FALSE + if(user) + user.update_action_buttons_icon() + return + if(is_blocked_turf(T)) + teleporting = FALSE + to_chat(user, "The rune is blocked by something, preventing teleportation!") + user.update_action_buttons_icon() + return + add_logs(user, rune, "teleported self from ([source.x],[source.y],[source.z]) to") + new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, user) + new /obj/effect/overlay/temp/hierophant/telegraph/teleport(source, user) + for(var/t in RANGE_TURFS(1, T)) + var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, user, TRUE) //blasts produced will not hurt allies + B.damage = 30 + for(var/t in RANGE_TURFS(1, source)) + var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, user, TRUE) //but absolutely will hurt enemies + B.damage = 30 + for(var/mob/living/L in range(1, source)) + spawn(0) + teleport_mob(source, L, T, user) //regardless, take all mobs near us along + sleep(6) //at this point the blasts detonate + else + timer = world.time + teleporting = FALSE + if(user) + user.update_action_buttons_icon() + +/obj/item/weapon/hierophant_staff/proc/teleport_mob(turf/source, mob/M, turf/target, mob/user) + var/turf/turf_to_teleport_to = get_step(target, get_dir(source, M)) //get position relative to caster + if(!turf_to_teleport_to || is_blocked_turf(turf_to_teleport_to)) + return + animate(M, alpha = 0, time = 2, easing = EASE_OUT) //fade out + sleep(1) + if(!M) + return + M.visible_message("[M] fades out!") + sleep(2) + if(!M) + return + M.forceMove(turf_to_teleport_to) + sleep(1) + if(!M) + return + animate(M, alpha = 255, time = 2, easing = EASE_IN) //fade IN + sleep(1) + if(!M) + return + M.visible_message("[M] fades in!") + if(user != M) + add_logs(user, M, "teleported", null, "from ([source.x],[source.y],[source.z])") + +/obj/item/weapon/hierophant_staff/proc/cardinal_blasts(turf/T, mob/living/user) //fire cardinal cross blasts with a delay + if(!T) + return + new /obj/effect/overlay/temp/hierophant/telegraph/cardinal(T, user) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/effects/bin_close.ogg', 200, 1) + sleep(2) + new /obj/effect/overlay/temp/hierophant/blast(T, user, friendly_fire_check) + for(var/d in cardinal) + spawn(0) + blast_wall(T, d, user) + +/obj/item/weapon/hierophant_staff/proc/blast_wall(turf/T, dir, mob/living/user) //make a wall of blasts blast_range tiles long + if(!T) + return + var/range = blast_range + var/turf/previousturf = T + var/turf/J = get_step(previousturf, dir) + for(var/i in 1 to range) + if(!J) + return + new /obj/effect/overlay/temp/hierophant/blast(J, user, friendly_fire_check) + previousturf = J + J = get_step(previousturf, dir) + +/obj/item/weapon/hierophant_staff/proc/aoe_burst(turf/T, mob/living/user) //make a 3x3 blast around a target + if(!T) + return + new /obj/effect/overlay/temp/hierophant/telegraph(T, user) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/effects/bin_close.ogg', 200, 1) + sleep(2) + for(var/t in RANGE_TURFS(1, T)) + new /obj/effect/overlay/temp/hierophant/blast(t, user, friendly_fire_check) \ No newline at end of file diff --git a/code/modules/mining/mine_areas.dm b/code/modules/mining/mine_areas.dm index 96ef9d3104b..e07d779c9a8 100644 --- a/code/modules/mining/mine_areas.dm +++ b/code/modules/mining/mine_areas.dm @@ -13,6 +13,7 @@ power_environ = 0 power_equip = 0 power_light = 0 + outdoors = 1 ambientsounds = list('sound/ambience/ambimine.ogg') /area/mine/dangerous/unexplored @@ -25,6 +26,7 @@ power_environ = 0 power_equip = 0 power_light = 0 + outdoors = 1 ambientsounds = list('sound/ambience/ambimine.ogg') /area/mine/lobby diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index 83e794b9d20..6027a0272d8 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -2,10 +2,12 @@ //this item is intended to give the effect of entering the mine, so that light gradually fades /obj/effect/light_emitter - name = "Light-emtter" + name = "Light emtter" anchored = 1 + invisibility = 101 unacidable = 1 light_range = 8 + light_power = 0 /**********************Miner Lockers**************************/ @@ -89,7 +91,7 @@ var/excavation_amount = 100 /obj/item/weapon/pickaxe/proc/playDigSound() - playsound(src, pick(digsound),20,1) + playsound(src, pick(digsound),20,1) /obj/item/weapon/pickaxe/silver name = "silver-plated pickaxe" diff --git a/code/modules/mining/ore.dm b/code/modules/mining/ore.dm index ec36988cb20..9e4d268281c 100644 --- a/code/modules/mining/ore.dm +++ b/code/modules/mining/ore.dm @@ -62,6 +62,10 @@ points = 1 refined_type = /obj/item/stack/sheet/glass materials = list(MAT_GLASS=MINERAL_MATERIAL_AMOUNT) + +/obj/item/weapon/ore/glass/basalt + name = "volcanic ash" + icon_state = "volcanic_sand" /obj/item/weapon/ore/glass/attack_self(mob/living/user as mob) to_chat(user, "You use the sand to make sandstone.") diff --git a/code/modules/mob/dead/observer/spells.dm b/code/modules/mob/dead/observer/spells.dm index 39dae4c0746..620c1854e73 100644 --- a/code/modules/mob/dead/observer/spells.dm +++ b/code/modules/mob/dead/observer/spells.dm @@ -25,7 +25,7 @@ var/global/list/boo_phrases=list( invocation_type = "none" range = 1 // Or maybe 3? -/obj/effect/proc_holder/spell/aoe_turf/boo/cast(list/targets) +/obj/effect/proc_holder/spell/aoe_turf/boo/cast(list/targets, mob/user = usr) for(var/turf/T in targets) for(var/atom/A in T.contents) diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm index 555fcff29da..e8afbb0360b 100644 --- a/code/modules/mob/living/carbon/brain/brain.dm +++ b/code/modules/mob/living/carbon/brain/brain.dm @@ -10,6 +10,7 @@ /mob/living/carbon/brain/New() create_reagents(330) + add_language("Galactic Common") ..() /mob/living/carbon/brain/Destroy() diff --git a/code/modules/mob/living/carbon/carbon_defenses.dm b/code/modules/mob/living/carbon/carbon_defenses.dm index efebc58ffc1..b2dcf20f1b2 100644 --- a/code/modules/mob/living/carbon/carbon_defenses.dm +++ b/code/modules/mob/living/carbon/carbon_defenses.dm @@ -36,4 +36,4 @@ for(var/datum/disease/D in user.viruses) if(D.IsSpreadByTouch()) ContractDisease(D) - return 0 + return 0 \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 558a6f8e9de..f9315966d27 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -83,12 +83,12 @@ message = "[src] pings at [param]." else message = "[src] pings." - playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) + playsound(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) + playsound(loc, 'sound/machines/buzz-two.ogg', 50, 0) m_type = 2 if("buzz", "buzzes") @@ -105,7 +105,7 @@ message = "[src] buzzes at [param]." else message = "[src] buzzes." - playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0) + playsound(loc, 'sound/machines/buzz-sigh.ogg', 50, 0) m_type = 2 if("beep", "beeps") @@ -122,7 +122,7 @@ message = "[src] beeps at [param]." else message = "[src] beeps." - playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0) + playsound(loc, 'sound/machines/twobeep.ogg', 50, 0) m_type = 2 if("drone", "drones", "hum", "hums", "rumble", "rumbles") @@ -139,7 +139,7 @@ message = "[src] drones at [param]." else message = "[src] rumbles." - playsound(src.loc, 'sound/voice/DraskTalk.ogg', 50, 0) + playsound(loc, 'sound/voice/DraskTalk.ogg', 50, 0) m_type = 2 if("squish", "squishes") @@ -156,7 +156,7 @@ message = "[src] squishes at [param]." else message = "[src] squishes." - playsound(src.loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound. + playsound(loc, 'sound/effects/slime_squish.ogg', 50, 0) //Credit to DrMinky (freesound.org) for the sound. m_type = 2 if("yes") @@ -173,7 +173,7 @@ message = "[src] emits an affirmative blip at [param]." else message = "[src] emits an affirmative blip." - playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0) + playsound(loc, 'sound/machines/synth_yes.ogg', 50, 0) m_type = 2 if("no") @@ -190,7 +190,7 @@ message = "[src] emits a negative blip at [param]." else message = "[src] emits a negative blip." - playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0) + playsound(loc, 'sound/machines/synth_no.ogg', 50, 0) m_type = 2 if("wag", "wags") @@ -202,7 +202,7 @@ else if(species.bodyflags & TAIL_WAGGING) if(!wear_suit || !(wear_suit.flags_inv & HIDETAIL) && !istype(wear_suit, /obj/item/clothing/suit/space)) message = "[src] starts wagging \his tail." - src.start_tail_wagging(1) + start_tail_wagging(1) else return else @@ -212,15 +212,25 @@ if("swag", "swags") if(species.bodyflags & TAIL_WAGGING || body_accessory) message = "[src] stops wagging \his tail." - src.stop_tail_wagging(1) + stop_tail_wagging(1) else return m_type = 1 if("airguitar") - if(!src.restrained()) + if(!restrained()) message = "[src] is strumming the air and headbanging like a safari chimp." m_type = 1 + + if("dance") + if(!restrained()) + message = "[src] dances around happily." + m_type = 1 + + if("jump") + if(!restrained()) + message = "[src] jumps!" + m_type = 1 if("blink", "blinks") message = "[src] blinks." @@ -231,7 +241,7 @@ m_type = 1 if("bow", "bows") - if(!src.buckled) + if(!buckled) var/M = null if(param) for(var/mob/A in view(null, null)) @@ -248,7 +258,7 @@ m_type = 1 if("salute", "salutes") - if(!src.buckled) + if(!buckled) var/M = null if(param) for(var/mob/A in view(null, null)) @@ -288,13 +298,13 @@ message = "[src] makes a peculiar noise." m_type = 2 if("clap", "claps") - if(!src.restrained()) + if(!restrained()) message = "[src] claps." m_type = 2 if(miming) m_type = 1 if("flap", "flaps") - if(!src.restrained()) + if(!restrained()) message = "[src] flaps \his wings." m_type = 2 if(miming) @@ -302,7 +312,7 @@ if("flip", "flips") m_type = 1 - if(!src.restrained()) + if(!restrained()) var/M = null if(param) for(var/mob/A in view(1, null)) @@ -340,7 +350,7 @@ SpinAnimation(5,1) if("aflap", "aflaps") - if(!src.restrained()) + if(!restrained()) message = "[src] flaps \his wings ANGRILY!" m_type = 2 if(miming) @@ -376,7 +386,7 @@ if("faint", "faints") message = "[src] faints." - if(src.sleeping) + if(sleeping) return //Can't faint while asleep AdjustSleeping(2) m_type = 1 @@ -578,11 +588,11 @@ message = "[src] takes a drag from a cigarette and blows \"[M]\" out in smoke." m_type = 1 else - message = "[src] says, \"[M], please. They had a family.\" [src.name] takes a drag from a cigarette and blows their name out in smoke." + message = "[src] says, \"[M], please. They had a family.\" [name] takes a drag from a cigarette and blows their name out in smoke." m_type = 2 if("point", "points") - if(!src.restrained()) + if(!restrained()) var/atom/M = null if(param) for(var/atom/A as mob|obj|turf in view()) @@ -597,7 +607,7 @@ m_type = 1 if("raise", "raises") - if(!src.restrained()) + if(!restrained()) message = "[src] raises a hand." m_type = 1 @@ -610,12 +620,12 @@ m_type = 1 if("signal", "signals") - if(!src.restrained()) + if(!restrained()) var/t1 = round(text2num(param)) if(isnum(t1)) - if(t1 <= 5 && (!src.r_hand || !src.l_hand)) + if(t1 <= 5 && (!r_hand || !l_hand)) message = "[src] raises [t1] finger\s." - else if(t1 <= 10 && (!src.r_hand && !src.l_hand)) + else if(t1 <= 10 && (!r_hand && !l_hand)) message = "[src] raises [t1] finger\s." m_type = 1 @@ -699,7 +709,7 @@ if("hug", "hugs") m_type = 1 - if(!src.restrained()) + if(!restrained()) var/M = null if(param) for(var/mob/A in view(1, null)) @@ -716,7 +726,7 @@ if("handshake") m_type = 1 - if(!src.restrained() && !src.r_hand) + if(!restrained() && !r_hand) var/mob/M = null if(param) for(var/mob/A in view(1, null)) @@ -734,7 +744,7 @@ if("dap", "daps") m_type = 1 - if(!src.restrained()) + if(!restrained()) var/M = null if(param) for(var/mob/A in view(1, null)) @@ -748,7 +758,7 @@ if("slap", "slaps") m_type = 1 - if(!src.restrained()) + if(!restrained()) var/M = null if(param) for(var/mob/A in view(1, null)) @@ -757,11 +767,11 @@ break if(M) message = "[src] slaps [M] across the face. Ouch!" - playsound(src.loc, 'sound/effects/snap.ogg', 50, 1) + playsound(loc, 'sound/effects/snap.ogg', 50, 1) else message = "[src] slaps \himself!" - playsound(src.loc, 'sound/effects/snap.ogg', 50, 1) - src.adjustFireLoss(4) + playsound(loc, 'sound/effects/snap.ogg', 50, 1) + adjustFireLoss(4) if("scream", "screams") if(miming) @@ -772,9 +782,9 @@ message = "[src] [species.scream_verb]!" m_type = 2 if(gender == FEMALE) - playsound(src.loc, "[species.female_scream_sound]", 80, 1, 0, pitch = get_age_pitch()) + playsound(loc, "[species.female_scream_sound]", 80, 1, 0, pitch = get_age_pitch()) else - playsound(src.loc, "[species.male_scream_sound]", 80, 1, 0, pitch = get_age_pitch()) //default to male screams if no gender is present. + playsound(loc, "[species.male_scream_sound]", 80, 1, 0, pitch = get_age_pitch()) //default to male screams if no gender is present. else message = "[src] makes a very loud noise." @@ -799,24 +809,24 @@ return message = "[src] snaps \his fingers." - playsound(src.loc, 'sound/effects/fingersnap.ogg', 50, 1, -3) + playsound(loc, 'sound/effects/fingersnap.ogg', 50, 1, -3) else message = "[src] snaps \his fingers right off!" - playsound(src.loc, 'sound/effects/snap.ogg', 50, 1) + playsound(loc, 'sound/effects/snap.ogg', 50, 1) // Needed for M_TOXIC_FART if("fart", "farts") if(reagents.has_reagent("simethicone")) return -// playsound(src.loc, 'sound/effects/fart.ogg', 50, 1, -3) //Admins still vote no to fun +// playsound(loc, 'sound/effects/fart.ogg', 50, 1, -3) //Admins still vote no to fun if(locate(/obj/item/weapon/storage/bible) in get_turf(src)) to_chat(viewers(src), "[src] farts on the Bible!") to_chat(viewers(src), "A mysterious force smites [src]!") var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread s.set_up(3, 1, src) s.start() - src.gib() + gib() else if(TOXIC_FARTS in mutations) message = "[src] unleashes a [pick("horrible","terrible","foul","disgusting","awful")] fart." else if(SUPER_FART in mutations) @@ -841,9 +851,9 @@ M.reagents.add_reagent("jenkem", 1) if("help") - var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-(none)/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s),cry, cries, custom, dap(s)(none)/mob," \ - + " deathgasp(s), drool(s), eyebrow,fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-(none)/mob, grin(s), groan(s), grumble(s), handshake-mob, hug(s)-(none)/mob," \ - + " glare(s)-(none)/mob, grin(s), johnny, laugh(s), look(s)-(none)/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-(none)/mob, scream(s), shake(s)," \ + var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-(none)/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s),cry, cries, custom, dance, dap(s)(none)/mob," \ + + " deathgasp(s), drool(s), eyebrow, fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-(none)/mob, grin(s), groan(s), grumble(s), grin(s)," \ + + " handshake-mob, hug(s)-(none)/mob, johnny, jump, laugh(s), look(s)-(none)/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-(none)/mob, scream(s), shake(s)," \ + " shiver(s), shrug(s), sigh(s), signal(s)-#1-10,slap(s)-(none)/mob, smile(s),snap(s), sneeze(s), sniff(s), snore(s), stare(s)-(none)/mob, swag(s), tremble(s), twitch(es), twitch(es)_s," \ + " wag(s), wave(s), whimper(s), wink(s), yawn(s)" if(species.name == "Machine") diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 48cc455c113..986a3ffb9c4 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -38,6 +38,7 @@ emp_act var/obj/item/organ/external/organ = get_organ(check_zone(def_zone)) if(isnull(organ)) + . = bullet_act(P, "chest") //act on chest instead return //Shrapnel @@ -56,6 +57,18 @@ emp_act organ.add_autopsy_data(P.name, P.damage) // Add the bullet's name to the autopsy data return (..(P , def_zone)) + +/mob/living/carbon/human/check_projectile_dismemberment(obj/item/projectile/P, def_zone) + var/obj/item/organ/external/affecting = get_organ(check_zone(def_zone)) + if(affecting && !affecting.cannot_amputate && affecting.get_damage() >= (affecting.max_damage - P.dismemberment)) + var/damtype = DROPLIMB_EDGE + switch(P.damage_type) + if(BRUTE) + damtype = DROPLIMB_BLUNT + if(BURN) + damtype = DROPLIMB_BURN + + affecting.droplimb(FALSE, damtype) /mob/living/carbon/human/getarmor(var/def_zone, var/type) var/armorval = 0 diff --git a/code/modules/mob/living/carbon/human/say.dm b/code/modules/mob/living/carbon/human/say.dm index 26ca4af83e8..7384ccc6796 100644 --- a/code/modules/mob/living/carbon/human/say.dm +++ b/code/modules/mob/living/carbon/human/say.dm @@ -1,10 +1,10 @@ -/mob/living/carbon/human/say(var/message) +/mob/living/carbon/human/say(var/message, var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE) var/alt_name = "" if(name != GetVoice()) alt_name = " (as [get_id_name("Unknown")])" - ..(message, alt_name = alt_name) //ohgod we should really be passing a datum here. + ..(message, alt_name = alt_name, sanitize = sanitize, ignore_speech_problems = ignore_speech_problems, ignore_atmospherics = ignore_atmospherics) //ohgod we should really be passing a datum here. /mob/living/carbon/human/proc/forcesay(list/append) if(stat == CONSCIOUS) diff --git a/code/modules/mob/living/carbon/human/species/shadow.dm b/code/modules/mob/living/carbon/human/species/shadow.dm index ca26348d188..66a62f1b10c 100644 --- a/code/modules/mob/living/carbon/human/species/shadow.dm +++ b/code/modules/mob/living/carbon/human/species/shadow.dm @@ -7,7 +7,10 @@ default_language = "Galactic Common" unarmed_type = /datum/unarmed_attack/claws + darksight = 8 + + ignored_by = list(/mob/living/simple_animal/hostile/faithless) blood_color = "#CCCCCC" flesh_color = "#AAAAAA" @@ -20,6 +23,7 @@ oxy_mod = 0 virus_immune = 1 + dietflags = DIET_OMNI //the mutation process allowed you to now digest all foods regardless of initial race reagent_tag = PROCESS_ORG suicide_messages = list( @@ -27,14 +31,46 @@ "is jamming their claws into their eye sockets!", "is twisting their own neck!", "is staring into the closest light source!") + + var/grant_vision_toggle = 1 + var/datum/action/innate/shadow/darkvision/vision_toggle + +/datum/action/innate/shadow/darkvision //Darkvision toggle so shadowpeople can actually see where darkness is + name = "Toggle Darkvision" + check_flags = AB_CHECK_CONSCIOUS + background_icon_state = "bg_default" + button_icon_state = "blind" + +/datum/action/innate/shadow/darkvision/Activate() + var/mob/living/carbon/human/H = owner + if(!H.vision_type) + H.vision_type = new /datum/vision_override/nightvision + to_chat(H, "You adjust your vision to pierce the darkness.") + else + H.vision_type = null + to_chat(H, "You adjust your vision to recognize the shadows.") + +/datum/species/shadow/grant_abilities(var/mob/living/carbon/human/H) + . = ..() + if(grant_vision_toggle) + vision_toggle = new + vision_toggle.Grant(H) + +/datum/species/shadow/remove_abilities(var/mob/living/carbon/human/H) + . = ..() + if(grant_vision_toggle && vision_toggle) + H.vision_type = null + vision_toggle.Remove(H) /datum/species/shadow/handle_life(var/mob/living/carbon/human/H) var/light_amount = 0 if(isturf(H.loc)) var/turf/T = H.loc - light_amount = T.get_lumcount()*10 + light_amount = T.get_lumcount() * 10 if(light_amount > 2) //if there's enough light, start dying H.take_overall_damage(1,1) + H.throw_alert("lightexposure", /obj/screen/alert/lightexposure) else if(light_amount < 2) //heal in the dark - H.heal_overall_damage(1,1) \ No newline at end of file + H.heal_overall_damage(1,1) + H.clear_alert("lightexposure") \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index e2238057533..7745f950aec 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -50,6 +50,7 @@ var/invis_sight = SEE_INVISIBLE_LIVING var/darksight = 2 + var/hazard_high_pressure = HAZARD_HIGH_PRESSURE // Dangerously high pressure. var/warning_high_pressure = WARNING_HIGH_PRESSURE // High pressure warning. var/warning_low_pressure = WARNING_LOW_PRESSURE // Low pressure warning. @@ -84,6 +85,8 @@ var/ventcrawler = 0 //Determines if the mob can go through the vents. var/has_fine_manipulation = 1 // Can use small items. + + var/mob/living/list/ignored_by = list() // list of mobs that will ignore this species var/list/allowed_consumed_mobs = list() //If a species can consume mobs, put the type of mobs it can consume here. @@ -162,7 +165,6 @@ "l_foot" = list("path" = /obj/item/organ/external/foot), "r_foot" = list("path" = /obj/item/organ/external/foot/right) ) - var/cyborg_type = "Cyborg" var/list/proc/species_abilities = list() /datum/species/New() diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index 5bde6ce8e5b..ec4fe892af9 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -808,8 +808,8 @@ return ..() /datum/species/diona/handle_life(var/mob/living/carbon/human/H) - var/rads = H.radiation/25 - H.radiation = Clamp(H.radiation - rads, 0, 100) + var/rads = H.radiation / 25 + H.apply_effect(-rads,IRRADIATE,0) H.nutrition += rads H.adjustBruteLoss(-(rads)) H.adjustOxyLoss(-(rads)) @@ -818,18 +818,23 @@ var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing if(isturf(H.loc)) //else, there's considered to be no light var/turf/T = H.loc - light_amount = min(T.get_lumcount()*10, 5) //hardcapped so it's not abused by having a ton of flashlights + light_amount = min(T.get_lumcount() * 10, 5) //hardcapped so it's not abused by having a ton of flashlights H.nutrition += light_amount H.traumatic_shock -= light_amount if(H.nutrition > NUTRITION_LEVEL_WELL_FED) H.nutrition = NUTRITION_LEVEL_WELL_FED + + if(light_amount > 0) + H.clear_alert("nolight") + else + H.throw_alert("nolight", /obj/screen/alert/nolight) if((light_amount >= 5) && !H.suiciding) //if there's enough light, heal + H.adjustBruteLoss(-(light_amount/2)) H.adjustFireLoss(-(light_amount/4)) H.adjustOxyLoss(-(light_amount)) - if(H.nutrition < 200) H.take_overall_damage(10,0) H.traumatic_shock++ diff --git a/code/modules/mob/living/carbon/superheroes.dm b/code/modules/mob/living/carbon/superheroes.dm index 60e1cd82654..fac41aa66f7 100644 --- a/code/modules/mob/living/carbon/superheroes.dm +++ b/code/modules/mob/living/carbon/superheroes.dm @@ -147,69 +147,69 @@ action_icon_state = "spell_greytide" var/recruiting = 0 -/obj/effect/proc_holder/spell/targeted/recruit/cast(list/targets) +/obj/effect/proc_holder/spell/targeted/recruit/cast(list/targets,mob/living/user = usr) 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)) - to_chat(usr, "You need to be closer to enthrall [target].") + to_chat(user, "You have already recruited the maximum number of henchmen.") + if(!in_range(user, target)) + to_chat(user, "You need to be closer to enthrall [target].") charge_counter = charge_max return if(!target.ckey) - to_chat(usr, "The target has no mind.") + to_chat(user, "The target has no mind.") charge_counter = charge_max return if(target.stat) - to_chat(usr, "The target must be conscious.") + to_chat(user, "The target must be conscious.") charge_counter = charge_max return if(!ishuman(target)) - to_chat(usr, "You can only recruit humans.") + to_chat(user, "You can only recruit humans.") charge_counter = charge_max return if(target.mind.assigned_role != "Civilian") - to_chat(usr, "You can only recruit Civilians.") + to_chat(user, "You can only recruit Civilians.") if(recruiting) - to_chat(usr, "You are already recruiting!") + to_chat(user, "You are already recruiting!") charge_counter = charge_max return recruiting = 1 - to_chat(usr, "This target is valid. You begin the recruiting process.") - to_chat(target, "[usr] focuses in concentration. Your head begins to ache.") + to_chat(user, "This target is valid. You begin the recruiting process.") + to_chat(target, "[user] focuses in concentration. Your head begins to ache.") for(var/progress = 0, progress <= 3, progress++) switch(progress) if(1) - to_chat(usr, "You begin by introducing yourself and explaining what you're about.") - usr.visible_message("[usr]'s introduces himself and explains his plans.") + to_chat(user, "You begin by introducing yourself and explaining what you're about.") + user.visible_message("[user]'s introduces himself and explains his plans.") if(2) - to_chat(usr, "You begin the recruitment of [target].") - usr.visible_message("[usr] leans over towards [target], whispering excitedly as he gives a speech.") - to_chat(target, "You feel yourself agreeing with [usr], and a surge of loyalty begins building.") + to_chat(user, "You begin the recruitment of [target].") + user.visible_message("[user] leans over towards [target], whispering excitedly as he gives a speech.") + to_chat(target, "You feel yourself agreeing with [user], and a surge of loyalty begins building.") target.Weaken(12) sleep(20) if(isloyal(target)) - to_chat(usr, "They are enslaved by Nanotrasen. You feel their interest in your cause wane and disappear.") - usr.visible_message("[usr] stops talking for a moment, then moves back away from [target].") + to_chat(user, "They are enslaved by Nanotrasen. You feel their interest in your cause wane and disappear.") + user.visible_message("[user] stops talking for a moment, then moves back away from [target].") to_chat(target, "Your mindshield implant activates, protecting you from conversion.") return if(3) - to_chat(usr, "You begin filling out the application form with [target].") - usr.visible_message("[usr] pulls out a pen and paper and begins filling an application form with [target].") - to_chat(target, "You are being convinced by [usr] to fill out an application form to become a henchman.")//Ow the edge + to_chat(user, "You begin filling out the application form with [target].") + user.visible_message("[user] pulls out a pen and paper and begins filling an application form with [target].") + to_chat(target, "You are being convinced by [user] to fill out an application form to become a henchman.")//Ow the edge - if(!do_mob(usr, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a mindshield implant - to_chat(usr, "The enrollment process has been interrupted - you have lost the attention of [target].") - to_chat(target, "You move away and are no longer under the charm of [usr]. The application form is null and void.") + if(!do_mob(user, target, 100)) //around 30 seconds total for enthralling, 45 for someone with a mindshield implant + to_chat(user, "The enrollment process has been interrupted - you have lost the attention of [target].") + to_chat(target, "You move away and are no longer under the charm of [user]. The application form is null and void.") recruiting = 0 return recruiting = 0 - to_chat(usr, "You have recruited [target] as your henchman!") - to_chat(target, "You have decided to enroll as a henchman for [usr]. You are now part of the feared 'Greyshirts'.") - to_chat(target, "You must follow the orders of [usr], and help him succeed in his dastardly schemes.") - to_chat(target, "You may not harm other Greyshirt or [usr]. However, you do not need to obey other Greyshirts.") + to_chat(user, "You have recruited [target] as your henchman!") + to_chat(target, "You have decided to enroll as a henchman for [user]. You are now part of the feared 'Greyshirts'.") + to_chat(target, "You must follow the orders of [user], and help him succeed in his dastardly schemes.") + to_chat(target, "You may not harm other Greyshirt or [user]. However, you do not need to obey other Greyshirts.") ticker.mode.greyshirts += target.mind target.set_species("Human") head_organ.h_style = "Bald" diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index c1f3f338893..bc849f9674e 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1,7 +1,15 @@ /mob/living/Destroy() + if(ranged_ability) + ranged_ability.remove_ranged_ability(src) ..() return QDEL_HINT_HARDDEL_NOW + +/mob/living/ghostize(can_reenter_corpse = 1) + var/prev_client = client + if(..()) + if(ranged_ability && prev_client) + ranged_ability.remove_mousepointer(prev_client) /mob/living/proc/OpenCraftingMenu() return diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 03e8331bde2..609d166183d 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -49,7 +49,12 @@ if(!P.nodamage) apply_damage(P.damage, P.damage_type, def_zone, armor) + if(P.dismemberment) + check_projectile_dismemberment(P, def_zone) return P.on_hit(src, armor, def_zone) + +/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone) + return 0 /mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0) return 0 //only carbon liveforms have this proc diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 0ec5f16c787..66aa234e2ca 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -52,3 +52,5 @@ var/list/surgeries = list() //a list of surgery datums. generally empty, they're added when the player wants them. var/gene_stability = DEFAULT_GENE_STABILITY + + var/obj/effect/proc_holder/ranged_ability //Any ranged ability the mob has, as a click override diff --git a/code/modules/mob/living/login.dm b/code/modules/mob/living/login.dm index a64126db27a..a2fc8e934cb 100644 --- a/code/modules/mob/living/login.dm +++ b/code/modules/mob/living/login.dm @@ -9,6 +9,10 @@ //Vents if(ventcrawler) to_chat(src, "You can ventcrawl! Use alt+click on vents to quickly travel about the station.") + + if(ranged_ability) + ranged_ability.add_ranged_ability(src, "You currently have [ranged_ability] active!") + //Should update regardless of if we can ventcrawl, since we can end up in pipes in other ways. update_pipe_vision() diff --git a/code/modules/mob/living/logout.dm b/code/modules/mob/living/logout.dm index 10ba19b4302..6235aecf2c4 100644 --- a/code/modules/mob/living/logout.dm +++ b/code/modules/mob/living/logout.dm @@ -1,4 +1,6 @@ /mob/living/Logout() + if(ranged_ability && client) + ranged_ability.remove_mousepointer(client) ..() if(mind) if(!key) //key and mind have become seperated. I believe this is for when a staff member aghosts. diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index bbf238fd037..b0f42e9a8cb 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -14,6 +14,7 @@ var/list/department_radio_keys = list( ":u" = "Supply", "#u" = "Supply", ".u" = "Supply", ":z" = "Service", "#z" = "Service", ".z" = "Service", ":p" = "AI Private", "#p" = "AI Private", ".p" = "AI Private", + ":x" = "cords", "#x" = "cords", ".x" = "cords", ":R" = "right ear", "#R" = "right ear", ".R" = "right ear", ":L" = "left ear", "#L" = "left ear", ".L" = "left ear", @@ -30,7 +31,8 @@ var/list/department_radio_keys = list( ":Z" = "Service", "#Z" = "Service", ".Z" = "Service", ":P" = "AI Private", "#P" = "AI Private", ".P" = "AI Private", ":-" = "Special Ops", "#-" = "Special Ops", ".-" = "Special Ops", - ":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam" + ":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam", + ":X" = "cords", "#X" = "cords", ".X" = "cords" ) @@ -106,13 +108,14 @@ proc/get_radio_key_from_channel(var/channel) return returns -/mob/living/say(var/message, var/datum/language/speaking = null, var/verb = "says", var/alt_name="") +/mob/living/say(var/message, var/datum/language/speaking = null, var/verb = "says", var/alt_name = "", var/sanitize = TRUE, var/ignore_speech_problems = FALSE, var/ignore_atmospherics = FALSE) if(client) if(client.prefs.muted & MUTE_IC) to_chat(src, "You cannot speak in IC (Muted).") return - message = trim_strip_html_properly(message) + if(sanitize) + message = trim_strip_html_properly(message) if(stat) if(stat == DEAD) @@ -146,6 +149,15 @@ proc/get_radio_key_from_channel(var/channel) if(speaking && (speaking.flags & HIVEMIND)) speaking.broadcast(src,trim(message)) return 1 + + if(message_mode == "cords") + if(iscarbon(src)) + var/mob/living/carbon/C = src + var/obj/item/organ/internal/vocal_cords/V = C.get_int_organ(/obj/item/organ/internal/vocal_cords) + if(V && V.can_speak_with()) + C.say(V.handle_speech(message), sanitize = FALSE, ignore_speech_problems = TRUE, ignore_atmospherics = TRUE) + V.speak_with(message) //words come before actions + return 1 verb = say_quote(message, speaking) @@ -162,7 +174,7 @@ proc/get_radio_key_from_channel(var/channel) message = handle_autohiss(message, speaking) - if(speaking && !(speaking.flags & NO_STUTTER)) + if(!ignore_speech_problems && (speaking && !(speaking.flags & NO_STUTTER))) var/list/handle_s = handle_speech_problems(message, verb) message = handle_s[1] verb = handle_s[2] @@ -217,12 +229,13 @@ proc/get_radio_key_from_channel(var/channel) //make sure the air can transmit speech - speaker's side var/datum/gas_mixture/environment = T.return_air() var/pressure = environment ? environment.return_pressure() : 0 - if(pressure < SOUND_MINIMUM_PRESSURE) - message_range = 1 + if(!ignore_atmospherics) + if(pressure < SOUND_MINIMUM_PRESSURE) + message_range = 1 - if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet - italics = 1 - sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact + if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet + italics = 1 + sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact var/list/hear = hear(message_range, T) var/list/hearturfs = list() diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 39f73310566..152ed03fec8 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -204,7 +204,7 @@ modules += new /obj/item/weapon/gripper(src) modules += new /obj/item/weapon/matter_decompiler(src) modules += new /obj/item/device/floor_painter(src) - + modules += new /obj/item/areaeditor/blueprints/cyborg(src) emag = new /obj/item/borg/stun(src) for(var/G in stacktypes) //Attempt to unify Engi-Borg material stacks into fewer lines. See Line 492 for example. Variables changed out of paranoia. diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm index ffd3f91cf5c..3ac858a8a6c 100644 --- a/code/modules/mob/living/simple_animal/bot/bot.dm +++ b/code/modules/mob/living/simple_animal/bot/bot.dm @@ -788,6 +788,7 @@ Pass a positive integer as an argument to override a bot's default speed. frustration = 0 /mob/living/simple_animal/bot/show_inv() + return /mob/living/simple_animal/bot/proc/show_controls(mob/M) users |= M diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm new file mode 100644 index 00000000000..c0f7efca2c6 --- /dev/null +++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm @@ -0,0 +1,51 @@ +/mob/living/simple_animal/cockroach + name = "cockroach" + desc = "This station is just crawling with bugs." + icon_state = "cockroach" + icon_dead = "cockroach" + health = 1 + maxHealth = 1 + turns_per_move = 5 + 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 = 270 + maxbodytemp = INFINITY + pass_flags = PASSTABLE | PASSGRILLE | PASSMOB + mob_size = MOB_SIZE_TINY + response_help = "pokes" + response_disarm = "shoos" + response_harm = "splats" + density = 0 + ventcrawler = 2 + gold_core_spawnable = 2 + var/squish_chance = 50 + loot = list(/obj/effect/decal/cleanable/deadcockroach) + del_on_death = 1 + +/mob/living/simple_animal/cockroach/death(gibbed) + if(ticker.cinematic) //If the nuke is going off, then cockroaches are invincible. Keeps the nuke from killing them, cause cockroaches are immune to nukes. + return + ..() + +/mob/living/simple_animal/cockroach/Crossed(var/atom/movable/AM) + if(isliving(AM)) + var/mob/living/A = AM + if(A.mob_size > MOB_SIZE_SMALL) + if(prob(squish_chance)) + A.visible_message("\The [A] squashed \the [name].", "You squashed \the [name].") + death() + else + visible_message("\The [name] avoids getting crushed.") + else if(istype(AM, /obj/structure)) + visible_message("As \the [AM] moved over \the [name], it was crushed.") + death() + +/mob/living/simple_animal/cockroach/ex_act() //Explosions are a terrible way to handle a cockroach. + return + +/obj/effect/decal/cleanable/deadcockroach + name = "cockroach guts" + desc = "One bug squashed. Four more will rise in its place." + icon = 'icons/effects/blood.dmi' + icon_state = "xfloor1" + random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7") + anchored = 1 \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/corgi.dm b/code/modules/mob/living/simple_animal/friendly/corgi.dm index 2f45d3e802e..dfc0bce32a3 100644 --- a/code/modules/mob/living/simple_animal/friendly/corgi.dm +++ b/code/modules/mob/living/simple_animal/friendly/corgi.dm @@ -58,7 +58,7 @@ dat += "
Back:[(inventory_back && !(inventory_back.flags&ABSTRACT)) ? inventory_back : "Empty"]
 
Collar:[(collar && !(collar.flags&ABSTRACT)) ? collar : "Empty"]
Collar:[(collar && !(collar.flags&ABSTRACT)) ? collar : "Empty"]
Close diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm index a3739dfe088..1df7348a839 100644 --- a/code/modules/mob/living/simple_animal/hostile/hostile.dm +++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm @@ -1,6 +1,5 @@ /mob/living/simple_animal/hostile faction = list("hostile") - mouse_opacity = 2 //This makes it easier to hit hostile mobs, you only need to click on their tile, and is set back to 1 when they die stop_automated_movement_when_pulled = 0 environment_smash = 1 //Set to 1 to break closets,tables,racks, etc; 2 for walls; 3 for rwalls var/atom/target @@ -13,7 +12,8 @@ var/list/friends = list() var/ranged_message = "fires" //Fluff text for ranged mobs var/ranged_cooldown = 0 //What the starting cooldown is on ranged attacks - var/ranged_cooldown_cap = 3 //What ranged attacks, after being used are set to, to go back on cooldown, defaults to 3 life() ticks + var/ranged_cooldown_time = 30 //How long, in deciseconds, the cooldown of ranged attacks is + var/ranged_ignores_vision = FALSE //if it'll fire ranged attacks even if it lacks vision on its target, only works with environment smash var/check_friendly_fire = 0 // Should the ranged mob check for friendlies when shooting var/retreat_distance = null //If our mob runs from players when they're too close, set in tile distance. By default, mobs do not retreat. var/minimum_distance = 1 //Minimum approach distance, so ranged mobs chase targets down, but still keep their distance set in tiles to the target, set higher to make mobs keep distance @@ -30,11 +30,33 @@ var/attack_same = 0 //Set us to 1 to allow us to attack our own faction, or 2, to only ever attack our own faction var/AIStatus = AI_ON //The Status of our AI, can be set to AI_ON (On, usual processing), AI_IDLE (Will not process, but will return to AI_ON if an enemy comes near), AI_OFF (Off, Not processing ever) + + //typecache of things this mob will attack in DestroySurroundings() if it has environment_smash + var/list/environment_target_typecache = list( + /obj/machinery/door/window, + /obj/structure/window, + /obj/structure/closet, + /obj/structure/table, + /obj/structure/grille, + /obj/structure/girder, + /obj/structure/rack, + /obj/structure/barricade) //turned into a typecache in New() + var/atom/targets_from = null //all range/attack/etc. calculations should be done from this atom, defaults to the mob itself, useful for Vehicles and such + var/list/emote_taunt = list() + var/taunt_chance = 0 + +/mob/living/simple_animal/hostile/New() + ..() + if(!targets_from) + targets_from = src + environment_target_typecache = typecacheof(environment_target_typecache) + +/mob/living/simple_animal/hostile/Destroy() + targets_from = null + return ..() /mob/living/simple_animal/hostile/Life() . = ..() - if(ranged) - ranged_cooldown-- if(!.) walk(src, 0) return 0 @@ -58,76 +80,89 @@ if(AIShouldSleep(possible_targets)) // we try to acquire a new one AIStatus = AI_IDLE // otherwise we go idle return 1 + +/mob/living/simple_animal/hostile/attacked_by(obj/item/I, mob/living/user) + if(stat == CONSCIOUS && !target && AIStatus != AI_OFF && !client && user) + FindTarget(list(user), 1) + return ..() + +/mob/living/simple_animal/hostile/bullet_act(obj/item/projectile/P) + if(stat == CONSCIOUS && !target && AIStatus != AI_OFF && !client) + if(P.firer && get_dist(src, P.firer) <= aggro_vision_range) + FindTarget(list(P.firer), 1) + Goto(P.starting, move_to_delay, 3) + return ..() + //////////////HOSTILE MOB TARGETTING AND AGGRESSION//////////// /mob/living/simple_animal/hostile/proc/ListTargets()//Step 1, find out what we can see - var/list/L = list() + . = list() if(!search_objects) - var/list/Mobs = hearers(vision_range, src) - src //Remove self, so we don't suicide - L += Mobs - for(var/obj/mecha/M in mechas_list) - if(get_dist(M, src) <= vision_range && can_see(src, M, vision_range)) - L += M - for(var/obj/spacepod/S in spacepods_list) - if(get_dist(S, src) <= vision_range && can_see(src, S, vision_range)) - L += S + var/list/Mobs = hearers(vision_range, targets_from) - src //Remove self, so we don't suicide + . += Mobs + + var/static/hostile_machines = typecacheof(list(/obj/machinery/porta_turret, /obj/mecha, /obj/spacepod)) + + for(var/HM in typecache_filter_list(range(vision_range, targets_from), hostile_machines)) + if(can_see(targets_from, HM, vision_range)) + . += HM else - var/list/Objects = oview(vision_range, src) - L += Objects - return L + var/list/Objects = oview(vision_range, targets_from) + . += Objects /mob/living/simple_animal/hostile/proc/FindTarget(var/list/possible_targets, var/HasTargetsList = 0)//Step 2, filter down possible targets to things we actually care about - var/list/Targets = list() + . = list() if(!HasTargetsList) possible_targets = ListTargets() - for(var/atom/A in possible_targets) + for(var/pos_targ in possible_targets) + var/atom/A = pos_targ if(Found(A))//Just in case people want to override targetting - Targets = list(A) + . = list(A) break if(CanAttack(A))//Can we attack it? - Targets += A + . += A continue - var/Target = PickTarget(Targets) + var/Target = PickTarget(.) GiveTarget(Target) return Target //We now have a target + +/mob/living/simple_animal/hostile/proc/PossibleThreats() + . = list() + for(var/pos_targ in ListTargets()) + var/atom/A = pos_targ + if(Found(A)) + . = list(A) + break + if(CanAttack(A)) + . += A + continue /mob/living/simple_animal/hostile/proc/Found(var/atom/A)//This is here as a potential override to pick a specific target if available return -/mob/living/simple_animal/hostile/proc/PickTarget(var/list/Targets)//Step 3, pick amongst the possible, attackable targets - if(!Targets.len)//We didnt find nothin! - return +/mob/living/simple_animal/hostile/proc/PickTarget(list/Targets)//Step 3, pick amongst the possible, attackable targets if(target != null)//If we already have a target, but are told to pick again, calculate the lowest distance between all possible, and pick from the lowest distance targets - for(var/atom/A in Targets) - var/target_dist = get_dist(src, target) - var/possible_target_distance = get_dist(src, A) + for(var/pos_targ in Targets) + var/atom/A = pos_targ + var/target_dist = get_dist(targets_from, target) + var/possible_target_distance = get_dist(targets_from, A) if(target_dist < possible_target_distance) Targets -= A - var/chosen_target = safepick(Targets)//Pick the remaining targets (if any) at random + if(!Targets.len)//We didnt find nothin! + return + var/chosen_target = pick(Targets)//Pick the remaining targets (if any) at random return chosen_target /mob/living/simple_animal/hostile/CanAttack(var/atom/the_target)//Can we actually attack a possible target? + if(!the_target) + return 0 if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it return 0 if(search_objects < 2) - if(istype(the_target, /obj/mecha)) - var/obj/mecha/M = the_target - if(M.occupant)//Just so we don't attack empty mechs - if(CanAttack(M.occupant)) - return 1 - if(istype(the_target, /obj/spacepod)) - var/obj/spacepod/S = the_target - 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 - var/faction_check = 0 - for(var/F in faction) - if(F in L.faction) - faction_check = 1 - break + var/faction_check = faction_check(L) if(robust_searching) if(L.stat > stat_attack || L.stat != stat_attack && stat_exclusive == 1) return 0 @@ -141,14 +176,42 @@ if(faction_check && !attack_same) return 0 return 1 + + if(ishuman(the_target)) + var/mob/living/carbon/human/H = the_target + if(is_type_in_list(src, H.species.ignored_by)) + return 0 + + if(istype(the_target, /obj/mecha)) + var/obj/mecha/M = the_target + if(M.occupant)//Just so we don't attack empty mechs + if(CanAttack(M.occupant)) + return 1 + + if(istype(the_target, /obj/spacepod)) + var/obj/spacepod/S = the_target + if(S.pilot) //Just so we don't attack empty pods + if(CanAttack(S.pilot)) + return 1 + + if(istype(the_target, /obj/machinery/porta_turret)) + var/obj/machinery/porta_turret/P = the_target + if(P.faction in faction) + return 0 + if(!P.raised) //Don't attack invincible turrets + return 0 + if(P.stat & BROKEN) //Or turrets that are already broken + return 0 + return 1 if(isobj(the_target)) if(is_type_in_list(the_target, wanted_objects)) return 1 return 0 -/mob/living/simple_animal/hostile/proc/GiveTarget(var/new_target)//Step 4, give us our selected target +/mob/living/simple_animal/hostile/proc/GiveTarget(new_target)//Step 4, give us our selected target target = new_target if(target != null) + Aggro() return 1 /mob/living/simple_animal/hostile/proc/MoveToTarget(var/list/possible_targets)//Step 5, handle movement between us and our target @@ -157,38 +220,45 @@ LoseTarget() return 0 if(target in possible_targets) - var/target_distance = get_dist(src,target) - if(ranged)//We ranged? Shoot at em - if(target_distance >= 2 && ranged_cooldown <= 0)//But make sure they're a tile away at least, and our range attack is off cooldown + if(target.z != z) + LoseTarget() + return 0 + var/target_distance = get_dist(targets_from,target) + if(ranged) //We ranged? Shoot at em + if(!target.Adjacent(targets_from) && ranged_cooldown <= world.time) //But make sure they're not in range for a melee attack and our range attack is off cooldown OpenFire(target) - if(retreat_distance != null)//If we have a retreat distance, check if we need to run from our target - if(target_distance <= retreat_distance)//If target's closer than our retreat distance, run + if(retreat_distance != null) //If we have a retreat distance, check if we need to run from our target + if(target_distance <= retreat_distance) //If target's closer than our retreat distance, run walk_away(src,target,retreat_distance,move_to_delay) else - Goto(target,move_to_delay,minimum_distance)//Otherwise, get to our minimum distance so we chase them + Goto(target,move_to_delay,minimum_distance) //Otherwise, get to our minimum distance so we chase them else Goto(target,move_to_delay,minimum_distance) - if(isturf(loc) && target.Adjacent(src)) //If they're next to us, attack - AttackingTarget() - return 1 + if(target) + if(targets_from && isturf(targets_from.loc) && target.Adjacent(targets_from)) //If they're next to us, attack + AttackingTarget() + return 1 + return 0 if(environment_smash) - if(target.loc != null && get_dist(src, target.loc) <= vision_range)//We can't see our target, but he's in our vision range still - if(environment_smash >= 2)//If we're capable of smashing through walls, forget about vision completely after finding our target + if(target.loc != null && get_dist(targets_from, target.loc) <= vision_range) //We can't see our target, but he's in our vision range still + if(ranged_ignores_vision && ranged_cooldown <= world.time) //we can't see our target... but we can fire at them! + OpenFire(target) + if(environment_smash >= 2) //If we're capable of smashing through walls, forget about vision completely after finding our target Goto(target,move_to_delay,minimum_distance) FindHidden() return 1 else if(FindHidden()) return 1 - LostTarget() + LoseTarget() return 0 -/mob/living/simple_animal/hostile/proc/Goto(var/target, var/delay, var/minimum_distance) +/mob/living/simple_animal/hostile/proc/Goto(target, delay, minimum_distance) walk_to(src, target, minimum_distance, delay) /mob/living/simple_animal/hostile/adjustHealth(damage) - ..(damage) - if(!stat && search_objects < 3)//Not unconscious, and we don't ignore mobs + . = ..() + if(!ckey && !stat && search_objects < 3 && damage > 0)//Not unconscious, and we don't ignore mobs if(search_objects)//Turn off item searching and ignore whatever item we were looking at, we're more concerned with fight or flight search_objects = 0 target = null @@ -203,101 +273,102 @@ /mob/living/simple_animal/hostile/proc/Aggro() vision_range = aggro_vision_range + if(target && emote_taunt.len && prob(taunt_chance)) + emote("me", 1, "[pick(emote_taunt)] at [target].") + taunt_chance = max(taunt_chance-7,2) /mob/living/simple_animal/hostile/proc/LoseAggro() stop_automated_movement = 0 vision_range = idle_vision_range + taunt_chance = initial(taunt_chance) /mob/living/simple_animal/hostile/proc/LoseTarget() target = null walk(src, 0) LoseAggro() -/mob/living/simple_animal/hostile/proc/LostTarget() - walk(src, 0) - LoseAggro() - //////////////END HOSTILE MOB TARGETTING AND AGGRESSION//////////// /mob/living/simple_animal/hostile/death(gibbed) - LoseAggro() - mouse_opacity = 1 - ..() - walk(src, 0) + LoseTarget() + ..(gibbed) + +/mob/living/simple_animal/hostile/proc/summon_backup(distance) + do_alert_animation(src) + playsound(loc, 'sound/machines/chime.ogg', 50, 1, -1) + for(var/mob/living/simple_animal/hostile/M in oview(distance, targets_from)) + var/list/L = M.faction&faction + if(L.len) + if(M.AIStatus == AI_OFF) + return + else + M.Goto(src,M.move_to_delay,M.minimum_distance) -/mob/living/simple_animal/hostile/proc/OpenFire(var/the_target) - var/target = the_target +/mob/living/simple_animal/hostile/proc/OpenFire(atom/A) if(check_friendly_fire) - for(var/turf/T in getline(src, target)) // Not 100% reliable but this is faster than simulating actual trajectory + for(var/turf/T in getline(src,A)) // Not 100% reliable but this is faster than simulating actual trajectory for(var/mob/living/L in T) - if(L == src || L == target) + if(L == src || L == A) continue if(faction_check(L) && !attack_same) return - visible_message("[src] [ranged_message] at [target]!") + visible_message("[src] [ranged_message] at [A]!") if(rapid) spawn(1) - Shoot(target, src.loc, src) - if(casingtype) - new casingtype(get_turf(src)) + Shoot(A) spawn(4) - Shoot(target, src.loc, src) - if(casingtype) - new casingtype(get_turf(src)) + Shoot(A) spawn(6) - Shoot(target, src.loc, src) - if(casingtype) - new casingtype(get_turf(src)) + Shoot(A) else - Shoot(target, src.loc, src) - if(casingtype) - new casingtype - ranged_cooldown = ranged_cooldown_cap - return + Shoot(A) + ranged_cooldown = world.time + ranged_cooldown_time -/mob/living/simple_animal/hostile/proc/Shoot(var/target, var/start, var/user, var/bullet = 0) - if(target == start) +/mob/living/simple_animal/hostile/proc/Shoot(atom/targeted_atom) + if(targeted_atom == targets_from.loc || targeted_atom == targets_from) return + var/turf/startloc = get_turf(targets_from) if(casingtype) - var/obj/item/ammo_casing/casing = new casingtype + var/obj/item/ammo_casing/casing = new casingtype(startloc) playsound(src, projectilesound, 100, 1) - casing.fire(target, src, zone_override = ran_zone()) - casing.loc = loc - else - var/obj/item/projectile/A = new projectiletype(loc) - playsound(user, projectilesound, 100, 1) - A.current = target - A.firer = src - A.yo = target:y - start:y - A.xo = target:x - start:x - if(AIStatus == AI_OFF)//Don't want mindless mobs to have their movement screwed up firing in space - newtonian_move(get_dir(target, user)) - A.original = target - A.fire() - return A + casing.fire(targeted_atom, src, zone_override = ran_zone()) + else if(projectiletype) + var/obj/item/projectile/P = new projectiletype(startloc) + playsound(src, projectilesound, 100, 1) + P.current = startloc + P.starting = startloc + P.firer = src + P.yo = targeted_atom.y - startloc.y + P.xo = targeted_atom.x - startloc.x + if(AIStatus != AI_ON)//Don't want mindless mobs to have their movement screwed up firing in space + newtonian_move(get_dir(targeted_atom, targets_from)) + P.original = targeted_atom + P.fire() + return P /mob/living/simple_animal/hostile/proc/DestroySurroundings() if(environment_smash) EscapeConfinement() for(var/dir in cardinal) - var/turf/T = get_step(src, dir) - if(istype(T, /turf/simulated/wall) || istype(T, /turf/simulated/mineral)) - if(T.Adjacent(src)) + var/turf/T = get_step(targets_from, dir) + if(iswallturf(T) || ismineralturf(T)) + if(T.Adjacent(targets_from)) T.attack_animal(src) - for(var/atom/A in T) - if(!A.Adjacent(src)) + for(var/a in T) + var/atom/A = a + if(!A.Adjacent(targets_from)) continue - if(istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille) || istype(A, /obj/structure/rack)) + if(is_type_in_typecache(A, environment_target_typecache)) A.attack_animal(src) return /mob/living/simple_animal/hostile/proc/EscapeConfinement() if(buckled) buckled.attack_animal(src) - if(!isturf(src.loc) && src.loc != null)//Did someone put us in something? - var/atom/A = src.loc + if(!isturf(targets_from.loc) && targets_from.loc != null)//Did someone put us in something? + var/atom/A = get_turf(targets_from) A.attack_animal(src)//Bang on it till we get out return @@ -305,12 +376,12 @@ 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)) + if(A.Adjacent(targets_from)) A.attack_animal(src) return 1 -/mob/living/simple_animal/hostile/RangedAttack(var/atom/A, var/params) //Player firing - if(ranged && ranged_cooldown <= 0) +/mob/living/simple_animal/hostile/RangedAttack(atom/A, params) //Player firing + if(ranged && ranged_cooldown <= world.time) target = A OpenFire(A) ..() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm new file mode 100644 index 00000000000..85a351606f6 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm @@ -0,0 +1,393 @@ +#define MEDAL_PREFIX "Bubblegum" + +/* + +BUBBLEGUM + +Bubblegum spawns randomly wherever a lavaland creature is able to spawn. It is the most powerful slaughter demon in existence. +Bubblegum's footsteps are heralded by shaking booms, proving its tremendous size. + +It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage. + +It tries to strike at its target through any bloodpools under them; if it fails to do that, it will spray blood and then attempt to warp to a bloodpool near the target. +If it fails to warp to a target, it may summon up to 6 slaughterlings from the blood around it. +If it does not summon all 6 slaughterlings, it will instead charge at its target, dealing massive damage to anything it hits and spraying a stream of blood. +At half health, it will either charge three times or warp, then charge, instead of doing a single charge. + +When Bubblegum dies, it leaves behind a chest that can contain three things: + 1. A bottle that, when activated, drives everyone nearby into a frenzy + 2. A contract that marks for death the chosen target + 3. A spellblade that can slice off limbs at range + +Difficulty: Hard + +*/ + +/mob/living/simple_animal/hostile/megafauna/bubblegum + name = "bubblegum" + desc = "In what passes for a heirarchy among slaughter demons, this one is king." + health = 2500 + maxHealth = 2500 + attacktext = "rends" + attack_sound = 'sound/misc/demon_attack1.ogg' + icon_state = "bubblegum" + icon_living = "bubblegum" + icon_dead = "" + friendly = "stares down" + icon = 'icons/mob/lavaland/96x96megafauna.dmi' + speak_emote = list("gurgles") + armour_penetration = 40 + melee_damage_lower = 40 + melee_damage_upper = 40 + speed = 1 + move_to_delay = 10 + ranged = 1 + pixel_x = -32 + del_on_death = 1 + loot = list(/obj/structure/closet/crate/necropolis/bubblegum) + var/charging = 0 + medal_type = MEDAL_PREFIX + score_type = BUBBLEGUM_SCORE + deathmessage = "sinks into a pool of blood, fleeing the battle. You've won, for now... " + death_sound = 'sound/misc/enter_blood.ogg' + +/obj/item/device/gps/internal/bubblegum + icon_state = null + gpstag = "Bloody Signal" + desc = "You're not quite sure how a signal can be bloody." + invisibility = 100 + +/mob/living/simple_animal/hostile/megafauna/bubblegum/adjustBruteLoss(amount) + if(amount > 0 && prob(25)) + var/obj/effect/decal/cleanable/blood/gibs/bubblegum/B = new /obj/effect/decal/cleanable/blood/gibs/bubblegum(loc) + if(prob(40)) + step(B, pick(cardinal)) + else + B.dir = pick(cardinal) + . = ..() + +/obj/effect/decal/cleanable/blood/gibs/bubblegum + name = "thick blood" + desc = "Thick, splattered blood." + random_icon_states = list("gib3", "gib5", "gib6") + amount = 20 + +/obj/effect/decal/cleanable/blood/gibs/bubblegum/can_bloodcrawl_in() + return TRUE + +/mob/living/simple_animal/hostile/megafauna/bubblegum/Life() + ..() + move_to_delay = Clamp((health/maxHealth) * 10, 5, 10) + +/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire() + anger_modifier = Clamp(((maxHealth - health)/60),0,20) + if(charging) + return + ranged_cooldown = world.time + ranged_cooldown_time + + var/warped = FALSE + if(!try_bloodattack()) + spawn(0) + blood_spray() + warped = blood_warp() + if(warped && prob(100 - anger_modifier)) + return + + if(prob(90 - anger_modifier) || slaughterlings()) + if(health > maxHealth * 0.5) + spawn(0) + charge() + else + if(prob(70) || warped) + spawn(0) + triple_charge() + else + spawn(0) + warp_charge() + +/mob/living/simple_animal/hostile/megafauna/bubblegum/New() + ..() + for(var/mob/living/simple_animal/hostile/megafauna/bubblegum/B in mob_list) + if(B != src) + qdel(src) //There can be only one + break + var/obj/effect/proc_holder/spell/bloodcrawl/bloodspell = new + AddSpell(bloodspell) + if(istype(loc, /obj/effect/dummy/slaughter)) + bloodspell.phased = 1 + internal_gps = new/obj/item/device/gps/internal/bubblegum(src) + +/mob/living/simple_animal/hostile/megafauna/bubblegum/do_attack_animation(atom/A, visual_effect_icon) + if(!charging) + ..() + +/mob/living/simple_animal/hostile/megafauna/bubblegum/AttackingTarget() + if(!charging) + ..() + +/mob/living/simple_animal/hostile/megafauna/bubblegum/Goto(target, delay, minimum_distance) + if(!charging) + ..() + +/mob/living/simple_animal/hostile/megafauna/bubblegum/Move() + if(charging) + new /obj/effect/overlay/temp/decoy/fading(loc, src) + DestroySurroundings() + . = ..() + if(!stat && .) + playsound(src, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1) + if(charging) + DestroySurroundings() + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/warp_charge() + blood_warp() + charge() + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/triple_charge() + charge() + charge() + charge() + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge() + var/turf/T = get_turf(target) + if(!T || T == loc) + return + new /obj/effect/overlay/temp/dragon_swoop(T) + charging = 1 + DestroySurroundings() + walk(src, 0) + dir = get_dir(src, T) + var/obj/effect/overlay/temp/decoy/D = new /obj/effect/overlay/temp/decoy(loc, src) + animate(D, alpha = 0, color = "#FF0000", transform = matrix()*2, time = 5) + sleep(5) + throw_at(T, get_dist(src, T), 1, src, 0) + charging = 0 + try_bloodattack() + if(target) + Goto(target, move_to_delay, minimum_distance) + + +/mob/living/simple_animal/hostile/megafauna/bubblegum/Bump(atom/A) + if(charging) + if(isturf(A) || isobj(A) && A.density) + A.ex_act(2) + DestroySurroundings() + ..() + +/mob/living/simple_animal/hostile/megafauna/bubblegum/throw_impact(atom/A) + if(!charging) + return ..() + + else if(isliving(A)) + var/mob/living/L = A + L.visible_message("[src] slams into [L]!", "[src] slams into you!") + L.apply_damage(40, BRUTE) + playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, 1) + shake_camera(L, 4, 3) + shake_camera(src, 2, 3) + var/throwtarget = get_edge_target_turf(src, get_dir(src, get_step_away(L, src))) + L.throw_at_fast(throwtarget, 3) + + charging = 0 + + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_mobs_on_blood() + var/list/targets = ListTargets() + . = list() + for(var/mob/living/L in targets) + var/list/bloodpool = get_pools(get_turf(L), 0) + if(bloodpool.len && (!faction_check(L) || L.stat == DEAD)) + . += L + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack() + var/list/targets = get_mobs_on_blood() + if(targets.len) + spawn(0) + bloodattack(targets, prob(50)) + + return TRUE + return FALSE + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodattack(list/targets, handedness) + var/mob/living/target_one = pick_n_take(targets) + var/turf/target_one_turf = get_turf(target_one) + var/mob/living/target_two + if(targets.len) + target_two = pick_n_take(targets) + var/turf/target_two_turf = get_turf(target_two) + if(target_two.stat != CONSCIOUS || prob(10)) + bloodgrab(target_two_turf, handedness) + else + bloodsmack(target_two_turf, handedness) + + if(target_one) + var/list/pools = get_pools(get_turf(target_one), 0) + if(pools.len) + target_one_turf = get_turf(target_one) + if(target_one_turf) + if(target_one.stat != CONSCIOUS || prob(10)) + bloodgrab(target_one_turf, !handedness) + else + bloodsmack(target_one_turf, !handedness) + + if(!target_two && target_one) + var/list/poolstwo = get_pools(get_turf(target_one), 0) + if(poolstwo.len) + target_one_turf = get_turf(target_one) + if(target_one_turf) + if(target_one.stat != CONSCIOUS || prob(10)) + bloodgrab(target_one_turf, handedness) + else + bloodsmack(target_one_turf, handedness) + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodsmack(turf/T, handedness) + if(handedness) + new /obj/effect/overlay/temp/bubblegum_hands/rightsmack(T) + else + new /obj/effect/overlay/temp/bubblegum_hands/leftsmack(T) + sleep(2.5) + for(var/mob/living/L in T) + if(!faction_check(L)) + to_chat(L, "[src] rends you!") + playsound(T, attack_sound, 100, 1, -1) + var/limb_to_hit = pick("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg") + L.apply_damage(25, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, "melee", null, null, armour_penetration)) + sleep(3) + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T, handedness) + if(handedness) + new /obj/effect/overlay/temp/bubblegum_hands/rightpaw(T) + new /obj/effect/overlay/temp/bubblegum_hands/rightthumb(T) + else + new /obj/effect/overlay/temp/bubblegum_hands/leftpaw(T) + new /obj/effect/overlay/temp/bubblegum_hands/leftthumb(T) + sleep(6) + for(var/mob/living/L in T) + if(!faction_check(L)) + to_chat(L, "[src] drags you through the blood!") + playsound(T, 'sound/misc/enter_blood.ogg', 100, 1, -1) + var/turf/targetturf = get_step(src, dir) + L.forceMove(targetturf) + playsound(targetturf, 'sound/misc/exit_blood.ogg', 100, 1, -1) + if(L.stat != CONSCIOUS) + spawn(2) + devour(L) + sleep(1) + +/obj/effect/overlay/temp/bubblegum_hands + icon = 'icons/effects/bubblegum.dmi' + duration = 9 + +/obj/effect/overlay/temp/bubblegum_hands/rightthumb + icon_state = "rightthumbgrab" + +/obj/effect/overlay/temp/bubblegum_hands/leftthumb + icon_state = "leftthumbgrab" + +/obj/effect/overlay/temp/bubblegum_hands/rightpaw + icon_state = "rightpawgrab" + layer = MOB_LAYER - 0.1 + +/obj/effect/overlay/temp/bubblegum_hands/leftpaw + icon_state = "leftpawgrab" + layer = MOB_LAYER - 0.1 + +/obj/effect/overlay/temp/bubblegum_hands/rightsmack + icon_state = "rightsmack" + +/obj/effect/overlay/temp/bubblegum_hands/leftsmack + icon_state = "leftsmack" + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_warp() + if(Adjacent(target)) + return FALSE + var/list/can_jaunt = get_pools(get_turf(src), 1) + if(!can_jaunt.len) + return FALSE + + var/list/pools = get_pools(get_turf(target), 2) + var/list/pools_to_remove = get_pools(get_turf(target), 1) + pools -= pools_to_remove + if(!pools.len) + return FALSE + + var/obj/effect/overlay/temp/decoy/DA = new /obj/effect/overlay/temp/decoy(loc, src) + DA.color = "#FF0000" + var/oldtransform = DA.transform + DA.transform = matrix()*2 + animate(DA, alpha = 255, color = initial(DA.color), transform = oldtransform, time = 5) + sleep(5) + qdel(DA) + + var/obj/effect/decal/cleanable/blood/found_bloodpool + pools = get_pools(get_turf(target), 2) + pools_to_remove = get_pools(get_turf(target), 1) + pools -= pools_to_remove + if(pools.len) + shuffle(pools) + found_bloodpool = pick(pools) + if(found_bloodpool) + visible_message("[src] sinks into the blood...") + playsound(get_turf(src), 'sound/misc/enter_blood.ogg', 100, 1, -1) + forceMove(get_turf(found_bloodpool)) + playsound(get_turf(src), 'sound/misc/exit_blood.ogg', 100, 1, -1) + visible_message("And springs back out!") + return TRUE + return FALSE + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/get_pools(turf/T, range) + . = list() + for(var/obj/effect/decal/cleanable/nearby in view(T, range)) + if(nearby.can_bloodcrawl_in()) + . += nearby + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_spray() + visible_message("[src] sprays a stream of gore!") + var/range = 6 + round(anger_modifier * 0.4) + var/turf/previousturf = get_turf(src) + var/turf/J = previousturf + var/targetdir = get_dir(src, target) + if(target.loc == loc) + targetdir = dir + face_atom(target) + new /obj/effect/decal/cleanable/blood/bubblegum(J) + for(var/i in 1 to range) + J = get_step(previousturf, targetdir) + new /obj/effect/overlay/temp/dir_setting/bloodsplatter(previousturf, get_dir(previousturf, J)) + playsound(previousturf,'sound/effects/splat.ogg', 100, 1, -1) + if(!J || !previousturf.CanAtmosPass(J)) + break + new /obj/effect/decal/cleanable/blood/bubblegum(J) + previousturf = J + sleep(1) + +/obj/effect/decal/cleanable/blood/bubblegum + amount = 0 + +/obj/effect/decal/cleanable/blood/bubblegum/can_bloodcrawl_in() + return TRUE + +/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings() + visible_message("[src] summons a shoal of slaughterlings!") + var/max_amount = 6 + for(var/H in get_pools(get_turf(src), 1)) + if(!max_amount) + break + max_amount-- + var/obj/effect/decal/cleanable/blood/B = H + new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter(B.loc) + return max_amount + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter + name = "slaughterling" + desc = "Though not yet strong enough to create a true physical form, it's nonetheless determined to murder you." + density = 0 + faction = list("mining", "boss") + weather_immunities = list("lava","ash") + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter/CanPass(atom/movable/mover, turf/target, height = 0) + if(istype(mover, /mob/living/simple_animal/hostile/megafauna/bubblegum)) + return 1 + return 0 + +#undef MEDAL_PREFIX \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm new file mode 100644 index 00000000000..b40e64c6a31 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm @@ -0,0 +1,266 @@ + +#define MEDAL_PREFIX "Colossus" +/* + +COLOSSUS + +The colossus spawns randomly wherever a lavaland creature is able to spawn. It is powerful, ancient, and extremely deadly. +The colossus has a degree of sentience, proving this in speech during its attacks. + +It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage. + +The colossus' true danger lies in its ranged capabilities. It fires immensely damaging death bolts that penetrate all armor in a variety of ways: + 1. The colossus fires death bolts in alternating patterns: the cardinal directions and the diagonal directions. + 2. The colossus fires death bolts in a shotgun-like pattern, instantly downing anything unfortunate enough to be hit by all of them. + 3. The colossus fires a spiral of death bolts. +At 33% health, the colossus gains an additional attack: + 4. The colossus fires two spirals of death bolts, spinning in opposite directions. + +When a colossus dies, it leaves behind a chunk of glowing crystal known as a black box. Anything placed inside will carry over into future rounds. +For instance, you could place a bag of holding into the black box, and then kill another colossus next round and retrieve the bag of holding from inside. + +Difficulty: Very Hard + +*/ + +/mob/living/simple_animal/hostile/megafauna/colossus + name = "colossus" + desc = "A monstrous creature protected by heavy shielding." + health = 2500 + maxHealth = 2500 + attacktext = "judges" + attack_sound = 'sound/magic/ratvar_attack.ogg' + icon_state = "eva" + icon_living = "eva" + icon_dead = "dragon_dead" + friendly = "stares down" + icon = 'icons/mob/lavaland/96x96megafauna.dmi' + speak_emote = list("roars") + armour_penetration = 40 + melee_damage_lower = 40 + melee_damage_upper = 40 + speed = 1 + move_to_delay = 10 + ranged = 1 + pixel_x = -32 + del_on_death = 1 + medal_type = MEDAL_PREFIX + score_type = COLOSSUS_SCORE + loot = list(/obj/machinery/anomalous_crystal/random, /obj/item/organ/internal/vocal_cords/colossus) + butcher_results = list(/obj/item/weapon/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30) + deathmessage = "disintegrates, leaving a glowing core in its wake." + death_sound = 'sound/misc/demon_dies.ogg' + +/mob/living/simple_animal/hostile/megafauna/colossus/devour(mob/living/L) + visible_message("[src] disintegrates [L]!") + L.dust() + +/mob/living/simple_animal/hostile/megafauna/colossus/OpenFire() + anger_modifier = Clamp(((maxHealth - health)/50),0,20) + ranged_cooldown = world.time + 120 + + if(enrage(target)) + if(move_to_delay == initial(move_to_delay)) + visible_message("\"You can't dodge.\"") + ranged_cooldown = world.time + 30 + telegraph() + dir_shots(alldirs) + move_to_delay = 3 + return + else + move_to_delay = initial(move_to_delay) + + if(prob(20+anger_modifier)) //Major attack + telegraph() + + if(health < maxHealth/3) + double_spiral() + else + visible_message("\"Judgement.\"") + spawn(0) + spiral_shoot(rand(0, 1)) + + else if(prob(20)) + ranged_cooldown = world.time + 30 + random_shots() + else + if(prob(70)) + ranged_cooldown = world.time + 20 + blast() + else + ranged_cooldown = world.time + 40 + spawn(0) + alternating_dir_shots() + + +/mob/living/simple_animal/hostile/megafauna/colossus/New() + ..() + internal_gps = new/obj/item/device/gps/internal/colossus(src) + +/obj/effect/overlay/temp/at_shield + name = "anti-toolbox field" + desc = "A shimmering forcefield protecting the colossus." + icon = 'icons/effects/effects.dmi' + icon_state = "at_shield2" + layer = FLY_LAYER + luminosity = 2 + duration = 8 + var/target + +/obj/effect/overlay/temp/at_shield/New(new_loc, new_target) + ..() + target = new_target + spawn(0) + orbit(target, 0, FALSE, 0, 0, FALSE, TRUE) + +/mob/living/simple_animal/hostile/megafauna/colossus/bullet_act(obj/item/projectile/P) + if(!stat) + var/obj/effect/overlay/temp/at_shield/AT = new /obj/effect/overlay/temp/at_shield(loc, src) + var/random_x = rand(-32, 32) + AT.pixel_x += random_x + + var/random_y = rand(0, 72) + AT.pixel_y += random_y + ..() + +/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(H.martial_art && prob(H.martial_art.deflection_chance)) + . = TRUE + +/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots() + dir_shots(diagonals) + sleep(10) + dir_shots(cardinal) + sleep(10) + dir_shots(diagonals) + sleep(10) + dir_shots(cardinal) + +/mob/living/simple_animal/hostile/megafauna/colossus/proc/double_spiral() + visible_message("\"Die.\"") + + sleep(10) + spawn(0) + spiral_shoot() + spawn(0) + spiral_shoot(1) + +/mob/living/simple_animal/hostile/megafauna/colossus/proc/spiral_shoot(negative = 0, counter_start = 1) + var/counter = counter_start + var/turf/marker + for(var/i in 1 to 80) + switch(counter) + if(1) + marker = locate(x, y - 2, z) + if(2) + marker = locate(x - 1, y - 2, z) + if(3) + marker = locate(x - 2, y - 2, z) + if(4) + marker = locate(x - 2, y - 1, z) + if(5) + marker = locate(x - 2, y, z) + if(6) + marker = locate(x - 2, y + 1, z) + if(7) + marker = locate(x - 2, y + 2, z) + if(8) + marker = locate(x - 1, y + 2, z) + if(9) + marker = locate(x, y + 2, z) + if(10) + marker = locate(x + 1, y + 2, z) + if(11) + marker = locate(x + 2, y + 2, z) + if(12) + marker = locate(x + 2, y + 1, z) + if(13) + marker = locate(x + 2, y, z) + if(14) + marker = locate(x + 2, y - 1, z) + if(15) + marker = locate(x + 2, y - 2, z) + if(16) + marker = locate(x + 1, y - 2, z) + + if(negative) + counter-- + else + counter++ + if(counter > 16) + counter = 1 + if(counter < 1) + counter = 16 + shoot_projectile(marker) + playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 20, 1) + sleep(1) + +/mob/living/simple_animal/hostile/megafauna/colossus/proc/shoot_projectile(turf/marker) + if(!marker || marker == loc) + return + var/turf/startloc = get_turf(src) + var/obj/item/projectile/P = new /obj/item/projectile/colossus(startloc) + P.current = startloc + P.starting = startloc + P.firer = src + P.yo = marker.y - startloc.y + P.xo = marker.x - startloc.x + if(target) + P.original = target + else + P.original = marker + P.fire() + +/mob/living/simple_animal/hostile/megafauna/colossus/proc/random_shots() + var/turf/U = get_turf(src) + playsound(U, 'sound/magic/invoke_general.ogg', 300, 1, 5) + for(var/T in RANGE_TURFS(12, U) - U) + if(prob(5)) + shoot_projectile(T) + +/mob/living/simple_animal/hostile/megafauna/colossus/proc/blast() + playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 200, 1, 2) + var/turf/T = get_turf(target) + newtonian_move(get_dir(T, targets_from)) + for(var/turf/turf in range(1, T)) + shoot_projectile(turf) + +/mob/living/simple_animal/hostile/megafauna/colossus/proc/dir_shots(list/dirs) + if(!islist(dirs)) + dirs = alldirs.Copy() + playsound(get_turf(src), 'sound/magic/invoke_general.ogg', 200, 1, 2) + for(var/d in dirs) + var/turf/E = get_step(src, d) + shoot_projectile(E) + +/mob/living/simple_animal/hostile/megafauna/colossus/proc/telegraph() + for(var/mob/M in range(10,src)) + if(M.client) + flash_color(M.client, rgb(200, 0, 0), 1) + shake_camera(M, 4, 3) + playsound(get_turf(src),'sound/magic/narsie_attack.ogg', 200, 1) + +/obj/item/projectile/colossus + name ="death bolt" + icon_state= "chronobolt" + damage = 25 + armour_penetration = 100 + speed = 2 + eyeblur = 0 + damage_type = BRUTE + pass_flags = PASSTABLE + +/obj/item/projectile/colossus/on_hit(atom/target, blocked = 0) + . = ..() + if(isturf(target) || isobj(target)) + target.ex_act(2) + +/obj/item/device/gps/internal/colossus + icon_state = null + gpstag = "Angelic Signal" + desc = "Get in the fucking robot." + invisibility = 100 + +#undef MEDAL_PREFIX diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm new file mode 100644 index 00000000000..5afa7613c78 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm @@ -0,0 +1,278 @@ +#define MEDAL_PREFIX "Drake" +/* + +ASH DRAKE + +Ash drakes spawn randomly wherever a lavaland creature is able to spawn. They are the draconic guardians of the Necropolis. + +It acts as a melee creature, chasing down and attacking its target while also using different attacks to augment its power that increase as it takes damage. + +Whenever possible, the drake will breathe fire in the four cardinal directions, igniting and heavily damaging anything caught in the blast. +It also often causes fire to rain from the sky - many nearby turfs will flash red as a fireball crashes into them, dealing damage to anything on the turfs. +The drake also utilizes its wings to fly into the sky and crash down onto a specified point. Anything on this point takes tremendous damage. + - Sometimes it will chain these swooping attacks over and over, making swiftness a necessity. + +When an ash drake dies, it leaves behind a chest that can contain four things: + 1. A spectral blade that allows its wielder to call ghosts to it, enhancing its power + 2. A lava staff that allows its wielder to create lava + 3. A spellbook and wand of fireballs + 4. A bottle of dragon's blood with several effects, including turning its imbiber into a drake themselves. + +When butchered, they leave behind diamonds, sinew, bone, and ash drake hide. Ash drake hide can be used to create a hooded cloak that protects its wearer from ash storms. + +Difficulty: Medium + +*/ + +/mob/living/simple_animal/hostile/megafauna/dragon + name = "ash drake" + desc = "Guardians of the necropolis." + health = 2500 + maxHealth = 2500 + attacktext = "chomps" + attack_sound = 'sound/misc/demon_attack1.ogg' + icon_state = "dragon" + icon_living = "dragon" + icon_dead = "dragon_dead" + friendly = "stares down" + icon = 'icons/mob/lavaland/dragon.dmi' + speak_emote = list("roars") + armour_penetration = 40 + melee_damage_lower = 40 + melee_damage_upper = 40 + speed = 1 + move_to_delay = 10 + ranged = 1 + pixel_x = -16 + loot = list(/obj/structure/closet/crate/necropolis/dragon) + butcher_results = list(/obj/item/weapon/ore/diamond = 5, /obj/item/stack/sheet/sinew = 5, /obj/item/stack/sheet/animalhide/ashdrake = 10, /obj/item/stack/sheet/bone = 30) + var/swooping = 0 + var/swoop_cooldown = 0 + medal_type = MEDAL_PREFIX + score_type = DRAKE_SCORE + deathmessage = "collapses into a pile of bones, its flesh sloughing away." + death_sound = 'sound/misc/demon_dies.ogg' + +/mob/living/simple_animal/hostile/megafauna/dragon/New() + ..() + internal_gps = new/obj/item/device/gps/internal/dragon(src) + +/mob/living/simple_animal/hostile/megafauna/dragon/ex_act(severity, target) + if(severity == 3) + return + ..() + +/mob/living/simple_animal/hostile/megafauna/dragon/adjustHealth(amount) + if(swooping) + return 0 + return ..() + +/mob/living/simple_animal/hostile/megafauna/dragon/AttackingTarget() + if(!swooping) + ..() + +/mob/living/simple_animal/hostile/megafauna/dragon/DestroySurroundings() + if(!swooping) + ..() + +/mob/living/simple_animal/hostile/megafauna/dragon/Move() + if(!swooping) + ..() + +/mob/living/simple_animal/hostile/megafauna/dragon/Goto(target, delay, minimum_distance) + if(!swooping) + ..() + +/mob/living/simple_animal/hostile/megafauna/dragon/Process_Spacemove(movement_dir = 0) + return 1 + +/obj/effect/overlay/temp/fireball + icon = 'icons/obj/wizard.dmi' + icon_state = "fireball" + name = "fireball" + desc = "Get out of the way!" + layer = 6 + randomdir = 0 + duration = 12 + pixel_z = 500 + +/obj/effect/overlay/temp/fireball/New(loc) + ..() + animate(src, pixel_z = 0, time = 12) + +/obj/effect/overlay/temp/target + icon = 'icons/mob/actions.dmi' + icon_state = "sniper_zoom" + layer = MOB_LAYER - 0.1 + luminosity = 2 + duration = 12 + +/obj/effect/overlay/temp/dragon_swoop + name = "certain death" + desc = "Don't just stand there, move!" + icon = 'icons/effects/96x96.dmi' + icon_state = "landing" + layer = MOB_LAYER - 0.1 + pixel_x = -32 + pixel_y = -32 + color = "#FF0000" + duration = 10 + +/obj/effect/overlay/temp/target/ex_act() + return + +/obj/effect/overlay/temp/target/New(loc) + ..() + spawn(0) + fall() + +/obj/effect/overlay/temp/target/proc/fall() + var/turf/T = get_turf(src) + playsound(T,'sound/magic/Fireball.ogg', 200, 1) + new /obj/effect/overlay/temp/fireball(T) + sleep(12) + explosion(T, 0, 0, 1, 0, 0, 0, 1) + +/mob/living/simple_animal/hostile/megafauna/dragon/OpenFire() + anger_modifier = Clamp(((maxHealth - health)/50),0,20) + ranged_cooldown = world.time + ranged_cooldown_time + if(swooping) + fire_rain() + return + + if(prob(15 + anger_modifier) && !client) + if(health < maxHealth/2) + spawn(0) + swoop_attack(1) + else + fire_rain() + + else if(prob(10+anger_modifier) && !client) + if(health > maxHealth/2) + spawn(0) + swoop_attack(0) + else + spawn(0) + triple_swoop(0) + else + fire_walls() + +/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_rain() + visible_message("Fire rains from the sky!") + for(var/turf/turf in range(12,get_turf(src))) + if(prob(10)) + new /obj/effect/overlay/temp/target(turf) + +/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_walls() + playsound(get_turf(src),'sound/magic/Fireball.ogg', 200, 1) + + for(var/d in cardinal) + spawn(0) + fire_wall(d) + +/mob/living/simple_animal/hostile/megafauna/dragon/proc/fire_wall(dir) + var/list/hit_things = list(src) + var/turf/E = get_edge_target_turf(src, dir) + var/range = 10 + var/turf/previousturf = get_turf(src) + for(var/turf/J in getline(src,E)) + if(!range || !previousturf.CanAtmosPass(J)) + break + range-- + new /obj/effect/hotspot(J) + J.hotspot_expose(700,50,1) + for(var/mob/living/L in J.contents - hit_things) + L.adjustFireLoss(20) + to_chat(L, "You're hit by the drake's fire breath!") + hit_things += L + previousturf = J + sleep(1) + +/mob/living/simple_animal/hostile/megafauna/dragon/proc/triple_swoop() + swoop_attack() + swoop_attack() + swoop_attack() + +/mob/living/simple_animal/hostile/megafauna/dragon/proc/swoop_attack(fire_rain = 0, atom/movable/manual_target) + if(stat || swooping) + return + swoop_cooldown = world.time + 200 + var/atom/swoop_target + if(manual_target) + swoop_target = manual_target + else + swoop_target = target + stop_automated_movement = TRUE + swooping = 1 + density = 0 + icon_state = "swoop" + visible_message("[src] swoops up high!") + if(prob(50)) + animate(src, pixel_x = 500, pixel_z = 500, time = 10) + else + animate(src, pixel_x = -500, pixel_z = 500, time = 10) + sleep(30) + + var/turf/tturf + if(fire_rain) + fire_rain() + + icon_state = "dragon" + if(swoop_target && !qdeleted(swoop_target) && swoop_target.z == src.z) + tturf = get_turf(swoop_target) + else + tturf = get_turf(src) + forceMove(tturf) + new /obj/effect/overlay/temp/dragon_swoop(tturf) + animate(src, pixel_x = initial(pixel_x), pixel_z = 0, time = 10) + sleep(10) + playsound(src.loc, 'sound/effects/meteorimpact.ogg', 200, 1) + for(var/mob/living/L in orange(1, src)) + if(L.stat) + visible_message("[src] slams down on [L], crushing them!") + L.gib() + else + L.adjustBruteLoss(75) + if(L && !qdeleted(L)) // Some mobs are deleted on death + var/throw_dir = get_dir(src, L) + if(L.loc == loc) + throw_dir = pick(alldirs) + var/throwtarget = get_edge_target_turf(src, throw_dir) + L.throw_at_fast(throwtarget, 3) + visible_message("[L] is thrown clear of [src]!") + + for(var/mob/M in range(7, src)) + shake_camera(M, 15, 1) + + stop_automated_movement = FALSE + swooping = 0 + density = 1 + +/mob/living/simple_animal/hostile/megafauna/dragon/AltClickOn(atom/movable/A) + if(!istype(A)) + return + if(swoop_cooldown >= world.time) + to_chat(src, "You need to wait 20 seconds between swoop attacks!") + return + swoop_attack(1, A) + +/obj/item/device/gps/internal/dragon + icon_state = null + gpstag = "Fiery Signal" + desc = "Here there be dragons." + invisibility = 100 + +/mob/living/simple_animal/hostile/megafauna/dragon/lesser + name = "lesser ash drake" + maxHealth = 200 + health = 200 + faction = list("neutral") + melee_damage_upper = 30 + melee_damage_lower = 30 + damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) + loot = list() + +/mob/living/simple_animal/hostile/megafauna/dragon/lesser/grant_achievement(medaltype,scoretype) + return + +#undef MEDAL_PREFIX \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm new file mode 100644 index 00000000000..dfb9948a1e3 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm @@ -0,0 +1,611 @@ +#define MEDAL_PREFIX "Hierophant" +/* + +The Hierophant + +The Hierophant spawns in its arena, an area designed to make it harder to fight than it would otherwise be. + +The text this boss speaks is ROT4, use ROT22 to decode + +The Hierophant's attacks are as follows, and INTENSIFY at a random chance based on Hierophant's health; +- Creates a cardinal or diagonal blast(Cross Blast) under its target, exploding after a short time. + INTENSITY EFFECT: Creates one of the cross blast types under itself instead of under the target. + INTENSITY EFFECT: The created Cross Blast fires in all directions if below half health. +- If no chasers exist, creates a chaser that will seek its target, leaving a trail of blasts. + INTENSITY EFFECT: Creates a second, slower chaser. +- Creates an expanding AoE burst. +- INTENSE ATTACKS: + If target is at least 2 tiles away; Blinks to the target after a very brief delay, damaging everything near the start and end points. + As above, but does so multiple times if below half health. + Rapidly creates Cross Blasts under a target. + If chasers are off cooldown, creates four high-speed chasers. +- IF TARGET WAS STRUCK IN MELEE: Creates a 3x3 square of blasts under the target. + +Cross Blasts and the AoE burst gain additional range as the Hierophant loses health, while Chasers gain additional speed. + +When The Hierophant dies, it leaves behind its staff, which, while much weaker than when wielded by The Hierophant itself, is still quite effective. +- The staff can place a teleport rune, allowing the user to teleport themself and their allies to the rune. + +Difficulty: Hard + +*/ + +/mob/living/simple_animal/hostile/megafauna/hierophant + name = "Hierophant" + desc = "An ancient, powerful priest-like being wielding a mighty staff." + health = 2500 + maxHealth = 2500 + attacktext = "clubs" + //attack_sound = 'sound/weapons/sonic_jackhammer.ogg' + attack_sound = "swing_hit" + icon_state = "hierophant" + icon_living = "hierophant" + friendly = "stares down" + icon = 'icons/mob/lavaland/hierophant.dmi' + faction = list("boss") //asteroid mobs? get that shit out of my beautiful square house + speak_emote = list("preaches") + armour_penetration = 50 + melee_damage_lower = 10 + melee_damage_upper = 10 + speed = 1 + move_to_delay = 10 + ranged = 1 + pixel_x = -16 + ranged_cooldown_time = 40 + aggro_vision_range = 23 + loot = list(/obj/item/weapon/hierophant_staff) + wander = FALSE + var/burst_range = 3 //range on burst aoe + var/beam_range = 5 //range on cross blast beams + var/chaser_speed = 3 //how fast chasers are currently + var/chaser_cooldown = 101 //base cooldown/cooldown var between spawning chasers + var/major_attack_cooldown = 60 //base cooldown for major attacks + var/blinking = FALSE //if we're doing something that requires us to stand still and not attack + var/obj/effect/hierophant/spawned_rune //the rune we teleport back to + var/timeout_time = 15 //after this many Life() ticks with no target, we return to our rune + var/did_reset = TRUE //if we timed out, returned to our rune, and healed some + //var/list/kill_phrases = list("Wsyvgi sj irivkc xettih. Vitemvmrk...", "Irivkc wsyvgi jsyrh. Vitemvmrk...", "Jyip jsyrh. Egxmzexmrk vitemv gcgpiw...") + //var/list/target_phrases = list("Xevkix psgexih.", "Iriqc jsyrh.", "Eguymvih xevkix.") + medal_type = MEDAL_PREFIX + score_type = BIRD_SCORE + del_on_death = TRUE + death_sound = 'sound/magic/Repulse.ogg' + +/mob/living/simple_animal/hostile/megafauna/hierophant/New() + ..() + internal_gps = new/obj/item/device/gps/internal/hierophant(src) + spawned_rune = new(loc) + +/mob/living/simple_animal/hostile/megafauna/hierophant/Life() + . = ..() + if(. && spawned_rune && !client) + if(target || loc == spawned_rune.loc) + timeout_time = initial(timeout_time) + else + timeout_time-- + if(timeout_time <= 0 && !did_reset) + did_reset = TRUE + //visible_message("\"Vixyvrmrk xs fewi...\"") + blink(spawned_rune) + adjustHealth(min((health - maxHealth) * 0.5, -50)) //heal for 50% of our missing health + wander = FALSE + /*if(health > maxHealth * 0.9) + visible_message("\"Vitemvw gsqtpixi. Stivexmrk ex qebmqyq ijjmgmirgc.\"") + else + visible_message("\"Vitemvw gsqtpixi. Stivexmsrep ijjmgmirgc gsqtvsqmwih.\"")*/ + +/mob/living/simple_animal/hostile/megafauna/hierophant/death() + if(health > 0 || stat == DEAD) + return + else + stat = DEAD + blinking = TRUE //we do a fancy animation, release a huge burst(), and leave our staff. + animate(src, alpha = 0, color = "660099", time = 20, easing = EASE_OUT) + burst_range = 10 + //visible_message("\"Mrmxmexmrk wipj-hiwxvygx wiuyirgi...\"") + visible_message("[src] disappears in a massive burst of magic, leaving only its staff.") + burst(get_turf(src)) + ..() + +/mob/living/simple_animal/hostile/megafauna/hierophant/Destroy() + qdel(spawned_rune) + . = ..() + +/mob/living/simple_animal/hostile/megafauna/hierophant/devour(mob/living/L) + for(var/obj/item/W in L) + if(!L.unEquip(W)) + qdel(W) + /*visible_message( + "\"[pick(kill_phrases)]\"\n[src] annihilates [L]!", + "You annihilate [L], restoring your health!")*/ + visible_message( + "\"Caw.\"\n[src] annihilates [L]!", + "You annihilate [L], restoring your health!") + adjustHealth(-L.maxHealth*0.5) + L.dust() + +/*/mob/living/simple_animal/hostile/megafauna/hierophant/GiveTarget(new_target) + var/targets_the_same = (new_target == target) + . = ..() + if(. && target && !targets_the_same) + visible_message("\"[pick(target_phrases)]\"")*/ + +/mob/living/simple_animal/hostile/megafauna/hierophant/adjustHealth(amount) + . = ..() + if(src && amount > 0 && !blinking) + wander = TRUE + did_reset = FALSE + +/mob/living/simple_animal/hostile/megafauna/hierophant/AttackingTarget() + if(!blinking) + if(target && isliving(target)) + spawn(0) + melee_blast(get_turf(target)) //melee attacks on living mobs produce a 3x3 blast + ..() + +/mob/living/simple_animal/hostile/megafauna/hierophant/DestroySurroundings() + if(!blinking) + ..() + +/mob/living/simple_animal/hostile/megafauna/hierophant/Move() + if(!blinking) + /*if(!stat) + playsound(loc, 'sound/mecha/mechmove04.ogg', 150, 1, -4)*/ + ..() + +/mob/living/simple_animal/hostile/megafauna/hierophant/Goto(target, delay, minimum_distance) + wander = TRUE + if(!blinking) + ..() + +/mob/living/simple_animal/hostile/megafauna/hierophant/proc/calculate_rage() //how angry we are overall + did_reset = FALSE //oh hey we're doing SOMETHING, clearly we might need to heal if we recall + anger_modifier = Clamp(((maxHealth - health) / 42),0,50) + burst_range = initial(burst_range) + round(anger_modifier * 0.08) + beam_range = initial(beam_range) + round(anger_modifier * 0.12) + +/mob/living/simple_animal/hostile/megafauna/hierophant/OpenFire() + calculate_rage() + var/target_is_slow = FALSE + if(isliving(target)) + var/mob/living/L = target + if(!blinking && L.stat == DEAD && get_dist(src, L) > 2) + blink(L) + return + if(L.movement_delay() > 1.5) + target_is_slow = TRUE + chaser_speed = max(1, (3 - anger_modifier * 0.04) + target_is_slow * 0.5) + if(blinking) + return + ranged_cooldown = world.time + max(5, ranged_cooldown_time - anger_modifier * 0.75) //scale cooldown lower with high anger. + + if(prob(anger_modifier * 0.75)) //major ranged attack + var/list/possibilities = list() + var/cross_counter = 1 + round(anger_modifier * 0.12) + if(cross_counter > 1) + possibilities += "cross_blast_spam" + if(get_dist(src, target) > 2) + possibilities += "blink_spam" + if(chaser_cooldown < world.time) + if(prob(anger_modifier * 2)) + possibilities = list("chaser_swarm") + else + possibilities += "chaser_swarm" + if(possibilities.len) + ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75) //we didn't cancel out of an attack, use the higher cooldown + var/blink_counter = 1 + round(anger_modifier * 0.08) + switch(pick(possibilities)) + if("blink_spam") //blink either once or multiple times. + if(health < maxHealth * 0.5 && !target_is_slow && blink_counter > 1) + //visible_message("\"Mx ampp rsx iwgeti.\"") + animate(src, color = "#660099", time = 6) + while(health && target && blink_counter) + if(loc == target.loc || loc == target) //we're on the same tile as them after about a second we can stop now + break + blink_counter-- + blinking = FALSE + blink(target) + blinking = TRUE + sleep(5) + animate(src, color = initial(color), time = 8) + sleep(8) + blinking = FALSE + else + blink(target) + if("cross_blast_spam") //fire a lot of cross blasts at a target. + //visible_message("\"Piezi mx rsalivi xs vyr.\"") + blinking = TRUE + animate(src, color = "#660099", time = 6) + while(health && target && cross_counter) + cross_counter-- + var/delay = 6 + if(prob(60)) + spawn(0) + cardinal_blasts(target) + else + spawn(0) + diagonal_blasts(target) + delay = 5 //this one isn't so mean, so do the next one faster(if there is one) + sleep(delay) + animate(src, color = initial(color), time = 8) + sleep(8) + blinking = FALSE + if("chaser_swarm") //fire four fucking chasers at a target and their friends. + //visible_message("\"Mx gerrsx lmhi.\"") + blinking = TRUE + animate(src, color = "#660099", time = 10) + var/list/targets = ListTargets() + var/list/cardinal_copy = cardinal.Copy() + while(health && targets.len && cardinal_copy.len) + var/mob/living/pickedtarget = pick(targets) + if(targets.len > 4) + pickedtarget = pick_n_take(targets) + if(pickedtarget.stat == DEAD) + pickedtarget = target + var/obj/effect/overlay/temp/hierophant/chaser/C = new /obj/effect/overlay/temp/hierophant/chaser(loc, src, pickedtarget, chaser_speed, FALSE) + C.moving = 3 + C.moving_dir = pick_n_take(cardinal_copy) + sleep(10) + chaser_cooldown = world.time + initial(chaser_cooldown) + animate(src, color = initial(color), time = 8) + sleep(8) + blinking = FALSE + return + + if(prob(10 + (anger_modifier * 0.5)) && get_dist(src, target) > 2) + blink(target) + + else if(prob(70 - anger_modifier)) //a cross blast of some type + if(prob(anger_modifier)) //at us? + if(prob(anger_modifier * 2) && health < maxHealth * 0.5) //we're super angry do it at all dirs + spawn(0) + alldir_blasts(src) + else if(prob(60)) + spawn(0) + cardinal_blasts(src) + else + spawn(0) + diagonal_blasts(src) + else //at them? + if(prob(anger_modifier * 2) && health < maxHealth * 0.5 && !target_is_slow) //we're super angry do it at all dirs + spawn(0) + alldir_blasts(target) + else if(prob(60)) + spawn(0) + cardinal_blasts(target) + else + spawn(0) + diagonal_blasts(target) + else if(chaser_cooldown < world.time) //if chasers are off cooldown, fire some! + var/obj/effect/overlay/temp/hierophant/chaser/C = new /obj/effect/overlay/temp/hierophant/chaser(loc, src, target, chaser_speed, FALSE) + chaser_cooldown = world.time + initial(chaser_cooldown) + if((prob(anger_modifier) || target.Adjacent(src)) && target != src) + var/obj/effect/overlay/temp/hierophant/chaser/OC = new /obj/effect/overlay/temp/hierophant/chaser(loc, src, target, max(1.5, 5 - anger_modifier * 0.07), FALSE) + OC.moving = 4 + OC.moving_dir = pick(cardinal - C.moving_dir) + else //just release a burst of power + spawn(0) + burst(get_turf(src)) + +/mob/living/simple_animal/hostile/megafauna/hierophant/proc/diagonal_blasts(mob/victim) //fire diagonal cross blasts with a delay + var/turf/T = get_turf(victim) + if(!T) + return + new /obj/effect/overlay/temp/hierophant/telegraph/diagonal(T, src) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/effects/bin_close.ogg', 200, 1) + sleep(2) + new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE) + for(var/d in diagonals) + spawn(0) + blast_wall(T, d) + +/mob/living/simple_animal/hostile/megafauna/hierophant/proc/cardinal_blasts(mob/victim) //fire cardinal cross blasts with a delay + var/turf/T = get_turf(victim) + if(!T) + return + new /obj/effect/overlay/temp/hierophant/telegraph/cardinal(T, src) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/effects/bin_close.ogg', 200, 1) + sleep(2) + new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE) + for(var/d in cardinal) + spawn(0) + blast_wall(T, d) + +/mob/living/simple_animal/hostile/megafauna/hierophant/proc/alldir_blasts(mob/victim) //fire alldir cross blasts with a delay + var/turf/T = get_turf(victim) + if(!T) + return + new /obj/effect/overlay/temp/hierophant/telegraph(T, src) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/effects/bin_close.ogg', 200, 1) + sleep(2) + new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE) + for(var/d in alldirs) + spawn(0) + blast_wall(T, d) + +/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blast_wall(turf/T, dir) //make a wall of blasts beam_range tiles long + var/range = beam_range + var/turf/previousturf = T + var/turf/J = get_step(previousturf, dir) + for(var/i in 1 to range) + new /obj/effect/overlay/temp/hierophant/blast(J, src, FALSE) + previousturf = J + J = get_step(previousturf, dir) + +/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink(mob/victim) //blink to a target + if(blinking || !victim) + return + var/turf/T = get_turf(victim) + var/turf/source = get_turf(src) + new /obj/effect/overlay/temp/hierophant/telegraph(T, src) + new /obj/effect/overlay/temp/hierophant/telegraph(source, src) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/magic/Wand_Teleport.ogg', 200, 1) + playsound(source,'sound/magic/blink.ogg', 200, 1) + //playsound(source,'sound/machines/AirlockOpen.ogg', 200, 1) + blinking = TRUE + sleep(2) //short delay before we start... + new /obj/effect/overlay/temp/hierophant/telegraph/teleport(T, src) + new /obj/effect/overlay/temp/hierophant/telegraph/teleport(source, src) + for(var/t in RANGE_TURFS(1, T)) + var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, src, FALSE) + B.damage = 30 + for(var/t in RANGE_TURFS(1, source)) + var/obj/effect/overlay/temp/hierophant/blast/B = new /obj/effect/overlay/temp/hierophant/blast(t, src, FALSE) + B.damage = 30 + animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out + sleep(1) + visible_message("[src] fades out!") + density = FALSE + sleep(2) + forceMove(T) + sleep(1) + animate(src, alpha = 255, time = 2, easing = EASE_IN) //fade IN + sleep(1) + density = TRUE + visible_message("[src] fades in!") + sleep(1) //at this point the blasts we made detonate + blinking = FALSE + +/mob/living/simple_animal/hostile/megafauna/hierophant/proc/melee_blast(mob/victim) //make a 3x3 blast around a target + if(!victim) + return + var/turf/T = get_turf(victim) + if(!T) + return + new /obj/effect/overlay/temp/hierophant/telegraph(T, src) + playsound(T,'sound/magic/blink.ogg', 200, 1) + //playsound(T,'sound/effects/bin_close.ogg', 200, 1) + sleep(2) + for(var/t in RANGE_TURFS(1, T)) + new /obj/effect/overlay/temp/hierophant/blast(t, src, FALSE) + +/mob/living/simple_animal/hostile/megafauna/hierophant/proc/burst(turf/original) //release a wave of blasts + playsound(original,'sound/magic/blink.ogg', 200, 1) + //playsound(original,'sound/machines/AirlockOpen.ogg', 200, 1) + var/last_dist = 0 + for(var/t in spiral_range_turfs(burst_range, original)) + var/turf/T = t + if(!T) + continue + var/dist = get_dist(original, T) + if(dist > last_dist) + last_dist = dist + sleep(1 + (burst_range - last_dist) * 0.5) //gets faster as it gets further out + new /obj/effect/overlay/temp/hierophant/blast(T, src, FALSE) + +/mob/living/simple_animal/hostile/megafauna/hierophant/AltClickOn(atom/A) //player control handler(don't give this to a player holy fuck) + if(!istype(A) || get_dist(A, src) <= 2) + return + blink(A) + +//Hierophant overlays +/obj/effect/overlay/temp/hierophant + layer = MOB_LAYER - 0.1 + var/mob/living/caster //who made this, anyway + +/obj/effect/overlay/temp/hierophant/New(loc, new_caster) + ..() + if(new_caster) + caster = new_caster + +/obj/effect/overlay/temp/hierophant/chaser //a hierophant's chaser. follows target around, moving and producing a blast every speed deciseconds. + duration = 98 + var/mob/living/target //what it's following + var/turf/targetturf //what turf the target is actually on + var/moving_dir //what dir it's moving in + var/previous_moving_dir //what dir it was moving in before that + var/more_previouser_moving_dir //what dir it was moving in before THAT + var/moving = 0 //how many steps to move before recalculating + var/standard_moving_before_recalc = 4 //how many times we step before recalculating normally + var/tiles_per_step = 1 //how many tiles we move each step + var/speed = 3 //how many deciseconds between each step + var/currently_seeking = FALSE + var/friendly_fire_check = FALSE //if blasts produced apply friendly fire + +/obj/effect/overlay/temp/hierophant/chaser/New(loc, new_caster, new_target, new_speed, is_friendly_fire) + ..() + target = new_target + friendly_fire_check = is_friendly_fire + if(new_speed) + speed = new_speed + spawn(0) + seek_target() + +/obj/effect/overlay/temp/hierophant/chaser/proc/get_target_dir() + . = get_cardinal_dir(src, targetturf) + if((. != previous_moving_dir && . == more_previouser_moving_dir) || . == 0) //we're alternating, recalculate + var/list/cardinal_copy = cardinal.Copy() + cardinal_copy -= more_previouser_moving_dir + . = pick(cardinal_copy) + +/obj/effect/overlay/temp/hierophant/chaser/proc/seek_target() + if(!currently_seeking) + currently_seeking = TRUE + targetturf = get_turf(target) + while(target && src && !qdeleted(src) && currently_seeking && x && y && targetturf) //can this target actually be sook out + if(!moving) //we're out of tiles to move, find more and where the target is! + more_previouser_moving_dir = previous_moving_dir + previous_moving_dir = moving_dir + moving_dir = get_target_dir() + var/standard_target_dir = get_cardinal_dir(src, targetturf) + if((standard_target_dir != previous_moving_dir && standard_target_dir == more_previouser_moving_dir) || standard_target_dir == 0) + moving = 1 //we would be repeating, only move a tile before checking + else + moving = standard_moving_before_recalc + if(moving) //move in the dir we're moving in right now + var/turf/T = get_turf(src) + for(var/i in 1 to tiles_per_step) + var/maybe_new_turf = get_step(T, moving_dir) + if(maybe_new_turf) + T = maybe_new_turf + else + break + forceMove(T) + make_blast() //make a blast, too + moving-- + sleep(speed) + targetturf = get_turf(target) + +/obj/effect/overlay/temp/hierophant/chaser/proc/make_blast() + new /obj/effect/overlay/temp/hierophant/blast(loc, caster, friendly_fire_check) + +/obj/effect/overlay/temp/hierophant/telegraph + icon = 'icons/effects/96x96.dmi' + icon_state = "hierophant_telegraph" + pixel_x = -32 + pixel_y = -32 + duration = 3 + +/obj/effect/overlay/temp/hierophant/telegraph/diagonal + icon_state = "hierophant_telegraph_diagonal" + +/obj/effect/overlay/temp/hierophant/telegraph/cardinal + icon_state = "hierophant_telegraph_cardinal" + +/obj/effect/overlay/temp/hierophant/telegraph/teleport + icon_state = "hierophant_telegraph_teleport" + duration = 9 + +/obj/effect/overlay/temp/hierophant/blast + icon = 'icons/effects/effects.dmi' + icon_state = "hierophant_blast" + name = "vortex blast" + luminosity = 1 + desc = "Get out of the way!" + duration = 9 + var/damage = 10 //how much damage do we do? + var/list/hit_things = list() //we hit these already, ignore them + var/friendly_fire_check = FALSE + var/bursting = FALSE //if we're bursting and need to hit anyone crossing us + +/obj/effect/overlay/temp/hierophant/blast/New(loc, new_caster, friendly_fire) + ..() + friendly_fire_check = friendly_fire + if(new_caster) + hit_things += new_caster + if(ismineralturf(loc)) //drill mineral turfs + var/turf/simulated/mineral/M = loc + M.gets_drilled(caster) + spawn(0) + blast() + +/obj/effect/overlay/temp/hierophant/blast/proc/blast() + var/turf/T = get_turf(src) + if(!T) + return + playsound(T,'sound/magic/Blind.ogg', 125, 1, -5) //make a sound + sleep(6) //wait a little + bursting = TRUE + do_damage(T) //do damage and mark us as bursting + sleep(1.3) //slightly forgiving; the burst animation is 1.5 deciseconds + bursting = FALSE //we no longer damage crossers + +/obj/effect/overlay/temp/hierophant/blast/Crossed(atom/movable/AM) + ..() + if(bursting) + do_damage(get_turf(src)) + +/obj/effect/overlay/temp/hierophant/blast/proc/do_damage(turf/T) + for(var/mob/living/L in T.contents - hit_things) //find and damage mobs... + hit_things += L + if((friendly_fire_check && caster && caster.faction_check(L)) || L.stat == DEAD) + continue + if(L.client) + flash_color(L.client, "#660099", 1) + playsound(L,'sound/weapons/sear.ogg', 50, 1, -4) + to_chat(L, "You're struck by a [name]!") + var/limb_to_hit = pick("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg") + var/armor = L.run_armor_check(limb_to_hit, "melee", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 50, "Your armor was penetrated by [src]!") + L.apply_damage(damage, BURN, limb_to_hit, armor) + if(ismegafauna(L) || istype(L, /mob/living/simple_animal/hostile/asteroid)) + L.adjustBruteLoss(damage) + add_logs(caster, L, "struck with a [name]") + for(var/obj/mecha/M in T.contents - hit_things) //and mechs. + hit_things += M + if(M.occupant) + if(friendly_fire_check && caster && caster.faction_check(M.occupant)) + continue + to_chat(M.occupant, "Your [M.name] is struck by a [name]!") + playsound(M,'sound/weapons/sear.ogg', 50, 1, -4) + M.take_damage(damage, BURN, 0, 0) + +/obj/effect/hierophant + name = "hierophant rune" + desc = "A powerful magic mark allowing whomever attunes themself to it to return to it at will." + icon = 'icons/obj/rune.dmi' + icon_state = "hierophant" + layer = 2.5 + anchored = TRUE + color = "#CC00FF" + +/obj/effect/hierophant/attackby(obj/item/I, mob/user, params) + if(istype(I, /obj/item/weapon/hierophant_staff)) + var/obj/item/weapon/hierophant_staff/H = I + if(H.rune == src) + to_chat(user, "You start removing your hierophant rune...") + H.timer = world.time + 51 + if(do_after(user, 50, target = src)) + playsound(src,'sound/magic/Blind.ogg', 200, 1, -4) + new /obj/effect/overlay/temp/hierophant/telegraph/teleport(get_turf(src), user) + to_chat(user, "You touch the rune with the staff, dispelling it!") + H.rune = null + user.update_action_buttons_icon() + qdel(src) + else + H.timer = world.time + else + to_chat(user, "You touch the rune with the staff, but nothing happens.") + + else + ..() + +/obj/item/device/gps/internal/hierophant + icon_state = null + gpstag = "Zealous Signal" + desc = "Heed its words." + invisibility = 100 + +/turf/simulated/indestructible/hierophant + icon_state = "hierophant1" + oxygen = 14 + nitrogen = 23 + temperature = 300 + desc = "A floor with a square pattern. It's faintly cool to the touch." + +/turf/simulated/indestructible/hierophant/New() + ..() + if(prob(50)) + icon_state = "hierophant2" + +/turf/simulated/indestructible/riveted/hierophant + name = "wall" + desc = "A wall made out of smooth, cold stone." + icon = 'icons/turf/walls/hierophant_wall.dmi' + icon_state = "hierophant" + smooth = SMOOTH_TRUE + +#undef MEDAL_PREFIX \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm new file mode 100644 index 00000000000..89119952f60 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm @@ -0,0 +1,142 @@ +#define MEDAL_PREFIX "Legion" +/* + +LEGION + +Legion spawns from the necropolis gate in the far north of lavaland. It is the guardian of the Necropolis and emerges from within whenever an intruder tries to enter through its gate. +Whenever Legion emerges, everything in lavaland will receive a notice via color, audio, and text. This is because Legion is powerful enough to slaughter the entirety of lavaland with little effort. + +It has two attack modes that it constantly rotates between. + +In ranged mode, it will behave like a normal legion - retreating when possible and firing legion skulls at the target. +In charge mode, it will spin and rush its target, attacking with melee whenever possible. + +When Legion dies, it drops a staff of storms, which allows its wielder to call and disperse ash storms at will and functions as a powerful melee weapon. + +Difficulty: Medium + +*/ + +/mob/living/simple_animal/hostile/megafauna/legion + name = "Legion" + health = 800 + maxHealth = 800 + icon_state = "legion" + icon_living = "legion" + desc = "One of many." + icon = 'icons/mob/lavaland/legion.dmi' + attacktext = "chomps" + attack_sound = 'sound/misc/demon_attack1.ogg' + speak_emote = list("echoes") + armour_penetration = 50 + melee_damage_lower = 25 + melee_damage_upper = 25 + speed = 2 + ranged = 1 + del_on_death = 1 + retreat_distance = 5 + minimum_distance = 5 + ranged_cooldown_time = 20 + var/size = 5 + var/charging = 0 + medal_type = MEDAL_PREFIX + score_type = LEGION_SCORE + pixel_y = -90 + pixel_x = -75 + loot = list(/obj/item/stack/sheet/bone = 3) + vision_range = 13 + elimination = 1 + idle_vision_range = 13 + appearance_flags = 0 + mouse_opacity = 1 + stat_attack = 1 // Overriden from /tg/ - otherwise Legion starts chasing its minions + +/mob/living/simple_animal/hostile/megafauna/legion/New() + ..() + internal_gps = new/obj/item/device/gps/internal/legion(src) + +/mob/living/simple_animal/hostile/megafauna/legion/AttackingTarget() + ..() + if(ishuman(target)) + var/mob/living/L = target + if(L.stat == UNCONSCIOUS) + var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc) + A.infest(L) + +/mob/living/simple_animal/hostile/megafauna/legion/OpenFire(the_target) + if(world.time >= ranged_cooldown && !charging) + if(prob(75)) + var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc) + A.GiveTarget(target) + A.friends = friends + A.faction = faction + ranged_cooldown = world.time + ranged_cooldown_time + else + visible_message("[src] charges!") + SpinAnimation(speed = 20, loops = 5) + ranged = 0 + retreat_distance = 0 + minimum_distance = 0 + speed = 0 + charging = 1 + spawn(50) + reset_charge() + +/mob/living/simple_animal/hostile/megafauna/legion/proc/reset_charge() + ranged = 1 + retreat_distance = 5 + minimum_distance = 5 + speed = 2 + charging = 0 + +/mob/living/simple_animal/hostile/megafauna/legion/death() + if(health > 0) + return + if(size > 1) + adjustHealth(-maxHealth) //heal ourself to full in prep for splitting + var/mob/living/simple_animal/hostile/megafauna/legion/L = new(loc) + + L.maxHealth = maxHealth * 0.6 + maxHealth = L.maxHealth + + L.health = L.maxHealth + health = maxHealth + + size-- + L.size = size + + L.resize = L.size * 0.2 + transform = initial(transform) + resize = size * 0.2 + + L.update_transform() + update_transform() + + L.faction = faction.Copy() + + L.GiveTarget(target) + + visible_message("[src] splits in twain!") + else + var/last_legion = TRUE + for(var/mob/living/simple_animal/hostile/megafauna/legion/other in mob_list) + if(other != src) + last_legion = FALSE + break + if(last_legion) + loot = list(/obj/item/weapon/staff/storm) + elimination = 0 + else if(prob(5)) + loot = list(/obj/structure/closet/crate/necropolis/tendril) + ..() + +/mob/living/simple_animal/hostile/megafauna/legion/Process_Spacemove(movement_dir = 0) + return 1 + +/obj/item/device/gps/internal/legion + icon_state = null + gpstag = "Echoing Signal" + desc = "The message repeats." + invisibility = 100 + +#undef MEDAL_PREFIX \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm new file mode 100644 index 00000000000..11d6b68aeec --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm @@ -0,0 +1,230 @@ +#define MEDAL_PREFIX "Boss" + +/mob/living/simple_animal/hostile/megafauna + name = "megafauna" + desc = "Attack the weak point for massive damage." + health = 1000 + maxHealth = 1000 + a_intent = "harm" + sentience_type = SENTIENCE_BOSS + environment_smash = 3 + luminosity = 3 + faction = list("mining", "boss") + weather_immunities = list("lava","ash") + flying = 1 + robust_searching = 1 + ranged_ignores_vision = TRUE + stat_attack = 2 + 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) + damage_coeff = list(BRUTE = 1, BURN = 0.5, TOX = 1, CLONE = 1, STAMINA = 0, OXY = 1) + minbodytemp = 0 + maxbodytemp = INFINITY + aggro_vision_range = 18 + idle_vision_range = 5 + environment_target_typecache = list( + /obj/machinery/door/window, + /obj/structure/window, + /obj/structure/closet, + /obj/structure/table, + /obj/structure/grille, + /obj/structure/girder, + /obj/structure/rack, + /obj/structure/barricade, + /obj/machinery/field, + /obj/machinery/power/emitter) + var/medal_type = MEDAL_PREFIX + var/score_type = BOSS_SCORE + var/elimination = 0 + var/anger_modifier = 0 + var/obj/item/device/gps/internal_gps + anchored = TRUE + mob_size = MOB_SIZE_LARGE + layer = MOB_LAYER + 0.5 //Looks weird with them slipping under mineral walls and cameras and shit otherwise + mouse_opacity = 2 // Easier to click on in melee, they're giant targets anyway + +/mob/living/simple_animal/hostile/megafauna/Destroy() + qdel(internal_gps) + . = ..() + +/mob/living/simple_animal/hostile/megafauna/death(gibbed) + if(health > 0) + return + else + if(!admin_spawned) + feedback_set_details("megafauna_kills","[initial(name)]") + if(!elimination) //used so the achievment only occurs for the last legion to die. + grant_achievement(medal_type,score_type) + ..() + +/mob/living/simple_animal/hostile/megafauna/gib() + if(health > 0) + return + else + ..() + +/mob/living/simple_animal/hostile/megafauna/dust() + if(health > 0) + return + else + ..() + +/mob/living/simple_animal/hostile/megafauna/AttackingTarget() + ..() + if(isliving(target)) + var/mob/living/L = target + if(L.stat != DEAD) + if(!client && ranged && ranged_cooldown <= world.time) + OpenFire() + else + devour(L) + +/mob/living/simple_animal/hostile/megafauna/onShuttleMove() + var/turf/oldloc = loc + . = ..() + if(!.) + return + var/turf/newloc = loc + message_admins("Megafauna [src] \ + (FLW) \ + moved via shuttle from ([oldloc.x], [oldloc.y], [oldloc.z]) to \ + ([newloc.x], [newloc.y], [newloc.z])") + +/mob/living/simple_animal/hostile/megafauna/proc/devour(mob/living/L) + if(!L) + return + visible_message( + "[src] devours [L]!", + "You feast on [L], restoring your health!") + adjustBruteLoss(-L.maxHealth/2) + L.gib() + +/mob/living/simple_animal/hostile/megafauna/ex_act(severity, target) + switch(severity) + if(1) + adjustBruteLoss(250) + + if(2) + adjustBruteLoss(100) + + if(3) + adjustBruteLoss(50) + +/mob/living/simple_animal/hostile/megafauna/proc/grant_achievement(medaltype,scoretype) + + if(medal_type == "Boss") //Don't award medals if the medal type isn't set + return + + if(admin_spawned) + return + + if(global.medal_hub && global.medal_pass && global.medals_enabled) + for(var/mob/living/L in view(7,src)) + if(L.stat) + continue + if(L.client) + var/client/C = L.client + var/suffixm = BOSS_KILL_MEDAL + UnlockMedal("Boss [suffixm]",C) + UnlockMedal("[medaltype] [suffixm]",C) + SetScore(BOSS_SCORE,C,1) + SetScore(score_type,C,1) + +/proc/UnlockMedal(medal,client/player) + + if(!player || !medal) + return + if(global.medal_hub && global.medal_pass && global.medals_enabled) + spawn() + var/result = world.SetMedal(medal, player, global.medal_hub, global.medal_pass) + if(isnull(result)) + global.medals_enabled = FALSE + log_game("MEDAL ERROR: Could not contact hub to award medal:[medal] player:[player.ckey]") + message_admins("Error! Failed to contact hub to award [medal] medal to [player.ckey]!") + else if(result) + to_chat(player.mob, "Achievement unlocked: [medal]!") + + +/proc/SetScore(score,client/player,increment,force) + + if(!score || !player) + return + if(global.medal_hub && global.medal_pass && global.medals_enabled) + spawn() + var/list/oldscore = GetScore(score,player,1) + + if(increment) + if(!oldscore[score]) + oldscore[score] = 1 + else + oldscore[score] = (text2num(oldscore[score]) + 1) + else + oldscore[score] = force + + var/newscoreparam = list2params(oldscore) + + var/result = world.SetScores(player.ckey, newscoreparam, global.medal_hub, global.medal_pass) + + if(isnull(result)) + global.medals_enabled = FALSE + log_game("SCORE ERROR: Could not contact hub to set score. Score:[score] player:[player.ckey]") + message_admins("Error! Failed to contact hub to set [score] score for [player.ckey]!") + + +/proc/GetScore(score,client/player,returnlist) + + if(!score || !player) + return + if(global.medal_hub && global.medal_pass && global.medals_enabled) + + var/scoreget = world.GetScores(player.ckey, score, global.medal_hub, global.medal_pass) + if(isnull(scoreget)) + global.medals_enabled = FALSE + log_game("SCORE ERROR: Could not contact hub to get score. Score:[score] player:[player.ckey]") + message_admins("Error! Failed to contact hub to get score: [score] for [player.ckey]!") + return + + var/list/scoregetlist = params2list(scoreget) + + if(returnlist) + return scoregetlist + else + return scoregetlist[score] + + +/proc/CheckMedal(medal,client/player) + + if(!player || !medal) + return + if(global.medal_hub && global.medal_pass && global.medals_enabled) + + var/result = world.GetMedal(medal, player, global.medal_hub, global.medal_pass) + + if(isnull(result)) + global.medals_enabled = FALSE + log_game("MEDAL ERROR: Could not contact hub to get medal:[medal] player:[player.ckey]") + message_admins("Error! Failed to contact hub to get [medal] medal for [player.ckey]!") + else if(result) + to_chat(player.mob, "[medal] is unlocked") + +/proc/LockMedal(medal,client/player) + + if(!player || !medal) + return + if(global.medal_hub && global.medal_pass && global.medals_enabled) + + var/result = world.ClearMedal(medal, player, global.medal_hub, global.medal_pass) + + if(isnull(result)) + global.medals_enabled = FALSE + log_game("MEDAL ERROR: Could not contact hub to clear medal:[medal] player:[player.ckey]") + message_admins("Error! Failed to contact hub to clear [medal] medal for [player.ckey]!") + else if(result) + message_admins("Medal: [medal] removed for [player.ckey]") + else + message_admins("Medal: [medal] was not found for [player.ckey]. Unable to clear.") + + +/proc/ClearScore(client/player) + world.SetScores(player.ckey, "", global.medal_hub, global.medal_pass) + +#undef MEDAL_PREFIX \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm index ac9b8562681..87754e1428a 100644 --- a/code/modules/mob/living/simple_animal/hostile/mimic.dm +++ b/code/modules/mob/living/simple_animal/hostile/mimic.dm @@ -91,10 +91,6 @@ ..() icon_state = initial(icon_state) -/mob/living/simple_animal/hostile/mimic/crate/LostTarget() - ..() - icon_state = initial(icon_state) - /mob/living/simple_animal/hostile/mimic/crate/death(gibbed) var/obj/structure/closet/crate/C = new(get_turf(src)) // Put loot in crate diff --git a/code/modules/mob/living/simple_animal/hostile/mining/goldgrub.dm b/code/modules/mob/living/simple_animal/hostile/mining/goldgrub.dm new file mode 100644 index 00000000000..3e6d98afd95 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/mining/goldgrub.dm @@ -0,0 +1,78 @@ +/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." + icon = 'icons/mob/animal.dmi' + icon_state = "Goldgrub" + icon_living = "Goldgrub" + icon_aggro = "Goldgrub_alert" + icon_dead = "Goldgrub_dead" + icon_gib = "syndicate_gib" + vision_range = 2 + aggro_vision_range = 9 + idle_vision_range = 2 + move_to_delay = 5 + friendly = "harmlessly rolls into" + maxHealth = 45 + health = 45 + harm_intent_damage = 5 + melee_damage_lower = 0 + melee_damage_upper = 0 + attacktext = "barrels into" + attack_sound = 'sound/weapons/punch1.ogg' + a_intent = I_HELP + speak_emote = list("screeches") + throw_message = "sinks in slowly, before being pushed out of " + status_flags = CANPUSH + search_objects = 1 + wanted_objects = list(/obj/item/weapon/ore/diamond, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/silver, + /obj/item/weapon/ore/uranium) + + var/chase_time = 100 + var/will_burrow = TRUE + +/mob/living/simple_animal/hostile/asteroid/goldgrub/New() + ..() + var/i = rand(1,3) + while(i) + loot += pick(/obj/item/weapon/ore/silver, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/uranium, /obj/item/weapon/ore/diamond) + i-- + +/mob/living/simple_animal/hostile/asteroid/goldgrub/GiveTarget(new_target) + target = new_target + if(target != null) + if(istype(target, /obj/item/weapon/ore) && loot.len < 10) + visible_message("The [src.name] looks at [target.name] with hungry eyes.") + else if(isliving(target)) + Aggro() + visible_message("The [src.name] tries to flee from [target.name]!") + retreat_distance = 10 + minimum_distance = 10 + if(will_burrow) + spawn(chase_time) + Burrow() + +/mob/living/simple_animal/hostile/asteroid/goldgrub/AttackingTarget() + if(istype(target, /obj/item/weapon/ore)) + EatOre(target) + return + ..() + +/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/EatOre(var/atom/targeted_ore) + for(var/obj/item/weapon/ore/O in targeted_ore.loc) + if(loot.len < 10) + loot += O.type + qdel(O) + visible_message("The ore was swallowed whole!") + +/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Burrow()//Begin the chase to kill the goldgrub in time + if(!stat) + visible_message("The [src.name] buries into the ground, vanishing from sight!") + qdel(src) + +/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(obj/item/projectile/P) + visible_message("The [P.name] was repelled by [src.name]'s girth!") + return + +/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(damage) + idle_vision_range = 9 + . = ..() \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm new file mode 100644 index 00000000000..c50e2dd2944 --- /dev/null +++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm @@ -0,0 +1,319 @@ +/mob/living/simple_animal/hostile/asteroid/hivelord + name = "hivelord" + desc = "A truly alien creature, it is a mass of unknown organic material, constantly fluctuating. When attacking, pieces of it split off and attack in tandem with the original." + icon = 'icons/mob/lavaland/lavaland_monsters.dmi' + icon_state = "Hivelord" + icon_living = "Hivelord" + icon_aggro = "Hivelord_alert" + icon_dead = "Hivelord_dead" + icon_gib = "syndicate_gib" + mouse_opacity = 2 + move_to_delay = 14 + ranged = 1 + vision_range = 5 + aggro_vision_range = 9 + idle_vision_range = 5 + speed = 3 + maxHealth = 75 + health = 75 + harm_intent_damage = 5 + melee_damage_lower = 0 + melee_damage_upper = 0 + attacktext = "lashes out at" + speak_emote = list("telepathically cries") + attack_sound = 'sound/weapons/pierce.ogg' + throw_message = "falls right through the strange body of the" + ranged_cooldown = 0 + ranged_cooldown_time = 20 + environment_smash = 0 + retreat_distance = 3 + minimum_distance = 3 + pass_flags = PASSTABLE + loot = list(/obj/item/organ/internal/hivelord_core) + var/brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood + +/mob/living/simple_animal/hostile/asteroid/hivelord/OpenFire(the_target) + if(world.time >= ranged_cooldown) + var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A = new brood_type(src.loc) + A.admin_spawned = admin_spawned + A.GiveTarget(target) + A.friends = friends + A.faction = faction.Copy() + ranged_cooldown = world.time + ranged_cooldown_time + +/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget() + OpenFire() + +/mob/living/simple_animal/hostile/asteroid/hivelord/death(gibbed) + mouse_opacity = 1 + ..(gibbed) + +/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." + icon_state = "roro core 2" + flags = NOBLUDGEON + slot = "hivecore" + force = 0 + actions_types = list(/datum/action/item_action/organ_action/use) + var/inert = 0 + var/preserved = 0 + +/obj/item/organ/internal/hivelord_core/New() + ..() + addtimer(src, "inert_check", 2400) + +/obj/item/organ/internal/hivelord_core/proc/inert_check() + if(!owner && !preserved) + go_inert() + else + preserved(implanted = 1) + +/obj/item/organ/internal/hivelord_core/proc/preserved(implanted = 0) + inert = FALSE + preserved = TRUE + update_icon() + + if(implanted) + feedback_add_details("hivelord_core", "[type]|implanted") + else + feedback_add_details("hivelord_core", "[type]|stabilizer") + + +/obj/item/organ/internal/hivelord_core/proc/go_inert() + inert = TRUE + desc = "The remains of a hivelord that have become useless, having been left alone too long after being harvested." + feedback_add_details("hivelord_core", "[src.type]|inert") + update_icon() + +/obj/item/organ/internal/hivelord_core/ui_action_click() + owner.revive() + qdel(src) + +/obj/item/organ/internal/hivelord_core/on_life() + ..() + if(owner.health < config.health_threshold_crit) + ui_action_click() + +/obj/item/organ/internal/hivelord_core/afterattack(atom/target, mob/user, proximity_flag) + if(proximity_flag && ishuman(target)) + var/mob/living/carbon/human/H = target + if(inert) + to_chat(user, "[src] has become inert, its healing properties are no more.") + return + else + if(H.stat == DEAD) + to_chat(user, "[src] are useless on the dead.") + return + if(H != user) + H.visible_message("[user] forces [H] to apply [src]... They quickly regenerate all injuries!") + feedback_add_details("hivelord_core","[src.type]|used|other") + else + to_chat(user, "You start to smear [src] on yourself. It feels and smells disgusting, but you feel amazingly refreshed in mere moments.") + feedback_add_details("hivelord_core","[src.type]|used|self") + playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1) + H.revive() + qdel(src) + ..() + +/obj/item/organ/internal/hivelord_core/prepare_eat() + return null + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood + name = "hivelord brood" + desc = "A fragment of the original Hivelord, rallying behind its original. One isn't much of a threat, but..." + icon = 'icons/mob/lavaland/lavaland_monsters.dmi' + icon_state = "Hivelordbrood" + icon_living = "Hivelordbrood" + icon_aggro = "Hivelordbrood" + icon_dead = "Hivelordbrood" + icon_gib = "syndicate_gib" + mouse_opacity = 2 + move_to_delay = 1 + friendly = "buzzes near" + vision_range = 10 + speed = 3 + maxHealth = 1 + health = 1 + flying = 1 + harm_intent_damage = 5 + melee_damage_lower = 2 + melee_damage_upper = 2 + attacktext = "slashes" + speak_emote = list("telepathically cries") + attack_sound = 'sound/weapons/pierce.ogg' + throw_message = "falls right through the strange body of the" + environment_smash = 0 + pass_flags = PASSTABLE + del_on_death = 1 + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/New() + ..() + addtimer(src, "death", 100) + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood + name = "blood brood" + desc = "A living string of blood and alien materials." + icon_state = "bloodbrood" + icon_living = "bloodbrood" + icon_aggro = "bloodbrood" + attacktext = "pierces" + color = "#C80000" + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/death() + if(loc) // Splash the turf we are on with blood + reagents.reaction(get_turf(src)) + ..() + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/New() + create_reagents(30) + ..() + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/AttackingTarget() + ..() + if(iscarbon(target)) + transfer_reagents(target, 1) + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/attack_hand(mob/living/carbon/human/M) + if("\ref[M]" in faction) + reabsorb_host(M) + else + return ..() + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/attack_alien(mob/living/carbon/alien/humanoid/M) + if("\ref[M]" in faction) + reabsorb_host(M) + else + return ..() + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/reabsorb_host(mob/living/carbon/C) + C.visible_message("[src] is reabsorbed by [C]'s body.", \ + "[src] is reabsorbed by your body.") + transfer_reagents(C) + death() + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/transfer_reagents(mob/living/carbon/C, volume = 30) + if(!reagents.total_volume) + return + + volume = min(volume, reagents.total_volume) + + var/fraction = min(volume/reagents.total_volume, 1) + reagents.reaction(C, INGEST, fraction) + reagents.trans_to(C, volume) + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/proc/link_host(mob/living/carbon/human/H) + faction = list("\ref[src]", "\ref[H]") // Hostile to everyone except the host. + H.vessel.trans_to(src, 30) + color = mix_color_from_reagents(reagents.reagent_list) + +// Legion +/mob/living/simple_animal/hostile/asteroid/hivelord/legion + name = "legion" + desc = "You can still see what was once a human under the shifting mass of corruption." + icon = 'icons/mob/lavaland/lavaland_monsters.dmi' + icon_state = "legion" + icon_living = "legion" + icon_aggro = "legion" + icon_dead = "legion" + icon_gib = "syndicate_gib" + melee_damage_lower = 15 + melee_damage_upper = 15 + attacktext = "lashes out at" + speak_emote = list("echoes") + attack_sound = 'sound/weapons/pierce.ogg' + throw_message = "bounces harmlessly off of" + loot = list(/obj/item/organ/internal/hivelord_core/legion) + brood_type = /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion + del_on_death = 1 + stat_attack = 1 + robust_searching = 1 + var/mob/living/carbon/human/stored_mob + +/mob/living/simple_animal/hostile/asteroid/hivelord/legion/death(gibbed) + visible_message("The skulls on [src] wail in anger as they flee from their dying host!") + var/turf/T = get_turf(src) + if(T) + if(stored_mob) + stored_mob.forceMove(get_turf(src)) + stored_mob = null + else + new /obj/effect/landmark/corpse/damaged(T) + ..(gibbed) + + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion + name = "legion" + desc = "One of many." + icon = 'icons/mob/lavaland/lavaland_monsters.dmi' + icon_state = "legion_head" + icon_living = "legion_head" + icon_aggro = "legion_head" + icon_dead = "legion_head" + icon_gib = "syndicate_gib" + friendly = "buzzes near" + vision_range = 10 + maxHealth = 1 + health = 5 + harm_intent_damage = 5 + melee_damage_lower = 12 + melee_damage_upper = 12 + attacktext = "bites" + speak_emote = list("echoes") + attack_sound = 'sound/weapons/pierce.ogg' + throw_message = "is shrugged off by" + pass_flags = PASSTABLE + del_on_death = 1 + stat_attack = 1 + robust_searching = 1 + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/Life() + if(isturf(loc)) + for(var/mob/living/carbon/human/H in view(src,1)) //Only for corpse right next to/on same tile + if(H.stat == UNCONSCIOUS) + infest(H) + ..() + +/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/proc/infest(mob/living/carbon/human/H) + visible_message("[name] burrows into the flesh of [H]!") + var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/L = new(H.loc) + visible_message("[L] staggers to their feet!") + H.death() + H.adjustBruteLoss(1000) + L.stored_mob = H + H.forceMove(L) + qdel(src) + +/obj/item/organ/internal/hivelord_core/legion + name = "legion's soul" + desc = "A strange rock that still crackles with power... its \ + healing properties will soon become inert if not used quickly." + icon_state = "legion_soul" + +/obj/item/organ/internal/hivelord_core/legion/New() + ..() + update_icon() + +/obj/item/organ/internal/hivelord_core/legion/update_icon() + icon_state = inert ? "legion_soul_inert" : "legion_soul" + overlays.Cut() + if(!inert && !preserved) + overlays += image(icon, "legion_soul_crackle") + for(var/X in actions) + var/datum/action/A = X + A.UpdateButtonIcon() + +/obj/item/organ/internal/hivelord_core/legion/go_inert() + . = ..() + desc = "[src] has become inert, it crackles no more and is useless for \ + healing injuries." + +/obj/item/organ/internal/hivelord_core/legion/preserved(implanted = 0) + ..() + desc = "[src] has been stabilized. It no longer crackles with power, but it's healing properties are preserved indefinitely." + +/obj/item/weapon/legion_skull + name = "legion's head" + desc = "The once living, now empty eyes of the former human's skull cut deep into your soul." + icon = 'icons/obj/mining.dmi' + icon_state = "skull" \ No newline at end of file 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 47c243e970e..f3ed8a34f51 100644 --- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm +++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm @@ -58,7 +58,7 @@ projectilesound = 'sound/weapons/pierce.ogg' ranged = 1 ranged_message = "stares" - ranged_cooldown_cap = 20 + ranged_cooldown_time = 30 throw_message = "does nothing against the hard shell of" vision_range = 2 speed = 3 @@ -71,7 +71,6 @@ a_intent = I_HARM speak_emote = list("chitters") attack_sound = 'sound/weapons/bladeslice.ogg' - ranged_cooldown_cap = 4 aggro_vision_range = 9 idle_vision_range = 2 turns_per_move = 5 @@ -104,232 +103,6 @@ if(3.0) adjustBruteLoss(110) -/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." - icon = 'icons/mob/animal.dmi' - icon_state = "Goldgrub" - icon_living = "Goldgrub" - icon_aggro = "Goldgrub_alert" - icon_dead = "Goldgrub_dead" - icon_gib = "syndicate_gib" - vision_range = 2 - aggro_vision_range = 9 - idle_vision_range = 2 - move_to_delay = 5 - friendly = "harmlessly rolls into" - maxHealth = 45 - health = 45 - harm_intent_damage = 5 - melee_damage_lower = 0 - melee_damage_upper = 0 - attacktext = "barrels into" - attack_sound = 'sound/weapons/punch1.ogg' - a_intent = I_HELP - speak_emote = list("screeches") - throw_message = "sinks in slowly, before being pushed out of " - status_flags = CANPUSH - search_objects = 1 - wanted_objects = list(/obj/item/weapon/ore/diamond, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/silver, - /obj/item/weapon/ore/uranium) - - var/list/ore_types_eaten = list() - var/alerted = 0 - var/ore_eaten = 1 - var/chase_time = 100 - var/will_burrow = 1 - -/mob/living/simple_animal/hostile/asteroid/goldgrub/New() - ..() - ore_types_eaten += pick(/obj/item/weapon/ore/silver, /obj/item/weapon/ore/gold, /obj/item/weapon/ore/uranium, /obj/item/weapon/ore/diamond) - ore_eaten = rand(1,3) - -/mob/living/simple_animal/hostile/asteroid/goldgrub/GiveTarget(var/new_target) - target = new_target - if(target != null) - if(istype(target, /obj/item/weapon/ore)) - visible_message("The [src.name] looks at [target.name] with hungry eyes.") - else if(isliving(target)) - Aggro() - visible_message("The [src.name] tries to flee from [target.name]!") - retreat_distance = 10 - minimum_distance = 10 - Burrow() - -/mob/living/simple_animal/hostile/asteroid/goldgrub/AttackingTarget() - if(istype(target, /obj/item/weapon/ore)) - EatOre(target) - return - ..() - -/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/EatOre(var/atom/targeted_ore) - for(var/obj/item/weapon/ore/O in targeted_ore.loc) - ore_eaten++ - if(!(O.type in ore_types_eaten)) - ore_types_eaten += O.type - qdel(O) - if(ore_eaten > 10)//Limit the scope of the reward you can get, or else things might get silly - ore_eaten = 10 - visible_message("The ore was swallowed whole!") - -/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Burrow()//Begin the chase to kill the goldgrub in time - if(!alerted && will_burrow) - alerted = 1 - spawn(chase_time) - if(alerted) - visible_message("The [src.name] buries into the ground, vanishing from sight!") - qdel(src) - -/mob/living/simple_animal/hostile/asteroid/goldgrub/proc/Reward() - if(!ore_eaten || ore_types_eaten.len == 0) - return - visible_message("[src] spits up the contents of its stomach before dying!") - var/counter - for(var/R in ore_types_eaten) - for(counter=0, counter < ore_eaten, counter++) - new R(src.loc) - ore_types_eaten.Cut() - ore_eaten = 0 - - -/mob/living/simple_animal/hostile/asteroid/goldgrub/bullet_act(var/obj/item/projectile/P) - visible_message("The [P.name] was repelled by [src.name]'s girth!") - return - -/mob/living/simple_animal/hostile/asteroid/goldgrub/death(gibbed) - alerted = 0 - Reward() - ..() - -/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(damage) - idle_vision_range = 9 - ..() - -/mob/living/simple_animal/hostile/asteroid/hivelord - name = "hivelord" - desc = "A truly alien creature, it is a mass of unknown organic material, constantly fluctuating. When attacking, pieces of it split off and attack in tandem with the original." - icon = 'icons/mob/animal.dmi' - icon_state = "Hivelord" - icon_living = "Hivelord" - icon_aggro = "Hivelord_alert" - icon_dead = "Hivelord_dead" - icon_gib = "syndicate_gib" - mouse_opacity = 2 - move_to_delay = 14 - ranged = 1 - vision_range = 5 - aggro_vision_range = 9 - idle_vision_range = 5 - speed = 3 - maxHealth = 75 - health = 75 - harm_intent_damage = 5 - melee_damage_lower = 0 - melee_damage_upper = 0 - attacktext = "lashes out at" - speak_emote = list("telepathically cries") - attack_sound = 'sound/weapons/pierce.ogg' - throw_message = "falls right through the strange body of the" - ranged_cooldown = 0 - ranged_cooldown_cap = 0 - environment_smash = 0 - 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) - A.GiveTarget(target) - A.friends = friends - A.faction = faction - return - -/mob/living/simple_animal/hostile/asteroid/hivelord/AttackingTarget() - OpenFire() - -/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." - icon = 'icons/obj/food/food.dmi' - icon_state = "boiledrorocore" - slot = "hivecore" - var/inert = 0 - var/preserved = 0 - -/obj/item/organ/internal/hivelord_core/New() - spawn(2400) - if(!preserved) - inert = 1 - desc = "The remains of a hivelord that have become useless, having been left alone too long after being harvested." - -/obj/item/organ/internal/hivelord_core/on_life() - ..() - if(owner) - owner.adjustBruteLoss(-1) - owner.adjustFireLoss(-1) - owner.adjustOxyLoss(-2) - if(ishuman(owner)) - var/mob/living/carbon/human/H = owner - var/datum/reagent/blood/B = locate() in H.vessel.reagent_list //Grab some blood - var/blood_volume = round(H.vessel.get_reagent_amount("blood")) - if(B && blood_volume < H.max_blood && blood_volume) - B.volume += 2 // Fast blood regen - -/obj/item/organ/internal/hivelord_core/attack(mob/living/M as mob, mob/living/user as mob) - if(ishuman(M)) - var/mob/living/carbon/human/H = M - if(inert) - to_chat(user, "[src] have become inert, its healing properties are no more.") - return - else - if(H.stat == DEAD) - to_chat(user, "[src] are useless on the dead.") - return - if(H != user) - H.visible_message("[user] forces [H] to eat [src]... they quickly regenerate all injuries!") - else - to_chat(user, "You chomp into [src], barely managing to hold it down, but feel amazingly refreshed in mere moments.") - playsound(src.loc,'sound/items/eatfood.ogg', rand(10,50), 1) - H.revive() - qdel(src) - ..() - -/obj/item/organ/internal/hivelord_core/prepare_eat() - return null - -/mob/living/simple_animal/hostile/asteroid/hivelordbrood - name = "hivelord brood" - desc = "A fragment of the original Hivelord, rallying behind its original. One isn't much of a threat, but..." - icon = 'icons/mob/animal.dmi' - icon_state = "Hivelordbrood" - icon_living = "Hivelordbrood" - icon_aggro = "Hivelordbrood" - icon_dead = "Hivelordbrood" - icon_gib = "syndicate_gib" - mouse_opacity = 2 - move_to_delay = 1 - friendly = "buzzes near" - vision_range = 10 - speed = 3 - maxHealth = 1 - health = 1 - harm_intent_damage = 5 - melee_damage_lower = 2 - melee_damage_upper = 2 - attacktext = "slashes" - speak_emote = list("telepathically cries") - attack_sound = 'sound/weapons/pierce.ogg' - throw_message = "falls right through the strange body of the" - environment_smash = 0 - pass_flags = PASSTABLE - del_on_death = 1 - -/mob/living/simple_animal/hostile/asteroid/hivelordbrood/New() - ..() - spawn(100) - death() - /mob/living/simple_animal/hostile/asteroid/goliath name = "goliath" desc = "A massive beast that uses long tentacles to ensare its prey, threatening them is not advised under any conditions." @@ -344,7 +117,7 @@ move_to_delay = 40 ranged = 1 ranged_cooldown = 2 //By default, start the Goliath with his cooldown off so that people can run away quickly on first sight - ranged_cooldown_cap = 8 + ranged_cooldown_time = 120 friendly = "wails at" speak_emote = list("bellows") vision_range = 4 @@ -368,7 +141,7 @@ handle_preattack() /mob/living/simple_animal/hostile/asteroid/goliath/proc/handle_preattack() - if(ranged_cooldown <= 2 && !pre_attack) + if(ranged_cooldown <= world.time + ranged_cooldown_time * 0.25 && !pre_attack) pre_attack++ if(!pre_attack || stat || AIStatus == AI_IDLE) return @@ -383,7 +156,7 @@ if(get_dist(src, target) <= 7)//Screen range check, so you can't get tentacle'd offscreen visible_message("The [src.name] digs its tentacles under [target.name]!") new /obj/effect/goliath_tentacle/original(tturf) - ranged_cooldown = ranged_cooldown_cap + ranged_cooldown = world.time + ranged_cooldown_time icon_state = icon_aggro pre_attack = 0 return diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm index d749db16bf5..41ca671bc56 100644 --- a/code/modules/mob/living/simple_animal/hostile/statue.dm +++ b/code/modules/mob/living/simple_animal/hostile/statue.dm @@ -163,7 +163,7 @@ clothes_req = 0 range = 14 -/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/cast(list/targets) +/obj/effect/proc_holder/spell/aoe_turf/flicker_lights/cast(list/targets, mob/user = usr) for(var/turf/T in targets) for(var/obj/machinery/light/L in T) L.flicker() @@ -179,9 +179,9 @@ clothes_req = 0 range = 10 -/obj/effect/proc_holder/spell/aoe_turf/blindness/cast(list/targets) +/obj/effect/proc_holder/spell/aoe_turf/blindness/cast(list/targets, mob/user = usr) for(var/mob/living/L in living_mob_list) - if(L == usr) + if(L == user) continue var/turf/T = get_turf(L.loc) if(T && T in targets) @@ -200,7 +200,7 @@ range = -1 include_user = 1 -/obj/effect/proc_holder/spell/targeted/night_vision/cast(list/targets) +/obj/effect/proc_holder/spell/targeted/night_vision/cast(list/targets, mob/user = usr) for(var/mob/living/target in targets) if(target.see_invisible == SEE_INVISIBLE_LIVING) diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index eae08eb4d0c..9669c90b3ec 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -301,6 +301,9 @@ var/damage = rand(M.melee_damage_lower, M.melee_damage_upper) attack_threshold_check(damage,M.melee_damage_type) +/mob/living/simple_animal/proc/attacked_by(obj/item/I, mob/living/user) // Handled in _onclick/click.dm + return + /mob/living/simple_animal/bullet_act(var/obj/item/projectile/Proj) if(!Proj) return @@ -579,21 +582,7 @@ density = initial(density) update_canmove() -/mob/living/simple_animal/show_inv(mob/user as mob) - user.set_machine(src) - var/dat = {" - - - "} - if(can_collar) - dat += "" - dat += {"
Left Hand:[(l_hand && !(l_hand.flags&ABSTRACT)) ? l_hand : "Empty"]
Right Hand:[(r_hand && !(r_hand.flags&ABSTRACT)) ? r_hand : "Empty"]
 
Collar:[(collar && !(collar.flags&ABSTRACT)) ? collar : "Empty"]
- Close - "} - var/datum/browser/popup = new(user, "mob\ref[src]", "[src]", 440, 250) - popup.set_content(dat) - popup.open() /mob/living/simple_animal/proc/make_babies() // <3 <3 <3 if(gender != FEMALE || stat || !scan_ready || !childtype || !simplespecies) @@ -652,57 +641,74 @@ if(changed) animate(src, transform = ntransform, time = 2, easing = EASE_IN|EASE_OUT) -/mob/living/simple_animal/Topic(href, href_list) - if(!usr.stat && usr.canmove && !usr.restrained() && in_range(src, usr)) - if(href_list["remove_inv"]) - if(!Adjacent(usr) || !(ishuman(usr) || isrobot(usr) || isalienadult(usr))) - return - var/remove_from = href_list["remove_inv"] - switch(remove_from) - if("collar") - if(!can_collar) - return - if(collar) - if(collar.flags & NODROP) - to_chat(usr, "\The [collar] is stuck too hard to [src] for you to remove!") - return - collar.dropped(src) - collar.forceMove(src.loc) - collar = null - regenerate_icons() - else - to_chat(usr, "There is nothing to remove from its [remove_from].") - return - show_inv(usr) - else if(href_list["add_inv"]) - if(!Adjacent(usr) || !(ishuman(usr) || isrobot(usr) || isalienadult(usr))) - return +/* Inventory */ - var/add_to = href_list["add_inv"] - switch(add_to) - if("collar") - if(!can_collar || collar) - return - var/obj/item/clothing/accessory/petcollar/C = usr.get_active_hand() - if(!istype(C)) - usr.visible_message("[usr] rubs [src]'s neck.","You rub [src]'s neck for a moment.") - return - usr.drop_item() - C.forceMove(src) - collar = C - collar.equipped(src) - regenerate_icons() - to_chat(usr, "You put \the [C] around \the [src]'s neck.") - if(C.tagname) - name = C.tagname - real_name = C.tagname - show_inv(usr) +/mob/living/simple_animal/show_inv(mob/user as mob) + if(!can_collar) + return + + user.set_machine(src) + var/dat = "
Collar:[(collar && !(collar.flags&ABSTRACT)) ? collar : "Empty"]
" + dat += "Close" + + var/datum/browser/popup = new(user, "mob\ref[src]", "[src]", 440, 250) + popup.set_content(dat) + popup.open() + +/mob/living/simple_animal/get_item_by_slot(slot_id) + switch(slot_id) + if(slot_collar) + return collar + . = ..() + +/mob/living/simple_animal/can_equip(obj/item/I, slot, disable_warning = 0) + // . = ..() // Do not call parent. We do not want animals using their hand slots. + switch(slot) + if(slot_collar) + if(collar) + return 0 + if(!can_collar) + return 0 + if(!istype(I, /obj/item/clothing/accessory/petcollar)) + return 0 + return 1 + +/mob/living/simple_animal/equip_to_slot(obj/item/W, slot) + if(!istype(W)) + return 0 + + if(!slot) + return 0 + + W.forceMove(src) + W.equipped(src, slot) + W.layer = 20 + W.plane = HUD_PLANE + + switch(slot) + if(slot_collar) + collar = W + if(collar.tagname) + name = collar.tagname + real_name = collar.tagname + regenerate_icons() + +/mob/living/simple_animal/unEquip(obj/item/I, force) + . = ..() + if(!. || !I) + return + + if(I == collar) + collar = null + regenerate_icons() /mob/living/simple_animal/get_access() . = ..() if(collar) . |= collar.GetAccess() +/* End Inventory */ + /mob/living/simple_animal/proc/sentience_act() //Called when a simple animal gains sentience via gold slime potion return diff --git a/code/modules/mob/living/simple_animal/spawner.dm b/code/modules/mob/living/simple_animal/spawner.dm index 0cbf24cf6e2..46a05daba98 100644 --- a/code/modules/mob/living/simple_animal/spawner.dm +++ b/code/modules/mob/living/simple_animal/spawner.dm @@ -40,6 +40,7 @@ return 0 spawn_delay = world.time + spawn_time var/mob/living/simple_animal/L = new mob_type(src.loc) + L.admin_spawned = admin_spawned //If we were admin spawned, lets have our children count as that as well. spawned_mobs += L L.nest = src L.faction = src.faction diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 9156fc19379..216bb896e7e 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1222,9 +1222,11 @@ mob/proc/yank_out_object() if(mind) return mind.grab_ghost(force = force) -/mob/proc/notify_ghost_cloning(var/message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", var/sound = 'sound/effects/genetics.ogg', var/atom/source = null) +/mob/proc/notify_ghost_cloning(message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", sound = 'sound/effects/genetics.ogg', atom/source = null, flashwindow = TRUE) var/mob/dead/observer/ghost = get_ghost() if(ghost) + if(flashwindow) + window_flash(ghost.client) ghost.notify_cloning(message, sound, source) return ghost diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 0b04647d094..4307ec02655 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -434,20 +434,22 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HARM) lname = "[lname] " to_chat(M, "[lname][follow][message]") -/proc/notify_ghosts(var/message, var/ghost_sound = null, var/enter_link = null, var/atom/source = null, var/image/alert_overlay = null, var/attack_not_jump = 0) //Easy notification of ghosts. +/proc/notify_ghosts(message, ghost_sound = null, enter_link = null, atom/source = null, image/alert_overlay = null, attack_not_jump = 0, flashwindow = TRUE, var/action = NOTIFY_JUMP) //Easy notification of ghosts. for(var/mob/dead/observer/O in player_list) if(O.client) to_chat(O, "[message][(enter_link) ? " [enter_link]" : ""]") if(ghost_sound) O << sound(ghost_sound) + if(flashwindow) + window_flash(O.client) if(source) - var/obj/screen/alert/notify_jump/A = O.throw_alert("\ref[source]_notify_jump", /obj/screen/alert/notify_jump) + var/obj/screen/alert/notify_action/A = O.throw_alert("\ref[source]_notify_action", /obj/screen/alert/notify_action) if(A) if(O.client.prefs && O.client.prefs.UI_style) A.icon = ui_style2icon(O.client.prefs.UI_style) A.desc = message - A.attack_not_jump = attack_not_jump - A.jump_target = source + A.action = action + A.target = source if(!alert_overlay) var/old_layer = source.layer var/old_plane = source.plane @@ -586,8 +588,8 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HARM) if(5) newletter="glor" newphrase+="[newletter]";counter-=1 - return newphrase - + return newphrase + /mob/proc/get_preference(toggleflag) if(!client) return FALSE diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm index 00028e58afd..03b1d07b85b 100644 --- a/code/modules/power/singularity/narsie.dm +++ b/code/modules/power/singularity/narsie.dm @@ -32,7 +32,7 @@ var/area/A = get_area(src) if(A) var/image/alert_overlay = image('icons/effects/effects.dmi', "ghostalertsie") - notify_ghosts("Nar-Sie has risen in \the [A.name]. Reach out to the Geometer to be given a new shell for your soul.", source = src, alert_overlay = alert_overlay, attack_not_jump = 1) + notify_ghosts("Nar-Sie has risen in \the [A.name]. Reach out to the Geometer to be given a new shell for your soul.", source = src, alert_overlay = alert_overlay, action=NOTIFY_ATTACK) narsie_spawn_animation() diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm index 2fa6facdab0..c0e61cc8236 100644 --- a/code/modules/power/singularity/singularity.dm +++ b/code/modules/power/singularity/singularity.dm @@ -37,6 +37,7 @@ src.energy = starting_energy ..() processing_objects.Add(src) + poi_list |= src for(var/obj/machinery/power/singularity_beacon/singubeacon in world) if(singubeacon.active) target = singubeacon @@ -45,6 +46,7 @@ /obj/singularity/Destroy() processing_objects.Remove(src) + poi_list.Remove(src) singularities -= src target = null return ..() diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 323c240d239..c1a202fa134 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -64,6 +64,7 @@ /obj/machinery/power/supermatter_shard/New() . = ..() + poi_list |= src radio = new(src) radio.listening = 0 investigate_log("has been created.", "supermatter") @@ -71,8 +72,10 @@ /obj/machinery/power/supermatter_shard/Destroy() investigate_log("has been destroyed.", "supermatter") - qdel(radio) - radio = null + if(radio) + qdel(radio) + radio = null + poi_list.Remove(src) return ..() /obj/machinery/power/supermatter_shard/proc/explode() diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 14407ef9202..67bad46f4b2 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -34,6 +34,8 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics, var/produced_power var/energy_to_raise = 32 var/energy_to_lower = -20 + + /obj/singularity/energy_ball/Destroy() if(orbiting && istype(orbiting, /obj/singularity/energy_ball)) @@ -44,6 +46,8 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics, for(var/ball in orbiting_balls) var/obj/singularity/energy_ball/EB = ball qdel(EB) + + poi_list.Remove(src) return ..() @@ -125,6 +129,7 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics, /obj/singularity/energy_ball/orbit(obj/singularity/energy_ball/target) if(istype(target)) target.orbiting_balls += src + poi_list.Remove(src) . = ..() diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm index b5a990dec69..cbbe43cd32c 100644 --- a/code/modules/projectiles/ammunition.dm +++ b/code/modules/projectiles/ammunition.dm @@ -188,3 +188,9 @@ //Behavior for magazines /obj/item/ammo_box/magazine/proc/ammo_count() return stored_ammo.len + +/obj/item/ammo_box/magazine/proc/empty_magazine() + var/turf_mag = get_turf(src) + for(var/obj/item/ammo in stored_ammo) + ammo.forceMove(turf_mag) + stored_ammo -= ammo \ No newline at end of file diff --git a/code/modules/projectiles/ammunition/ammo_casings.dm b/code/modules/projectiles/ammunition/ammo_casings.dm index a5b8c891c69..3b808c64d53 100644 --- a/code/modules/projectiles/ammunition/ammo_casings.dm +++ b/code/modules/projectiles/ammunition/ammo_casings.dm @@ -375,3 +375,9 @@ desc = "A cap for children toys." caliber = "caps" projectile_type = /obj/item/projectile/bullet/cap + +/obj/item/ammo_casing/laser + desc = "An experimental laser casing." + caliber = "laser" + projectile_type = /obj/item/projectile/beam/laser + icon_state = "lasercasing" diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm index aecd66b1ea5..5487f8d5bc9 100644 --- a/code/modules/projectiles/ammunition/magazines.dm +++ b/code/modules/projectiles/ammunition/magazines.dm @@ -437,3 +437,12 @@ /obj/item/ammo_box/magazine/toy/m762/update_icon() ..() icon_state = "a762-[round(ammo_count(),10)]" + +/obj/item/ammo_box/magazine/laser + name = "encased laser projector magazine" + desc = "Fits experimental laser ammo casings." + icon_state = "laser" + ammo_type = /obj/item/ammo_casing/laser + origin_tech = "combat=3" + caliber = "laser" + max_ammo = 20 diff --git a/code/modules/projectiles/ammunition/special.dm b/code/modules/projectiles/ammunition/special.dm index d17d65e9fc8..d5c7df48200 100644 --- a/code/modules/projectiles/ammunition/special.dm +++ b/code/modules/projectiles/ammunition/special.dm @@ -26,6 +26,9 @@ /obj/item/ammo_casing/magic/chaos projectile_type = /obj/item/projectile/magic + +/obj/item/ammo_casing/magic/spellblade + projectile_type = /obj/item/projectile/magic/spellblade /obj/item/ammo_casing/magic/chaos/newshot() projectile_type = pick(typesof(/obj/item/projectile/magic)) diff --git a/code/modules/projectiles/guns/magic/staff.dm b/code/modules/projectiles/guns/magic/staff.dm index 9ef7de7f369..6479854f854 100644 --- a/code/modules/projectiles/guns/magic/staff.dm +++ b/code/modules/projectiles/guns/magic/staff.dm @@ -8,6 +8,7 @@ ammo_type = /obj/item/ammo_casing/magic/change icon_state = "staffofchange" item_state = "staffofchange" + fire_sound = "sound/magic/Staff_Change.ogg" /obj/item/weapon/gun/magic/staff/animate name = "staff of animation" @@ -15,6 +16,7 @@ ammo_type = /obj/item/ammo_casing/magic/animate icon_state = "staffofanimation" item_state = "staffofanimation" + fire_sound = "sound/magic/Staff_animation.ogg" /obj/item/weapon/gun/magic/staff/healing name = "staff of healing" @@ -22,6 +24,7 @@ ammo_type = /obj/item/ammo_casing/magic/heal icon_state = "staffofhealing" item_state = "staffofhealing" + fire_sound = "sound/magic/Staff_Healing.ogg" /obj/item/weapon/gun/magic/staff/healing/handle_suicide() //Stops people trying to commit suicide to heal themselves return @@ -35,6 +38,7 @@ max_charges = 10 recharge_rate = 2 no_den_usage = 1 + fire_sound = "sound/magic/Staff_Chaos.ogg" /obj/item/weapon/gun/magic/staff/door name = "staff of door creation" @@ -45,16 +49,17 @@ max_charges = 10 recharge_rate = 2 no_den_usage = 1 + fire_sound = "sound/magic/Staff_Door.ogg" /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 + fire_sound = "sound/items/airhorn.ogg" /obj/item/weapon/gun/magic/staff/focus name = "mental focus" @@ -63,3 +68,23 @@ icon_state = "focus" item_state = "focus" ammo_type = list(/obj/item/ammo_casing/forcebolt) + +/obj/item/weapon/gun/magic/staff/spellblade + name = "spellblade" + desc = "A deadly combination of laziness and boodlust, this blade allows the user to dismember their enemies without all the hard work of actually swinging the sword." + fire_sound = "sound/magic/Fireball.ogg" + ammo_type = /obj/item/ammo_casing/magic/spellblade + icon_state = "spellblade" + item_state = "spellblade" + hitsound = 'sound/weapons/rapierhit.ogg' + force = 20 + armour_penetration = 75 + block_chance = 50 + sharp = 1 + edge = 1 + max_charges = 4 + +/obj/item/weapon/gun/magic/staff/spellblade/hit_reaction(mob/living/carbon/human/owner, attack_text, final_block_chance, damage, attack_type) + if(attack_type == PROJECTILE_ATTACK) + final_block_chance = 0 + return ..() diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm index a1c1d828288..572412dee8b 100644 --- a/code/modules/projectiles/guns/magic/wand.dm +++ b/code/modules/projectiles/guns/magic/wand.dm @@ -59,6 +59,7 @@ /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." + fire_sound = "sound/magic/WandoDeath.ogg" ammo_type = /obj/item/ammo_casing/magic/death icon_state = "deathwand" max_charges = 3 //3, 2, 2, 1 @@ -79,6 +80,7 @@ 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." ammo_type = /obj/item/ammo_casing/magic/heal + fire_sound = "sound/magic/Staff_Healing.ogg" icon_state = "revivewand" max_charges = 3 //3, 2, 2, 1 @@ -96,6 +98,7 @@ name = "wand of polymorph" desc = "This wand is attuned to chaos and will radically alter the victim's form." ammo_type = /obj/item/ammo_casing/magic/change + fire_sound = "sound/magic/Staff_Change.ogg" icon_state = "polywand" max_charges = 10 //10, 5, 5, 4 @@ -115,6 +118,7 @@ icon_state = "telewand" max_charges = 10 //10, 5, 5, 4 no_den_usage = 1 + fire_sound = "sound/magic/Wand_Teleport.ogg" /obj/item/weapon/gun/magic/wand/teleport/zap_self(mob/living/user) do_teleport(user, user, 10) @@ -132,6 +136,7 @@ name = "wand of door creation" desc = "This particular wand can create doors in any wall for the unscrupulous wizard who shuns teleportation magics." ammo_type = /obj/item/ammo_casing/magic/door + fire_sound = "sound/magic/Staff_Door.ogg" icon_state = "doorwand" max_charges = 20 //20, 10, 10, 7 @@ -147,6 +152,7 @@ /obj/item/weapon/gun/magic/wand/fireball name = "wand of fireball" desc = "This wand shoots scorching balls of fire that explode into destructive flames." + fire_sound = "sound/magic/Fireball.ogg" ammo_type = /obj/item/ammo_casing/magic/fireball icon_state = "firewand" max_charges = 8 //8, 4, 4, 3 diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index d0e7efcd26b..e8ff8969fdf 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -249,3 +249,15 @@ /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() + +/obj/item/weapon/gun/projectile/automatic/lasercarbine + name = "\improper IK-60 Laser Carbine" + desc = "An experimental carbine. Uses encased laser projectors as ammunition."//we need to uncouple the toroidal resistance dejammers + icon_state = "lasercarbine" + item_state = "laser" + w_class = 3 + origin_tech = "combat=5;materials=5" + mag_type = /obj/item/ammo_box/magazine/laser + fire_sound = 'sound/weapons/emitter2.ogg' + can_suppress = 0 + burst_size = 2 diff --git a/code/modules/projectiles/guns/projectile/bow.dm b/code/modules/projectiles/guns/projectile/bow.dm new file mode 100644 index 00000000000..2512ebfa35f --- /dev/null +++ b/code/modules/projectiles/guns/projectile/bow.dm @@ -0,0 +1,98 @@ +/obj/item/weapon/gun/projectile/bow + name = "bow" + desc = "A sturdy bow made out of wood and reinforced with iron." + icon_state = "bow_unloaded" + item_state = "bow" + fire_sound = 'sound/weapons/grenadelaunch.ogg' + mag_type = /obj/item/ammo_box/magazine/internal/bow + flags = HANDSLOW + weapon_weight = WEAPON_HEAVY + var/draw_sound = 'sound/weapons/draw_bow.ogg' + var/ready_to_fire = 0 + var/slowdown_when_ready = 2 + +/obj/item/weapon/gun/projectile/bow/update_icon() + if(magazine.ammo_count() && !ready_to_fire) + icon_state = "bow_loaded" + else if(ready_to_fire) + icon_state = "bow_firing" + slowdown = slowdown_when_ready + else + icon_state = initial(icon_state) + slowdown = initial(slowdown) + +/obj/item/weapon/gun/projectile/bow/dropped(mob/user) + if(magazine && magazine.ammo_count()) + magazine.empty_magazine() + ready_to_fire = FALSE + update_icon() + +/obj/item/weapon/gun/projectile/bow/attack_self(mob/living/user) + if(!ready_to_fire && magazine.ammo_count()) + ready_to_fire = TRUE + playsound(user, draw_sound, 100, 1) + update_icon() + else + ready_to_fire = FALSE + update_icon() + +/obj/item/weapon/gun/projectile/bow/attackby(obj/item/A, mob/user, params) + var/num_loaded = magazine.attackby(A, user, params, 1) + if(num_loaded) + to_chat(user, "You ready \the [A] into \the [src].") + update_icon() + chamber_round() + +/obj/item/weapon/gun/projectile/bow/can_shoot() + . = ..() + if(!ready_to_fire) + return FALSE + +/obj/item/weapon/gun/projectile/bow/shoot_with_empty_chamber(mob/living/user as mob|obj) + return + +/obj/item/weapon/gun/projectile/bow/process_chamber(eject_casing = 0, empty_chamber = 1) + . = ..() + ready_to_fire = FALSE + update_icon() + +// ammo +/obj/item/ammo_box/magazine/internal/bow + name = "bow internal magazine" + ammo_type = /obj/item/ammo_casing/caseless/arrow + caliber = "arrow" + max_ammo = 1 + + +/obj/item/projectile/bullet/reusable/arrow + name = "arrow" + icon_state = "arrow" + ammo_type = /obj/item/ammo_casing/caseless/arrow + range = 10 + damage = 25 + damage_type = BRUTE + +/obj/item/ammo_casing/caseless/arrow + name = "arrow" + desc = "Stab, stab, stab." + icon_state = "arrow" + force = 10 + sharp = 1 + projectile_type = /obj/item/projectile/bullet/reusable/arrow + caliber = "arrow" + +//quiver +/obj/item/weapon/storage/backpack/quiver + name = "quiver" + desc = "A quiver for holding arrows." + icon_state = "quiver" + item_state = "quiver" + storage_slots = 20 + can_hold = list( + /obj/item/ammo_casing/caseless/arrow + ) + +/obj/item/weapon/storage/backpack/quiver/full/New() + ..() + for(var/i in 1 to storage_slots) + new /obj/item/ammo_casing/caseless/arrow(src) diff --git a/code/modules/projectiles/guns/projectile/sniper.dm b/code/modules/projectiles/guns/projectile/sniper.dm index cf7c2a4bb35..bf26dad78b3 100644 --- a/code/modules/projectiles/guns/projectile/sniper.dm +++ b/code/modules/projectiles/guns/projectile/sniper.dm @@ -53,6 +53,7 @@ damage = 70 stun = 5 weaken = 5 + dismemberment = 50 armour_penetration = 50 var/breakthings = TRUE @@ -82,6 +83,7 @@ armour_penetration = 0 nodamage = 1 stun = 0 + dismemberment = 0 weaken = 0 breakthings = FALSE @@ -113,6 +115,7 @@ armour_penetration = 15 damage = 15 stun = 0 + dismemberment = 0 weaken = 0 breakthings = FALSE @@ -142,5 +145,6 @@ damage = 60 forcedodge = 1 stun = 0 + dismemberment = 0 weaken = 0 breakthings = FALSE diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 7d6f629aa4c..7b0bcda17d0 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -50,6 +50,7 @@ var/jitter = 0 var/embed = 0 // whether or not the projectile can embed itself in the mob var/forcedodge = 0 //to pass through everything + var/dismemberment = 0 //The higher the number, the greater the bonus to dismembering. 0 will not dismember at all. var/log = 1 //whether print to admin attack logs or just keep it in the diary diff --git a/code/modules/projectiles/projectile/magic.dm b/code/modules/projectiles/projectile/magic.dm index 19bfd4b02fa..b0d2a53c0d9 100644 --- a/code/modules/projectiles/projectile/magic.dm +++ b/code/modules/projectiles/projectile/magic.dm @@ -17,6 +17,12 @@ damage = 10 damage_type = BRUTE nodamage = 0 + + //explosion values + var/exp_heavy = 0 + var/exp_light = 2 + var/exp_flash = 3 + var/exp_fire = 2 /obj/item/projectile/magic/death/on_hit(var/mob/living/carbon/G) . = ..() @@ -27,11 +33,16 @@ /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/turf/T3 = get_step(src,dir) 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 + L = locate(/mob/living) in T3 if(L && L.stat != DEAD) Bump(L) return @@ -44,6 +55,14 @@ if(ismob(target)) //multiple flavors of pain var/mob/living/M = target M.take_overall_damage(0,10) //between this 10 burn, the 10 brute, the explosion brute, and the onfire burn, your at about 65 damage if you stop drop and roll immediately + + +/obj/item/projectile/magic/fireball/infernal + name = "infernal fireball" + exp_heavy = -1 + exp_light = -1 + exp_flash = 4 + exp_fire= 5 /obj/item/projectile/magic/resurrection name = "bolt of resurrection" @@ -266,3 +285,12 @@ proc/wabbajack(mob/living/M) // Change our allegiance! var/mob/living/simple_animal/hostile/mimic/copy/C = change C.ChangeOwner(firer) + +/obj/item/projectile/magic/spellblade + name = "blade energy" + icon_state = "lavastaff" + damage = 15 + damage_type = BURN + flag = "magic" + dismemberment = 50 + nodamage = 0 \ No newline at end of file diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm index ab65418b6f1..b1cdef1f73c 100644 --- a/code/modules/projectiles/projectile/special.dm +++ b/code/modules/projectiles/projectile/special.dm @@ -299,6 +299,7 @@ obj/item/projectile/kinetic/New() damage_type = BRUTE damage = 5 range = 3 + dismemberment = 20 /obj/item/projectile/plasma/New() var/turf/proj_turf = get_turf(src) diff --git a/code/modules/reagents/chemistry/reagents/food.dm b/code/modules/reagents/chemistry/reagents/food.dm index 38b1f4bfa95..e3b16330986 100644 --- a/code/modules/reagents/chemistry/reagents/food.dm +++ b/code/modules/reagents/chemistry/reagents/food.dm @@ -846,4 +846,52 @@ /datum/reagent/greenvomit/reaction_turf(turf/T, volume) if(volume >= 5 && !istype(T, /turf/space)) new /obj/effect/decal/cleanable/vomit/green(T) - playsound(T, 'sound/effects/splat.ogg', 50, 1, -3) \ No newline at end of file + playsound(T, 'sound/effects/splat.ogg', 50, 1, -3) + +////Lavaland Flora Reagents//// + +/datum/reagent/consumable/entpoly + name = "Entropic Polypnium" + id = "entpoly" + description = "An ichor, derived from a certain mushroom, makes for a bad time." + color = "#1d043d" + +/datum/reagent/consumable/entpoly/on_mob_life(mob/living/M) + if(current_cycle >= 10) + M.Paralyse(2) + if(prob(20)) + M.LoseBreath(4) + M.adjustBrainLoss(2 * REAGENTS_EFFECT_MULTIPLIER) + M.adjustToxLoss(3 * REAGENTS_EFFECT_MULTIPLIER) + M.adjustStaminaLoss(10 * REAGENTS_EFFECT_MULTIPLIER) + M.EyeBlurry(5) + ..() + +/datum/reagent/consumable/tinlux + name = "Tinea Luxor" + id = "tinlux" + description = "A stimulating ichor which causes luminescent fungi to grow on the skin. " + color = "#b5a213" + var/light_activated = 0 + +/datum/reagent/consumable/tinlux/on_mob_life(mob/living/M) + if(!light_activated) + M.set_light(2) + light_activated = 1 + ..() + +/datum/reagent/consumable/tinlux/on_mob_delete(mob/living/M) + M.set_light(0) + +/datum/reagent/consumable/vitfro + name = "Vitrium Froth" + id = "vitfro" + description = "A bubbly paste that heals wounds of the skin." + color = "#d3a308" + nutriment_factor = 3 * REAGENTS_METABOLISM + +/datum/reagent/consumable/vitfro/on_mob_life(mob/living/M) + if(prob(80)) + M.adjustBruteLoss(-1 * REAGENTS_EFFECT_MULTIPLIER) + M.adjustFireLoss(-1 * REAGENTS_EFFECT_MULTIPLIER) + ..() \ No newline at end of file diff --git a/code/modules/reagents/chemistry/reagents/medicine.dm b/code/modules/reagents/chemistry/reagents/medicine.dm index cb9406a57ce..451452936fe 100644 --- a/code/modules/reagents/chemistry/reagents/medicine.dm +++ b/code/modules/reagents/chemistry/reagents/medicine.dm @@ -634,7 +634,8 @@ return var/mob/dead/observer/ghost = M.get_ghost() if(ghost) - to_chat(ghost, "Your are attempting to be revived with Strange Reagent. Return to your body if you want to be revived! (Verbs -> Ghost -> Re-enter corpse)") + to_chat(ghost, "You are attempting to be revived with Strange Reagent. Return to your body if you want to be revived! (Verbs -> Ghost -> Re-enter corpse)") + window_flash(ghost.client) ghost << sound('sound/effects/genetics.ogg') M.visible_message("[M] doesn't appear to respond, perhaps try again later?") if(!M.suiciding && !ghost && !(NOCLONE in M.mutations)) diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm index 4a8bd0f657d..286af5d4863 100644 --- a/code/modules/reagents/chemistry/reagents/water.dm +++ b/code/modules/reagents/chemistry/reagents/water.dm @@ -349,25 +349,24 @@ metabolization_rate = 1 /datum/reagent/fuel/unholywater/on_mob_life(mob/living/M) - M.adjustBrainLoss(3) if(iscultist(M)) - M.status_flags |= GOTTAGOFAST M.AdjustDrowsy(-5) - M.AdjustParalysis(-2) + M.AdjustParalysis(-1) M.AdjustStunned(-2) M.AdjustWeakened(-2) + M.adjustToxLoss(-2) + M.adjustFireLoss(-2) + M.adjustOxyLoss(-2) + M.adjustBruteLoss(-2) else - M.adjustToxLoss(2) + M.adjustBrainLoss(3) + M.adjustToxLoss(1) M.adjustFireLoss(2) M.adjustOxyLoss(2) M.adjustBruteLoss(2) M.AdjustCultSlur(10)//CUASE WHY THE HELL NOT ..() -/datum/reagent/fuel/unholywater/on_mob_delete(mob/living/M) - M.status_flags &= ~GOTTAGOFAST - ..() - /datum/reagent/hellwater name = "Hell Water" id = "hell_water" diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm index 9a48e07e6a5..133ab0e6378 100644 --- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm +++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm @@ -67,12 +67,24 @@ /datum/chemical_reaction/slimemetal/on_reaction(datum/reagents/holder) feedback_add_details("slime_cores_used","[type]") - var/obj/item/stack/sheet/metal/M = new /obj/item/stack/sheet/metal - M.amount = 15 - M.forceMove(get_turf(holder.my_atom)) - var/obj/item/stack/sheet/plasteel/P = new /obj/item/stack/sheet/plasteel - P.amount = 5 - P.forceMove(get_turf(holder.my_atom)) + var/turf/location = get_turf(holder.my_atom) + new /obj/item/stack/sheet/plasteel (location, 5) + new /obj/item/stack/sheet/metal (location, 15) + +/datum/chemical_reaction/slimeglass + name = "Slime Glass" + id = "m_glass" + result = null + required_reagents = list("water" = 1) + result_amount = 1 + required_container = /obj/item/slime_extract/metal + required_other = 1 + +/datum/chemical_reaction/slimeglass/on_reaction(datum/reagents/holder) + feedback_add_details("slime_cores_used","[type]") + var/turf/location = get_turf(holder.my_atom) + new /obj/item/stack/sheet/rglass (location, 5) + new /obj/item/stack/sheet/glass (location, 15) //Gold /datum/chemical_reaction/slimecrit @@ -209,8 +221,7 @@ required_other = 1 /datum/chemical_reaction/slimefrost/on_reaction(datum/reagents/holder) - feedback_add_details("slime_cores_used","[type]") - + feedback_add_details("slime_cores_used","[type]") /datum/chemical_reaction/slimestabilizer name = "Slime Stabilizer" @@ -226,8 +237,6 @@ var/obj/item/slimepotion/stabilizer/P = new /obj/item/slimepotion/stabilizer P.forceMove(get_turf(holder.my_atom)) - - //Dark Blue /datum/chemical_reaction/slimefreeze name = "Slime Freeze" @@ -383,12 +392,10 @@ /datum/chemical_reaction/slimeplasma/on_reaction(datum/reagents/holder) feedback_add_details("slime_cores_used","[type]") - var/obj/item/stack/sheet/mineral/plasma/P = new /obj/item/stack/sheet/mineral/plasma - P.amount = 3 - P.forceMove(get_turf(holder.my_atom)) + var/turf/location = get_turf(holder.my_atom) + new /obj/item/stack/sheet/mineral/plasma (location, 3) //Red - /datum/chemical_reaction/slimemutator name = "Slime Mutator" id = "m_slimemutator" @@ -661,4 +668,18 @@ var/mob/living/carbon/slime/S = new /mob/living/carbon/slime S.colour = pick("grey","orange", "metal", "blue", "purple", "dark purple", "dark blue", "green", "silver", "yellow", "gold", "yellow", "red", "silver", "pink", "cerulean", "sepia", "bluespace", "pyrite", "light pink", "oil", "adamantine", "black") S.forceMove(get_turf(holder.my_atom)) - S.visible_message("Infused with plasma, the core begins to quiver and grow, and soon a new baby slime emerges from it!") \ No newline at end of file + S.visible_message("Infused with plasma, the core begins to quiver and grow, and soon a new baby slime emerges from it!") + +/datum/chemical_reaction/slime_transfer + name = "Transfer Potion" + id = "slimetransfer" + result = null + required_reagents = list("blood" = 1) + result_amount = 1 + required_other = 1 + required_container = /obj/item/slime_extract/rainbow + +/datum/chemical_reaction/slime_transfer/on_reaction(datum/reagents/holder) + feedback_add_details("slime_cores_used","[type]") + var/obj/item/slimepotion/transference/P = new /obj/item/slimepotion/transference + P.forceMove(get_turf(holder.my_atom)) diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm index a2ed354657b..622fe780031 100644 --- a/code/modules/recycling/disposal.dm +++ b/code/modules/recycling/disposal.dm @@ -138,7 +138,8 @@ msg_admin_attack("[key_name_admin(user)] placed [key_name_admin(GM)] in a disposals unit. (JMP)") return - if(!I) return + if(!I) + return if(!user.drop_item()) return @@ -530,14 +531,18 @@ has_fat_guy = 1 // set flag on holder if(istype(AM, /obj/structure/bigDelivery) && !hasmob) var/obj/structure/bigDelivery/T = AM - src.destinationTag = T.sortTag + destinationTag = T.sortTag if(istype(AM, /obj/item/smallDelivery) && !hasmob) var/obj/item/smallDelivery/T = AM - src.destinationTag = T.sortTag + destinationTag = T.sortTag //Drones can mail themselves through maint. if(istype(AM, /mob/living/silicon/robot/drone)) var/mob/living/silicon/robot/drone/drone = AM - src.destinationTag = drone.mail_destination + destinationTag = drone.mail_destination + if(istype(AM, /obj/item/shippingPackage) && !hasmob) + var/obj/item/shippingPackage/sp = AM + if(sp.sealed) //only sealed packages get delivered to their intended destination + destinationTag = sp.sortTag // start the movement process @@ -987,7 +992,7 @@ /obj/structure/disposalpipe/sortjunction icon_state = "pipe-j1s" - var/sortType = 0 //Look at the list called TAGGERLOCATIONS in setup.dm + var/sortType = 0 //Look at the list called TAGGERLOCATIONS in /code/_globalvars/lists/flavor_misc.dm var/posdir = 0 var/negdir = 0 var/sortdir = 0 diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm index dec76eaa5f0..a0e9d59a803 100755 --- a/code/modules/recycling/sortingmachinery.dm +++ b/code/modules/recycling/sortingmachinery.dm @@ -35,6 +35,16 @@ sortTag = O.currTag playsound(loc, 'sound/machines/twobeep.ogg', 100, 1) + else if(istype(W, /obj/item/shippingPackage)) + var/obj/item/shippingPackage/sp = W + if(sp.sealed) + return + else + sortTag = sp.sortTag + to_chat(user, "You rip the label off the shipping package and affix it to [src].") + qdel(sp) + playsound(loc, 'sound/items/poster_ripped.ogg', 50, 1) + else if(istype(W, /obj/item/weapon/pen)) var/str = copytext(sanitize(input(user,"Label text?","Set label","")),1,MAX_NAME_LEN) if(!str || !length(str)) @@ -89,6 +99,16 @@ sortTag = O.currTag playsound(loc, 'sound/machines/twobeep.ogg', 100, 1) + else if(istype(W, /obj/item/shippingPackage)) + var/obj/item/shippingPackage/sp = W + if(sp.sealed) + return + else + sortTag = sp.sortTag + to_chat(user, "You rip the label off the shipping package and affix it to [src].") + qdel(sp) + playsound(loc, 'sound/items/poster_ripped.ogg', 50, 1) + else if(istype(W, /obj/item/weapon/pen)) var/str = copytext(sanitize(input(user,"Label text?","Set label","")),1,MAX_NAME_LEN) if(!str || !length(str)) @@ -134,7 +154,7 @@ - if(istype(target, /obj/item) && !(istype(target, /obj/item/weapon/storage) && !istype(target,/obj/item/weapon/storage/box))) + if(istype(target, /obj/item) && !(istype(target, /obj/item/weapon/storage) && !istype(target,/obj/item/weapon/storage/box) && !istype(target, /obj/item/shippingPackage))) var/obj/item/O = target if(use(1)) var/obj/item/smallDelivery/P = new /obj/item/smallDelivery(get_turf(O.loc)) //Aaannd wrap it up! @@ -235,101 +255,181 @@ var/c_mode = 0 - New() - ..() - spawn(5) - trunk = locate() in src.loc - if(trunk) - trunk.linked = src // link the pipe trunk to self +/obj/machinery/disposal/deliveryChute/New() + ..() + spawn(5) + trunk = locate() in src.loc + if(trunk) + trunk.linked = src // link the pipe trunk to self - interact() - return +/obj/machinery/disposal/deliveryChute/interact() + return - update() - return +/obj/machinery/disposal/deliveryChute/update() + return - Bumped(var/atom/movable/AM) //Go straight into the chute - if(istype(AM, /obj/item/projectile)) return - switch(dir) - if(NORTH) - if(AM.loc.y != src.loc.y+1) return - if(EAST) - if(AM.loc.x != src.loc.x+1) return - if(SOUTH) - if(AM.loc.y != src.loc.y-1) return - if(WEST) - if(AM.loc.x != src.loc.x-1) return +/obj/machinery/disposal/deliveryChute/Bumped(atom/movable/AM) //Go straight into the chute + if(istype(AM, /obj/item/projectile)) return + switch(dir) + if(NORTH) + if(AM.loc.y != src.loc.y+1) return + if(EAST) + if(AM.loc.x != src.loc.x+1) return + if(SOUTH) + if(AM.loc.y != src.loc.y-1) return + if(WEST) + if(AM.loc.x != src.loc.x-1) return - if(istype(AM, /obj)) - var/obj/O = AM - O.loc = src - else if(istype(AM, /mob)) - var/mob/M = AM - M.loc = src - src.flush() + if(istype(AM, /obj)) + var/obj/O = AM + O.loc = src + else if(istype(AM, /mob)) + var/mob/M = AM + M.loc = src + src.flush() - flush() - flushing = 1 - flick("intake-closing", src) - var/deliveryCheck = 0 - var/obj/structure/disposalholder/H = new() // virtual holder object which actually +/obj/machinery/disposal/deliveryChute/flush() + flushing = 1 + flick("intake-closing", src) + var/deliveryCheck = 0 + var/obj/structure/disposalholder/H = new() // virtual holder object which actually // travels through the pipes. - for(var/obj/structure/bigDelivery/O in src) - deliveryCheck = 1 - if(O.sortTag == 0) - O.sortTag = 1 - for(var/obj/item/smallDelivery/O in src) - deliveryCheck = 1 - if(O.sortTag == 0) - O.sortTag = 1 - if(deliveryCheck == 0) - H.destinationTag = 1 + for(var/obj/structure/bigDelivery/O in src) + deliveryCheck = 1 + if(O.sortTag == 0) + O.sortTag = 1 + for(var/obj/item/smallDelivery/O in src) + deliveryCheck = 1 + if(O.sortTag == 0) + O.sortTag = 1 + for(var/obj/item/shippingPackage/O in src) + deliveryCheck = 1 + if(!O.sealed || O.sortTag == 0) //unsealed or untagged shipping packages will default to disposals + O.sortTag = 1 + if(deliveryCheck == 0) + H.destinationTag = 1 - sleep(10) - playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0) - sleep(5) // wait for animation to finish + sleep(10) + playsound(src, 'sound/machines/disposalflush.ogg', 50, 0, 0) + sleep(5) // wait for animation to finish - H.init(src) // copy the contents of disposer to holder - air_contents = new() // The holder just took our gas; replace it - H.start(src) // start the holder processing movement - flushing = 0 - // now reset disposal state - flush = 0 - if(mode == 2) // if was ready, - mode = 1 // switch to charging - update() + H.init(src) // copy the contents of disposer to holder + air_contents = new() // The holder just took our gas; replace it + H.start(src) // start the holder processing movement + flushing = 0 + // now reset disposal state + flush = 0 + if(mode == 2) // if was ready, + mode = 1 // switch to charging + update() + return + +/obj/machinery/disposal/deliveryChute/attackby(obj/item/I, mob/user, params) + if(!I || !user) return - attackby(var/obj/item/I, var/mob/user, params) - if(!I || !user) + if(istype(I, /obj/item/weapon/screwdriver)) + if(c_mode==0) + c_mode=1 + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You remove the screws around the power connection.") + return + else if(c_mode==1) + c_mode=0 + playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) + to_chat(user, "You attach the screws around the power connection.") + return + else if(istype(I,/obj/item/weapon/weldingtool) && c_mode==1) + var/obj/item/weapon/weldingtool/W = I + if(W.remove_fuel(0,user)) + playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) + to_chat(user, "You start slicing the floorweld off the delivery chute.") + if(do_after(user,20, target = src)) + if(!src || !W.isOn()) return + to_chat(user, "You sliced the floorweld off the delivery chute.") + var/obj/structure/disposalconstruct/C = new (src.loc) + C.ptype = 8 // 8 = Delivery chute + C.update() + C.anchored = 1 + C.density = 1 + qdel(src) + return + else + to_chat(user, "You need more welding fuel to complete this task.") return - if(istype(I, /obj/item/weapon/screwdriver)) - if(c_mode==0) - c_mode=1 - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - to_chat(user, "You remove the screws around the power connection.") - return - else if(c_mode==1) - c_mode=0 - playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) - to_chat(user, "You attach the screws around the power connection.") - return - else if(istype(I,/obj/item/weapon/weldingtool) && c_mode==1) - var/obj/item/weapon/weldingtool/W = I - if(W.remove_fuel(0,user)) - playsound(src.loc, 'sound/items/Welder2.ogg', 100, 1) - to_chat(user, "You start slicing the floorweld off the delivery chute.") - if(do_after(user,20, target = src)) - if(!src || !W.isOn()) return - to_chat(user, "You sliced the floorweld off the delivery chute.") - var/obj/structure/disposalconstruct/C = new (src.loc) - C.ptype = 8 // 8 = Delivery chute - C.update() - C.anchored = 1 - C.density = 1 - qdel(src) - return - else - to_chat(user, "You need more welding fuel to complete this task.") + +/obj/item/shippingPackage + name = "Shipping package" + desc = "A pre-labeled package for shipping an item to coworkers." + icon = 'icons/obj/storage.dmi' + icon_state = "shippack" + var/obj/item/wrapped = null + var/sortTag = 0 + var/sealed = 0 + +/obj/item/shippingPackage/attackby(obj/item/O, mob/user, params) + if(sealed) + if(istype(O, /obj/item/weapon/pen)) + var/str = copytext(sanitize(input(user,"Intended recipient?","Address","")),1,MAX_NAME_LEN) + if(!str || !length(str)) + to_chat(user, "Invalid text.") return + user.visible_message("[user] addresses [src] to [str].") + name = "Shipping package (RE: [str])" + return + if(wrapped) + to_chat(user, "[src] already contains \a [wrapped].") + return + if(istype(O, /obj/item) && !istype(O, /obj/item/weapon/storage) && !istype(O, /obj/item/shippingPackage)) + if(!user.canUnEquip(O)) + to_chat(user, "[O] is stuck to your hand, you cannot put it in [src]!") + return + if(O.w_class > 3) + to_chat(user, "[O] is too large to fit in [src].") + else + wrapped = O + user.unEquip(O) + O.forceMove(src) + O.add_fingerprint(usr) + add_fingerprint(usr) + to_chat(user, "You put [O] in [src].") + +/obj/item/shippingPackage/attack_self(mob/user) + if(sealed) + to_chat(user, "You tear open [src], dropping the contents onto the floor.") + playsound(loc, 'sound/items/poster_ripped.ogg', 50, 1) + user.unEquip(src) + wrapped.forceMove(get_turf(user)) + wrapped = null + qdel(src) + else if(wrapped) + switch(alert("Select an action:",, "Remove Object", "Seal Package", "Cancel")) + if("Remove Object") + to_chat(user, "You shake out [src]'s contents onto the floor.") + wrapped.forceMove(get_turf(user)) + wrapped = null + if("Seal Package") + to_chat(user, "You seal [src], preparing it for delivery.") + icon_state = "shippack_sealed" + sealed = 1 + update_desc() + else + if(alert("Do you want to tear up the package?",, "Yes", "No") == "Yes") + to_chat(user, "You shred [src].") + playsound(loc, 'sound/items/poster_ripped.ogg', 50, 1) + user.unEquip(src) + qdel(src) + +/obj/item/shippingPackage/proc/update_desc() + desc = "A pre-labeled package for shipping an item to coworkers." + if(sortTag) + desc += " The label says \"Deliver to [TAGGERLOCATIONS[sortTag]]\"." + if(!sealed) + desc += " The package is not sealed." + +/obj/item/shippingPackage/Destroy() + if(wrapped) + qdel(wrapped) + wrapped = null + return ..() \ No newline at end of file diff --git a/code/modules/research/designs/autolathe_designs.dm b/code/modules/research/designs/autolathe_designs.dm index 5cec47a0f5d..53b728f20b2 100644 --- a/code/modules/research/designs/autolathe_designs.dm +++ b/code/modules/research/designs/autolathe_designs.dm @@ -162,6 +162,14 @@ materials = list(MAT_METAL = 50, MAT_GLASS = 50) build_path = /obj/item/weapon/firealarm_electronics category = list("initial", "Electronics") + +/datum/design/earmuffs + name = "Earmuffs" + id = "earmuffs" + build_type = AUTOLATHE + materials = list(MAT_METAL = 500, MAT_GLASS = 500) + build_path = /obj/item/clothing/ears/earmuffs + category = list("initial", "Miscellaneous") /datum/design/igniter name = "Igniter" @@ -188,7 +196,7 @@ category = list("initial", "Medical") /datum/design/kitchen_knife - name = "Kitchen knife" + name = "Kitchen Knife" id = "kitchen_knife" build_type = AUTOLATHE materials = list(MAT_METAL = 12000) @@ -196,7 +204,7 @@ category = list("initial","Miscellaneous") /datum/design/minihoe - name = "Mini hoe" + name = "Mini Hoe" id = "mini_hoe" build_type = AUTOLATHE materials = list(MAT_METAL = 50) @@ -204,7 +212,7 @@ category = list("initial","Miscellaneous") /datum/design/plant_analyzer - name = "Plant analyzer" + name = "Plant Analyzer" id = "plant_analyzer" build_type = AUTOLATHE materials = list(MAT_METAL = 30, MAT_GLASS = 20) @@ -324,12 +332,12 @@ category = list("initial", "Miscellaneous") /datum/design/foambox - name = "Box of Foam Force darts" - id = "foamforce" - build_type = AUTOLATHE - materials = list(MAT_METAL = 2000) - build_path = /obj/item/ammo_box/foambox - category = list("initial", "Miscellaneous") + name = "Box of Foam Force darts" + id = "foamforce" + build_type = AUTOLATHE + materials = list(MAT_METAL = 2000) + build_path = /obj/item/ammo_box/foambox + category = list("initial", "Miscellaneous") /datum/design/canvas/twentythreeXtwentythree name = "23px by 23px Canvas" diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm index ab57eeefadb..c3072758331 100644 --- a/code/modules/research/xenobiology/xenobiology.dm +++ b/code/modules/research/xenobiology/xenobiology.dm @@ -25,8 +25,8 @@ ..() /obj/item/slime_extract/New() - ..() - create_reagents(100) + ..() + create_reagents(100) /obj/item/slime_extract/grey name = "grey slime extract" @@ -124,7 +124,9 @@ w_class = 1 origin_tech = "biotech=4" -/obj/item/slimepotion/afterattack(obj/item/weapon/reagent_containers/target, mob/user , proximity) +/obj/item/slimepotion/afterattack(obj/item/weapon/reagent_containers/target, mob/user, proximity_flag) + if(!proximity_flag) + return if(istype(target)) to_chat(user, "You cannot transfer [src] to [target]! It appears the potion must be given directly to a slime to absorb.") // le fluff faec return @@ -174,7 +176,7 @@ /obj/item/slimepotion/sentience name = "sentience potion" - desc = "A miraculous chemical mix that can raise the intelligence of creatures to human levels. Unlike normal slime potions, it can be absorbed by any nonsentient being." + desc = "A miraculous chemical mix that can raise the intelligence of creatures to human levels." icon = 'icons/obj/chemical.dmi' icon_state = "bottle19" origin_tech = "biotech=5" @@ -182,7 +184,9 @@ var/being_used = 0 var/sentience_type = SENTIENCE_ORGANIC -/obj/item/slimepotion/sentience/afterattack(mob/living/M, mob/user) +/obj/item/slimepotion/sentience/afterattack(mob/living/M, mob/user, proximity_flag) + if(!proximity_flag) + return if(being_used || !ismob(M)) return if(!isanimal(M) || M.ckey) //only works on animals that aren't player controlled @@ -221,6 +225,50 @@ being_used = 0 ..() +/obj/item/slimepotion/transference + name = "consciousness transference potion" + desc = "A strange slime-based chemical that, when used, allows the user to transfer their consciousness to a lesser being." + icon = 'icons/obj/chemical.dmi' + icon_state = "bottle19" + origin_tech = "biotech=6" + var/prompted = FALSE + var/animal_type = SENTIENCE_ORGANIC + +/obj/item/slimepotion/transference/afterattack(mob/living/M, mob/user, proximity_flag) + if(!proximity_flag) + return + if(prompted || !ismob(M)) + return + if(!isanimal(M) || M.ckey) //much like sentience, these will not work on something that is already player controlled + to_chat(user, "[M] already has a higher consciousness!") + return ..() + if(M.stat) + to_chat(user, "[M] is dead!") + return ..() + var/mob/living/simple_animal/SM = M + if(SM.sentience_type != animal_type) + to_chat(user, "You cannot transfer your consciousness to [SM].") //no controlling machines + return ..() + if(jobban_isbanned(user, ROLE_SENTIENT)) + to_chat(user, "Your mind goes blank as you attempt to use the potion.") + return + + prompted = TRUE + if(alert("This will permanently transfer your consciousness to [SM]. Are you sure you want to do this?",,"Yes","No")=="No") + prompted = FALSE + return + + to_chat(user, "You drink the potion then place your hands on [SM]...") + user.mind.transfer_to(SM) + SM.universal_speak = 1 + SM.faction = user.faction + SM.sentience_act() //Same deal here as with sentience + user.death() + to_chat(SM, "In a quick flash, you feel your consciousness flow into [SM]!") + to_chat(SM, "You are now [SM]. Your allegiances, alliances, and roles are still the same as they were prior to consciousness transfer!") + SM.name = "[SM.name] as [user.real_name]" + qdel(src) + /obj/item/slimepotion/steroid name = "slime steroid" desc = "A potent chemical mix that will cause a baby slime to generate more extract." @@ -303,15 +351,17 @@ icon = 'icons/obj/chemical.dmi' icon_state = "bottle3" -/obj/item/slimepotion/speed/afterattack(obj/item/C, mob/user) +/obj/item/slimepotion/speed/afterattack(obj/item/C, mob/user, proximity_flag) + if(!proximity_flag) + return ..() if(!istype(C)) to_chat(user, "The potion can only be used on items!") return if(C.slowdown <= 0) - to_chat(user, "The [C] can't be made any faster!") + to_chat(user, "[C] can't be made any faster!") return..() - to_chat(user, "You slather the red gunk over the [C], making it faster.") + to_chat(user, "You slather the red gunk over [C], making it faster.") C.color = "#FF0000" C.slowdown = 0 qdel(src) @@ -323,8 +373,10 @@ icon_state = "bottle17" var/uses = 3 -/obj/item/slimepotion/fireproof/afterattack(obj/item/clothing/C, mob/user) +/obj/item/slimepotion/fireproof/afterattack(obj/item/clothing/C, mob/user, proximity_flag) ..() + if(!proximity_flag) + return if(!uses) qdel(src) return @@ -332,9 +384,9 @@ to_chat(user, "The potion can only be used on clothing!") return if(C.max_heat_protection_temperature == FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT) - to_chat(user, "The [C] is already fireproof!") + to_chat(user, "[C] is already fireproof!") return ..() - to_chat(user, "You slather the blue gunk over the [C], fireproofing it.") + to_chat(user, "You slather the blue gunk over [C], fireproofing it.") C.name = "fireproofed [C.name]" C.color = "#000080" C.max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT @@ -366,9 +418,9 @@ else icon_state = "golem" -/obj/effect/golemrune/attack_hand(mob/living/user as mob) +/obj/effect/golemrune/attack_hand(mob/living/user) var/mob/dead/observer/ghost - for(var/mob/dead/observer/O in src.loc) + for(var/mob/dead/observer/O in loc) if(!check_observer(O)) to_chat(O, "\red You are not eligible to become a golem.") continue @@ -391,21 +443,22 @@ volunteer(O) /obj/effect/golemrune/attack_ghost(var/mob/dead/observer/O) - if(!O) return + if(!O) + return volunteer(O) /obj/effect/golemrune/proc/check_observer(var/mob/dead/observer/O) if(!O) - return 0 + return FALSE if(!O.client) - return 0 + return FALSE if(O.mind && O.mind.current && O.mind.current.stat != DEAD) - return 0 + return FALSE if(!O.can_reenter_corpse) - return 0 + return FALSE if(O.has_enabled_antagHUD == 1 && config.antag_hud_restricted) - return 0 - return 1 + return FALSE + return TRUE /obj/effect/golemrune/proc/volunteer(var/mob/dead/observer/O) if(O in ghosts) @@ -448,8 +501,8 @@ /obj/effect/timestop/proc/timestop() playsound(get_turf(src), 'sound/magic/TIMEPARADOX2.ogg', 100, 1, -1) for(var/i in 1 to duration-1) - for(var/A in orange (freezerange, src.loc)) - if(istype(A, /mob/living)) + for(var/A in orange (freezerange, loc)) + if(isliving(A)) var/mob/living/M = A if(M in immune) continue diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm index 2595d9bf95d..ba772007b62 100644 --- a/code/modules/surgery/dental_implant.dm +++ b/code/modules/surgery/dental_implant.dm @@ -24,14 +24,13 @@ return 0 var/dental_implants = 0 - for(var/obj/item/weapon/reagent_containers/food/pill in target.internal_organs) // Can't give them more than 4 dental implants. + for(var/obj/item/weapon/reagent_containers/food/pill in target.contents) // Can't give them more than 4 dental implants. dental_implants++ if(dental_implants >= 4) user.visible_message("[user] pulls \the [tool] back out of [target]'s [parse_zone(target_zone)]!", "You pull \the [tool] back out of [target]'s [parse_zone(target_zone)], there wans't enough room...") return 0 user.drop_item() - target.internal_organs += tool tool.forceMove(target) var/datum/action/item_action/hands_free/activate_pill/P = new diff --git a/code/modules/surgery/organs/vocal_cords.dm b/code/modules/surgery/organs/vocal_cords.dm new file mode 100644 index 00000000000..63fe8fc81bc --- /dev/null +++ b/code/modules/surgery/organs/vocal_cords.dm @@ -0,0 +1,455 @@ +var/static/regex/stun_words = regex("stop|wait|stand still|hold on|halt") +var/static/regex/weaken_words = regex("drop|fall|trip") +var/static/regex/sleep_words = regex("sleep|slumber") +var/static/regex/vomit_words = regex("vomit|throw up") +var/static/regex/silence_words = regex("shut up|silence|ssh|quiet|hush") +var/static/regex/hallucinate_words = regex("see the truth|hallucinate") +var/static/regex/wakeup_words = regex("wake up|awaken") +var/static/regex/heal_words = regex("live|heal|survive|mend|heroes never die") +var/static/regex/hurt_words = regex("die|suffer") +var/static/regex/bleed_words = regex("bleed") +var/static/regex/burn_words = regex("burn|ignite") +var/static/regex/repulse_words = regex("shoo|go away|leave me alone|begone|flee|fus ro dah") +var/static/regex/whoareyou_words = regex("who are you|say your name|state your name|identify") +var/static/regex/saymyname_words = regex("say my name") +var/static/regex/knockknock_words = regex("knock knock") +var/static/regex/statelaws_words = regex("state laws|state your laws") +var/static/regex/move_words = regex("move") +var/static/regex/walk_words = regex("walk|slow down") +var/static/regex/run_words = regex("run") +var/static/regex/helpintent_words = regex("help") +var/static/regex/disarmintent_words = regex("disarm") +var/static/regex/grabintent_words = regex("grab") +var/static/regex/harmintent_words = regex("harm|fight") +var/static/regex/throwmode_words = regex("throw|catch") +var/static/regex/flip_words = regex("flip|rotate|revolve|roll|somersault") +var/static/regex/rest_words = regex("rest") +var/static/regex/getup_words = regex("get up") +var/static/regex/sit_words = regex("sit") +var/static/regex/stand_words = regex("stand") +var/static/regex/dance_words = regex("dance") +var/static/regex/jump_words = regex("jump") +var/static/regex/salute_words = regex("salute") +var/static/regex/deathgasp_words = regex("play dead") +var/static/regex/clap_words = regex("clap|applaud") +var/static/regex/honk_words = regex("ho+nk") //hooooooonk +var/static/regex/multispin_words = regex("like a record baby") + +/obj/item/organ/internal/vocal_cords //organs that are activated through speech with the :x channel + name = "vocal cords" + icon_state = "appendix" + zone = "mouth" + slot = "vocal_cords" + parent_organ = "mouth" + var/spans = null + +/obj/item/organ/internal/vocal_cords/proc/can_speak_with() //if there is any limitation to speaking with these cords + return TRUE + +/obj/item/organ/internal/vocal_cords/proc/speak_with(message) //do what the organ does + return + +/obj/item/organ/internal/vocal_cords/proc/handle_speech(message) //change the message + return message + +//Colossus drop, forces the listeners to obey certain commands +/obj/item/organ/internal/vocal_cords/colossus + name = "divine vocal cords" + desc = "They carry the voice of an ancient god." + icon_state = "voice_of_god" + actions_types = list(/datum/action/item_action/organ_action/colossus) + var/next_command = 0 + var/cooldown_stun = 1200 + var/cooldown_damage = 600 + var/cooldown_meme = 300 + var/cooldown_none = 150 + var/base_multiplier = 1 + spans = "colossus yell" + +/datum/action/item_action/organ_action/colossus + name = "Voice of God" + var/obj/item/organ/internal/vocal_cords/colossus/cords = null + +/datum/action/item_action/organ_action/colossus/New() + ..() + cords = target + +/datum/action/item_action/organ_action/colossus/IsAvailable() + if(world.time < cords.next_command) + return FALSE + if(!owner) + return FALSE + if(!owner.can_speak()) + return FALSE + if(check_flags & AB_CHECK_CONSCIOUS) + if(owner.stat) + return FALSE + return TRUE + +/datum/action/item_action/organ_action/colossus/Trigger() + . = ..() + if(!IsAvailable()) + if(world.time < cords.next_command) + to_chat(owner, "You must wait [(cords.next_command - world.time)/10] seconds before Speaking again.") + return + var/command = input(owner, "Speak with the Voice of God", "Command") + if(!command) + return + owner.say(".x[command]") + +/obj/item/organ/internal/vocal_cords/colossus/can_speak_with() + if(world.time < next_command) + to_chat(owner, "You must wait [(next_command - world.time)/10] seconds before Speaking again.") + return FALSE + if(!owner) + return FALSE + if(!owner.can_speak()) + to_chat(owner, "You are unable to speak!") + return FALSE + if(owner.stat) + return FALSE + return TRUE + +/obj/item/organ/internal/vocal_cords/colossus/handle_speech(message) + spans = "colossus yell" //reset spans, just in case someone gets deculted or the cords change owner + if(iscultist(owner)) + spans += " narsiesmall" + return "[uppertext(message)]" + +/obj/item/organ/internal/vocal_cords/colossus/speak_with(message) + var/log_message = uppertext(message) + message = lowertext(message) + playsound(get_turf(owner), 'sound/magic/invoke_general.ogg', 300, 1, 5) + + var/mob/living/list/listeners = list() + for(var/mob/living/L in get_mobs_in_view(8, owner, TRUE)) + if(!L.ear_deaf && !L.null_rod_check() && L != owner && L.stat != DEAD) + if(ishuman(L)) + var/mob/living/carbon/human/H = L + if(istype(H.l_ear, /obj/item/clothing/ears/earmuffs) || istype(H.r_ear, /obj/item/clothing/ears/earmuffs)) + continue + listeners += L + + if(!listeners.len) + next_command = world.time + cooldown_none + return + + var/power_multiplier = base_multiplier + + if(owner.mind) + //Chaplains are very good at speaking with the voice of god + if(owner.mind.assigned_role == "Chaplain") + power_multiplier *= 2 + //Command staff has authority + if(owner.mind.assigned_role in command_positions) + power_multiplier *= 1.4 + //Why are you speaking + if(owner.mind.assigned_role == "Mime") + power_multiplier *= 0.5 + + //Cultists are closer to their gods and are more powerful, but they'll give themselves away + if(iscultist(owner)) + power_multiplier *= 2 + + //Try to check if the speaker specified a name or a job to focus on + var/list/specific_listeners = list() + var/found_string = null + + for(var/V in listeners) + var/mob/living/L = V + /*if(L.mind && L.mind.devilinfo && findtext(message, L.mind.devilinfo.truename)) + var/start = findtext(message, L.mind.devilinfo.truename) + listeners = list(L) //let's be honest you're never going to find two devils with the same name + power_multiplier *= 5 //if you're a devil and god himself addressed you, you fucked up + //Cut out the name so it doesn't trigger commands + message = copytext(message, 0, start)+copytext(message, start + length(L.mind.devilinfo.truename), length(message) + 1) + break*/ + if(findtext(message, L.real_name) == 1) + specific_listeners += L //focus on those with the specified name + //Cut out the name so it doesn't trigger commands + found_string = L.real_name + + else if(L.mind && findtext(message, L.mind.assigned_role) == 1) + specific_listeners += L //focus on those with the specified job + //Cut out the job so it doesn't trigger commands + found_string = L.mind.assigned_role + + if(specific_listeners.len) + listeners = specific_listeners + power_multiplier *= (1 + (1/specific_listeners.len)) //2x on a single guy, 1.5x on two and so on + message = copytext(message, 0, 1)+copytext(message, 1 + length(found_string), length(message) + 1) + + //STUN + if(findtext(message, stun_words)) + for(var/V in listeners) + var/mob/living/L = V + L.Stun(3 * power_multiplier) + next_command = world.time + cooldown_stun + + //WEAKEN + else if(findtext(message, weaken_words)) + for(var/V in listeners) + var/mob/living/L = V + L.Weaken(3 * power_multiplier) + next_command = world.time + cooldown_stun + + //SLEEP + else if((findtext(message, sleep_words))) + for(var/V in listeners) + var/mob/living/L = V + L.Sleeping(2 * power_multiplier) + next_command = world.time + cooldown_stun + + //VOMIT + else if((findtext(message, vomit_words))) + for(var/mob/living/carbon/C in listeners) + C.vomit(10 * power_multiplier) + next_command = world.time + cooldown_stun + + //SILENCE + else if((findtext(message, silence_words))) + for(var/mob/living/carbon/C in listeners) + if(owner.mind && (owner.mind.assigned_role == "Librarian" || owner.mind.assigned_role == "Mime")) + power_multiplier *= 3 + C.silent += (10 * power_multiplier) + next_command = world.time + cooldown_stun + + //HALLUCINATE + else if((findtext(message, hallucinate_words))) + for(var/V in listeners) + var/mob/living/L = V + new /obj/effect/hallucination/delusion(get_turf(L),L,duration=150 * power_multiplier,skip_nearby=0) + next_command = world.time + cooldown_meme + + //WAKE UP + else if((findtext(message, wakeup_words))) + for(var/V in listeners) + var/mob/living/L = V + L.SetSleeping(0) + next_command = world.time + cooldown_damage + + //HEAL + else if((findtext(message, heal_words))) + for(var/V in listeners) + var/mob/living/L = V + L.heal_overall_damage(10 * power_multiplier, 10 * power_multiplier, 0, 0) + next_command = world.time + cooldown_damage + + //BRUTE DAMAGE + else if((findtext(message, hurt_words))) + for(var/V in listeners) + var/mob/living/L = V + L.apply_damage(15 * power_multiplier, def_zone = "chest") + next_command = world.time + cooldown_damage + + //BLEED + else if((findtext(message, bleed_words))) + for(var/mob/living/carbon/human/H in listeners) + H.drip(100 * power_multiplier) + next_command = world.time + cooldown_damage + + //FIRE + else if((findtext(message, burn_words))) + for(var/V in listeners) + var/mob/living/L = V + L.adjust_fire_stacks(1 * power_multiplier) + L.IgniteMob() + next_command = world.time + cooldown_damage + + //REPULSE + else if((findtext(message, repulse_words))) + for(var/V in listeners) + var/mob/living/L = V + var/throwtarget = get_edge_target_turf(owner, get_dir(owner, get_step_away(L, owner))) + L.throw_at(throwtarget, 3 * power_multiplier, 1) + next_command = world.time + cooldown_damage + + //WHO ARE YOU? + else if((findtext(message, whoareyou_words))) + for(var/V in listeners) + var/mob/living/L = V + /*if(L.mind && L.mind.devilinfo) + L.say("[L.mind.devilinfo.truename]") + else*/ + L.say("[L.real_name]") + next_command = world.time + cooldown_meme + + //SAY MY NAME + else if((findtext(message, saymyname_words))) + for(var/V in listeners) + var/mob/living/L = V + L.say("[owner.name]!") //"Unknown!" + next_command = world.time + cooldown_meme + + //KNOCK KNOCK + else if((findtext(message, knockknock_words))) + for(var/V in listeners) + var/mob/living/L = V + L.say("Who's there?") + next_command = world.time + cooldown_meme + + //STATE LAWS + else if((findtext(message, statelaws_words))) + for(var/mob/living/silicon/S in listeners) + S.statelaws(S.laws) + next_command = world.time + cooldown_stun + + //MOVE + else if((findtext(message, move_words))) + for(var/V in listeners) + var/mob/living/L = V + step(L, pick(cardinal)) + next_command = world.time + cooldown_meme + + //WALK + else if((findtext(message, walk_words))) + for(var/V in listeners) + var/mob/living/L = V + if(L.m_intent != "walk") + L.m_intent = "walk" + if(L.hud_used) + L.hud_used.move_intent.icon_state = "walking" + next_command = world.time + cooldown_meme + + //RUN + else if((findtext(message, run_words))) + for(var/V in listeners) + var/mob/living/L = V + if(L.m_intent != "run") + L.m_intent = "run" + if(L.hud_used) + L.hud_used.move_intent.icon_state = "running" + next_command = world.time + cooldown_meme + + //HELP INTENT + else if((findtext(message, helpintent_words))) + for(var/mob/living/carbon/human/H in listeners) + H.a_intent_change(I_HELP) + next_command = world.time + cooldown_meme + + //DISARM INTENT + else if((findtext(message, disarmintent_words))) + for(var/mob/living/carbon/human/H in listeners) + H.a_intent_change(I_DISARM) + next_command = world.time + cooldown_meme + + //GRAB INTENT + else if((findtext(message, grabintent_words))) + for(var/mob/living/carbon/human/H in listeners) + H.a_intent_change(I_GRAB) + next_command = world.time + cooldown_meme + + //HARM INTENT + else if((findtext(message, harmintent_words))) + for(var/mob/living/carbon/human/H in listeners) + H.a_intent_change(I_HARM) + next_command = world.time + cooldown_meme + + //THROW/CATCH + else if((findtext(message, throwmode_words))) + for(var/mob/living/carbon/C in listeners) + C.throw_mode_on() + next_command = world.time + cooldown_meme + + //FLIP + else if((findtext(message, flip_words))) + for(var/V in listeners) + var/mob/living/L = V + L.emote("flip") + next_command = world.time + cooldown_meme + + //REST + else if((findtext(message, rest_words))) + for(var/V in listeners) + var/mob/living/L = V + if(!L.resting) + L.lay_down() + next_command = world.time + cooldown_meme + + //GET UP + else if((findtext(message, getup_words))) + for(var/V in listeners) + var/mob/living/L = V + if(L.resting) + L.lay_down() //aka get up + L.SetStunned(0) + L.SetWeakened(0) + L.SetParalysis(0) //i said get up i don't care if you're being tazed + next_command = world.time + cooldown_damage + + //SIT + else if((findtext(message, sit_words))) + for(var/V in listeners) + var/mob/living/L = V + for(var/obj/structure/stool/bed/chair/chair in get_turf(L)) + chair.buckle_mob(L) + break + next_command = world.time + cooldown_meme + + //STAND UP + else if((findtext(message, stand_words))) + for(var/V in listeners) + var/mob/living/L = V + if(L.buckled && istype(L.buckled, /obj/structure/stool/bed/chair)) + L.buckled.unbuckle_mob(L) + next_command = world.time + cooldown_meme + + //DANCE + else if((findtext(message, dance_words))) + for(var/V in listeners) + var/mob/living/L = V + L.emote("dance") + next_command = world.time + cooldown_meme + + //JUMP + else if((findtext(message, jump_words))) + for(var/V in listeners) + var/mob/living/L = V + L.say("HOW HIGH?!!") + L.emote("jump") + next_command = world.time + cooldown_meme + + //SALUTE + else if((findtext(message, salute_words))) + for(var/V in listeners) + var/mob/living/L = V + L.emote("salute") + next_command = world.time + cooldown_meme + + //PLAY DEAD + else if((findtext(message, deathgasp_words))) + for(var/V in listeners) + var/mob/living/L = V + L.emote("deathgasp") + next_command = world.time + cooldown_meme + + //PLEASE CLAP + else if((findtext(message, clap_words))) + for(var/V in listeners) + var/mob/living/L = V + L.emote("clap") + next_command = world.time + cooldown_meme + + //HONK + else if((findtext(message, honk_words))) + spawn(25) + playsound(get_turf(owner), "sound/items/bikehorn.ogg", 300, 1) + if(owner.mind && owner.mind.assigned_role == "Clown") + for(var/mob/living/carbon/C in listeners) + C.slip(0,7 * power_multiplier) + next_command = world.time + cooldown_stun + else + next_command = world.time + cooldown_meme + + //RIGHT ROUND + else if((findtext(message, multispin_words))) + for(var/V in listeners) + var/mob/living/L = V + L.SpinAnimation(speed = 10, loops = 5) + next_command = world.time + cooldown_meme + + else + next_command = world.time + cooldown_none + + message_admins("[key_name_admin(owner)] has said '[log_message]' with a Voice of God, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].") + log_game("[key_name(owner)] has said '[log_message]' with a Voice of God, affecting [english_list(listeners)], with a power multiplier of [power_multiplier].") \ No newline at end of file diff --git a/code/modules/telesci/gps.dm b/code/modules/telesci/gps.dm index 2d99a538244..7558fd602ee 100644 --- a/code/modules/telesci/gps.dm +++ b/code/modules/telesci/gps.dm @@ -10,6 +10,7 @@ var/list/GPS_list = list() var/gpstag = "COM0" var/emped = 0 var/turf/locked_location + var/tracking = TRUE /obj/item/device/gps/New() ..() @@ -25,13 +26,32 @@ var/list/GPS_list = list() emped = 1 overlays -= "working" overlays += "emp" - spawn(300) - emped = 0 - overlays -= "emp" + addtimer(src, "reboot", 300) + +/obj/item/device/gps/proc/reboot() + emped = FALSE + overlays -= "emp" + overlays += "working" + +/obj/item/device/gps/AltClick(mob/user) + if(CanUseTopic(user, inventory_state) != STATUS_INTERACTIVE) + return 1 //user not valid to use gps + if(emped) + to_chat(user, "It's busted!") + if(tracking) + overlays -= "working" + to_chat(user, "[src] is no longer tracking, or visible to other GPS devices.") + tracking = FALSE + else overlays += "working" + to_chat(user, "[src] is now tracking, and visible to other GPS devices.") + tracking = TRUE /obj/item/device/gps/attack_self(mob/user as mob) - + if(!tracking) + to_chat(user, "[src] is turned off. Use alt+click to toggle it back on.") + return + var/obj/item/device/gps/t = "" var/gps_window_height = 110 + GPS_list.len * 20 // Variable window height, depending on how many GPS units there are to show if(emped) @@ -49,8 +69,10 @@ var/list/GPS_list = list() var/tracked_gpstag = G.gpstag if(G.emped == 1) t += "
[tracked_gpstag]: ERROR" - else + else if(G.tracking) t += "
[tracked_gpstag]: [format_text(gps_area.name)] ([pos.x], [pos.y], [pos.z])" + else + continue var/datum/browser/popup = new(user, "GPS", name, 360, min(gps_window_height, 800)) popup.set_content(t) @@ -58,9 +80,14 @@ var/list/GPS_list = list() popup.open() /obj/item/device/gps/Topic(href, href_list) - ..() + if(..(state = inventory_state)) + return 1 + if(href_list["tag"] ) - var/a = input("Please enter desired tag.", name, gpstag) as text + var/a = input("Please enter desired tag.", name, gpstag) as text|null + if(!a || ..(state = inventory_state)) + return 1 + a = uppertext(sanitize(copytext(a, 1, 5))) if(src.loc == usr) gpstag = a @@ -84,4 +111,55 @@ var/list/GPS_list = list() icon_state = "gps-b" gpstag = "BORG0" desc = "A mining cyborg internal positioning system. Used as a recovery beacon for damaged cyborg assets, or a collaboration tool for mining teams." - flags = NODROP \ No newline at end of file + flags = NODROP + +/obj/item/device/gps/internal + icon_state = null + flags = ABSTRACT + gpstag = "Eerie Signal" + desc = "Report to a coder immediately." + invisibility = INVISIBILITY_MAXIMUM + +/obj/item/device/gps/internal/mining + icon_state = "gps-m" + gpstag = "MINER" + desc = "A positioning system helpful for rescuing trapped or injured miners, keeping one on you at all times while mining might just save your life." + +/obj/item/device/gps/internal/base + gpstag = "NT_AUX" + desc = "A homing signal from Nanotrasen's mining base." + +/obj/item/device/gps/visible_debug + name = "visible GPS" + gpstag = "ADMIN" + desc = "This admin-spawn GPS unit leaves the coordinates visible \ + on any turf that it passes over, for debugging. Especially useful \ + for marking the area around the transition edges." + var/list/turf/tagged + +/obj/item/device/gps/visible_debug/New() + . = ..() + tagged = list() + fast_processing.Add(src) + +/obj/item/device/gps/visible_debug/process() + var/turf/T = get_turf(src) + if(T) + // I assume it's faster to color,tag and OR the turf in, rather + // then checking if its there + T.color = RANDOM_COLOUR + T.maptext = "[T.x],[T.y],[T.z]" + tagged |= T + +/obj/item/device/gps/visible_debug/proc/clear() + while(tagged.len) + var/turf/T = pop(tagged) + T.color = initial(T.color) + T.maptext = initial(T.maptext) + +/obj/item/device/gps/visible_debug/Destroy() + if(tagged) + clear() + tagged = null + fast_processing.Remove(src) + . = ..() \ No newline at end of file diff --git a/code/modules/vehicle/atv.dm b/code/modules/vehicle/atv.dm index d4a843b80bf..a67310c8874 100644 --- a/code/modules/vehicle/atv.dm +++ b/code/modules/vehicle/atv.dm @@ -9,45 +9,39 @@ vehicle_move_delay = 1 var/static/image/atvcover = null - /obj/vehicle/atv/New() ..() if(!atvcover) atvcover = image("icons/vehicles/4wheeler.dmi", "4wheeler_north") atvcover.layer = MOB_LAYER + 0.1 - -obj/vehicle/atv/post_buckle_mob(mob/living/M) +/obj/vehicle/atv/post_buckle_mob(mob/living/M) if(buckled_mob) overlays += atvcover else overlays -= atvcover - /obj/vehicle/atv/handle_vehicle_layer() if(dir == SOUTH) layer = MOB_LAYER+0.1 else layer = OBJ_LAYER - //TURRETS! /obj/vehicle/atv/turret - var/obj/machinery/gun_turret/vehicle_turret/turret = null + var/obj/machinery/porta_turret/syndicate/vehicle_turret/turret = null - -/obj/machinery/gun_turret/vehicle_turret +/obj/machinery/porta_turret/syndicate/vehicle_turret name = "mounted turret" scan_range = 7 + emp_vulnerable = 1 density = 0 - /obj/vehicle/atv/turret/New() ..() turret = new(loc) //turret.base = src - /obj/vehicle/atv/turret/handle_vehicle_layer() if(dir == SOUTH) layer = MOB_LAYER+0.1 @@ -60,7 +54,6 @@ obj/vehicle/atv/post_buckle_mob(mob/living/M) else turret.layer = OBJ_LAYER - /obj/vehicle/atv/turret/handle_vehicle_offsets() ..() if(turret) diff --git a/config/example/config.txt b/config/example/config.txt index 8f7e0e009ef..5bcd469be87 100644 --- a/config/example/config.txt +++ b/config/example/config.txt @@ -326,5 +326,12 @@ DISABLE_SPACE_RUINS # Setting this to 0 will disable the penalty period #ROUND_ABANDON_PENALTY_PERIOD 30 +## Hub address for tracking stats +## example: Hubmakerckey.Hubname +#MEDAL_HUB_ADDRESS + +## Password for the hub page +#MEDAL_HUB_PASSWORD + ## Uncomment this if you want to disable usage of emoji in OOC #DISABLE_OOC_EMOJI \ No newline at end of file diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css index c7204d36577..970e94bb3b4 100644 --- a/goon/browserassets/css/browserOutput.css +++ b/goon/browserassets/css/browserOutput.css @@ -239,6 +239,7 @@ em {font-style: normal; font-weight: bold;} .playerreply {color: #8800bb; font-weight: bold;} .name { font-weight: bold;} .say {} +.yell { font-weight: bold;} .siliconsay {font-family: 'Courier New', Courier, monospace;} .deadsay {color: #5c00e6;} .radio {color: #008000;} @@ -323,8 +324,9 @@ h1.alert, h2.alert {color: #000000;} .cult {color: #800080; font-weight: bold; font-style: italic;} .cultspeech {color: #7F0000; font-style: italic;} .cultitalic {color: #960000; font-style: italic;} -.cultlarge {color: #960000; font-weight: bold; font-size: 3;} -.narsie {color: #960000; font-weight: bold; font-size: 15;} +.cultlarge {color: #960000; font-weight: bold; font-size: 120%;} +.narsie {color: #960000; font-weight: bold; font-size: 300%;} +.narsiesmall {color: #960000; font-weight: bold; font-size: 200%;} .interface {color: #330033;} .big {font-size: 150%;} .reallybig {font-size: 175%;} @@ -341,10 +343,10 @@ h1.alert, h2.alert {color: #000000;} .revennotice {color: #1d2953;} .revenboldnotice {color: #1d2953; font-weight: bold;} -.revenbignotice {color: #1d2953; font-weight: bold; font-size: 3;} +.revenbignotice {color: #1d2953; font-weight: bold; font-size: 120%;} .revenminor {color: #823abb} .revenwarning {color: #760fbb; font-style: italic;} -.revendanger {color: #760fbb; font-weight: bold; font-size: 3;} +.revendanger {color: #760fbb; font-weight: bold; font-size: 120%;} /* /vg/ */ .good {color: green;} @@ -358,7 +360,7 @@ h1.alert, h2.alert {color: #000000;} "} .memo {color: #638500; text-align: center;} -.memoedit {text-align: center; font-size: 2;} +.memoedit {text-align: center; font-size: 75%;} .connectionClosed, .fatalError {background: red; color: white; padding: 5px;} .connectionClosed.restored {background: green;} @@ -368,5 +370,10 @@ h1.alert, h2.alert {color: #000000;} .text-normal {font-weight: normal; font-style: normal;} .hidden {display: none; visibility: hidden;} +/* MEGAFAUNA */ +.colossus {color: #7F282A; font-size: 175%;} +.hierophant {color: #660099; font-weight: bold; font-size: 150%;} +.hierophant_warning {color: #660099; font-weight: bold; font-style: italic;} + /* EMOJI STUFF */ .emoji {max-height: 16px; max-width: 16px} \ No newline at end of file diff --git a/html/changelog.html b/html/changelog.html index ebf6431a935..a85680fcc94 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,11 +55,105 @@ -->
+

05 February 2017

+

Fethas updated:

+
    +
  • Brings unholy water in line with its description.
  • +
+

Ported by Markolie, developed by KorPhaeron and others from /tg/. The Hierophant was developed by ChangelingRain. updated:

+
    +
  • Megafauna and their rewards have been added to the code. These are not on the map yet.
  • +
  • Fireball is now a targeted spell instead of a dumbfire spell.
  • +
  • Most spells, wands and staffs now have unique spell sounds.
  • +
  • Added a new nullrod type, the "spellblade".
  • +
  • Added bows, arrows and quivers. Currently only available for admins.
  • +
  • Added cockroaches. Currently only available for admins.
  • +
  • Added support for BYOND medals. Currently disabled.
  • +
  • Added a number of Lavaland objects (flora, basalt, food and stacks). Currently only available for admins.
  • +
  • Earmuffs can now be produced in autolathes.
  • +
  • Syndicate gun turrets are now subtypes of regular turrets: this makes them controllable with Syndicate ID's and improves their targeting.
  • +
  • Diona and Shadow People now receive a warning when they're not exposed/exposed to light.
  • +
  • The sniper AP rounds that Nuke Ops can purchase now have a chance of dismembering limbs.
  • +
  • Shadow People can now switch their night vision properly.
  • +
  • Certain messages in chat weren't showing up in their proper (large) size, such as the Nar'Sie spawned message. This has been resolved.
  • +
+

uraniummeltdown updated:

+
    +
  • Supply ID skin is now selectable in the Agent ID and ID Computer
  • +
+ +

03 February 2017

+

DrunkDwarf updated:

+
    +
  • Set the Mr Chang's vending machine to be refillable
  • +
  • Added a Supply Crate to the Vending section of the Cargo Request Console for Chinese Refill Canisters
  • +
+ +

02 February 2017

+

Alexshreds updated:

+
    +
  • Deconstructing closets yields the proper amount of metal
  • +
+

Kyep updated:

+
    +
  • Using the 'summon narsie' rune as cult, when you don't have the objective to do so, is now punished by the cult's god. Just as using the 'call forth the slaughter' rune, when you don't have the objective to do that, is already punished.
  • +
+

uraniummeltdown updated:

+
    +
  • Engineering Cyborgs now have a digital copy of the station blueprints.
  • +
+ +

31 January 2017

+

Ar3nn updated:

+
    +
  • cursed cluwne mask now allows internals to be fed through it
  • +
+

FalseIncarnate updated:

+
    +
  • All requests consoles can print off a single-use, pre-tagged Shipping Package for sending a single item via disposals to a destination of your choosing.
  • +
  • Shipping Packages can be used to tag packages wrapped with wrapping paper, in case you don't have access to cargo's destination tagger.
  • +
  • Requests Consoles log the printer and destination of all shipping labels printed from that particular console. There currently is no way to clear your mailing history, so mail responsibly.
  • +
+

Fethas updated:

+
    +
  • Fixes a rune runtime.
  • +
+

FlattestGuitar updated:

+
    +
  • adds an admin-only laser carbine
  • +
+

uraniummeltdown updated:

+
    +
  • Your game window will now flash on receiving Admin PMs, being revived, and ghost roles. You can disable this in Game Preferences.
  • +
+ +

30 January 2017

+

Alexshreds updated:

+
    +
  • No more double traitor 241 Special
  • +
+ +

29 January 2017

+

uraniummeltdown updated:

+
    +
  • You can now take items directly out of a storage item in your backpack.
  • +
+

27 January 2017

+

Alffd updated:

+
    +
  • Adds missing hat and shoe sprites that were inadvertently deleted.
  • +

Fox McCloud updated:

  • Adds in stungloves (inaccessible to players)
+

uraniummeltdown updated:

+
    +
  • Injecting a rainbow slime extract with blood will create a consciousness transference potion.
  • +
  • Injecting a metal slime extract with water will create 15 sheets of glass and 5 sheets of reinforced glass.
  • +
  • Slime potions now check for proximity.
  • +

26 January 2017

FalseIncarnate updated:

diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index cc3d58389bd..2d6d1264eff 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -3424,5 +3424,77 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. FreeStylaLT: - tweak: AI sat transport tubes are no longer misaligned 2017-01-27: + Alffd: + - bugfix: Adds missing hat and shoe sprites that were inadvertently deleted. Fox McCloud: - rscadd: Adds in stungloves (inaccessible to players) + uraniummeltdown: + - rscadd: Injecting a rainbow slime extract with blood will create a consciousness + transference potion. + - rscadd: Injecting a metal slime extract with water will create 15 sheets of glass + and 5 sheets of reinforced glass. + - bugfix: Slime potions now check for proximity. +2017-01-29: + uraniummeltdown: + - tweak: You can now take items directly out of a storage item in your backpack. +2017-01-30: + Alexshreds: + - bugfix: No more double traitor 241 Special +2017-01-31: + Ar3nn: + - tweak: cursed cluwne mask now allows internals to be fed through it + FalseIncarnate: + - rscadd: All requests consoles can print off a single-use, pre-tagged Shipping + Package for sending a single item via disposals to a destination of your choosing. + - rscadd: Shipping Packages can be used to tag packages wrapped with wrapping paper, + in case you don't have access to cargo's destination tagger. + - rscadd: Requests Consoles log the printer and destination of all shipping labels + printed from that particular console. There currently is no way to clear your + mailing history, so mail responsibly. + Fethas: + - bugfix: Fixes a rune runtime. + FlattestGuitar: + - rscadd: adds an admin-only laser carbine + uraniummeltdown: + - rscadd: Your game window will now flash on receiving Admin PMs, being revived, + and ghost roles. You can disable this in Game Preferences. +2017-02-02: + Alexshreds: + - bugfix: Deconstructing closets yields the proper amount of metal + Kyep: + - tweak: Using the 'summon narsie' rune as cult, when you don't have the objective + to do so, is now punished by the cult's god. Just as using the 'call forth the + slaughter' rune, when you don't have the objective to do that, is already punished. + uraniummeltdown: + - rscadd: Engineering Cyborgs now have a digital copy of the station blueprints. +2017-02-03: + DrunkDwarf: + - tweak: Set the Mr Chang's vending machine to be refillable + - rscadd: Added a Supply Crate to the Vending section of the Cargo Request Console + for Chinese Refill Canisters +2017-02-05: + Fethas: + - tweak: Brings unholy water in line with its description. + Ported by Markolie, developed by KorPhaeron and others from /tg/. The Hierophant was developed by ChangelingRain.: + - rscadd: Megafauna and their rewards have been added to the code. These are not + on the map yet. + - rscadd: Fireball is now a targeted spell instead of a dumbfire spell. + - rscadd: Most spells, wands and staffs now have unique spell sounds. + - rscadd: Added a new nullrod type, the "spellblade". + - rscadd: Added bows, arrows and quivers. Currently only available for admins. + - rscadd: Added cockroaches. Currently only available for admins. + - rscadd: Added support for BYOND medals. Currently disabled. + - rscadd: Added a number of Lavaland objects (flora, basalt, food and stacks). Currently + only available for admins. + - rscadd: Earmuffs can now be produced in autolathes. + - tweak: 'Syndicate gun turrets are now subtypes of regular turrets: this makes + them controllable with Syndicate ID''s and improves their targeting.' + - tweak: Diona and Shadow People now receive a warning when they're not exposed/exposed + to light. + - tweak: The sniper AP rounds that Nuke Ops can purchase now have a chance of dismembering + limbs. + - bugfix: Shadow People can now switch their night vision properly. + - bugfix: Certain messages in chat weren't showing up in their proper (large) size, + such as the Nar'Sie spawned message. This has been resolved. + uraniummeltdown: + - bugfix: Supply ID skin is now selectable in the Agent ID and ID Computer diff --git a/html/changelogs/AutoChangeLog-pr-6265.yml b/html/changelogs/AutoChangeLog-pr-6265.yml deleted file mode 100644 index 09e3ced7cab..00000000000 --- a/html/changelogs/AutoChangeLog-pr-6265.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Alffd" -delete-after: True -changes: - - bugfix: "Adds missing hat and shoe sprites that were inadvertently deleted." diff --git a/icons/effects/96x96.dmi b/icons/effects/96x96.dmi index 4061ac44a96..01729aa70af 100644 Binary files a/icons/effects/96x96.dmi and b/icons/effects/96x96.dmi differ diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi index 1c971f8d3f4..28e2fd791ff 100644 Binary files a/icons/effects/blood.dmi and b/icons/effects/blood.dmi differ diff --git a/icons/effects/bubblegum.dmi b/icons/effects/bubblegum.dmi new file mode 100644 index 00000000000..a53dd7d563a Binary files /dev/null and b/icons/effects/bubblegum.dmi differ diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index 254587a15a2..93a175f3efc 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi index fcdd79b3741..9bf1a315131 100644 Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi index 11cfc6df017..db8191aed53 100644 Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi index 9cf930476d5..7ea4f58b941 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/mob/inhands/guns_lefthand.dmi b/icons/mob/inhands/guns_lefthand.dmi index 3088c274007..cc5330db825 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 ea22f2728b1..359045c25e0 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 c0f993cdcee..a9b5aa09fa3 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 31642e2c213..95a78da4df2 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/mob/lavaland/96x96megafauna.dmi b/icons/mob/lavaland/96x96megafauna.dmi new file mode 100644 index 00000000000..e13419532df Binary files /dev/null and b/icons/mob/lavaland/96x96megafauna.dmi differ diff --git a/icons/mob/lavaland/dragon.dmi b/icons/mob/lavaland/dragon.dmi new file mode 100644 index 00000000000..7e44b775de8 Binary files /dev/null and b/icons/mob/lavaland/dragon.dmi differ diff --git a/icons/mob/lavaland/hierophant.dmi b/icons/mob/lavaland/hierophant.dmi new file mode 100644 index 00000000000..d05bc3bd62d Binary files /dev/null and b/icons/mob/lavaland/hierophant.dmi differ diff --git a/icons/mob/lavaland/lavaland_monsters.dmi b/icons/mob/lavaland/lavaland_monsters.dmi new file mode 100644 index 00000000000..8cf32385df3 Binary files /dev/null and b/icons/mob/lavaland/lavaland_monsters.dmi differ diff --git a/icons/mob/lavaland/legion.dmi b/icons/mob/lavaland/legion.dmi new file mode 100644 index 00000000000..9cc19c4558f Binary files /dev/null and b/icons/mob/lavaland/legion.dmi differ diff --git a/icons/mob/lavaland/watcher.dmi b/icons/mob/lavaland/watcher.dmi new file mode 100644 index 00000000000..23960478b39 Binary files /dev/null and b/icons/mob/lavaland/watcher.dmi differ diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi index 003f24892bc..99359f5b079 100644 Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ diff --git a/icons/obj/ammo.dmi b/icons/obj/ammo.dmi index 10f3c91437e..1fd541fbc7d 100644 Binary files a/icons/obj/ammo.dmi and b/icons/obj/ammo.dmi differ diff --git a/icons/obj/bureaucracy.dmi b/icons/obj/bureaucracy.dmi index 500f0f29141..9e0eb73a992 100644 Binary files a/icons/obj/bureaucracy.dmi and b/icons/obj/bureaucracy.dmi differ diff --git a/icons/obj/guns/magic.dmi b/icons/obj/guns/magic.dmi index 2f3fc52957a..05c8aa7794f 100644 Binary files a/icons/obj/guns/magic.dmi and b/icons/obj/guns/magic.dmi differ diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi index d410ca031c0..84aa0490569 100644 Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ diff --git a/icons/obj/lavaland/artefacts.dmi b/icons/obj/lavaland/artefacts.dmi new file mode 100644 index 00000000000..45927256e35 Binary files /dev/null and b/icons/obj/lavaland/artefacts.dmi differ diff --git a/icons/obj/lavaland/ash_flora.dmi b/icons/obj/lavaland/ash_flora.dmi new file mode 100644 index 00000000000..d58541612d2 Binary files /dev/null and b/icons/obj/lavaland/ash_flora.dmi differ diff --git a/icons/obj/lavaland/dragonboat.dmi b/icons/obj/lavaland/dragonboat.dmi new file mode 100644 index 00000000000..13b6509fcd7 Binary files /dev/null and b/icons/obj/lavaland/dragonboat.dmi differ diff --git a/icons/obj/lavaland/spawners.dmi b/icons/obj/lavaland/spawners.dmi new file mode 100644 index 00000000000..42fdc988add Binary files /dev/null and b/icons/obj/lavaland/spawners.dmi differ diff --git a/icons/obj/library.dmi b/icons/obj/library.dmi index 2b1b1cab0c1..81c5c39ddf8 100644 Binary files a/icons/obj/library.dmi and b/icons/obj/library.dmi differ diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi index ef7ea2ddac7..d6cb7a676c4 100644 Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ diff --git a/icons/obj/narsie.dmi b/icons/obj/narsie.dmi index ac11a2730cb..55ab046eb42 100644 Binary files a/icons/obj/narsie.dmi and b/icons/obj/narsie.dmi differ diff --git a/icons/obj/projectiles.dmi b/icons/obj/projectiles.dmi index cd5c6120a27..316790998c5 100644 Binary files a/icons/obj/projectiles.dmi and b/icons/obj/projectiles.dmi differ diff --git a/icons/obj/rune.dmi b/icons/obj/rune.dmi index 901b7466d57..5df6a842ad5 100644 Binary files a/icons/obj/rune.dmi and b/icons/obj/rune.dmi differ diff --git a/icons/obj/storage.dmi b/icons/obj/storage.dmi index bd09b38dcd4..3990643d1ea 100644 Binary files a/icons/obj/storage.dmi and b/icons/obj/storage.dmi differ diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi index 88161a20b5c..a5638d1db1b 100644 Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi index f75b236465e..d49373de19e 100644 Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ diff --git a/icons/obj/wizard.dmi b/icons/obj/wizard.dmi index c51a531b2f8..8cf3b48100c 100644 Binary files a/icons/obj/wizard.dmi and b/icons/obj/wizard.dmi differ diff --git a/icons/turf/floors.dmi b/icons/turf/floors.dmi index cf2df6a17f5..1688122b563 100644 Binary files a/icons/turf/floors.dmi and b/icons/turf/floors.dmi differ diff --git a/icons/turf/floors/ash.dmi b/icons/turf/floors/ash.dmi new file mode 100644 index 00000000000..718cd120194 Binary files /dev/null and b/icons/turf/floors/ash.dmi differ diff --git a/icons/turf/floors/lava.dmi b/icons/turf/floors/lava.dmi index 1017a60b73a..29afb2cc869 100644 Binary files a/icons/turf/floors/lava.dmi and b/icons/turf/floors/lava.dmi differ diff --git a/icons/turf/walls/hierophant_wall.dmi b/icons/turf/walls/hierophant_wall.dmi new file mode 100644 index 00000000000..8482970eaf0 Binary files /dev/null and b/icons/turf/walls/hierophant_wall.dmi differ diff --git a/nano/templates/request_console.tmpl b/nano/templates/request_console.tmpl index 73a00c74471..aaa8726f50a 100644 --- a/nano/templates/request_console.tmpl +++ b/nano/templates/request_console.tmpl @@ -3,8 +3,8 @@ Title: Request Console Used In File(s): \code\game\machinery\requests_console.dm #define RCS_MAINMENU 0 // Main men -#define RCS_RQASSIST 1 // Request supplies -#define RCS_RQSUPPLY 2 // Request assistance +#define RCS_RQSUPPLY 1 // Request supplies +#define RCS_RQASSIST 2 // Request assistance #define RCS_SENDINFO 3 // Relay information #define RCS_SENTPASS 4 // Message sent successfully #define RCS_SENTFAIL 5 // Message sent unsuccessfully @@ -102,6 +102,33 @@ Used In File(s): \code\game\machinery\requests_console.dm {{:helper.link('Announce', 'signal', { 'sendAnnouncement' : 1 }, (data.announceAuth && data.message) ? null : 'disabled' )}} {{:helper.link('Back', 'arrow-left', { 'setScreen' : 0 })}}
+{{else data.screen == 9}} +

Print a Shipping Label.

+
+
Destination: {{:data.shipDest}}
+
Validated by: {{:data.msgVerified}}
+
{{:helper.link('Print Label', null, { 'printLabel' : 1 })}}
+
+ + {{for data.ship_dept}} + + + + + {{empty}} + + {{/for}} +
{{:value}} -
{{:helper.link('Select', null, { 'shipSelect' : value })}}
There are no available shipping destinations.

+
{{:helper.link('Back', 'arrow-left', { 'setScreen' : 0 })}}
+{{else data.screen == 10}} +
+ {{for data.shipping_log}} +
{{:value}}
+ {{empty}} +
No shipping labels have been printed.
+ {{/for}} +
+
{{:helper.link('Back', 'arrow-left', { 'setScreen' : 0 })}}
{{else}} {{if data.newmessagepriority == 1}}
There are new messages
@@ -114,6 +141,9 @@ Used In File(s): \code\game\machinery\requests_console.dm
{{:helper.link('Request Supplies', 'gear', { 'setScreen' : 2 })}}
{{:helper.link('Relay Anonymous Information', 'gear', { 'setScreen' : 3})}}

+
{{:helper.link('Print Shipping Label', 'gear', { 'setScreen' : 9})}}
+
{{:helper.link('View Shipping Logs', 'gear', { 'setScreen' : 10})}}
+
{{if data.announcementConsole}}
{{:helper.link('Send Station-wide Announcement', 'signal', { 'setScreen' : 8})}}

diff --git a/nano/templates/turret_control.tmpl b/nano/templates/turret_control.tmpl index 25e3c2a592c..50f733ea80f 100644 --- a/nano/templates/turret_control.tmpl +++ b/nano/templates/turret_control.tmpl @@ -23,7 +23,7 @@ {{/if}} - {{if data.is_lethal}} + {{if data.lethal_control}}
Lethal Mode: diff --git a/paradise.dme b/paradise.dme index e49d0dcbaeb..9776de13d69 100644 --- a/paradise.dme +++ b/paradise.dme @@ -304,6 +304,7 @@ #include "code\datums\spells\mind_transfer.dm" #include "code\datums\spells\projectile.dm" #include "code\datums\spells\rathens.dm" +#include "code\datums\spells\shapeshift.dm" #include "code\datums\spells\summonitem.dm" #include "code\datums\spells\touch_attacks.dm" #include "code\datums\spells\trigger.dm" @@ -542,7 +543,6 @@ #include "code\game\machinery\transformer.dm" #include "code\game\machinery\turntable.dm" #include "code\game\machinery\turret_control.dm" -#include "code\game\machinery\turrets.dm" #include "code\game\machinery\vending.dm" #include "code\game\machinery\washing_machine.dm" #include "code\game\machinery\wishgranter.dm" @@ -1450,6 +1450,9 @@ #include "code\modules\mining\laborcamp\laborminerals.dm" #include "code\modules\mining\laborcamp\laborshuttle.dm" #include "code\modules\mining\laborcamp\laborstacker.dm" +#include "code\modules\mining\lavaland\ash_flora.dm" +#include "code\modules\mining\lavaland\colossus_loot.dm" +#include "code\modules\mining\lavaland\necropolis_chests.dm" #include "code\modules\mob\abilities.dm" #include "code\modules\mob\death.dm" #include "code\modules\mob\emote.dm" @@ -1661,6 +1664,7 @@ #include "code\modules\mob\living\simple_animal\bot\secbot.dm" #include "code\modules\mob\living\simple_animal\friendly\butterfly.dm" #include "code\modules\mob\living\simple_animal\friendly\cat.dm" +#include "code\modules\mob\living\simple_animal\friendly\cockroach.dm" #include "code\modules\mob\living\simple_animal\friendly\corgi.dm" #include "code\modules\mob\living\simple_animal\friendly\corgi_powers.dm" #include "code\modules\mob\living\simple_animal\friendly\crab.dm" @@ -1700,6 +1704,14 @@ #include "code\modules\mob\living\simple_animal\hostile\tree.dm" #include "code\modules\mob\living\simple_animal\hostile\venus_human_trap.dm" #include "code\modules\mob\living\simple_animal\hostile\winter_mobs.dm" +#include "code\modules\mob\living\simple_animal\hostile\megafauna\bubblegum.dm" +#include "code\modules\mob\living\simple_animal\hostile\megafauna\colossus.dm" +#include "code\modules\mob\living\simple_animal\hostile\megafauna\dragon.dm" +#include "code\modules\mob\living\simple_animal\hostile\megafauna\hierophant.dm" +#include "code\modules\mob\living\simple_animal\hostile\megafauna\legion.dm" +#include "code\modules\mob\living\simple_animal\hostile\megafauna\megafauna.dm" +#include "code\modules\mob\living\simple_animal\hostile\mining\goldgrub.dm" +#include "code\modules\mob\living\simple_animal\hostile\mining\hivelord.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\clown.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\drone.dm" #include "code\modules\mob\living\simple_animal\hostile\retaliate\fish.dm" @@ -1853,6 +1865,7 @@ #include "code\modules\projectiles\guns\magic\staff.dm" #include "code\modules\projectiles\guns\magic\wand.dm" #include "code\modules\projectiles\guns\projectile\automatic.dm" +#include "code\modules\projectiles\guns\projectile\bow.dm" #include "code\modules\projectiles\guns\projectile\launchers.dm" #include "code\modules\projectiles\guns\projectile\pistol.dm" #include "code\modules\projectiles\guns\projectile\revolver.dm" @@ -2077,6 +2090,7 @@ #include "code\modules\surgery\organs\parasites.dm" #include "code\modules\surgery\organs\robolimbs.dm" #include "code\modules\surgery\organs\skeleton.dm" +#include "code\modules\surgery\organs\vocal_cords.dm" #include "code\modules\surgery\organs\wound.dm" #include "code\modules\surgery\organs\subtypes\diona.dm" #include "code\modules\surgery\organs\subtypes\drask.dm" diff --git a/sound/magic/Blind.ogg b/sound/magic/Blind.ogg new file mode 100644 index 00000000000..ded32a594e4 Binary files /dev/null and b/sound/magic/Blind.ogg differ diff --git a/sound/magic/CastSummon.ogg b/sound/magic/CastSummon.ogg new file mode 100644 index 00000000000..493fb239764 Binary files /dev/null and b/sound/magic/CastSummon.ogg differ diff --git a/sound/magic/Disable_Tech.ogg b/sound/magic/Disable_Tech.ogg new file mode 100644 index 00000000000..478dd042b53 Binary files /dev/null and b/sound/magic/Disable_Tech.ogg differ diff --git a/sound/magic/Ethereal_Enter.ogg b/sound/magic/Ethereal_Enter.ogg new file mode 100644 index 00000000000..a0c7222c167 Binary files /dev/null and b/sound/magic/Ethereal_Enter.ogg differ diff --git a/sound/magic/Ethereal_Exit.ogg b/sound/magic/Ethereal_Exit.ogg new file mode 100644 index 00000000000..bd60ca8c695 Binary files /dev/null and b/sound/magic/Ethereal_Exit.ogg differ diff --git a/sound/magic/Fireball.ogg b/sound/magic/Fireball.ogg new file mode 100644 index 00000000000..b9f6937f06b Binary files /dev/null and b/sound/magic/Fireball.ogg differ diff --git a/sound/magic/ForceWall.ogg b/sound/magic/ForceWall.ogg new file mode 100644 index 00000000000..4fbca3f42b7 Binary files /dev/null and b/sound/magic/ForceWall.ogg differ diff --git a/sound/magic/HorseHead_curse.ogg b/sound/magic/HorseHead_curse.ogg new file mode 100644 index 00000000000..598d096036b Binary files /dev/null and b/sound/magic/HorseHead_curse.ogg differ diff --git a/sound/magic/Knock.ogg b/sound/magic/Knock.ogg new file mode 100644 index 00000000000..fe2f54f97ac Binary files /dev/null and b/sound/magic/Knock.ogg differ diff --git a/sound/magic/MAGIC_MISSILE.ogg b/sound/magic/MAGIC_MISSILE.ogg new file mode 100644 index 00000000000..9d0799d82e9 Binary files /dev/null and b/sound/magic/MAGIC_MISSILE.ogg differ diff --git a/sound/magic/MM_Hit.ogg b/sound/magic/MM_Hit.ogg new file mode 100644 index 00000000000..4f09ef46d51 Binary files /dev/null and b/sound/magic/MM_Hit.ogg differ diff --git a/sound/magic/MindSwap.ogg b/sound/magic/MindSwap.ogg new file mode 100644 index 00000000000..2f4848becb0 Binary files /dev/null and b/sound/magic/MindSwap.ogg differ diff --git a/sound/magic/Repulse.ogg b/sound/magic/Repulse.ogg new file mode 100644 index 00000000000..ed010370754 Binary files /dev/null and b/sound/magic/Repulse.ogg differ diff --git a/sound/magic/Smoke.ogg b/sound/magic/Smoke.ogg new file mode 100644 index 00000000000..ca50a349676 Binary files /dev/null and b/sound/magic/Smoke.ogg differ diff --git a/sound/magic/Staff_Change.ogg b/sound/magic/Staff_Change.ogg new file mode 100644 index 00000000000..9e6eb72ae06 Binary files /dev/null and b/sound/magic/Staff_Change.ogg differ diff --git a/sound/magic/Staff_Door.ogg b/sound/magic/Staff_Door.ogg new file mode 100644 index 00000000000..220f8124825 Binary files /dev/null and b/sound/magic/Staff_Door.ogg differ diff --git a/sound/magic/Staff_Healing.ogg b/sound/magic/Staff_Healing.ogg new file mode 100644 index 00000000000..af2a56049c8 Binary files /dev/null and b/sound/magic/Staff_Healing.ogg differ diff --git a/sound/magic/Staff_animation.ogg b/sound/magic/Staff_animation.ogg new file mode 100644 index 00000000000..8abd7faa60f Binary files /dev/null and b/sound/magic/Staff_animation.ogg differ diff --git a/sound/magic/SummonItems_generic.ogg b/sound/magic/SummonItems_generic.ogg new file mode 100644 index 00000000000..80cc412a4a8 Binary files /dev/null and b/sound/magic/SummonItems_generic.ogg differ diff --git a/sound/magic/Summon_Karp.ogg b/sound/magic/Summon_Karp.ogg new file mode 100644 index 00000000000..d3890776f6d Binary files /dev/null and b/sound/magic/Summon_Karp.ogg differ diff --git a/sound/magic/Summon_Magic.ogg b/sound/magic/Summon_Magic.ogg new file mode 100644 index 00000000000..86b33032826 Binary files /dev/null and b/sound/magic/Summon_Magic.ogg differ diff --git a/sound/magic/Summon_guns.ogg b/sound/magic/Summon_guns.ogg new file mode 100644 index 00000000000..b9b5394a4ed Binary files /dev/null and b/sound/magic/Summon_guns.ogg differ diff --git a/sound/magic/Tail_swing.ogg b/sound/magic/Tail_swing.ogg new file mode 100644 index 00000000000..d39462fae30 Binary files /dev/null and b/sound/magic/Tail_swing.ogg differ diff --git a/sound/magic/Teleport_app.ogg b/sound/magic/Teleport_app.ogg new file mode 100644 index 00000000000..dd9222ae0c3 Binary files /dev/null and b/sound/magic/Teleport_app.ogg differ diff --git a/sound/magic/Teleport_diss.ogg b/sound/magic/Teleport_diss.ogg new file mode 100644 index 00000000000..edc0c55ed00 Binary files /dev/null and b/sound/magic/Teleport_diss.ogg differ diff --git a/sound/magic/WandODeath.ogg b/sound/magic/WandODeath.ogg new file mode 100644 index 00000000000..4412609657c Binary files /dev/null and b/sound/magic/WandODeath.ogg differ diff --git a/sound/magic/Wand_Teleport.ogg b/sound/magic/Wand_Teleport.ogg new file mode 100644 index 00000000000..8a300d7763f Binary files /dev/null and b/sound/magic/Wand_Teleport.ogg differ diff --git a/sound/magic/blink.ogg b/sound/magic/blink.ogg new file mode 100644 index 00000000000..58b7cc8562c Binary files /dev/null and b/sound/magic/blink.ogg differ diff --git a/sound/magic/invoke_general.ogg b/sound/magic/invoke_general.ogg new file mode 100644 index 00000000000..6f0c0dd097a Binary files /dev/null and b/sound/magic/invoke_general.ogg differ diff --git a/sound/magic/narsie_attack.ogg b/sound/magic/narsie_attack.ogg new file mode 100644 index 00000000000..89fac778058 Binary files /dev/null and b/sound/magic/narsie_attack.ogg differ diff --git a/sound/magic/ratvar_attack.ogg b/sound/magic/ratvar_attack.ogg new file mode 100644 index 00000000000..1c17fe10510 Binary files /dev/null and b/sound/magic/ratvar_attack.ogg differ diff --git a/sound/misc/e1m1.ogg b/sound/misc/e1m1.ogg new file mode 100644 index 00000000000..e611e154ae6 Binary files /dev/null and b/sound/misc/e1m1.ogg differ diff --git a/sound/weapons/ZapBang.ogg b/sound/weapons/ZapBang.ogg new file mode 100644 index 00000000000..4e14e30a11b Binary files /dev/null and b/sound/weapons/ZapBang.ogg differ diff --git a/sound/weapons/bulletflyby.ogg b/sound/weapons/bulletflyby.ogg new file mode 100644 index 00000000000..ce9405a5776 Binary files /dev/null and b/sound/weapons/bulletflyby.ogg differ diff --git a/sound/weapons/bulletflyby2.ogg b/sound/weapons/bulletflyby2.ogg new file mode 100644 index 00000000000..63956534ba3 Binary files /dev/null and b/sound/weapons/bulletflyby2.ogg differ diff --git a/sound/weapons/bulletflyby3.ogg b/sound/weapons/bulletflyby3.ogg new file mode 100644 index 00000000000..e8afd28b06d Binary files /dev/null and b/sound/weapons/bulletflyby3.ogg differ diff --git a/sound/weapons/draw_bow.ogg b/sound/weapons/draw_bow.ogg new file mode 100644 index 00000000000..01f1393bc84 Binary files /dev/null and b/sound/weapons/draw_bow.ogg differ diff --git a/sound/weapons/rapierhit.ogg b/sound/weapons/rapierhit.ogg new file mode 100644 index 00000000000..6e214d2821f Binary files /dev/null and b/sound/weapons/rapierhit.ogg differ