diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 27cc7d4835a..368181ea2fd 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -17,7 +17,7 @@ If you want to contribute the first thing you'll need to do is [set up Git](http
We have a [list of guides on the wiki](http://www.tgstation13.org/wiki/index.php/Guides#Development_and_Contribution_Guides) which will help you get started contributing to /tg/station with git and Dream Maker. For beginners, it is recommended you work on small projects, at first. If you need help learning to program in BYOND check out this [repository of resources](http://www.byond.com/developer/articles/resources).
-There is an open list of approachable issues for [your inspiration here](https://github.com/tgstation/-tg-station/issues?q=is%3Aopen+is%3Aissue+label%3A%22Easy+Fix%22).
+There is an open list of approachable issues for [your inspiration here](https://github.com/tgstation/-tg-station/issues?q=is%3Aopen+is%3Aissue+label%3A%22Easy+Task%22).
You can of course, as always, ask for help at [#coderbus](irc://irc.rizon.net/coderbus) on irc.rizon.net. We are just here to have fun and help so do not expect professional support please.
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_fountain_hall.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_fountain_hall.dmm
index b367a068f15..918b0e894b7 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_fountain_hall.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_fountain_hall.dmm
@@ -8,19 +8,19 @@
},
/area/ruin/unpowered)
"c" = (
-/obj/structure/divine/healingfountain/anyone,
+/obj/structure/healingfountain,
/turf/open/floor/engine/cult{
baseturf = /turf/open/floor/plating/lava/smooth
},
/area/ruin/unpowered)
"d" = (
-/obj/structure/divine/conduit,
+/obj/structure/fluff/divine/conduit,
/turf/open/floor/engine/cult{
baseturf = /turf/open/floor/plating/lava/smooth
},
/area/ruin/unpowered)
"e" = (
-/obj/structure/divine/sacrificealtar,
+/obj/structure/sacrificealtar,
/turf/open/floor/engine/cult{
baseturf = /turf/open/floor/plating/lava/smooth
},
diff --git a/_maps/RandomZLevels/Academy.dmm b/_maps/RandomZLevels/Academy.dmm
index 4577417fc7b..260a66f8642 100644
--- a/_maps/RandomZLevels/Academy.dmm
+++ b/_maps/RandomZLevels/Academy.dmm
@@ -852,7 +852,7 @@
/turf/closed/wall,
/area/awaymission/academy/headmaster)
"cI" = (
-/obj/structure/divine/trap/damage,
+/obj/structure/trap/damage,
/turf/open/floor/carpet,
/area/awaymission/academy/headmaster)
"cJ" = (
@@ -3881,11 +3881,11 @@
d2 = 4;
icon_state = "2-4"
},
-/obj/structure/divine/trap/chill,
+/obj/structure/trap/chill,
/turf/open/floor/plating,
/area/awaymission/academy/academyaft)
"kN" = (
-/obj/structure/divine/trap/fire,
+/obj/structure/trap/fire,
/turf/open/floor/engine,
/area/awaymission/academy/academyaft)
"kO" = (
@@ -3946,7 +3946,7 @@
/turf/open/floor/engine/cult,
/area/awaymission/academy/academycellar)
"la" = (
-/obj/structure/divine/trap/damage,
+/obj/structure/trap/damage,
/turf/open/floor/engine/cult,
/area/awaymission/academy/academycellar)
"lb" = (
diff --git a/_maps/RandomZLevels/caves.dmm b/_maps/RandomZLevels/caves.dmm
index 839dee842a4..dea105695ea 100644
--- a/_maps/RandomZLevels/caves.dmm
+++ b/_maps/RandomZLevels/caves.dmm
@@ -167,7 +167,7 @@
name = "\improper BMP Asteroid Level 4"
})
"av" = (
-/obj/structure/divine/trap/stun{
+/obj/structure/trap/stun{
desc = "A rune inscribed in the floor, the air feeling electrified around it.";
name = "shock rune"
},
@@ -474,7 +474,7 @@
name = "\improper BMP Asteroid Level 3"
})
"aY" = (
-/obj/structure/divine/trap/fire{
+/obj/structure/trap/fire{
desc = "An old rune inscribed on the floor, giving off an intense amount of heat.";
name = "flame rune"
},
@@ -485,7 +485,7 @@
name = "\improper BMP Asteroid Level 4"
})
"aZ" = (
-/obj/structure/divine/trap/fire{
+/obj/structure/trap/fire{
desc = "An old rune inscribed on the floor, giving off an intense amount of heat.";
name = "flame rune"
},
@@ -672,7 +672,7 @@
name = "\improper BMP Asteroid Level 4"
})
"bs" = (
-/obj/structure/divine/trap/stun{
+/obj/structure/trap/stun{
desc = "A rune inscribed in the floor, the air feeling electrified around it.";
name = "shock rune"
},
diff --git a/_maps/RandomZLevels/moonoutpost19.dmm b/_maps/RandomZLevels/moonoutpost19.dmm
index 16ba61919d5..e688e19691d 100644
--- a/_maps/RandomZLevels/moonoutpost19.dmm
+++ b/_maps/RandomZLevels/moonoutpost19.dmm
@@ -5810,7 +5810,7 @@
pixel_x = -5;
pixel_y = -2
},
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/l_arm/robot,
/turf/open/floor/plasteel/white{
heat_capacity = 1e+006
},
diff --git a/_maps/RandomZLevels/research.dmm b/_maps/RandomZLevels/research.dmm
index d66f49ddb40..3f56227c366 100644
--- a/_maps/RandomZLevels/research.dmm
+++ b/_maps/RandomZLevels/research.dmm
@@ -4907,7 +4907,7 @@
/turf/open/floor/mineral/plasma,
/area/space)
"nd" = (
-/obj/structure/divine/healingfountain/anyone,
+/obj/structure/healingfountain,
/turf/open/floor/mineral/plasma,
/area/space)
"ne" = (
diff --git a/_maps/map_files/BirdStation/BirdStation.dmm b/_maps/map_files/BirdStation/BirdStation.dmm
index 35ae80339e6..8fa869b173d 100644
--- a/_maps/map_files/BirdStation/BirdStation.dmm
+++ b/_maps/map_files/BirdStation/BirdStation.dmm
@@ -446,8 +446,8 @@
dir = 1
},
/obj/structure/table,
-/obj/item/robot_parts/r_arm,
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/r_arm/robot,
+/obj/item/bodypart/l_arm/robot,
/turf/open/floor/mineral/titanium,
/area/shuttle/syndicate)
"abh" = (
diff --git a/_maps/map_files/DreamStation/dreamstation04.dmm b/_maps/map_files/DreamStation/dreamstation04.dmm
index d3573c3e30b..18420d099e9 100644
--- a/_maps/map_files/DreamStation/dreamstation04.dmm
+++ b/_maps/map_files/DreamStation/dreamstation04.dmm
@@ -1344,8 +1344,8 @@
/area/turret_protected/aisat_interior)
"acv" = (
/obj/structure/table,
-/obj/item/robot_parts/robot_suit,
-/obj/item/robot_parts/head,
+/obj/item/robot_suit,
+/obj/item/bodypart/head/robot,
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/turf/open/floor/bluegrid,
/area/turret_protected/aisat_interior)
@@ -1418,9 +1418,9 @@
/area/turret_protected/aisat_interior)
"acF" = (
/obj/structure/table,
-/obj/item/robot_parts/l_arm,
-/obj/item/robot_parts/chest,
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/l_arm/robot,
+/obj/item/bodypart/chest/robot,
+/obj/item/bodypart/l_arm/robot,
/obj/structure/cable/blue{
tag = "icon-2-8";
icon_state = "2-8"
@@ -1443,7 +1443,7 @@
/area/turret_protected/aisat_interior)
"acI" = (
/obj/structure/table,
-/obj/item/robot_parts/r_arm,
+/obj/item/bodypart/r_arm/robot,
/obj/structure/cable/blue{
tag = "icon-2-4";
icon_state = "2-4"
@@ -1511,7 +1511,7 @@
},
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
/obj/item/device/assembly/flash/handheld,
-/obj/item/robot_parts/r_leg,
+/obj/item/bodypart/r_leg/robot,
/turf/open/floor/plasteel/black,
/area/turret_protected/aisat_interior)
"acP" = (
@@ -1575,7 +1575,7 @@
/area/turret_protected/aisat_interior)
"acU" = (
/obj/structure/table,
-/obj/item/robot_parts/l_leg,
+/obj/item/bodypart/l_leg/robot,
/obj/structure/cable/blue{
tag = "icon-4-8";
icon_state = "4-8"
@@ -3189,8 +3189,8 @@
dir = 1
},
/obj/structure/table,
-/obj/item/robot_parts/r_arm,
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/r_arm/robot,
+/obj/item/bodypart/l_arm/robot,
/turf/open/floor/mineral/titanium,
/area/shuttle/syndicate)
"agA" = (
@@ -16264,7 +16264,7 @@
/area/maintenance/fore)
"aIo" = (
/obj/structure/rack,
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/l_arm/robot,
/obj/item/stack/sheet/metal{
amount = 2
},
@@ -17026,7 +17026,7 @@
"aJN" = (
/obj/structure/table,
/obj/item/stack/cable_coil/green,
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/l_arm/robot,
/obj/item/weapon/storage/fancy/cigarettes/cigpack_robustgold,
/obj/item/weapon/reagent_containers/food/drinks/mug/coco,
/turf/open/floor/plating,
@@ -18024,7 +18024,7 @@
/area/maintenance/port)
"aMb" = (
/obj/effect/spawner/lootdrop/maintenance,
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/l_arm/robot,
/turf/open/floor/plating,
/area/maintenance/port)
"aMc" = (
@@ -63145,7 +63145,7 @@
/turf/open/floor/plating,
/area/maintenance/apmaint)
"cvz" = (
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/l_arm/robot,
/obj/structure/closet,
/obj/item/weapon/reagent_containers/glass/beaker/large,
/obj/effect/spawner/lootdrop/maintenance,
diff --git a/_maps/map_files/EfficiencyStation/EfficiencyStation.dmm b/_maps/map_files/EfficiencyStation/EfficiencyStation.dmm
index 45e4e748284..f7e7e86f172 100644
--- a/_maps/map_files/EfficiencyStation/EfficiencyStation.dmm
+++ b/_maps/map_files/EfficiencyStation/EfficiencyStation.dmm
@@ -3505,8 +3505,8 @@
dir = 1
},
/obj/structure/table,
-/obj/item/robot_parts/r_arm,
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/r_arm/robot,
+/obj/item/bodypart/l_arm/robot,
/turf/open/floor/mineral/titanium,
/area/shuttle/syndicate)
"agJ" = (
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 1713fbaec40..7f6836d2ebf 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -3923,7 +3923,7 @@
pixel_y = 0
},
/obj/structure/rack,
-/obj/item/weapon/storage/fancy,
+/obj/item/weapon/storage/fancy/donut_box,
/turf/open/floor/plasteel/vault{
dir = 1
},
@@ -47246,7 +47246,6 @@
/turf/open/floor/wood,
/area/library)
"bDx" = (
-/obj/machinery/portable_atmospherics/canister/bz,
/turf/open/floor/plasteel/bot,
/area/atmos)
"bDy" = (
@@ -49975,6 +49974,7 @@
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/portable_atmospherics/canister/freon,
/turf/open/floor/plasteel,
/area/atmos)
"bHQ" = (
@@ -49985,6 +49985,7 @@
dir = 2;
on = 1
},
+/obj/machinery/portable_atmospherics/canister/freon,
/turf/open/floor/plasteel/black/corner{
dir = 2
},
@@ -55774,12 +55775,12 @@
d2 = 2;
icon_state = "1-2"
},
-/obj/item/robot_parts/chest{
+/obj/item/bodypart/chest/robot{
name = "cyborg torso";
pixel_x = -2;
pixel_y = 2
},
-/obj/item/robot_parts/head{
+/obj/item/bodypart/head/robot{
name = "cyborg head";
pixel_x = 3;
pixel_y = 2
@@ -62702,6 +62703,8 @@
network = list("SS13","Medbay")
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
+/obj/machinery/limbgrower,
+/obj/item/weapon/reagent_containers/glass/beaker/synthflesh,
/turf/open/floor/plasteel/whiteblue/side{
dir = 4
},
@@ -73092,7 +73095,6 @@
/obj/structure/sign/nosmoking_2{
pixel_y = 32
},
-/obj/machinery/portable_atmospherics/canister/bz,
/turf/open/floor/plasteel/warning{
dir = 5
},
@@ -73555,6 +73557,7 @@
dir = 2;
icon_state = "pipe-c"
},
+/obj/machinery/portable_atmospherics/canister/freon,
/turf/open/floor/plasteel/warning{
dir = 4
},
@@ -74082,6 +74085,7 @@
/turf/open/floor/plasteel/bot,
/area/toxins/storage)
"cxf" = (
+/obj/machinery/portable_atmospherics/canister/freon,
/turf/open/floor/plasteel/warning{
dir = 8
},
@@ -74089,6 +74093,7 @@
"cxg" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/disposalpipe/segment,
+/obj/machinery/portable_atmospherics/canister/freon,
/turf/open/floor/plasteel/warning{
dir = 4
},
@@ -90220,8 +90225,8 @@
dir = 1
},
/obj/structure/table,
-/obj/item/robot_parts/r_arm,
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/r_arm/robot,
+/obj/item/bodypart/l_arm/robot,
/turf/open/floor/mineral/titanium,
/area/shuttle/syndicate)
"cYu" = (
diff --git a/_maps/map_files/MiniStation/MiniStation.dmm b/_maps/map_files/MiniStation/MiniStation.dmm
index 0db7e381bd7..4ce944db059 100644
--- a/_maps/map_files/MiniStation/MiniStation.dmm
+++ b/_maps/map_files/MiniStation/MiniStation.dmm
@@ -14145,8 +14145,8 @@
dir = 1
},
/obj/structure/table,
-/obj/item/robot_parts/r_arm,
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/r_arm/robot,
+/obj/item/bodypart/l_arm/robot,
/turf/open/floor/mineral/titanium,
/area/shuttle/syndicate)
"Gv" = (
diff --git a/_maps/map_files/MiniStation/cargopacks.dm b/_maps/map_files/MiniStation/cargopacks.dm
index a6a1db75df3..097711e7f43 100644
--- a/_maps/map_files/MiniStation/cargopacks.dm
+++ b/_maps/map_files/MiniStation/cargopacks.dm
@@ -1,31 +1,3 @@
-/datum/supply_pack/engineering/oxygen
- name = "Oxygen Canister"
- cost = 15
- contains = list(/obj/machinery/portable_atmospherics/canister/oxygen)
- crate_name = "oxygen canister crate"
- crate_type = /obj/structure/closet/crate/large
-
-/datum/supply_pack/engineering/toxins
- name = "Plasma Canister"
- cost = 30
- contains = list(/obj/machinery/portable_atmospherics/canister/toxins)
- crate_name = "plasma canister crate"
- crate_type = /obj/structure/closet/crate/large
-
-/datum/supply_pack/engineering/nitrogen
- name = "Nitrogen Canister"
- cost = 20
- contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen)
- crate_name = "nitrogen canister crate"
- crate_type = /obj/structure/closet/crate/large
-
-/datum/supply_pack/engineering/carbon_dio
- name = "Carbon Dioxide Canister"
- cost = 35
- contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide)
- crate_name = "carbon dioxide canister crate"
- crate_type = /obj/structure/closet/crate/large
-
/obj/machinery/hydroponics/constructable/unattached
anchored = 0
diff --git a/_maps/map_files/TgStation/tgstation.2.1.3.dmm b/_maps/map_files/TgStation/tgstation.2.1.3.dmm
index d6a019fa8e2..ec77a16dc25 100644
--- a/_maps/map_files/TgStation/tgstation.2.1.3.dmm
+++ b/_maps/map_files/TgStation/tgstation.2.1.3.dmm
@@ -7384,6 +7384,7 @@
/turf/open/floor/plating,
/area/shuttle/pod_1)
"apI" = (
+/obj/machinery/portable_atmospherics/canister/freon,
/turf/open/floor/plasteel/floorgrime,
/area/toxins/storage)
"apJ" = (
@@ -36590,6 +36591,7 @@
scrub_N2O = 0;
scrub_Toxins = 0
},
+/obj/machinery/portable_atmospherics/canister/freon,
/turf/open/floor/plasteel/floorgrime,
/area/toxins/storage)
"bCY" = (
@@ -37039,6 +37041,7 @@
icon_state = "4-8";
pixel_y = 0
},
+/obj/machinery/portable_atmospherics/canister/freon,
/mob/living/simple_animal/mouse,
/turf/open/floor/plasteel/floorgrime,
/area/toxins/storage)
@@ -37088,6 +37091,7 @@
icon_state = "4-8";
pixel_y = 0
},
+/obj/machinery/portable_atmospherics/canister/freon,
/turf/open/floor/plasteel/floorgrime,
/area/toxins/storage)
"bEd" = (
@@ -37871,7 +37875,6 @@
/obj/machinery/light/small{
dir = 8
},
-/obj/machinery/portable_atmospherics/canister/bz,
/turf/open/floor/plasteel/floorgrime,
/area/toxins/storage)
"bFJ" = (
@@ -38435,13 +38438,8 @@
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"bGS" = (
-/obj/structure/table,
-/obj/item/weapon/reagent_containers/glass/bottle/epinephrine{
- pixel_x = 7;
- pixel_y = -3
- },
-/obj/item/weapon/reagent_containers/glass/bottle/morphine,
-/obj/item/weapon/reagent_containers/syringe,
+/obj/machinery/limbgrower,
+/obj/item/weapon/reagent_containers/glass/beaker/synthflesh,
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"bGT" = (
@@ -38550,7 +38548,6 @@
dir = 4;
network = list("SS13","RD")
},
-/obj/machinery/portable_atmospherics/canister/bz,
/turf/open/floor/plasteel/floorgrime,
/area/toxins/storage)
"bHf" = (
@@ -39185,6 +39182,18 @@
pixel_y = 2
},
/obj/item/weapon/storage/box/syringes,
+/obj/item/weapon/reagent_containers/glass/bottle/epinephrine{
+ pixel_x = 7;
+ pixel_y = -3
+ },
+/obj/item/weapon/reagent_containers/glass/bottle/morphine{
+ pixel_x = 8;
+ pixel_y = -3
+ },
+/obj/item/weapon/reagent_containers/syringe{
+ pixel_x = 6;
+ pixel_y = -3
+ },
/turf/open/floor/plasteel/white,
/area/medical/sleeper)
"bIn" = (
@@ -41814,13 +41823,13 @@
name = "Station Intercom (General)";
pixel_x = -30
},
-/obj/machinery/portable_atmospherics/canister/bz,
/turf/open/floor/plasteel,
/area/atmos)
"bNQ" = (
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/machinery/portable_atmospherics/canister/freon,
/turf/open/floor/plasteel,
/area/atmos)
"bNR" = (
@@ -41853,6 +41862,7 @@
scrub_N2O = 0;
scrub_Toxins = 0
},
+/obj/machinery/portable_atmospherics/canister/freon,
/turf/open/floor/plasteel,
/area/atmos)
"bNT" = (
@@ -54091,8 +54101,8 @@
dir = 1
},
/obj/structure/table,
-/obj/item/robot_parts/r_arm,
-/obj/item/robot_parts/l_arm,
+/obj/item/bodypart/r_arm/robot,
+/obj/item/bodypart/l_arm/robot,
/turf/open/floor/mineral/titanium,
/area/shuttle/syndicate)
"coo" = (
@@ -90902,7 +90912,7 @@ bJs
bKy
bLM
bLM
-alX
+bNQ
bOV
bQk
bRt
@@ -106060,7 +106070,7 @@ bDc
bEo
bDf
bEb
-bIC
+apI
bGY
bJN
bMp
diff --git a/_maps/map_files/generic/z2.dmm b/_maps/map_files/generic/z2.dmm
index b9586bc48b5..723bcc61f73 100644
--- a/_maps/map_files/generic/z2.dmm
+++ b/_maps/map_files/generic/z2.dmm
@@ -5307,7 +5307,7 @@
/turf/open/floor/plating,
/area/ctf)
"qD" = (
-/obj/structure/divine/trap/ctf/blue,
+/obj/structure/trap/ctf/blue,
/turf/open/floor/plasteel/blue,
/area/ctf)
"qE" = (
@@ -5335,7 +5335,7 @@
/turf/open/floor/plasteel/darkred,
/area/ctf)
"qI" = (
-/obj/structure/divine/trap/ctf/red,
+/obj/structure/trap/ctf/red,
/turf/open/floor/plasteel/darkred,
/area/ctf)
"qJ" = (
@@ -5379,7 +5379,7 @@
/turf/open/floor/plasteel/circuit/gcircuit/off,
/area/ctf)
"qQ" = (
-/obj/structure/divine/trap/ctf/red,
+/obj/structure/trap/ctf/red,
/turf/open/floor/plasteel/red,
/area/ctf)
"qR" = (
diff --git a/code/__DEFINES/clockcult.dm b/code/__DEFINES/clockcult.dm
index 3bc8ff23a82..8102b0c48e6 100644
--- a/code/__DEFINES/clockcult.dm
+++ b/code/__DEFINES/clockcult.dm
@@ -38,8 +38,12 @@ var/global/clockwork_gateway_activated = FALSE //if a gateway to the celestial d
#define REPLICANT_WALL_MINUS_FLOOR REPLICANT_ALLOY_UNIT*0.4 //amount of alloy in a clockwork wall, determines the cost of clockwork wall production
+#define REPLICANT_GEAR REPLICANT_ALLOY_UNIT*0.3 //amount of alloy in a wall gear, minus the brass from the wall
+
#define REPLICANT_WALL_TOTAL REPLICANT_WALL_MINUS_FLOOR+REPLICANT_FLOOR //how much alloy is in a clockwork wall and the floor under it
+#define RATVAR_ALLOY_CHECK "ratvar?" //when passed into can_use_alloy(), converts it into a check for if ratvar has woken/the proselytizer is debug
+
//Ark defines
#define GATEWAY_SUMMON_RATE 2 //the time amount the Gateway to the Celestial Derelict gets each process tick; defaults to 2 per tick
diff --git a/code/__DEFINES/genetics.dm b/code/__DEFINES/genetics.dm
index a9c91450c62..de99eca0917 100644
--- a/code/__DEFINES/genetics.dm
+++ b/code/__DEFINES/genetics.dm
@@ -84,6 +84,14 @@
#define ORGAN_ORGANIC 1
#define ORGAN_ROBOTIC 2
+#define BODYPART_ORGANIC 1
+#define BODYPART_ROBOTIC 2
+
+#define MONKEY_BODYPART "monkey"
+#define ALIEN_BODYPART "alien"
+#define LARVA_BODYPART "larva"
+#define DEVIL_BODYPART "devil"
+
//Nutrition levels for humans. No idea where else to put it
#define NUTRITION_LEVEL_FAT 600
#define NUTRITION_LEVEL_FULL 550
diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm
index 57e6573bc73..6bbc2fe1b59 100644
--- a/code/__DEFINES/hud.dm
+++ b/code/__DEFINES/hud.dm
@@ -30,16 +30,14 @@
#define ANTAG_HUD_OPS 8
#define ANTAG_HUD_WIZ 9
#define ANTAG_HUD_SHADOW 10
-#define ANTAG_HUD_HOG_BLUE 11
-#define ANTAG_HUD_HOG_RED 12
-#define ANTAG_HUD_TRAITOR 13
-#define ANTAG_HUD_NINJA 14
-#define ANTAG_HUD_CHANGELING 15
-#define ANTAG_HUD_ABDUCTOR 16
-#define ANTAG_HUD_DEVIL 17
-#define ANTAG_HUD_SINTOUCHED 18
-#define ANTAG_HUD_SOULLESS 19
-#define ANTAG_HUD_CLOCKWORK 20
+#define ANTAG_HUD_TRAITOR 11
+#define ANTAG_HUD_NINJA 12
+#define ANTAG_HUD_CHANGELING 13
+#define ANTAG_HUD_ABDUCTOR 14
+#define ANTAG_HUD_DEVIL 15
+#define ANTAG_HUD_SINTOUCHED 16
+#define ANTAG_HUD_SOULLESS 17
+#define ANTAG_HUD_CLOCKWORK 18
// Notification action types
#define NOTIFY_JUMP "jump"
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 1e66100e551..ad3d3d6027b 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -4,6 +4,8 @@
#define in_range(source, user) (get_dist(source, user) <= 1)
+#define is_cleanable(A) (istype(A, /obj/effect/decal/cleanable) || istype(A, /obj/effect/rune)) //if something is cleanable
+
// MOB HELPERS
#define ishuman(A) (istype(A, /mob/living/carbon/human))
@@ -22,7 +24,7 @@
#define ismonkey(A) (istype(A, /mob/living/carbon/monkey))
-#define isbrain(A) (istype(A, /mob/living/carbon/brain))
+#define isbrain(A) (istype(A, /mob/living/brain))
#define isalien(A) (istype(A, /mob/living/carbon/alien))
diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index 27a5a3f1034..0d0b54b8ee0 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -50,6 +50,7 @@
#define LIGHTING_LAYER 15
//HUD layer defines
+#define COLORED_VISION_LAYER 17.8
#define FLASH_LAYER 17.9
#define FULLSCREEN_LAYER 18
#define UI_DAMAGE_LAYER 18.1
diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm
index 27280edfd79..0ff00ff276f 100644
--- a/code/__DEFINES/machines.dm
+++ b/code/__DEFINES/machines.dm
@@ -22,4 +22,14 @@
#define CRAFTLATHE 8 //Uses fuck if I know. For use eventually.
#define MECHFAB 16 //Remember, objects utilising this flag should have construction_time and construction_cost vars.
#define BIOGENERATOR 32 //Uses biomass
-//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
\ No newline at end of file
+#define LIMBGROWER 64 //Uses synthetic flesh
+//Note: More then one of these can be added to a design but imprinter and lathe designs are incompatable.
+
+#define MC_CPU "CPU"
+#define MC_HDD "HDD"
+#define MC_SDD "SDD"
+#define MC_CARD "CARD"
+#define MC_NET "NET"
+#define MC_PRINT "PRINT"
+#define MC_CELL "CELL"
+#define MC_CHARGE "CHARGE"
\ No newline at end of file
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index 906a3b3498d..1ec6a0ed426 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -482,7 +482,6 @@ var/global/list/ghost_others_options = list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define STORAGE_VIEW_DEPTH 2
-
// Medal names
#define BOSS_KILL_MEDAL "Killer"
@@ -528,3 +527,8 @@ var/global/list/ghost_others_options = list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
#define MIN_NTNET_LOGS 10
//TODO Move to a pref
#define STATION_GOAL_BUDGET 1
+
+//Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1.
+#define LUMA_R 0.213
+#define LUMA_G 0.715
+#define LUMA_B 0.072
\ No newline at end of file
diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm
index aff4dea38c8..51502947f6b 100644
--- a/code/__DEFINES/role_preferences.dm
+++ b/code/__DEFINES/role_preferences.dm
@@ -21,8 +21,6 @@
#define ROLE_GANG "gangster"
#define ROLE_ABDUCTOR "abductor"
#define ROLE_REVENANT "revenant"
-#define ROLE_HOG_GOD "hand of god: god"
-#define ROLE_HOG_CULTIST "hand of god: cultist"
#define ROLE_DEVIL "devil"
#define ROLE_SERVANT_OF_RATVAR "servant of Ratvar"
@@ -45,8 +43,6 @@ var/global/list/special_roles = list(
ROLE_GANG = /datum/game_mode/gang,
ROLE_REVENANT,
ROLE_ABDUCTOR = /datum/game_mode/abduction,
- ROLE_HOG_GOD = /datum/game_mode/hand_of_god,
- ROLE_HOG_CULTIST = /datum/game_mode/hand_of_god,
ROLE_DEVIL = /datum/game_mode/devil,
ROLE_SERVANT_OF_RATVAR = /datum/game_mode/clockwork_cult,
)
diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm
index 226bfee6310..070837bee97 100644
--- a/code/__DEFINES/say.dm
+++ b/code/__DEFINES/say.dm
@@ -24,6 +24,7 @@
#define SPAN_PAPYRUS "papyrus"
#define SPAN_REALLYBIG "reallybig"
#define SPAN_COMMAND "command_headset"
+#define SPAN_CLOWN "clown"
//bitflag #defines for return value of the radio() proc.
#define ITALICS 1
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index 54cdc9bb8ca..1cad2a5e5e4 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -41,4 +41,7 @@ var/cmp_field = "name"
return a.priority - b.priority
/proc/cmp_clientcolour_priority(datum/client_colour/A, datum/client_colour/B)
- return B.priority - A.priority
\ No newline at end of file
+ return B.priority - A.priority
+
+/proc/cmp_clockscripture_priority(datum/clockwork_scripture/A, datum/clockwork_scripture/B)
+ return initial(A.sort_priority) - initial(B.sort_priority)
\ No newline at end of file
diff --git a/code/__HELPERS/icon_smoothing.dm b/code/__HELPERS/icon_smoothing.dm
index 7f76e50e434..22b6e15808e 100644
--- a/code/__HELPERS/icon_smoothing.dm
+++ b/code/__HELPERS/icon_smoothing.dm
@@ -386,6 +386,5 @@
name = "smooth wall"
icon = 'icons/turf/smooth_wall.dmi'
icon_state = "smooth"
- walltype = "shuttle"
smooth = SMOOTH_TRUE|SMOOTH_DIAGONAL|SMOOTH_BORDER
canSmoothWith = null
diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm
index ff1c86cec1d..6f1ea32d2a3 100644
--- a/code/__HELPERS/matrices.dm
+++ b/code/__HELPERS/matrices.dm
@@ -63,91 +63,96 @@
// Color matrices:
-//Luma coefficients suggested for HDTVs. If you change these, make sure they add up to 1.
-#define LUMR 0.2126
-#define LUMG 0.7152
-#define LUMB 0.0722
+/* Documenting a couple of potentially useful color matrices here to inspire ideas
+// Greyscale - indentical to saturation @ 0
+list(LUMA_R,LUMA_R,LUMA_R,0, LUMA_G,LUMA_G,LUMA_G,0, LUMA_B,LUMA_B,LUMA_B,0, 0,0,0,1, 0,0,0,0)
-//Still need color matrix addition, negation, and multiplication.
+// Color inversion
+list(-1,0,0,0, 0,-1,0,0, 0,0,-1,0, 0,0,0,1, 1,1,1,0)
-//Returns an identity color matrix which does nothing
-/proc/color_identity()
- return list(1,0,0, 0,1,0, 0,0,1)
+// Sepiatone
+list(0.393,0.349,0.272,0, 0.769,0.686,0.534,0, 0.189,0.168,0.131,0, 0,0,0,1, 0,0,0,0)
+*/
-//Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting whites
-//TODO: Need a version that only affects one color (ie shift red to blue but leave greens and blues alone)
-/proc/color_rotation(angle)
- if(angle == 0)
- return color_identity()
- angle = Clamp(angle, -180, 180)
- var/cos = cos(angle)
+//Does nothing
+/proc/color_matrix_identity()
+ return list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0)
+
+//Adds/subtracts overall lightness
+//0 is identity, 1 makes everything white, -1 makes everything black
+/proc/color_matrix_lightness(power)
+ return list(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, power,power,power,0)
+
+//Changes distance hues have from grey while maintaining the overall lightness. Greys are unaffected.
+//1 is identity, 0 is greyscale, >1 oversaturates colors
+/proc/color_matrix_saturation(value)
+ var/inv = 1 - value
+ var/R = round(LUMA_R * inv, 0.001)
+ var/G = round(LUMA_G * inv, 0.001)
+ var/B = round(LUMA_B * inv, 0.001)
+
+ return list(R + value,R,R,0, G,G + value,G,0, B,B,B + value,0, 0,0,0,1, 0,0,0,0)
+
+//Changes distance colors have from rgb(127,127,127) grey
+//1 is identity. 0 makes everything grey >1 blows out colors and greys
+/proc/color_matrix_contrast(value)
+ var/add = (1 - value) / 2
+ return list(value,0,0,0, 0,value,0,0, 0,0,value,0, 0,0,0,1, add,add,add,0)
+
+//Moves all colors angle degrees around the color wheel while maintaining intensity of the color and not affecting greys
+//0 is identity, 120 moves reds to greens, 240 moves reds to blues
+/proc/color_matrix_rotate_hue(angle)
var/sin = sin(angle)
-
- var/constA = 0.143
- var/constB = 0.140
- var/constC = -0.283
+ var/cos = cos(angle)
+ var/cos_inv_third = 0.333*(1-cos)
+ var/sqrt3_sin = sqrt(3)*sin
return list(
- LUMR + cos * (1-LUMR) + sin * -LUMR, LUMR + cos * -LUMR + sin * constA, LUMR + cos * -LUMR + sin * -(1-LUMR),
- LUMG + cos * -LUMG + sin * -LUMG, LUMG + cos * (1-LUMG) + sin * constB, LUMG + cos * -LUMG + sin * LUMG,
- LUMB + cos * -LUMB + sin * (1-LUMB), LUMB + cos * -LUMB + sin * constC, LUMB + cos * (1-LUMB) + sin * LUMB
- )
+round(cos+cos_inv_third, 0.001), round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), 0,
+round(cos_inv_third-sqrt3_sin, 0.001), round(cos+cos_inv_third, 0.001), round(cos_inv_third+sqrt3_sin, 0.001), 0,
+round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), round(cos+cos_inv_third, 0.001), 0,
+0,0,0,1,
+0,0,0,0)
-//Makes everything brighter or darker without regard to existing color or brightness
-/proc/color_brightness(power)
- power = Clamp(power, -255, 255)
- power = power/255
+//These next three rotate values about one axis only
+//x is the red axis, y is the green axis, z is the blue axis.
+/proc/color_matrix_rotate_x(angle)
+ var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001)
+ return list(1,0,0,0, 0,cosval,sinval,0, 0,-sinval,cosval,0, 0,0,0,1, 0,0,0,0)
- return list(1,0,0, 0,1,0, 0,0,1, power,power,power)
+/proc/color_matrix_rotate_y(angle)
+ var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001)
+ return list(cosval,0,-sinval,0, 0,1,0,0, sinval,0,cosval,0, 0,0,0,1, 0,0,0,0)
-/var/list/delta_index = list(
- 0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11,
- 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24,
- 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42,
- 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68,
- 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98,
- 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54,
- 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25,
- 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8,
- 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0,
- 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8,
- 10.0)
+/proc/color_matrix_rotate_z(angle)
+ var/sinval = round(sin(angle), 0.001); var/cosval = round(cos(angle), 0.001)
+ return list(cosval,sinval,0,0, -sinval,cosval,0,0, 0,0,1,0, 0,0,0,1, 0,0,0,0)
-//Exxagerates or removes brightness
-/proc/color_contrast(value)
- value = Clamp(value, -100, 100)
- if(value == 0)
- return color_identity()
- var/x = 0
- if (value < 0)
- x = 127 + value / 100 * 127;
- else
- x = value % 1
- if(x == 0)
- x = delta_index[value]
- else
- x = delta_index[value] * (1-x) + delta_index[value+1] * x//use linear interpolation for more granularity.
- x = x * 127 + 127
+//Returns a matrix addition of A with B
+/proc/color_matrix_add(list/A, list/B)
+ if(!istype(A) || !istype(B))
+ return color_matrix_identity()
+ if(A.len != 20 || B.len != 20)
+ return color_matrix_identity()
+ var/list/output = list()
+ output.len = 20
+ for(var/value in 1 to 20)
+ output[value] = A[value] + B[value]
+ return output
- var/mult = x / 127
- var/add = 0.5 * (127-x) / 255
- return list(mult,0,0, 0,mult,0, 0,0,mult, add,add,add)
-
-//Exxagerates or removes colors
-/proc/color_saturation(value as num)
- if(value == 0)
- return color_identity()
- value = Clamp(value, -100, 100)
- if(value > 0)
- value *= 3
- var/x = 1 + value / 100
- var/inv = 1 - x
- var/R = LUMR * inv
- var/G = LUMG * inv
- var/B = LUMB * inv
-
- return list(R + x,R,R, G,G + x,G, B,B,B + x)
-
-#undef LUMR
-#undef LUMG
-#undef LUMB
+//Returns a matrix multiplication of A with B
+/proc/color_matrix_multiply(list/A, list/B)
+ if(!istype(A) || !istype(B))
+ return color_matrix_identity()
+ if(A.len != 20 || B.len != 20)
+ return color_matrix_identity()
+ var/list/output = list()
+ output.len = 20
+ var/x = 1
+ var/y = 1
+ var/offset = 0
+ for(y in 1 to 5)
+ offset = (y-1)*4
+ for(x in 1 to 4)
+ output[offset+x] = round(A[offset+1]*B[x] + A[offset+2]*B[x+4] + A[offset+3]*B[x+8] + A[offset+4]*B[x+12]+(y==5?B[x+16]:0), 0.001)
+ return output
\ No newline at end of file
diff --git a/code/__HELPERS/type2type.dm b/code/__HELPERS/type2type.dm
index 0a58fff019a..cdd827a3895 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -572,4 +572,25 @@ for(var/t in test_times)
var/R = hex2num(copytext(A,2,4))
var/G = hex2num(copytext(A,4,6))
var/B = hex2num(copytext(A,6,0))
- return R+G+B
\ No newline at end of file
+ return R+G+B
+
+//word of warning: using a matrix like this as a color value will simplify it back to a string after being set
+/proc/color_hex2color_matrix(string)
+ var/length = length(string)
+ if(length != 7 && length != 9)
+ return color_matrix_identity()
+ var/r = hex2num(copytext(string, 2, 4))/255
+ var/g = hex2num(copytext(string, 4, 6))/255
+ var/b = hex2num(copytext(string, 6, 8))/255
+ var/a = 1
+ if(length == 9)
+ a = hex2num(copytext(string, 8, 10))/255
+ if(!isnum(r) || !isnum(g) || !isnum(b) || !isnum(a))
+ return color_matrix_identity()
+ return list(r,0,0,0, 0,g,0,0, 0,0,b,0, 0,0,0,a, 0,0,0,0)
+
+//will drop all values not on the diagonal
+/proc/color_matrix2color_hex(list/the_matrix)
+ if(!istype(the_matrix) || the_matrix.len != 20)
+ return "#ffffffff"
+ return rgb(the_matrix[1]*255, the_matrix[6]*255, the_matrix[11]*255, the_matrix[16]*255)
\ No newline at end of file
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 39892a67e3a..8f9f98e82fe 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -337,7 +337,7 @@ Turf and target are seperate in case you want to teleport some distance from a t
moblist.Add(M)
for(var/mob/living/carbon/human/M in sortmob)
moblist.Add(M)
- for(var/mob/living/carbon/brain/M in sortmob)
+ for(var/mob/living/brain/M in sortmob)
moblist.Add(M)
for(var/mob/living/carbon/alien/M in sortmob)
moblist.Add(M)
@@ -496,25 +496,6 @@ Turf and target are seperate in case you want to teleport some distance from a t
var/y=arcsin(x/sqrt(1+x*x))
return y
-
-/proc/anim(turf/location,target as mob|obj,a_icon,a_icon_state as text,flick_anim as text,sleeptime = 0,direction as num)
-//This proc throws up either an icon or an animation for a specified amount of time.
-//The variables should be apparent enough.
- var/atom/movable/overlay/animation = new(location)
- if(direction)
- animation.setDir(direction)
- animation.icon = a_icon
- animation.layer = target:layer+1
- if(a_icon_state)
- animation.icon_state = a_icon_state
- else
- animation.icon_state = "blank"
- animation.master = target
- flick(flick_anim, animation)
- sleep(max(sleeptime, 15))
- qdel(animation)
-
-
/atom/proc/GetAllContents()
var/list/processing_list = list(src)
var/list/assembled = list()
@@ -1348,17 +1329,23 @@ proc/pick_closest_path(value)
CRASH(msg)
//Key thing that stops lag. Cornerstone of performance in ss13, Just sitting here, in unsorted.dm.
+
+//Increases delay as the server gets more overloaded,
+//as sleeps aren't cheap and sleeping only to wake up and sleep again is wasteful
+#define DELTA_CALC max(((max(world.tick_usage, world.cpu) / 100) * max(Master.sleep_delta,1)), 1)
+
/proc/stoplag()
- . = 1
+ . = round(1*DELTA_CALC)
sleep(world.tick_lag)
if (world.tick_usage > TICK_LIMIT_TO_RUN) //woke up, still not enough tick, sleep for more.
- . += 2
- sleep(world.tick_lag*2)
+ . += round(2*DELTA_CALC)
+ sleep(world.tick_lag*2*DELTA_CALC)
if (world.tick_usage > TICK_LIMIT_TO_RUN) //woke up, STILL not enough tick, sleep for more.
- . += 4
- sleep(world.tick_lag*4)
+ . += round(4*DELTA_CALC)
+ sleep(world.tick_lag*4*DELTA_CALC)
//you might be thinking of adding more steps to this, or making it use a loop and a counter var
// not worth it.
+#undef DELTA_CALC
/proc/flash_color(mob_or_client, flash_color="#960000", flash_time=20)
var/client/C
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index dc21aa4185a..3300602476c 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -104,6 +104,7 @@
if(W == A)
W.attack_self(src)
update_inv_hands()
+ return
// operate three levels deep here (item in backpack in src; item in box in backpack in src, not any deeper)
if(A.ClickAccessible(src, depth=INVENTORY_DEPTH))
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index ad0ea23e9da..0902579bac8 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -51,17 +51,17 @@
#define ui_storage1 "CENTER+1:18,SOUTH:5"
#define ui_storage2 "CENTER+2:20,SOUTH:5"
-#define ui_borg_sensor "CENTER-3:16, SOUTH:5" //borgs
-#define ui_borg_lamp "CENTER-4:16, SOUTH:5" //borgies
-#define ui_borg_thrusters "CENTER-5:16, SOUTH:5"//borgies
-#define ui_inv1 "CENTER-2:16,SOUTH:5" //borgs
-#define ui_inv2 "CENTER-1 :16,SOUTH:5" //borgs
-#define ui_inv3 "CENTER :16,SOUTH:5" //borgs
-#define ui_borg_module "CENTER+1:16,SOUTH:5"
-#define ui_borg_store "CENTER+2:16,SOUTH:5" //borgs
-
-#define ui_borg_camera "CENTER+3:21,SOUTH:5" //borgs
-#define ui_borg_album "CENTER+4:21,SOUTH:5" //borgs
+#define ui_borg_sensor "CENTER-3:16, SOUTH:5" //borgs
+#define ui_borg_lamp "CENTER-4:16, SOUTH:5" //borgs
+#define ui_borg_thrusters "CENTER-5:16, SOUTH:5" //borgs
+#define ui_inv1 "CENTER-2:16,SOUTH:5" //borgs
+#define ui_inv2 "CENTER-1 :16,SOUTH:5" //borgs
+#define ui_inv3 "CENTER :16,SOUTH:5" //borgs
+#define ui_borg_module "CENTER+1:16,SOUTH:5" //borgs
+#define ui_borg_store "CENTER+2:16,SOUTH:5" //borgs
+#define ui_borg_camera "CENTER+3:21,SOUTH:5" //borgs
+#define ui_borg_album "CENTER+4:21,SOUTH:5" //borgs
+#define ui_borg_talk_wheel "CENTER+4:21,SOUTH+1:5" //borgs
#define ui_monkey_head "CENTER-4:13,SOUTH:5" //monkey
#define ui_monkey_mask "CENTER-3:14,SOUTH:5" //monkey
@@ -69,6 +69,7 @@
#define ui_alien_storage_l "CENTER-2:14,SOUTH:5"//alien
#define ui_alien_storage_r "CENTER+1:18,SOUTH:5"//alien
+#define ui_alien_talk_wheel "EAST-3:26,SOUTH:5" //alien
#define ui_drone_drop "CENTER+1:18,SOUTH:5" //maintenance drones
#define ui_drone_pull "CENTER+2:2,SOUTH:5" //maintenance drones
diff --git a/code/_onclick/hud/alien.dm b/code/_onclick/hud/alien.dm
index 2cd637f9653..305d7719b68 100644
--- a/code/_onclick/hud/alien.dm
+++ b/code/_onclick/hud/alien.dm
@@ -70,6 +70,11 @@
H.leap_icon.screen_loc = ui_alien_storage_r
static_inventory += H.leap_icon
+ using = new/obj/screen/wheel/talk
+ using.screen_loc = ui_alien_talk_wheel
+ wheels += using
+ static_inventory += using
+
using = new /obj/screen/drop()
using.icon = 'icons/mob/screen_alien.dmi'
using.screen_loc = ui_drop_throw
diff --git a/code/_onclick/hud/alien_larva.dm b/code/_onclick/hud/alien_larva.dm
index 9594fe08e61..4c04cc363ac 100644
--- a/code/_onclick/hud/alien_larva.dm
+++ b/code/_onclick/hud/alien_larva.dm
@@ -21,6 +21,11 @@
pull_icon.screen_loc = ui_pull_resist
hotkeybuttons += pull_icon
+ using = new/obj/screen/wheel/talk
+ using.screen_loc = ui_alien_talk_wheel
+ wheels += using
+ static_inventory += using
+
zone_select = new /obj/screen/zone_sel/alien()
zone_select.update_icon(mymob)
static_inventory += zone_select
diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm
index 4c6b79fdbb2..9ceaa67bf6a 100644
--- a/code/_onclick/hud/fullscreen.dm
+++ b/code/_onclick/hud/fullscreen.dm
@@ -106,3 +106,18 @@
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
icon_state = "druggy"
+
+/obj/screen/fullscreen/color_vision
+ icon = 'icons/mob/screen_gen.dmi'
+ screen_loc = "WEST,SOUTH to EAST,NORTH"
+ icon_state = "flash"
+ alpha = 80
+
+/obj/screen/fullscreen/color_vision/green
+ color = "#00ff00"
+
+/obj/screen/fullscreen/color_vision/red
+ color = "#ff0000"
+
+/obj/screen/fullscreen/color_vision/blue
+ color = "#0000ff"
\ No newline at end of file
diff --git a/code/_onclick/hud/generic_dextrous.dm b/code/_onclick/hud/generic_dextrous.dm
index 509af712b90..bb0bac5d4ce 100644
--- a/code/_onclick/hud/generic_dextrous.dm
+++ b/code/_onclick/hud/generic_dextrous.dm
@@ -60,3 +60,12 @@
for(var/obj/item/I in D.held_items)
I.screen_loc = null
D.client.screen -= I
+
+
+//Dextrous simple mobs can use hands!
+/mob/living/simple_animal/create_mob_hud()
+ if(client && !hud_used)
+ if(dextrous)
+ hud_used = new dextrous_hud_type(src, ui_style2icon(client.prefs.UI_style))
+ else
+ ..()
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index a7930dc8c2c..0dfb1dbb14a 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -33,6 +33,8 @@
var/obj/screen/throw_icon
var/obj/screen/module_store_icon
+ var/list/wheels = list() //list of the wheel screen objects
+
var/list/static_inventory = list() //the screen objects which are static
var/list/toggleable_inventory = list() //the screen objects which can be hidden
var/list/obj/screen/hotkeybuttons = list() //the buttons that can be used via hotkeys
@@ -64,6 +66,8 @@
qdel(module_store_icon)
module_store_icon = null
+ wheels = null //all wheels are also in static_inventory
+
if(static_inventory.len)
for(var/thing in static_inventory)
qdel(thing)
@@ -199,7 +203,18 @@
return
/datum/hud/proc/persistant_inventory_update(mob/viewer)
- return
+ if(!mymob)
+ return
+ var/mob/living/L = mymob
+
+ var/mob/screenmob = viewer || L
+
+ for(var/X in wheels)
+ var/obj/screen/wheel/W = X
+ if(W.toggled)
+ screenmob.client.screen |= W.buttons_list
+ else
+ screenmob.client.screen -= W.buttons_list
//Triggered when F12 is pressed (Unless someone changed something in the DMF)
/mob/verb/button_pressed_F12()
@@ -241,5 +256,5 @@
i++
for(var/obj/screen/human/equip/E in static_inventory)
E.screen_loc = ui_equip_position(mymob)
-
- show_hud(HUD_STYLE_STANDARD,mymob)
\ No newline at end of file
+ if(mymob.hud_used)
+ show_hud(HUD_STYLE_STANDARD,mymob)
\ No newline at end of file
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index c117ba5bb82..b52d23375ab 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -95,6 +95,11 @@
using.icon = ui_style
static_inventory += using
+ using = new/obj/screen/wheel/talk
+ using.icon = ui_style
+ wheels += using
+ static_inventory += using
+
using = new /obj/screen/inventory/area_creator
using.icon = ui_style
static_inventory += using
@@ -352,9 +357,12 @@
if(H.wear_mask) screenmob.client.screen -= H.wear_mask
if(H.head) screenmob.client.screen -= H.head
+
+
/datum/hud/human/persistant_inventory_update(mob/viewer)
if(!mymob)
return
+ ..()
var/mob/living/carbon/human/H = mymob
var/mob/screenmob = viewer || H
@@ -396,11 +404,12 @@
if(hud_version != HUD_STYLE_NOHUD)
for(var/obj/item/I in H.held_items)
I.screen_loc = ui_hand_position(H.get_held_index_of_item(I))
- H.client.screen += I
+ screenmob.client.screen += I
else
for(var/obj/item/I in H.held_items)
I.screen_loc = null
- H.client.screen -= I
+ screenmob.client.screen -= I
+
/mob/living/carbon/human/verb/toggle_hotkey_verbs()
set category = "OOC"
diff --git a/code/_onclick/hud/monkey.dm b/code/_onclick/hud/monkey.dm
index dd6ec4bef44..588d212375a 100644
--- a/code/_onclick/hud/monkey.dm
+++ b/code/_onclick/hud/monkey.dm
@@ -16,6 +16,11 @@
using.screen_loc = ui_movi
static_inventory += using
+ using = new/obj/screen/wheel/talk
+ using.icon = ui_style
+ wheels += using
+ static_inventory += using
+
using = new /obj/screen/drop()
using.icon = ui_style
using.screen_loc = ui_drop_throw
diff --git a/code/_onclick/hud/other_mobs.dm b/code/_onclick/hud/other_mobs.dm
index 2bbc92c7cd4..af7eabd8e9a 100644
--- a/code/_onclick/hud/other_mobs.dm
+++ b/code/_onclick/hud/other_mobs.dm
@@ -7,35 +7,7 @@
mymob.client.screen = list()
mymob.client.screen += mymob.client.void
-/mob/living/carbon/brain/create_mob_hud()
+/mob/living/brain/create_mob_hud()
if(client && !hud_used)
hud_used = new /datum/hud/brain(src)
-/datum/hud/hog_god/New(mob/owner)
- ..()
- healths = new /obj/screen/healths/deity()
- infodisplay += healths
-
- deity_power_display = new /obj/screen/deity_power_display()
- infodisplay += deity_power_display
-
- deity_follower_display = new /obj/screen/deity_follower_display()
- infodisplay += deity_follower_display
-
-
-/mob/camera/god/create_mob_hud()
- if(client && !hud_used)
- hud_used = new /datum/hud/hog_god(src)
-
-/obj/screen/deity_power_display
- name = "Faith"
- icon_state = "deity_power"
- screen_loc = ui_deitypower
- layer = HUD_LAYER
-
-/obj/screen/deity_follower_display
- name = "Followers"
- icon_state = "deity_followers"
- screen_loc = ui_deityfollowers
- layer = HUD_LAYER
-
diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm
index 8f247f130c1..0e8129962ec 100644
--- a/code/_onclick/hud/robot.dm
+++ b/code/_onclick/hud/robot.dm
@@ -93,6 +93,11 @@
var/mob/living/silicon/robot/mymobR = mymob
var/obj/screen/using
+ using = new/obj/screen/wheel/talk
+ using.screen_loc = ui_borg_talk_wheel
+ wheels += using
+ static_inventory += using
+
//Radio
using = new /obj/screen/robot/radio()
using.screen_loc = ui_borg_radio
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index cb9c698efaf..8dedf4b91b7 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -480,3 +480,139 @@
/obj/screen/healthdoll
name = "health doll"
screen_loc = ui_healthdoll
+
+
+
+/obj/screen/wheel
+ name = "wheel"
+ layer = HUD_LAYER
+ icon_state = ""
+ screen_loc = null //if you make a new wheel, remember to give it a screen_loc
+ var/list/buttons_names = list() //list of the names for each button, its length is the amount of buttons.
+ var/toggled = 0 //wheel is hidden/shown
+ var/wheel_buttons_type //the type of buttons used with this wheel.
+ var/list/buttons_list = list()
+
+/obj/screen/wheel/New()
+ ..()
+ build_options()
+
+
+//we create the buttons for the wheel and place them in a square spiral fashion.
+/obj/screen/wheel/proc/build_options()
+ var/obj/screen/wheel_button/close_wheel/CW = new ()
+ buttons_list += CW //the close option
+ CW.wheel = src
+
+ var/list/offset_x_list = list()
+ var/list/offset_y_list = list()
+ var/num = 1
+ var/N = 1
+ var/M = 0
+ var/sign = -1
+ my_loop:
+ while(offset_y_list.len < buttons_names.len)
+ for(var/i=1, i<=num, i++)
+ offset_y_list += N
+ offset_x_list += M
+ if(offset_y_list.len == buttons_names.len)
+ break my_loop
+ if(N != 0)
+ N = 0
+ M = -sign
+ else
+ N = sign
+ M = 0
+ sign = -sign
+ num++
+
+ var/screenx = 8
+ var/screeny = 8
+ for(var/i = 1, i <= buttons_names.len, i++)
+ var/obj/screen/wheel_button/WB = new wheel_buttons_type()
+ WB.wheel = src
+ buttons_list += WB
+ screenx += offset_x_list[i]
+ screeny += offset_y_list[i]
+ WB.screen_loc = "[screenx], [screeny]"
+ set_button(WB, i)
+
+/obj/screen/wheel/proc/set_button(obj/screen/wheel_button/WB, button_number)
+ WB.name = buttons_names[button_number]
+ return
+
+/obj/screen/wheel/Destroy()
+ for(var/obj/screen/S in buttons_list)
+ qdel(S)
+ return ..()
+
+/obj/screen/wheel/Click()
+ if(world.time <= usr.next_move)
+ return
+ if(usr.stat)
+ return
+ if(isliving(usr))
+ var/mob/living/L = usr
+ if(toggled)
+ L.client.screen -= buttons_list
+ else
+ L.client.screen |= buttons_list
+ toggled = !toggled
+
+
+/obj/screen/wheel/talk
+ name = "talk wheel"
+ icon_state = "talk_wheel"
+ screen_loc = "11:6,2:-11"
+ wheel_buttons_type = /obj/screen/wheel_button/talk
+ buttons_names = list("help","hello","bye","stop","thanks","come","out", "yes", "no")
+ var/list/word_messages = list(list("Help!","Help me!"), list("Hello.", "Hi."), list("Bye.", "Goodbye."),\
+ list("Stop!", "Halt!"), list("Thanks.", "Thanks!", "Thank you."), \
+ list("Come.", "Follow me."), list("Out!", "Go away!", "Get out!"), \
+ list("Yes.", "Affirmative."), list("No.", "Negative"))
+
+/obj/screen/wheel/talk/set_button(obj/screen/wheel_button/WB, button_number)
+ ..()
+ var/obj/screen/wheel_button/talk/T = WB //we already know what type the button is exactly.
+ T.icon_state = "talk_[T.name]"
+ T.word_messages = word_messages[button_number]
+
+
+/obj/screen/wheel_button
+ name = "default wheel button"
+ screen_loc = "8,8"
+ layer = HUD_LAYER
+ mouse_opacity = 2
+ var/obj/screen/wheel/wheel
+
+/obj/screen/wheel_button/Destroy()
+ wheel = null
+ return ..()
+
+/obj/screen/wheel_button/close_wheel
+ name = "close wheel"
+ icon_state = "x3"
+
+/obj/screen/wheel_button/close_wheel/Click()
+ if(isliving(usr))
+ var/mob/living/L = usr
+ L.client.screen -= wheel.buttons_list
+ wheel.toggled = !wheel.toggled
+
+
+/obj/screen/wheel_button/talk
+ name = "talk option"
+ icon_state = "talk_help"
+ var/talk_cooldown = 0
+ var/list/word_messages = list()
+
+/obj/screen/wheel_button/talk/Click(location, control,params)
+ if(isliving(usr))
+ var/mob/living/L = usr
+ if(L.stat)
+ return
+
+ if(word_messages.len && talk_cooldown < world.time)
+ talk_cooldown = world.time + 10
+ L.say(pick(word_messages))
+
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index 838f913536f..ced66536d87 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -34,6 +34,8 @@
user.lastattacked = M
M.lastattacker = user
+ if(user != M)
+ user.do_attack_animation(M)
M.attacked_by(src, user)
add_logs(user, M, "attacked", src.name, "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])")
@@ -58,19 +60,27 @@
user.visible_message("[user] has hit [src] with [I]!", "You hit [src] with [I]!")
/mob/living/attacked_by(obj/item/I, mob/living/user)
- if(user != src)
- user.do_attack_animation(src)
- if(send_item_attack_message(I, user))
- if(apply_damage(I.force, I.damtype))
- if(I.damtype == BRUTE)
- if(prob(33))
- I.add_mob_blood(src)
- var/turf/location = get_turf(src)
- add_splatter_floor(location)
- if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood
- user.add_mob_blood(src)
- return TRUE
+ send_item_attack_message(I, user)
+ if(I.force)
+ apply_damage(I.force, I.damtype)
+ if(I.damtype == BRUTE)
+ if(prob(33))
+ I.add_mob_blood(src)
+ var/turf/location = get_turf(src)
+ add_splatter_floor(location)
+ if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood
+ user.add_mob_blood(src)
+ return TRUE //successful attack
+/mob/living/simple_animal/attacked_by(obj/item/I, mob/living/user)
+ if(!I.force)
+ user.visible_message("[user] gently taps [src] with [I].",\
+ "This weapon is ineffective, it does no damage!")
+ else if(I.force < force_threshold || I.damtype == STAMINA)
+ visible_message("[I] bounces harmlessly off of [src].",\
+ "[I] bounces harmlessly off of [src]!")
+ else
+ return ..()
// Proximity_flag is 1 if this afterattack was called on something adjacent, in your square, or on your person.
// Click parameters is the params string from byond Click() code, see that documentation.
@@ -90,7 +100,7 @@
if(I.attack_verb && I.attack_verb.len)
message_verb = "[pick(I.attack_verb)]"
else if(!I.force)
- return 0
+ return
var/message_hit_area = ""
if(hit_area)
message_hit_area = " in the [hit_area]"
@@ -102,12 +112,3 @@
"[attack_message]")
return 1
-/mob/living/simple_animal/send_item_attack_message(obj/item/I, mob/living/user, hit_area)
- if(!I.force)
- user.visible_message("[user] gently taps [src] with [I].",\
- "This weapon is ineffective, it does no damage!")
- else if(I.force < force_threshold || I.damtype == STAMINA)
- visible_message("[I] bounces harmlessly off of [src].",\
- "[I] bounces harmlessly off of [src]!")
- else
- return ..()
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 95c2ff9836a..f6986e8d4f1 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -50,9 +50,8 @@
for(var/datum/mutation/human/HM in dna.mutations)
HM.on_ranged_attack(src, A)
- var/turf/T = A
- if(istype(T) && get_dist(src,T) <= 1)
- src.Move_Pulled(T)
+ if(isturf(A) && get_dist(src,A) <= 1)
+ src.Move_Pulled(A)
/*
Animals & All Unspecified
@@ -111,7 +110,7 @@
*/
/mob/living/carbon/alien/UnarmedAttack(atom/A)
A.attack_alien(src)
-/atom/proc/attack_alien(mob/user)
+/atom/proc/attack_alien(mob/living/carbon/alien/user)
attack_paw(user)
return
/mob/living/carbon/alien/RestrainedClickOn(atom/A)
@@ -135,6 +134,68 @@
/mob/living/simple_animal/slime/RestrainedClickOn(atom/A)
return
+
+/*
+ Drones
+*/
+/mob/living/simple_animal/drone/UnarmedAttack(atom/A)
+ A.attack_drone(src)
+
+/atom/proc/attack_drone(mob/living/simple_animal/drone/user)
+ attack_hand(user) //defaults to attack_hand. Override it when you don't want drones to do same stuff as humans.
+
+/mob/living/simple_animal/slime/RestrainedClickOn(atom/A)
+ return
+
+
+/*
+ True Devil
+*/
+
+/mob/living/carbon/true_devil/UnarmedAttack(atom/A, proximity)
+ A.attack_hand(src)
+
+/*
+ Brain
+*/
+
+/mob/living/brain/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default
+ return
+
+
+/*
+ pAI
+*/
+
+/mob/living/silicon/pai/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default
+ return
+
+
+/*
+ Simple animals
+*/
+
+/mob/living/simple_animal/UnarmedAttack(atom/A, proximity)
+ if(!dextrous)
+ return ..()
+ if(!ismob(A))
+ A.attack_hand(src)
+ update_inv_hands()
+
+
+/*
+ Hostile animals
+*/
+
+/mob/living/simple_animal/hostile/UnarmedAttack(atom/A)
+ target = A
+ if(dextrous && !is_type_in_typecache(A, environment_target_typecache) && !ismob(A))
+ ..()
+ else
+ AttackingTarget()
+
+
+
/*
New Players:
Have no reason to click on anything at all.
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index bce1a852783..333d7447396 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -184,6 +184,7 @@
var/grey_assistants = 0
var/lavaland_budget = 60
+ var/space_budget = 16
var/aggressive_changelog = 0
@@ -620,6 +621,8 @@
config.grey_assistants = 1
if("lavaland_budget")
config.lavaland_budget = text2num(value)
+ if("space_budget")
+ config.space_budget = text2num(value)
if("no_summon_guns")
config.no_summon_guns = 1
if("no_summon_magic")
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 6c0658aa2e7..43155df2247 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -35,6 +35,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
var/init_time
var/tickdrift = 0
+ var/sleep_delta
+
var/make_runtime = 0
// Has round started? (So we know what subsystems to run)
@@ -280,6 +282,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
iteration++
last_run = world.time
+ src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
sleep(world.tick_lag * (processing + sleep_delta))
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index b39fca4a6e1..f86153f34f0 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -34,7 +34,7 @@ var/datum/subsystem/mapping/SSmapping
else
space_zlevels += i
- seedRuins(space_zlevels, rand(8,16), /area/space, space_ruins_templates)
+ seedRuins(space_zlevels, config.space_budget, /area/space, space_ruins_templates)
// Set up Z-level transistions.
setup_map_transitions()
diff --git a/code/controllers/subsystem/minimap.dm b/code/controllers/subsystem/minimap.dm
index 421d9ba312d..d651cabd498 100644
--- a/code/controllers/subsystem/minimap.dm
+++ b/code/controllers/subsystem/minimap.dm
@@ -13,25 +13,55 @@ var/datum/subsystem/minimap/SSminimap
NEW_SS_GLOBAL(SSminimap)
/datum/subsystem/minimap/Initialize(timeofday)
- if(!config.generate_minimaps)
- world << "Minimap generation disabled... Skipping"
- return
var/hash = md5(file2text("_maps/[MAP_PATH]/[MAP_FILE]"))
- if(hash == trim(file2text(hash_path())))
- return ..()
-
- for(var/z in z_levels)
- generate(z)
- register_asset("minimap_[z].png", fcopy_rsc(map_path(z)))
- fdel(hash_path())
- text2file(hash, hash_path())
+ if(config.generate_minimaps)
+ if(hash == trim(file2text(hash_path())))
+ for(var/z in z_levels) //We have these files cached, let's register them
+ register_asset("minimap_[z].png", fcopy_rsc(map_path(z)))
+ return ..()
+ for(var/z in z_levels)
+ generate(z)
+ register_asset("minimap_[z].png", fcopy_rsc(map_path(z)))
+ fdel(hash_path())
+ text2file(hash, hash_path())
+ else
+ world << "Minimap generation disabled. Loading from cache..."
+ var/fileloc = 0
+ if(check_files(0)) //Let's first check if we have maps cached in the data folder. NOTE: This will override the backup files even if this map is older.
+ world.log << "cache"
+ if(hash != trim(file2text(hash_path())))
+ world << "Loaded cached minimap is outdated. There may be minor discrepancies in layout." //Disclaimer against players saying map is wrong.
+ fileloc = 0
+ else
+ if(!check_files(1))
+ world << "Failed to load backup minimap file. Aborting." //We couldn't find something. Bail to prevent issues with null files
+ return
+ fileloc = 1 //No map image cached with the current map, and we have a backup. Let's fall back to it.
+ world << "No cached minimaps detected. Backup files loaded."
+ for(var/z in z_levels)
+ register_asset("minimap_[z].png", fcopy_rsc(map_path(z,fileloc)))
..()
-/datum/subsystem/minimap/proc/hash_path()
- return "data/minimaps/[MAP_NAME].md5"
+/datum/subsystem/minimap/proc/check_files(backup) // If the backup argument is true, looks in the icons folder. If false looks in the data folder.
+ for(var/z in z_levels)
+ if(!fexists(file(map_path(z,backup)))) //Let's make sure we have a file for this map
+ if(backup)
+ world.log << "Failed to find backup file for map [MAP_NAME] on zlevel [z]."
+ return FALSE
+ return TRUE
-/datum/subsystem/minimap/proc/map_path(z)
- return "data/minimaps/[MAP_NAME]_[z].png"
+
+/datum/subsystem/minimap/proc/hash_path(backup)
+ if(backup)
+ return "icons/minimaps/[MAP_NAME].md5"
+ else
+ return "data/minimaps/[MAP_NAME].md5"
+
+/datum/subsystem/minimap/proc/map_path(z,backup)
+ if(backup)
+ return "icons/minimaps/[MAP_NAME]_[z].png"
+ else
+ return "data/minimaps/[MAP_NAME]_[z].png"
/datum/subsystem/minimap/proc/send(client/client)
for(var/z in z_levels)
@@ -43,24 +73,10 @@ var/datum/subsystem/minimap/SSminimap
// Scale it up to our target size.
minimap.Scale(MINIMAP_SIZE, MINIMAP_SIZE)
- var/counter = 512
// Loop over turfs and generate icons.
for(var/T in block(locate(x1, y1, z), locate(x2, y2, z)))
generate_tile(T, minimap)
- //byond bug, this fixes OOM crashes by flattening and reseting the minimap icon holder every so and so tiles
- counter--
- if(counter <= 0)
- counter = 512
- var/icon/flatten = new /icon()
- flatten.Insert(minimap, "", SOUTH, 1, 0)
- del(minimap)
- minimap = flatten
- stoplag() //we have to sleep in order to get byond to clear out the proc's garbage bin
-
- CHECK_TICK
-
-
// Create a new icon and insert the generated minimap, so that BYOND doesn't generate different directions.
var/icon/final = new /icon()
final.Insert(minimap, "", SOUTH, 1, 0)
@@ -69,7 +85,7 @@ var/datum/subsystem/minimap/SSminimap
/datum/subsystem/minimap/proc/generate_tile(turf/tile, icon/minimap)
var/icon/tile_icon
var/obj/obj
- var/list/obj_icons = list()
+ var/list/obj_icons
// Don't use icons for space, just add objects in space if they exist.
if(istype(tile, /turf/open/space))
obj = locate(/obj/structure/lattice/catwalk) in tile
@@ -86,18 +102,20 @@ var/datum/subsystem/minimap/SSminimap
tile_icon = new /icon('icons/obj/atmospherics/pipes/transit_tube.dmi', obj.icon_state, obj.dir)
else
tile_icon = new /icon(tile.icon, tile.icon_state, tile.dir)
- obj_icons.Cut()
+ obj_icons = list()
obj = locate(/obj/structure) in tile
if(obj)
- obj_icons += getFlatIcon(obj)
+ obj_icons += new /icon(obj.icon, obj.icon_state, obj.dir, 1, 0)
obj = locate(/obj/machinery) in tile
if(obj)
obj_icons += new /icon(obj.icon, obj.icon_state, obj.dir, 1, 0)
obj = locate(/obj/structure/window) in tile
if(obj)
obj_icons += new /icon('icons/obj/smooth_structures/window.dmi', "window", SOUTH)
-
+ obj = locate(/obj/structure/table) in tile
+ if(obj)
+ obj_icons += new /icon('icons/obj/smooth_structures/table.dmi', "table", SOUTH)
for(var/I in obj_icons)
var/icon/obj_icon = I
tile_icon.Blend(obj_icon, ICON_OVERLAY)
@@ -107,4 +125,3 @@ var/datum/subsystem/minimap/SSminimap
tile_icon.Scale(TILE_SIZE, TILE_SIZE)
// Add the tile to the minimap.
minimap.Blend(tile_icon, ICON_OVERLAY, ((tile.x - 1) * TILE_SIZE), ((tile.y - 1) * TILE_SIZE))
- del(tile_icon)
diff --git a/code/controllers/subsystem/spacedrift.dm b/code/controllers/subsystem/spacedrift.dm
new file mode 100644
index 00000000000..856f51ce7ac
--- /dev/null
+++ b/code/controllers/subsystem/spacedrift.dm
@@ -0,0 +1,64 @@
+var/datum/subsystem/spacedrift/SSspacedrift
+
+/datum/subsystem/spacedrift
+ name = "Space Drift"
+ priority = 40
+ wait = 5
+ flags = SS_NO_INIT|SS_BACKGROUND
+
+ var/list/currentrun = list()
+ var/list/processing = list()
+
+/datum/subsystem/spacedrift/New()
+ NEW_SS_GLOBAL(SSspacedrift)
+
+
+/datum/subsystem/spacedrift/stat_entry()
+ ..("P:[processing.len]")
+
+
+/datum/subsystem/spacedrift/fire(resumed = 0)
+ if (!resumed)
+ src.currentrun = processing.Copy()
+
+ //cache for sanic speed (lists are references anyways)
+ var/list/currentrun = src.currentrun
+
+ while (currentrun.len)
+ var/atom/movable/AM = currentrun[currentrun.len]
+ currentrun.len--
+ if (!AM)
+ processing -= AM
+ if (MC_TICK_CHECK)
+ return
+ continue
+
+ if (AM.inertia_next_move > world.time)
+ if (MC_TICK_CHECK)
+ return
+ continue
+
+ if (!AM.loc || AM.loc != AM.inertia_last_loc || AM.Process_Spacemove(0))
+ AM.inertia_dir = 0
+
+ if (!AM.inertia_dir)
+ AM.inertia_last_loc = null
+ processing -= AM
+ if (MC_TICK_CHECK)
+ return
+ continue
+
+ var/old_dir = AM.dir
+ var/old_loc = AM.loc
+ AM.inertia_moving = TRUE
+ step(AM, AM.inertia_dir)
+ AM.inertia_moving = FALSE
+ AM.inertia_next_move = world.time + AM.inertia_move_delay
+ if (AM.loc == old_loc)
+ AM.inertia_dir = 0
+
+ AM.setDir(old_dir)
+ AM.inertia_last_loc = AM.loc
+ if (MC_TICK_CHECK)
+ return
+
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index ed93eb9369a..5b251a3edfa 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -279,11 +279,11 @@ var/global/list/internal_byond_list_vars = list("contents" = TRUE, "verbs" = TRU
if(iscarbon(D))
body += ""
body += ""
+ body += ""
body += ""
if(ishuman(D))
body += ""
body += ""
- body += ""
body += ""
body += ""
body += ""
@@ -898,25 +898,51 @@ body
var/newtype = species_list[result]
H.set_species(newtype)
- else if(href_list["removebodypart"])
+ else if(href_list["editbodypart"])
if(!check_rights(R_SPAWN))
return
- var/mob/living/carbon/human/H = locate(href_list["removebodypart"])
- if(!istype(H))
- usr << "This can only be done to instances of type /mob/living/carbon/human"
+ var/mob/living/carbon/C = locate(href_list["editbodypart"])
+ if(!istype(C))
+ usr << "This can only be done to instances of type /mob/living/carbon"
return
- var/result = input(usr, "Please choose which body part to remove","Remove Body Part") as null|anything in list("head", "l_arm", "r_arm", "l_leg", "r_leg")
+ var/edit_action = input(usr, "What would you like to do?","Modify Body Part") as null|anything in list("add","remove", "augment")
+ if(!edit_action)
+ return
+ var/list/limb_list = list("head", "l_arm", "r_arm", "l_leg", "r_leg")
+ if(edit_action == "augment")
+ limb_list += "chest"
+ var/result = input(usr, "Please choose which body part to [edit_action]","[capitalize(edit_action)] Body Part") as null|anything in limb_list
- if(!H)
+ if(!C)
usr << "Mob doesn't exist anymore"
return
if(result)
- var/obj/item/bodypart/BP = H.get_bodypart(result)
- if(BP)
- BP.drop_limb()
+ var/obj/item/bodypart/BP = C.get_bodypart(result)
+ switch(edit_action)
+ if("remove")
+ if(BP)
+ BP.drop_limb()
+ else
+ usr << "[C] doesn't have such bodypart."
+ if("add")
+ if(BP)
+ usr << "[C] already has such bodypart."
+ else
+ if(!C.regenerate_limb(result))
+ usr << "[C] cannot have such bodypart."
+ if("augment")
+ if(ishuman(C))
+ if(BP)
+ BP.change_bodypart_status(BODYPART_ROBOTIC, 1)
+ else
+ usr << "[C] doesn't have such bodypart."
+ else
+ usr << "Only humans can be augmented."
+
+
else if(href_list["purrbation"])
if(!check_rights(R_SPAWN))
@@ -985,3 +1011,4 @@ body
log_admin("[key_name(usr)] dealt [amount] amount of [Text] damage to [L] ")
message_admins("[key_name(usr)] dealt [amount] amount of [Text] damage to [L] ")
href_list["datumrefresh"] = href_list["mobToDamage"]
+
diff --git a/code/datums/diseases/advance/symptoms/damage_converter.dm b/code/datums/diseases/advance/symptoms/damage_converter.dm
index ba315278a20..f9109df17c1 100644
--- a/code/datums/diseases/advance/symptoms/damage_converter.dm
+++ b/code/datums/diseases/advance/symptoms/damage_converter.dm
@@ -33,30 +33,19 @@ Bonus
Convert(M)
return
-/datum/symptom/damage_converter/proc/Convert(mob/living/M)
+/datum/symptom/damage_converter/proc/Convert(mob/living/carbon/C)
- var/get_damage = rand(1, 2)
+ var/heal_amt = rand(1, 2)
- if(istype(M, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = M
+ var/list/parts = C.get_damaged_bodyparts(1,1) //1,1 because it needs inputs.
- var/list/parts = H.get_damaged_bodyparts(1,1) //1,1 because it needs inputs.
-
- if(!parts.len)
- return
-
- for(var/obj/item/bodypart/L in parts)
- L.heal_damage(get_damage, get_damage, 0)
- M.adjustToxLoss(get_damage*parts.len)
-
- else
- if(M.getFireLoss() > 0 || M.getBruteLoss() > 0)
- M.adjustFireLoss(-get_damage)
- M.adjustBruteLoss(-get_damage)
- M.adjustToxLoss(get_damage)
- else
- return
+ if(!parts.len)
+ return
+ for(var/obj/item/bodypart/L in parts)
+ if(L.heal_damage(heal_amt, heal_amt))
+ C.update_damage_overlays()
+ C.adjustToxLoss(heal_amt*parts.len)
return 1
/*
diff --git a/code/datums/diseases/advance/symptoms/genetics.dm b/code/datums/diseases/advance/symptoms/genetics.dm
index 3a5dc527f09..e3ffbc868ba 100644
--- a/code/datums/diseases/advance/symptoms/genetics.dm
+++ b/code/datums/diseases/advance/symptoms/genetics.dm
@@ -30,14 +30,14 @@ Bonus
/datum/symptom/genetic_mutation/Activate(datum/disease/advance/A)
..()
if(prob(SYMPTOM_ACTIVATION_PROB * 5)) // 15% chance
- var/mob/living/carbon/M = A.affected_mob
- if(!M.has_dna())
+ var/mob/living/carbon/C = A.affected_mob
+ if(!C.has_dna())
return
switch(A.stage)
if(4, 5)
- M << "[pick("Your skin feels itchy.", "You feel light headed.")]"
- M.dna.remove_mutation_group(possible_mutations)
- randmut(M, possible_mutations)
+ C << "[pick("Your skin feels itchy.", "You feel light headed.")]"
+ C.dna.remove_mutation_group(possible_mutations)
+ C.randmut(possible_mutations)
return
// Archive their DNA before they were infected.
diff --git a/code/datums/diseases/dna_spread.dm b/code/datums/diseases/dna_spread.dm
index 11a8eebbe5d..626fb567c3d 100644
--- a/code/datums/diseases/dna_spread.dm
+++ b/code/datums/diseases/dna_spread.dm
@@ -38,7 +38,7 @@
if(prob(1))
affected_mob << "Your muscles ache."
if(prob(20))
- affected_mob.take_organ_damage(1)
+ affected_mob.take_bodypart_damage(1)
if(prob(1))
affected_mob << "Your stomach hurts."
if(prob(20))
diff --git a/code/datums/diseases/flu.dm b/code/datums/diseases/flu.dm
index 1df55bbb9d7..20bea2da922 100644
--- a/code/datums/diseases/flu.dm
+++ b/code/datums/diseases/flu.dm
@@ -26,7 +26,7 @@
if(prob(1))
affected_mob << "Your muscles ache."
if(prob(20))
- affected_mob.take_organ_damage(1)
+ affected_mob.take_bodypart_damage(1)
if(prob(1))
affected_mob << "Your stomach hurts."
if(prob(20))
@@ -45,7 +45,7 @@
if(prob(1))
affected_mob << "Your muscles ache."
if(prob(20))
- affected_mob.take_organ_damage(1)
+ affected_mob.take_bodypart_damage(1)
if(prob(1))
affected_mob << "Your stomach hurts."
if(prob(20))
diff --git a/code/datums/diseases/fluspanish.dm b/code/datums/diseases/fluspanish.dm
index c041f2610de..57ded9abc30 100644
--- a/code/datums/diseases/fluspanish.dm
+++ b/code/datums/diseases/fluspanish.dm
@@ -22,7 +22,7 @@
affected_mob.emote("cough")
if(prob(1))
affected_mob << "You're burning in your own skin!"
- affected_mob.take_organ_damage(0,5)
+ affected_mob.take_bodypart_damage(0,5)
if(3)
affected_mob.bodytemperature += 20
@@ -32,5 +32,5 @@
affected_mob.emote("cough")
if(prob(5))
affected_mob << "You're burning in your own skin!"
- affected_mob.take_organ_damage(0,5)
+ affected_mob.take_bodypart_damage(0,5)
return
diff --git a/code/datums/dna.dm b/code/datums/dna.dm
index ee19e8483a6..e3d88e8b15e 100644
--- a/code/datums/dna.dm
+++ b/code/datums/dna.dm
@@ -11,13 +11,15 @@
var/list/mutations = list() //All mutations are from now on here
var/list/temporary_mutations = list() //Timers for temporary mutations
var/list/previous = list() //For temporary name/ui/ue/blood_type modifications
- var/mob/living/carbon/holder
+ var/mob/living/holder
-/datum/dna/New(mob/living/carbon/new_holder)
+/datum/dna/New(mob/living/new_holder)
if(new_holder)
holder = new_holder
/datum/dna/proc/transfer_identity(mob/living/carbon/destination, transfer_SE = 0)
+ if(!istype(destination))
+ return
destination.dna.unique_enzymes = unique_enzymes
destination.dna.uni_identity = uni_identity
destination.dna.blood_type = blood_type
@@ -166,12 +168,36 @@
features = random_features()
+/datum/dna/stored //subtype used by brain mob's stored_dna
+
+/datum/dna/stored/add_mutation(mutation_name) //no mutation changes on stored dna.
+ return
+
+/datum/dna/stored/remove_mutation(mutation_name)
+ return
+
+/datum/dna/stored/check_mutation(mutation_name)
+ return
+
+/datum/dna/stored/remove_all_mutations()
+ return
+
+/datum/dna/stored/remove_mutation_group(list/group)
+ return
/////////////////////////// DNA MOB-PROCS //////////////////////
/mob/proc/set_species(datum/species/mrace, icon_update = 1)
return
+/mob/living/brain/set_species(datum/species/mrace, icon_update = 1)
+ if(mrace)
+ if(ispath(mrace))
+ stored_dna.species = new mrace()
+ else
+ stored_dna.species = mrace //not calling any species update procs since we're a brain, not a monkey/human
+
+
/mob/living/carbon/set_species(datum/species/mrace, icon_update = 1)
if(mrace && has_dna())
dna.species.on_species_loss(src)
@@ -290,48 +316,46 @@ mob/living/carbon/human/updateappearance(icon_update=1, mutcolor_update=0, mutat
return 0
return getleftblocks(istring, blocknumber, blocksize) + replacement + getrightblocks(istring, blocknumber, blocksize)
-/proc/randmut(mob/living/carbon/M, list/candidates, difficulty = 2)
- if(!M.has_dna())
+/mob/living/carbon/proc/randmut(list/candidates, difficulty = 2)
+ if(!has_dna())
return
var/datum/mutation/human/num = pick(candidates)
- . = num.force_give(M)
- return
+ . = num.force_give(src)
-/proc/randmutb(mob/living/carbon/M)
- if(!M.has_dna())
+/mob/living/carbon/proc/randmutb()
+ if(!has_dna())
return
var/datum/mutation/human/HM = pick((bad_mutations | not_good_mutations) - mutations_list[RACEMUT])
- . = HM.force_give(M)
+ . = HM.force_give(src)
-/proc/randmutg(mob/living/carbon/M)
- if(!M.has_dna())
+/mob/living/carbon/proc/randmutg()
+ if(!has_dna())
return
var/datum/mutation/human/HM = pick(good_mutations)
- . = HM.force_give(M)
+ . = HM.force_give(src)
-/proc/randmutvg(mob/living/carbon/M)
- if(!M.has_dna())
+/mob/living/carbon/proc/randmutvg()
+ if(!has_dna())
return
var/datum/mutation/human/HM = pick((good_mutations) - mutations_list[HULK] - mutations_list[DWARFISM])
- . = HM.force_give(M)
+ . = HM.force_give(src)
-/proc/randmuti(mob/living/carbon/M)
- if(!M.has_dna())
+/mob/living/carbon/proc/randmuti()
+ if(!has_dna())
return
var/num = rand(1, DNA_UNI_IDENTITY_BLOCKS)
- var/newdna = setblock(M.dna.uni_identity, num, random_string(DNA_BLOCK_SIZE, hex_characters))
- M.dna.uni_identity = newdna
- M.updateappearance(mutations_overlay_update=1)
- return
+ var/newdna = setblock(dna.uni_identity, num, random_string(DNA_BLOCK_SIZE, hex_characters))
+ dna.uni_identity = newdna
+ updateappearance(mutations_overlay_update=1)
-/proc/clean_dna(mob/living/carbon/M)
- if(!M.has_dna())
+/mob/living/carbon/proc/clean_dna()
+ if(!has_dna())
return
- M.dna.remove_all_mutations()
+ dna.remove_all_mutations()
-/proc/clean_randmut(mob/living/carbon/M, list/candidates, difficulty = 2)
- clean_dna(M)
- randmut(M, candidates, difficulty)
+/mob/living/carbon/proc/clean_randmut(list/candidates, difficulty = 2)
+ clean_dna()
+ randmut(candidates, difficulty)
/proc/scramble_dna(mob/living/carbon/M, ui=FALSE, se=FALSE, probability)
if(!M.has_dna())
diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm
index b9609214cc3..c00950a6fee 100644
--- a/code/datums/helper_datums/teleport.dm
+++ b/code/datums/helper_datums/teleport.dm
@@ -106,6 +106,8 @@
if(!center)
center = destination
for(var/turf/T in range(precision,center))
+ if(T.is_transition_turf())
+ continue // Avoid picking these.
var/area/A = T.loc
if(!A.noteleport)
posturfs.Add(T)
@@ -114,7 +116,7 @@
else
destturf = get_turf(destination)
- if(!destturf || !curturf)
+ if(!destturf || !curturf || destturf.is_transition_turf())
return 0
var/area/A = get_area(curturf)
diff --git a/code/datums/hud.dm b/code/datums/hud.dm
index 62c1700f58d..75adb165d3a 100644
--- a/code/datums/hud.dm
+++ b/code/datums/hud.dm
@@ -12,8 +12,6 @@ var/datum/atom_hud/huds = list( \
ANTAG_HUD_OPS = new/datum/atom_hud/antag(), \
ANTAG_HUD_WIZ = new/datum/atom_hud/antag(), \
ANTAG_HUD_SHADOW = new/datum/atom_hud/antag(), \
- ANTAG_HUD_HOG_BLUE = new/datum/atom_hud/antag(),\
- ANTAG_HUD_HOG_RED = new/datum/atom_hud/antag(),\
ANTAG_HUD_TRAITOR = new/datum/atom_hud/antag/hidden(),\
ANTAG_HUD_NINJA = new/datum/atom_hud/antag/hidden(),\
ANTAG_HUD_CHANGELING = new/datum/atom_hud/antag/hidden(),\
diff --git a/code/datums/martial.dm b/code/datums/martial.dm
index 0a93341a63d..9b9cfb3c3d6 100644
--- a/code/datums/martial.dm
+++ b/code/datums/martial.dm
@@ -482,7 +482,7 @@
var/mob/living/carbon/human/H = user
H.apply_damage(2*force, BRUTE, "head")
else
- user.take_organ_damage(2*force)
+ user.take_bodypart_damage(2*force)
return
if(isrobot(target))
return ..()
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 61c61673d11..b335ccdd762 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -174,16 +174,6 @@
ticker.mode.remove_gangster(src,0,1,1)
remove_objectives()
-/datum/mind/proc/remove_hog_follower_prophet()
- ticker.mode.red_deity_followers -= src
- ticker.mode.red_deity_prophets -= src
- ticker.mode.blue_deity_prophets -= src
- ticker.mode.blue_deity_followers -= src
- ticker.mode.update_hog_icons_removed(src, "red")
- ticker.mode.update_hog_icons_removed(src, "blue")
-
-
-
/datum/mind/proc/remove_antag_equip()
var/list/Mob_Contents = current.get_contents()
for(var/obj/item/I in Mob_Contents)
@@ -221,12 +211,6 @@
else if(is_gangster(creator))
ticker.mode.add_gangster(src, creator.mind.gang_datum, TRUE)
- else if(is_handofgod_redcultist(creator) || is_handofgod_redprophet(creator))
- ticker.mode.add_hog_follower(src, "Red")
-
- else if(is_handofgod_bluecultist(creator) || is_handofgod_blueprophet(creator))
- ticker.mode.add_hog_follower(src, "Blue")
-
else if(is_revolutionary_in_general(creator))
ticker.mode.add_revolutionary(src)
@@ -490,38 +474,6 @@
sections["traitor"] = text
- /** HAND OF GOD **/
- text = "hand of god"
- if(ticker.mode.config_tag == "handofgod")
- text = uppertext(text)
- text = "[text]: "
- if (src in ticker.mode.red_deities)
- text += "RED GOD|red prophet|red follower|employee|blue god|blue prophet|blue follower"
- else if(src in ticker.mode.red_deity_prophets)
- text += "red god|RED PROPHET|red follower|employee|blue god|blue prophet|blue follower"
- else if (src in ticker.mode.red_deity_followers)
- text += "red god|red prophet|RED FOLLOWER|employee|blue god|blue prophet|blue follower"
- else if (src in ticker.mode.blue_deities)
- text += "red god|red prophet|red follower|employee|BLUE GOD|blue prophet|blue follower"
- else if (src in ticker.mode.blue_deity_prophets)
- text += "red god|red prophet|red follower|employee|blue god|BLUE PROPHET|blue follower"
- else if (src in ticker.mode.blue_deity_followers)
- text += "red god|red prophet|red follower|employee|blue god|blue prophet|BLUE FOLLOWER"
- else
- text += "red god|red prophet|red follower|EMPLOYEE|blue god|blue prophet|blue follower"
-
- if(current && current.client && (ROLE_HOG_GOD in current.client.prefs.be_special))
- text += "|HOG God Enabled in Prefs"
- else
- text += "|HOG God Disabled in Prefs"
-
- if(current && current.client && (ROLE_HOG_CULTIST in current.client.prefs.be_special))
- text += "|HOG Cultist Enabled in Prefs"
- else
- text += "|HOG Disabled in Prefs"
-
- sections["follower"] = text
-
if(ishuman(current) || ismonkey(current))
/** CHANGELING ***/
@@ -696,7 +648,7 @@
if(!def_value)//If it's a custom objective, it will be an empty string.
def_value = "custom"
- var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "maroon", "debrain", "protect", "destroy", "prevent", "hijack", "escape", "survive", "martyr", "steal", "download", "nuclear", "capture", "absorb", "custom","follower block (HOG)","build (HOG)","deicide (HOG)", "follower escape (HOG)", "sacrifice prophet (HOG)")
+ var/new_obj_type = input("Select objective type:", "Objective type", def_value) as null|anything in list("assassinate", "maroon", "debrain", "protect", "destroy", "prevent", "hijack", "escape", "survive", "martyr", "steal", "download", "nuclear", "capture", "absorb", "custom")
if (!new_obj_type)
return
@@ -798,22 +750,6 @@
new_objective.owner = src
new_objective.target_amount = target_number
- if("follower block (HOG)")
- new_objective = new /datum/objective/follower_block
- new_objective.owner = src
- if("build (HOG)")
- new_objective = new /datum/objective/build
- new_objective.owner = src
- if("deicide (HOG)")
- new_objective = new /datum/objective/deicide
- new_objective.owner = src
- if("follower escape (HOG)")
- new_objective = new /datum/objective/escape_followers
- new_objective.owner = src
- if("sacrifice prophet (HOG)")
- new_objective = new /datum/objective/sacrifice_prophet
- new_objective.owner = src
-
if ("custom")
var/expl = stripped_input(usr, "Custom objective:", "Objective", objective ? objective.explanation_text : "")
if (!expl)
@@ -850,46 +786,6 @@
objective.completed = !objective.completed
log_admin("[key_name(usr)] toggled the win state for [current]'s objective: [objective.explanation_text]")
- else if (href_list["handofgod"])
- switch(href_list["handofgod"])
- if("clear") //wipe handofgod status
- if((src in ticker.mode.red_deity_followers) || (src in ticker.mode.blue_deity_followers) || (src in ticker.mode.red_deity_prophets) || (src in ticker.mode.blue_deity_prophets))
- remove_hog_follower_prophet()
- current << "You have been brainwashed... again! Your faith is no more!"
- message_admins("[key_name_admin(usr)] has de-hand of god'ed [current].")
- log_admin("[key_name(usr)] has de-hand of god'ed [current].")
-
- if("red follower")
- make_Handofgod_follower("red")
- message_admins("[key_name_admin(usr)] has red follower'ed [current].")
- log_admin("[key_name(usr)] has red follower'ed [current].")
-
- if("red prophet")
- make_Handofgod_prophet("red")
- message_admins("[key_name_admin(usr)] has red prophet'ed [current].")
- log_admin("[key_name(usr)] has red prophet'ed [current].")
-
- if("blue follower")
- make_Handofgod_follower("blue")
- message_admins("[key_name_admin(usr)] has blue follower'ed [current].")
- log_admin("[key_name(usr)] has blue follower'ed [current].")
-
- if("blue prophet")
- make_Handofgod_prophet("blue")
- message_admins("[key_name_admin(usr)] has blue prophet'ed [current].")
- log_admin("[key_name(usr)] has blue prophet'ed [current].")
-
- if("red god")
- make_Handofgod_god("red")
- message_admins("[key_name_admin(usr)] has red god'ed [current].")
- log_admin("[key_name(usr)] has red god'ed [current].")
-
- if("blue god")
- make_Handofgod_god("blue")
- message_admins("[key_name_admin(usr)] has blue god'ed [current].")
- log_admin("[key_name(usr)] has blue god'ed [current].")
-
-
else if (href_list["revolution"])
switch(href_list["revolution"])
if("clear")
@@ -1563,119 +1459,6 @@
L = agent_landmarks[team]
H.loc = L.loc
-
-/datum/mind/proc/make_Handofgod_follower(colour)
- . = 0
- switch(colour)
- if("red")
- //Remove old allegiances
- if(src in ticker.mode.blue_deity_followers || src in ticker.mode.blue_deity_prophets)
- current << "You are no longer a member of the Blue cult!"
-
- ticker.mode.blue_deity_followers -= src
- ticker.mode.blue_deity_prophets -= src
- current.faction |= "red god"
- current.faction -= "blue god"
-
- if(src in ticker.mode.red_deity_prophets)
- current << "You have lost the connection with your deity, but you still believe in their grand design, You are no longer a prophet!"
- ticker.mode.red_deity_prophets -= src
-
- ticker.mode.red_deity_followers |= src
- current << "You are now a follower of the red cult's god!"
-
- special_role = "Hand of God: Red Follower"
- . = 1
- if("blue")
- //Remove old allegiances
- if(src in ticker.mode.red_deity_followers || src in ticker.mode.red_deity_prophets)
- current << "You are no longer a member of the Red cult!"
-
- ticker.mode.red_deity_followers -= src
- ticker.mode.red_deity_prophets -= src
- current.faction -= "red god"
- current.faction |= "blue god"
-
- if(src in ticker.mode.blue_deity_prophets)
- current << "You have lost the connection with your deity, but you still believe in their grand design, You are no longer a prophet!"
- ticker.mode.blue_deity_prophets -= src
-
- ticker.mode.blue_deity_followers |= src
- current << "You are now a follower of the blue cult's god!"
-
- special_role = "Hand of God: Blue Follower"
- . = 1
- else
- return 0
-
- ticker.mode.update_hog_icons_removed(src,"red")
- ticker.mode.update_hog_icons_removed(src,"blue")
- //ticker.mode.greet_hog_follower(src,colour)
- ticker.mode.update_hog_icons_added(src, colour)
-
-/datum/mind/proc/make_Handofgod_prophet(colour)
- . = 0
- switch(colour)
- if("red")
- //Remove old allegiances
-
- if(src in ticker.mode.blue_deity_followers || src in ticker.mode.blue_deity_prophets)
- current << "You are no longer a member of the Blue cult!"
- current.faction -= "blue god"
- current.faction |= "red god"
-
- ticker.mode.blue_deity_followers -= src
- ticker.mode.blue_deity_prophets -= src
- ticker.mode.red_deity_followers -= src
-
- ticker.mode.red_deity_prophets |= src
- current << "You are now a prophet of the red cult's god!"
-
- special_role = "Hand of God: Red Prophet"
- . = 1
- if("blue")
- //Remove old allegiances
-
- if(src in ticker.mode.red_deity_followers || src in ticker.mode.red_deity_prophets)
- current << "You are no longer a member of the Red cult!"
- current.faction -= "red god"
- current.faction |= "blue god"
-
- ticker.mode.red_deity_followers -= src
- ticker.mode.red_deity_prophets -= src
- ticker.mode.blue_deity_followers -= src
-
- ticker.mode.blue_deity_prophets |= src
- current << "You are now a prophet of the blue cult's god!"
-
- special_role = "Hand of God: Blue Prophet"
- . = 1
-
- else
- return 0
-
- ticker.mode.update_hog_icons_removed(src,"red")
- ticker.mode.update_hog_icons_removed(src,"blue")
- ticker.mode.greet_hog_follower(src,colour)
- ticker.mode.update_hog_icons_added(src, colour)
-
-/datum/mind/proc/make_Handofgod_god(colour)
- switch(colour)
- if("red")
- current.become_god("red")
- ticker.mode.add_god(src,"red")
- if("blue")
- current.become_god("blue")
- ticker.mode.add_god(src,"blue")
- else
- return 0
- ticker.mode.forge_deity_objectives(src)
- ticker.mode.remove_hog_follower(src,0)
- ticker.mode.update_hog_icons_added(src, colour)
-// ticker.mode.greet_hog_follower(src,colour)
- return 1
-
-
/datum/mind/proc/AddSpell(obj/effect/proc_holder/spell/S)
spell_list += S
S.action.Grant(current)
diff --git a/code/datums/mutations.dm b/code/datums/mutations.dm
index af57e091efa..6ac88edf050 100644
--- a/code/datums/mutations.dm
+++ b/code/datums/mutations.dm
@@ -187,7 +187,7 @@
/datum/mutation/human/cold_resistance/on_life(mob/living/carbon/human/owner)
if(owner.getFireLoss())
if(prob(1))
- owner.heal_organ_damage(0,1) //Is this really needed?
+ owner.heal_bodypart_damage(0,1) //Is this really needed?
/datum/mutation/human/x_ray
@@ -252,11 +252,11 @@
var/mob/new_mob
if(prob(95))
if(prob(50))
- new_mob = randmutb(owner)
+ new_mob = owner.randmutb()
else
- new_mob = randmuti(owner)
+ new_mob = owner.randmuti()
else
- new_mob = randmutg(owner)
+ new_mob = owner.randmutg()
if(new_mob && ismob(new_mob))
owner = new_mob
. = owner
diff --git a/code/datums/weather/weather.dm b/code/datums/weather/weather.dm
index c1afdea4ca6..a02e516c942 100644
--- a/code/datums/weather/weather.dm
+++ b/code/datums/weather/weather.dm
@@ -109,7 +109,8 @@
update_areas()
/datum/weather/proc/can_impact(mob/living/L) //Can this weather impact a mob?
- if(L.z != target_z)
+ var/turf/mob_turf = get_turf(L)
+ if(mob_turf.z != target_z)
return
if(immunity_type in L.weather_immunities)
return
diff --git a/code/datums/weather/weather_types.dm b/code/datums/weather/weather_types.dm
index 9f75bf714e6..6213eacc75c 100644
--- a/code/datums/weather/weather_types.dm
+++ b/code/datums/weather/weather_types.dm
@@ -150,15 +150,14 @@
if(H.dna && H.dna.species)
if(!(RADIMMUNE in H.dna.species.specflags))
if(prob(max(0,100-resist)))
- randmuti(H)
+ H.randmuti()
if(prob(50))
if(prob(90))
- randmutb(H)
+ H.randmutb()
else
- randmutg(H)
+ H.randmutg()
H.domutcheck()
L.rad_act(20,1)
-
/datum/weather/rad_storm/end()
if(..())
return
diff --git a/code/datums/wires/wires.dm b/code/datums/wires/wires.dm
index bf749e18e5f..cf4b1f1e862 100644
--- a/code/datums/wires/wires.dm
+++ b/code/datums/wires/wires.dm
@@ -1,121 +1,20 @@
-var/list/wire_colors = list( // http://www.crockford.com/wrrrld/color.html
- "aliceblue",
- "antiquewhite",
- "aqua",
- "aquamarine",
- "beige",
- "blanchedalmond",
+var/list/wire_colors = list(
"blue",
- "blueviolet",
"brown",
- "burlywood",
- "cadetblue",
- "chartreuse",
- "chocolate",
- "coral",
- "cornflowerblue",
- "cornsilk",
"crimson",
"cyan",
- "deeppink",
- "deepskyblue",
- "dimgray",
- "dodgerblue",
- "firebrick",
- "floralwhite",
- "forestgreen",
- "fuchsia",
- "gainsboro",
- "ghostwhite",
"gold",
- "goldenrod",
- "gray",
+ "grey",
"green",
- "greenyellow",
- "honeydew",
- "hotpink",
- "indianred",
- "ivory",
- "khaki",
- "lavender",
- "lavenderblush",
- "lawngreen",
- "lemonchiffon",
- "lightblue",
- "lightcoral",
- "lightcyan",
- "lightgoldenrodyellow",
- "lightgray",
- "lightgreen",
- "lightpink",
- "lightsalmon",
- "lightseagreen",
- "lightskyblue",
- "lightslategray",
- "lightsteelblue",
- "lightyellow",
- "lime",
- "limegreen",
- "linen",
"magenta",
- "maroon",
- "mediumaquamarine",
- "mediumblue",
- "mediumorchid",
- "mediumpurple",
- "mediumseagreen",
- "mediumslateblue",
- "mediumspringgreen",
- "mediumturquoise",
- "mediumvioletred",
- "mintcream",
- "mistyrose",
- "moccasin",
- "navajowhite",
- "oldlace",
- "olive",
- "olivedrab",
"orange",
- "orangered",
- "orchid",
- "palegoldenrod",
- "palegreen",
- "paleturquoise",
- "palevioletred",
- "papayawhip",
- "peachpuff",
- "peru",
"pink",
- "plum",
- "powderblue",
"purple",
"red",
- "rosybrown",
- "royalblue",
- "saddlebrown",
- "salmon",
- "sandybrown",
- "seagreen",
- "seashell",
- "sienna",
"silver",
- "skyblue",
- "slateblue",
- "slategray",
- "snow",
- "springgreen",
- "steelblue",
- "tan",
- "teal",
- "thistle",
- "tomato",
- "turquoise",
"violet",
- "wheat",
"white",
- "whitesmoke",
"yellow",
- "yellowgreen",
)
var/list/wire_color_directory = list()
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index ef0611a9cd7..e71b533d3c8 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -13,6 +13,10 @@
var/verb_exclaim = "exclaims"
var/verb_yell = "yells"
var/inertia_dir = 0
+ var/atom/inertia_last_loc
+ var/inertia_moving = 0
+ var/inertia_next_move = 0
+ var/inertia_move_delay = 5
var/pass_flags = 0
var/moving_diagonally = 0 //0: not doing a diagonal move. 1 and 2: doing the first/second step of the diagonal move
glide_size = 8
@@ -70,20 +74,16 @@
last_move = direct
setDir(direct)
-
- spawn(5) // Causes space drifting. /tg/station has no concept of speed, we just use 5
- if(loc && direct && last_move == direct)
- if(loc == newloc) //Remove this check and people can accelerate. Not opening that can of worms just yet.
- newtonian_move(last_move)
-
if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc,direct)) //movement failed due to buckled mob(s)
. = 0
//Called after a successful Move(). By this point, we've already moved
/atom/movable/proc/Moved(atom/OldLoc, Dir)
+ if (!inertia_moving)
+ inertia_next_move = world.time + inertia_move_delay
+ newtonian_move(Dir)
return 1
-
/atom/movable/Destroy()
. = ..()
if(loc)
@@ -146,7 +146,7 @@
reset_perspective(destination)
update_canmove() //if the mob was asleep inside a container and then got forceMoved out we need to make them fall.
-/mob/living/carbon/brain/forceMove(atom/destination)
+/mob/living/brain/forceMove(atom/destination)
if(container)
container.forceMove(destination)
else //something went very wrong.
@@ -172,13 +172,16 @@
if(pulledby)
return 1
+ if(throwing)
+ return 1
+
if(locate(/obj/structure/lattice) in range(1, get_turf(src))) //Not realistic but makes pushing things in space easier
return 1
return 0
-/atom/movable/proc/newtonian_move(direction) //Only moves the object if it's under no gravity
+/atom/movable/proc/newtonian_move(direction) //Only moves the object if it's under no gravity
if(!loc || Process_Spacemove(0))
inertia_dir = 0
return 0
@@ -186,10 +189,9 @@
inertia_dir = direction
if(!direction)
return 1
-
- var/old_dir = dir
- . = step(src, direction)
- setDir(old_dir)
+ inertia_last_loc = loc
+ SSspacedrift.processing[src] = src
+ return 1
/atom/movable/proc/checkpass(passflag)
return pass_flags&passflag
@@ -294,6 +296,7 @@
return 1
throw_impact(get_turf(src)) // we haven't hit something yet and we still must, let's hit the ground.
+ newtonian_move(init_dir)
return 1
/atom/movable/proc/hitcheck()
@@ -305,26 +308,6 @@
throw_impact(AM)
return 1
-//Overlays
-/atom/movable/overlay
- var/atom/master = null
- anchored = 1
-
-/atom/movable/overlay/New()
- verbs.Cut()
-
-/atom/movable/overlay/attackby(a, b, c)
- if (src.master)
- return src.master.attackby(a, b, c)
-
-/atom/movable/overlay/attack_paw(a, b, c)
- if (src.master)
- return src.master.attack_paw(a, b, c)
-
-/atom/movable/overlay/attack_hand(a, b, c)
- if (src.master)
- return src.master.attack_hand(a, b, c)
-
/atom/movable/proc/handle_buckled_mob_movement(newloc,direct)
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index fe14f5486f8..8cd3b7d2f89 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -61,10 +61,16 @@
//called when a carbon changes virus
/mob/living/carbon/proc/check_virus()
+ var/threat = 0
for(var/datum/disease/D in viruses)
- if((!(D.visibility_flags & HIDDEN_SCANNER)) && (D.severity != NONTHREAT))
- return 1
- return 0
+ if(!(D.visibility_flags & HIDDEN_SCANNER))
+ if (D.severity != NONTHREAT) //a buffing virus gets an icon
+ threat = 2
+ return threat //harmful viruses have priority
+ else
+ threat = 1 //aka good virus
+
+ return threat
//helper for getting the appropriate health status
/proc/RoundHealth(mob/living/M)
@@ -155,13 +161,16 @@
/mob/living/carbon/med_hud_set_status()
var/image/holder = hud_list[STATUS_HUD]
var/icon/I = icon(icon, icon_state, dir)
+ var/virus_state = check_virus()
holder.pixel_y = I.Height() - world.icon_size
if(status_flags & XENO_HOST)
holder.icon_state = "hudxeno"
else if(stat == DEAD || (status_flags & FAKEDEATH))
holder.icon_state = "huddead"
- else if(check_virus())
+ else if(virus_state == 2)
holder.icon_state = "hudill"
+ else if(virus_state == 1)
+ holder.icon_state = "hudbuff"
else
holder.icon_state = "hudhealthy"
diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm
index 59cbfc05095..53f07c8ffd8 100644
--- a/code/game/gamemodes/antag_spawner.dm
+++ b/code/game/gamemodes/antag_spawner.dm
@@ -165,7 +165,7 @@
var/mob/living/carbon/human/M = new/mob/living/carbon/human(T)
C.prefs.copy_to(M)
M.key = C.key
- M.mind.make_Nuke(null, nuke_code = null, 0, FALSE)
+ M.mind.make_Nuke(null, null, 0, FALSE)
var/newname = M.dna.species.random_name(M.gender,0,ticker.mode.nukeops_lastname)
M.mind.name = newname
M.real_name = newname
diff --git a/code/game/gamemodes/changeling/powers/regenerate.dm b/code/game/gamemodes/changeling/powers/regenerate.dm
index f14c1c95780..6d38a58cc47 100644
--- a/code/game/gamemodes/changeling/powers/regenerate.dm
+++ b/code/game/gamemodes/changeling/powers/regenerate.dm
@@ -13,21 +13,20 @@
/obj/effect/proc_holder/changeling/regenerate/sting_action(mob/living/user)
user << "You feel an itching, both inside and \
outside as your tissues knit and reknit."
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- H.restore_blood()
- H.remove_all_embedded_objects()
- var/list/missing = H.get_missing_limbs()
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ var/list/missing = C.get_missing_limbs()
if(missing.len)
playsound(user, 'sound/magic/Demon_consume.ogg', 50, 1)
- H.visible_message("[user]'s missing limbs \
+ C.visible_message("[user]'s missing limbs \
reform, making a loud, grotesque sound!",
"Your limbs regrow, making a \
loud, crunchy sound and giving you great pain!",
"You hear organic matter ripping \
and tearing!")
- H.emote("scream")
- H.regenerate_limbs(1)
-
- CHECK_DNA_AND_SPECIES(H)
- H.dna.species.on_species_gain(H, H.dna.species)
+ C.emote("scream")
+ C.regenerate_limbs(1)
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ H.restore_blood()
+ H.remove_all_embedded_objects()
diff --git a/code/game/gamemodes/changeling/powers/strained_muscles.dm b/code/game/gamemodes/changeling/powers/strained_muscles.dm
index 1c7ce8d11a5..79c707bff04 100644
--- a/code/game/gamemodes/changeling/powers/strained_muscles.dm
+++ b/code/game/gamemodes/changeling/powers/strained_muscles.dm
@@ -33,7 +33,7 @@
break
stacks++
- //user.take_organ_damage(stacks * 0.03, 0)
+ //user.take_bodypart_damage(stacks * 0.03, 0)
user.staminaloss += stacks * 1.3 //At first the changeling may regenerate stamina fast enough to nullify fatigue, but it will stack
if(stacks == 11) //Warning message that the stacks are getting too high
diff --git a/code/game/gamemodes/changeling/powers/tiny_prick.dm b/code/game/gamemodes/changeling/powers/tiny_prick.dm
index ea792abe4b3..9f3df575613 100644
--- a/code/game/gamemodes/changeling/powers/tiny_prick.dm
+++ b/code/game/gamemodes/changeling/powers/tiny_prick.dm
@@ -97,7 +97,7 @@
var/mob/living/carbon/C = target
if(C.status_flags & CANWEAKEN)
C.do_jitter_animation(500)
- C.take_organ_damage(20, 0) //The process is extremely painful
+ C.take_bodypart_damage(20, 0) //The process is extremely painful
target.visible_message("[target] begins to violenty convulse!","You feel a tiny prick and a begin to uncontrollably convulse!")
spawn(10)
diff --git a/code/game/gamemodes/clock_cult/clock_items.dm b/code/game/gamemodes/clock_cult/clock_items.dm
index d3164bffe80..a69220d5fe5 100644
--- a/code/game/gamemodes/clock_cult/clock_items.dm
+++ b/code/game/gamemodes/clock_cult/clock_items.dm
@@ -223,7 +223,7 @@
else
user << "That section of scripture is still locked!"
return 0
- for(var/S in subtypesof(/datum/clockwork_scripture))
+ for(var/S in sortList(subtypesof(/datum/clockwork_scripture), /proc/cmp_clockscripture_priority))
var/datum/clockwork_scripture/C = S
if(initial(C.tier) == scripture_tier)
available_scriptures += "[initial(C.name)] ([initial(C.descname)])"
@@ -265,121 +265,73 @@
universe and Reebe (the Celestial Derelict) can be created and utilized. This is typically done via the creation of a slab akin to the one you are holding right now. The slabs tap into the \
tidal flow of energy and information keeping Reebe sealed and presents it as meaningless images to preserve sanity. This slab can utilize the power in many different ways.
\
\
- This is done through Components - pieces of the Justiciar's body that have since fallen off in the countless years since his imprisonment. Ratvar's unfortunate condition results \
- in the fragmentation of his body. These components still house great power on their own, and can slowly be drawn from Reebe by links capable of doing so. The most basic of these links lies \
- in the clockwork slab, which will slowly generate components over time - one component of a random type is produced every 1 minute and 30 seconds, plus 30 seconds per each servant above 5, \
- which is obviously inefficient. There are other ways to create these components through scripture and certain structures.
\
+ This is done through Components - pieces of the Justiciar's body that have since fallen off in the countless years since his imprisonment. Ratvar's unfortunate condition results \
+ in the fragmentation of his body. These components still house great power on their own, and can slowly be drawn from Reebe by links capable of doing so. \
+ The most basic of these links lies in the clockwork slab, which will slowly generate components over time - one component of a random type is produced every 1 minute and 30 seconds, plus 30 seconds per each servant above 5, \
+ which is obviously inefficient. There are other, more efficient, ways to create these components through scripture and certain structures.
\
\
- In addition to their ability to pull components, slabs also possess other functionalities...
\
+ In addition to their ability to generate components, slabs also possess other functionalities...
\
\
- The first functionality of the slab is Recital. This allows you to consume components either from your slab or from the global cache (more on that in the scripture list) to perform \
- effects usually considered magical in nature. Effects vary considerably - you might drain the power of nearby APCs, cause mass confusion, or force people to walk. Nevertheless, scripture \
- is extremely important to a successful takeover.
\
+ The first functionality of the slab is Recital. This allows you to consume components either from your slab or from the global cache (more on that in the scripture list) to perform \
+ effects usually considered magical in nature. \
+ Effects vary considerably, including mass conversion, construction of various structures, or causing a massive global hallucination. Nevertheless, scripture is extremely important to a successful takeover.
\
\
- The second functionality of the clockwork slab is Recollection, which will display this guide.
\
+ The second functionality of the clockwork slab is Recollection, which will display this guide.
\
\
The third to fifth functionalities are several buttons in the top left while holding the slab, from left to right, they are: \
- Hierophant Network, which allows communication to other servants. \
- Guvax, which simply allows you to quickly invoke the Guvax scripture. \
- Vanguard, which, like Guvax, simply allows you to quickly invoke the Vanguard scripture.
\
+ Hierophant Network, which allows communication to other servants. \
+ Guvax, which simply allows you to quickly invoke the Guvax scripture. \
+ Vanguard, which, like Guvax, simply allows you to quickly invoke the Vanguard scripture.
\
\
Examine the slab for component amount information.
\
\
- A complete list of scripture, its effects, and its requirements can be found below. Note that anything above a driver always consumes the components listed unless otherwise \
- specified.
"
text += text_to_add
@@ -407,7 +359,7 @@
var/message = stripped_input(user, "Enter a message to send to your fellow servants.", "Hierophant")
if(!message || !user || !user.canUseTopic(src))
return 0
- clockwork_say(user, text2ratvar("Servants, hear my words. [message]"), TRUE)
+ clockwork_say(user, text2ratvar("Servants, hear my words. [html_decode(message)]"), TRUE)
titled_hierophant_message(user, message)
return 1
@@ -616,7 +568,7 @@
icon = 'icons/obj/clothing/clockwork_garb.dmi'
icon_state = "clockwork_helmet"
w_class = 3
- armor = list(melee = 80, bullet = 50, laser = -15, energy = 5, bomb = 35, bio = 0, rad = 0)
+ armor = list(melee = 80, bullet = 50, laser = -15, energy = 0, bomb = 35, bio = 0, rad = 0)
/obj/item/clothing/head/helmet/clockwork/equipped(mob/living/user, slot)
..()
@@ -647,7 +599,7 @@
icon_state = "clockwork_cuirass"
w_class = 4
body_parts_covered = CHEST|GROIN|LEGS
- armor = list(melee = 80, bullet = 50, laser = -15, energy = 5, bomb = 35, bio = 0, rad = 0)
+ armor = list(melee = 80, bullet = 50, laser = -15, energy = 0, bomb = 35, bio = 0, rad = 0)
allowed = list(/obj/item/clockwork, /obj/item/clothing/glasses/wraith_spectacles, /obj/item/clothing/glasses/judicial_visor, /obj/item/device/mmi/posibrain/soul_vessel)
/obj/item/clothing/suit/armor/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
@@ -686,7 +638,7 @@
burn_state = FIRE_PROOF
siemens_coefficient = 0
permeability_coefficient = 0.05
- armor = list(melee = 80, bullet = 50, laser = -15, energy = 5, bomb = 35, bio = 0, rad = 0)
+ armor = list(melee = 80, bullet = 50, laser = -15, energy = 0, bomb = 35, bio = 0, rad = 0)
/obj/item/clothing/gloves/clockwork/mob_can_equip(mob/M, mob/equipper, slot, disable_warning = 0)
if(equipper && !is_servant_of_ratvar(equipper))
@@ -820,13 +772,13 @@
impale_cooldown = world.time + initial(impale_cooldown)
attack_cooldown = world.time + initial(attack_cooldown)
if(target)
- PoolOrNew(/obj/effect/overlay/temp/bloodsplatter, list(get_turf(target), get_dir(user, target)))
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/bloodsplatter, list(get_turf(target), get_dir(user, target)))
target.Stun(2)
user << "You prepare to remove your ratvarian spear from [target]..."
var/remove_verb = pick("pull", "yank", "drag")
if(do_after(user, 10, 1, target))
var/turf/T = get_turf(target)
- var/obj/effect/overlay/temp/bloodsplatter/B = PoolOrNew(/obj/effect/overlay/temp/bloodsplatter, list(T, get_dir(target, user)))
+ var/obj/effect/overlay/temp/dir_setting/bloodsplatter/B = PoolOrNew(/obj/effect/overlay/temp/dir_setting/bloodsplatter, list(T, get_dir(target, user)))
playsound(T, 'sound/misc/splort.ogg', 200, 1)
playsound(T, 'sound/weapons/pierce.ogg', 200, 1)
if(target.stat != CONSCIOUS)
@@ -1117,7 +1069,15 @@
/obj/item/clockwork/component/replicant_alloy/examine(mob/user)
..()
if(is_servant_of_ratvar(user))
- user << "Can be used to fuel Clockwork Proselytizers and Mending Motors."
+ user << "Can be used to fuel Clockwork Proselytizers and Mending Motors, or shaped into brass sheets."
+
+/obj/item/clockwork/component/replicant_alloy/attack_self(mob/user)
+ if(is_servant_of_ratvar(user))
+ var/obj/item/stack/sheet/brass/B = new /obj/item/stack/sheet/brass(get_turf(src), 10)
+ user.unEquip(src, TRUE)
+ user.put_in_hands(B)
+ user << "You shape the alloy into some brass sheets."
+ qdel(src)
/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment
name = "smashed anima fragment"
diff --git a/code/game/gamemodes/clock_cult/clock_machines.dm b/code/game/gamemodes/clock_cult/clock_machines.dm
index c682142aa5d..4509cf916c8 100644
--- a/code/game/gamemodes/clock_cult/clock_machines.dm
+++ b/code/game/gamemodes/clock_cult/clock_machines.dm
@@ -138,8 +138,8 @@
active_icon = "mending_motor"
inactive_icon = "mending_motor_inactive"
construction_value = 20
- max_health = 150
- health = 150
+ max_health = 125
+ health = 125
break_message = "The prism collapses with a heavy thud!"
debris = list(/obj/item/clockwork/alloy_shards/small = 5, \
/obj/item/clockwork/alloy_shards/medium = 1, \
@@ -439,46 +439,14 @@
CHECK_TICK
for(var/M in atoms_to_test)
- if(istype(M, /obj/machinery/power/apc))
- var/obj/machinery/power/apc/A = M
- if(A.cell && A.cell.charge)
- successfulprocess = TRUE
- playsound(A, "sparks", 50, 1)
- flick("apc-spark", A)
- power_drained += min(A.cell.charge, 100)
- A.cell.charge = max(0, A.cell.charge - 100)
- if(!A.cell.charge && !A.shorted)
- A.shorted = 1
- A.visible_message("The [A.name]'s screen blurs with static.")
- A.update()
- A.update_icon()
- else if(istype(M, /obj/machinery/power/smes))
- var/obj/machinery/power/smes/S = M
- if(S.charge)
- successfulprocess = TRUE
- power_drained += min(S.charge, 500)
- S.charge = max(0, S.charge - 50000) //SMES units contain too much power and could run an interdiction lens basically forever, or provide power forever
- if(!S.charge && !S.panel_open)
- S.panel_open = TRUE
- S.icon_state = "[initial(S.icon_state)]-o"
- var/datum/effect_system/spark_spread/spks = new(get_turf(S))
- spks.set_up(10, 0, get_turf(S))
- spks.start()
- S.visible_message("[S]'s panel flies open with a flurry of sparks.")
- S.update_icon()
- else if(isrobot(M))
- var/mob/living/silicon/robot/R = M
- if(!is_servant_of_ratvar(R) && R.cell && R.cell.charge)
- successfulprocess = TRUE
- power_drained += min(R.cell.charge, 200)
- R.cell.charge = max(0, R.cell.charge - 200)
- R << "ERROR: Power loss detected!"
- var/datum/effect_system/spark_spread/spks = new(get_turf(R))
- spks.set_up(3, 0, get_turf(R))
- spks.start()
+ var/atom/movable/A = M
+ power_drained += A.power_drain(TRUE)
CHECK_TICK
+ if(power_drained)
+ successfulprocess = TRUE
+
if(!return_power(power_drained) || power_drained < 50) //failed to return power drained or too little power to return
successfulprocess = FALSE
if(try_use_power(disrupt_cost) && total_accessable_power() >= disrupt_cost) //if we can disable at least one object
@@ -537,8 +505,8 @@
active_icon = "obelisk"
inactive_icon = "obelisk_inactive"
construction_value = 20
- max_health = 200
- health = 200
+ max_health = 150
+ health = 150
break_message = "The obelisk falls to the ground, undamaged!"
debris = list(/obj/item/clockwork/alloy_shards/small = 3, \
/obj/item/clockwork/component/hierophant_ansible/obelisk = 1)
diff --git a/code/game/gamemodes/clock_cult/clock_mobs.dm b/code/game/gamemodes/clock_cult/clock_mobs.dm
index d8d3025e088..4793b33766d 100644
--- a/code/game/gamemodes/clock_cult/clock_mobs.dm
+++ b/code/game/gamemodes/clock_cult/clock_mobs.dm
@@ -38,8 +38,8 @@
health = 90
maxHealth = 90
speed = -1
- melee_damage_lower = 20
- melee_damage_upper = 20
+ melee_damage_lower = 18
+ melee_damage_upper = 18
attacktext = "crushes"
attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg'
loot = list(/obj/item/clockwork/component/replicant_alloy/smashed_anima_fragment)
diff --git a/code/game/gamemodes/clock_cult/clock_powerdrain.dm b/code/game/gamemodes/clock_cult/clock_powerdrain.dm
new file mode 100644
index 00000000000..3f2ae58d4ae
--- /dev/null
+++ b/code/game/gamemodes/clock_cult/clock_powerdrain.dm
@@ -0,0 +1,54 @@
+//horrifying power drain proc made for clockcult's power drain in lieu of six istypes or six for(x in view) loops
+/atom/movable/proc/power_drain(clockcult_user)
+ return 0
+
+/obj/machinery/power/apc/power_drain(clockcult_user)
+ if(cell && cell.charge)
+ playsound(src, "sparks", 50, 1)
+ flick("apc-spark", src)
+ . += min(cell.charge, 500)
+ cell.charge = max(0, cell.charge - 500) //Better than a power sink!
+ if(!cell.charge && !shorted)
+ shorted = 1
+ visible_message("The [name]'s screen blurs with static.")
+ update()
+ update_icon()
+
+/obj/machinery/power/smes/power_drain(clockcult_user)
+ if(charge)
+ . += min(charge, 500)
+ charge = max(0, charge - 50000)
+ if(!charge && !panel_open)
+ panel_open = TRUE
+ icon_state = "[initial(icon_state)]-o"
+ var/datum/effect_system/spark_spread/spks = new(get_turf(src))
+ spks.set_up(10, 0, get_turf(src))
+ spks.start()
+ visible_message("[src]'s panel flies open with a flurry of spark")
+ update_icon()
+
+/obj/item/weapon/stock_parts/cell/power_drain(clockcult_user)
+ if(charge)
+ . += min(charge, 500)
+ charge = use(max(0, charge - 500))
+ updateicon()
+
+/obj/machinery/light/power_drain(clockcult_user)
+ if(on)
+ playsound(src, 'sound/effects/light_flicker.ogg', 50, 1)
+ flicker(2)
+ . += 50
+
+/mob/living/silicon/robot/power_drain(clockcult_user)
+ if((!clockcult_user || !is_servant_of_ratvar(src)) && cell && cell.charge)
+ . += min(cell.charge, 500)
+ cell.charge = max(0, cell.charge - 500)
+ src << "ERROR: Power loss detected!"
+ spark_system.start()
+
+/obj/mecha/power_drain(clockcult_user)
+ if((!clockcult_user || !occupant || occupant && !is_servant_of_ratvar(occupant)) && cell && cell.charge)
+ . += min(cell.charge, 500)
+ cell.charge = max(0, cell.charge - 500)
+ occupant_message("Power loss detected!")
+ spark_system.start()
\ No newline at end of file
diff --git a/code/game/gamemodes/clock_cult/clock_proselytizer.dm b/code/game/gamemodes/clock_cult/clock_proselytizer.dm
index a00443d6cfb..404452d064d 100644
--- a/code/game/gamemodes/clock_cult/clock_proselytizer.dm
+++ b/code/game/gamemodes/clock_cult/clock_proselytizer.dm
@@ -55,7 +55,7 @@
playsound(src, 'sound/items/Deconstruct.ogg', 50, 1)
new/obj/item/clockwork/component/replicant_alloy(user.loc)
user << "You force [stored_alloy ? "some":"all"] of the alloy in [src]'s compartments to reform and solidify. \
- It now contains [stored_alloy]/[max_alloy] units of liquified alloy."
+ It now contains [stored_alloy]/[max_alloy] units of liquified alloy."
/obj/item/clockwork/clockwork_proselytizer/attackby(obj/item/I, mob/living/user, params)
if(istype(I, /obj/item/clockwork/component/replicant_alloy) && is_servant_of_ratvar(user) && uses_alloy)
@@ -79,16 +79,17 @@
proselytize(target, user)
/obj/item/clockwork/clockwork_proselytizer/proc/modify_stored_alloy(amount)
- if(can_use_alloy(0)) //Ratvar makes it free
+ if(can_use_alloy(RATVAR_ALLOY_CHECK)) //Ratvar makes it free
amount = 0
stored_alloy = Clamp(stored_alloy + amount, 0, max_alloy)
return 1
/obj/item/clockwork/clockwork_proselytizer/proc/can_use_alloy(amount)
- if(ratvar_awakens || !uses_alloy)
- return TRUE
- if(!amount) //functions thus as a check for if ratvar is up/it doesn't use alloy if no amount is provided
- return FALSE
+ if(amount == RATVAR_ALLOY_CHECK)
+ if(ratvar_awakens || !uses_alloy)
+ return TRUE
+ else
+ return FALSE
if(stored_alloy - amount < 0)
return FALSE
if(stored_alloy - amount > max_alloy)
@@ -100,10 +101,9 @@
return 0
var/target_type = target.type
var/list/proselytize_values = target.proselytize_vals(user, src) //relevant values for proselytizing stuff, given as an associated list
- if(proselytize_values == TRUE) //if we get true, fail, but don't send a message for whatever reason
- return 0
if(!islist(proselytize_values))
- user << "[target] cannot be proselytized!"
+ if(proselytize_values != TRUE) //if we get true, fail, but don't send a message for whatever reason
+ user << "[target] cannot be proselytized!"
return 0
if(repairing)
user << "You are currently repairing [repairing] with [src]!"
@@ -118,7 +118,7 @@
user << "You have too much liquified alloy stored to proselytize [target]!"
return 0
- if(can_use_alloy(0)) //Ratvar makes it faster
+ if(can_use_alloy(RATVAR_ALLOY_CHECK)) //Ratvar makes it faster
proselytize_values["operation_time"] *= 0.5
user.visible_message("[user]'s [name] begins tearing apart [target]!", "You begin proselytizing [target]...")
@@ -171,7 +171,7 @@
/turf/open/floor/plating/asteroid/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
-/turf/open/floor/plating/ash/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
+/turf/open/floor/plating/ashplanet/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return FALSE
/turf/open/floor/plating/lava/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
@@ -185,22 +185,44 @@
return list("operation_time" = 100, "new_obj_type" = /turf/closed/wall/clockwork, "alloy_cost" = REPLICANT_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
/obj/item/stack/rods/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
- if(!proselytizer.metal_to_alloy)
- return 0
- var/prosel_costtime = -amount
- return list("operation_time" = -prosel_costtime, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = prosel_costtime, "spawn_dir" = SOUTH)
+ if(get_amount() >= 10)
+ var/sheets_to_make = round(get_amount() * 0.1)
+ var/remainder = get_amount() - (sheets_to_make * 10)
+ if(remainder)
+ new type(loc, remainder)
+ return list("operation_time" = 0, "new_obj_type" = /obj/item/stack/sheet/brass, "alloy_cost" = 0, "spawn_dir" = sheets_to_make, "dir_in_new" = TRUE)
+ else
+ user << "You need at least 10 rods to convert into brass."
+ return TRUE
/obj/item/stack/sheet/metal/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
- if(!proselytizer.metal_to_alloy)
- return 0
- var/prosel_costtime = -amount*2
- return list("operation_time" = -prosel_costtime, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = prosel_costtime, "spawn_dir" = SOUTH)
+ if(src.get_amount() >= 5)
+ var/sheets_to_make = round(src.get_amount() * 0.2)
+ var/remainder = src.get_amount() - (sheets_to_make * 5)
+ if(remainder)
+ new type(loc, remainder)
+ return list("operation_time" = 0, "new_obj_type" = /obj/item/stack/sheet/brass, "alloy_cost" = 0, "spawn_dir" = sheets_to_make, "dir_in_new" = TRUE)
+ else
+ user << "You need at least 5 sheets of metal to convert into brass."
+ return TRUE
/obj/item/stack/sheet/plasteel/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
+ if(get_amount() >= 10)
+ var/sheets_to_make = round(get_amount() * 0.4)
+ var/remainder = get_amount() - (sheets_to_make * 2.5)
+ if(remainder)
+ new type(loc, remainder)
+ return list("operation_time" = 0, "new_obj_type" = /obj/item/stack/sheet/brass, "alloy_cost" = 0, "spawn_dir" = sheets_to_make, "dir_in_new" = TRUE)
+ else
+ user << "You need at least 10 sheets of plasteel to convert into brass."
+ return TRUE
+
+/obj/item/stack/sheet/brass/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
if(!proselytizer.metal_to_alloy)
- return 0
- var/prosel_costtime = -amount*3
- return list("operation_time" = -prosel_costtime, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = prosel_costtime, "spawn_dir" = SOUTH)
+ return FALSE
+ var/prosel_cost = -amount*10
+ var/prosel_time = -amount*1
+ return list("operation_time" = -prosel_time, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = prosel_cost, "spawn_dir" = SOUTH)
/obj/machinery/door/airlock/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
var/doortype = /obj/machinery/door/airlock/clockwork
@@ -319,7 +341,7 @@
return
/obj/structure/destructible/clockwork/wall_gear/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
- return list("operation_time" = 10, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -REPLICANT_WALL_MINUS_FLOOR, "spawn_dir" = SOUTH)
+ return list("operation_time" = 10, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -REPLICANT_GEAR, "spawn_dir" = SOUTH)
/obj/item/clockwork/alloy_shards/proselytize_vals(mob/living/user, obj/item/clockwork/clockwork_proselytizer/proselytizer)
return list("operation_time" = 5, "new_obj_type" = /obj/effect/overlay/temp/ratvar/beam/itemconsume, "alloy_cost" = -REPLICANT_STANDARD, "spawn_dir" = SOUTH)
diff --git a/code/game/gamemodes/clock_cult/clock_scripture.dm b/code/game/gamemodes/clock_cult/clock_scripture.dm
index 28f3574c91c..ad2615e54a1 100644
--- a/code/game/gamemodes/clock_cult/clock_scripture.dm
+++ b/code/game/gamemodes/clock_cult/clock_scripture.dm
@@ -25,6 +25,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
var/multiple_invokers_used = FALSE //If scripture requires more than one invoker
var/multiple_invokers_optional = FALSE //If scripture can have multiple invokers to bolster its effects
var/tier = SCRIPTURE_PERIPHERAL //The scripture's tier
+ var/sort_priority = 1 //what position the scripture should have in a list of scripture. Should be based off of component costs/reqs, but you can't initial() lists.
//components the scripture used from a slab
var/list/used_slab_components = list("belligerent_eye" = 0, "vanguard_cogwheel" = 0, "guvax_capacitor" = 0, "replicant_alloy" = 0, "hierophant_ansible" = 0)
@@ -160,6 +161,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
var/observer_message
var/one_per_tile = FALSE
var/prevent_path
+ var/space_allowed = FALSE
/datum/clockwork_scripture/create_object/New()
..()
@@ -167,7 +169,11 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
prevent_path = object_path
/datum/clockwork_scripture/create_object/check_special_requirements()
- if(one_per_tile && (locate(prevent_path) in get_turf(invoker)))
+ var/turf/T = get_turf(invoker)
+ if(!space_allowed && istype(T, /turf/open/space))
+ invoker << "You need solid ground to place this object!"
+ return 0
+ if(one_per_tile && (locate(prevent_path) in T))
invoker << "You can only place one of this object on each tile!"
return 0
return 1
@@ -194,19 +200,22 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
required_components = list("belligerent_eye" = 1)
usage_tip = "Useful for crowd control in a populated area and disrupting mass movement."
tier = SCRIPTURE_DRIVER
+ sort_priority = 1
+ var/noncultist_damage = 2 //damage per chant to noncultists
+ var/cultist_damage = 8 //damage per chant to non-walking cultists
/datum/clockwork_scripture/channeled/belligerent/chant_effects(chant_number)
for(var/mob/living/carbon/C in hearers(7, invoker))
if(!is_servant_of_ratvar(C) && !C.null_rod_check() && C.get_num_legs()) //you have legs right
- C.apply_damage(1, BURN, "l_leg")
- C.apply_damage(1, BURN, "r_leg")
+ C.apply_damage(noncultist_damage * 0.5, BURN, "l_leg")
+ C.apply_damage(noncultist_damage * 0.5, BURN, "r_leg")
if(C.m_intent != "walk")
if(!iscultist(C))
C << "Your legs shiver with pain!"
else //Cultists take extra burn damage
C << "Your legs burn with pain!"
- C.apply_damage(4, BURN, "l_leg")
- C.apply_damage(4, BURN, "r_leg")
+ C.apply_damage(cultist_damage * 0.5, BURN, "l_leg")
+ C.apply_damage(cultist_damage * 0.5, BURN, "r_leg")
C.m_intent = "walk"
@@ -225,6 +234,8 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
creator_message = "You form a judicial visor, which is capable of smiting the unworthy."
usage_tip = "The visor has a thirty-second cooldown once used, and the marker it creates has a delay of 3 seconds before exploding."
tier = SCRIPTURE_DRIVER
+ space_allowed = TRUE
+ sort_priority = 2
@@ -238,6 +249,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
required_components = list("vanguard_cogwheel" = 1)
usage_tip = "You cannot reactivate Vanguard while still shielded by it."
tier = SCRIPTURE_DRIVER
+ sort_priority = 3
/datum/clockwork_scripture/vanguard/check_special_requirements()
if(islist(invoker.stun_absorption) && invoker.stun_absorption["vanguard"] && invoker.stun_absorption["vanguard"]["end_time"] > world.time)
@@ -254,13 +266,14 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
/datum/clockwork_scripture/sentinels_compromise //Sentinel's Compromise: Allows the invoker to select a nearby servant convert their brute and burn damage into half as much toxin damage.
descname = "Convert Brute/Burn to Half Toxin"
name = "Sentinel's Compromise"
- desc = "Heals all brute and burn damage on a nearby living, friendly servant, but deals 50% of that amount as toxin damage."
+ desc = "Heals all brute and burn damage on a nearby living, friendly servant, but deals 50% of the damage they had as toxin damage."
invocations = list("Mend the wounds of...", "...my inferior flesh.")
channel_time = 30
required_components = list("vanguard_cogwheel" = 2)
consumed_components = list("vanguard_cogwheel" = 1)
usage_tip = "The Compromise is very fast to invoke."
tier = SCRIPTURE_DRIVER
+ sort_priority = 4
/datum/clockwork_scripture/sentinels_compromise/scripture_effects()
var/list/nearby_cultists = list()
@@ -303,6 +316,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
required_components = list("guvax_capacitor" = 1)
usage_tip = "Only works on those in melee range and does not penetrate mindshield implants. Much more efficient than a Sigil of Submission at low Servant amounts."
tier = SCRIPTURE_DRIVER
+ sort_priority = 5
/datum/clockwork_scripture/guvax/run_scripture()
var/servants = 0
@@ -338,6 +352,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
consumed_components = list("guvax_capacitor" = 1)
usage_tip = "Useful for fleeing attackers, as few will be able to follow someone using this scripture."
tier = SCRIPTURE_DRIVER
+ sort_priority = 6
var/flee_time = 47 //allow fleeing for 5 seconds
var/grace_period = 3 //very short grace period so you don't have to stop immediately
var/datum/progressbar/progbar
@@ -373,11 +388,12 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
name = "Replicant"
desc = "Creates a new clockwork slab."
invocations = list("Metal, become greater!")
- channel_time = 0
+ channel_time = 10
required_components = list("replicant_alloy" = 1)
whispered = TRUE
usage_tip = "This is inefficient as a way to produce components, as the slab produced must be held by someone with no other slabs to produce components."
tier = SCRIPTURE_DRIVER
+ sort_priority = 7
/datum/clockwork_scripture/replicant/scripture_effects()
invoker << "You copy a piece of replicant alloy and command it into a new slab." //No visible message, for stealth purposes
@@ -401,6 +417,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "Slabs will draw components from the global cache after the slab's own repositories, making caches very efficient."
tier = SCRIPTURE_DRIVER
one_per_tile = TRUE
+ sort_priority = 8
/datum/clockwork_scripture/create_object/tinkerers_cache/New()
var/cache_cost_increase = min(round(clockwork_caches*0.2), 5)
@@ -426,6 +443,8 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
creator_message = "You form a pair of wraith spectacles, which will grant true sight when worn."
usage_tip = "\"True sight\" means that you are able to see through walls and in darkness."
tier = SCRIPTURE_DRIVER
+ space_allowed = TRUE
+ sort_priority = 9
@@ -443,6 +462,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "The sigil, while fairly powerful in its stun, does not induce muteness in its victim."
tier = SCRIPTURE_DRIVER
one_per_tile = TRUE
+ sort_priority = 10
/////////////
// SCRIPTS //
@@ -462,6 +482,8 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "Although powerful, the warden is very weak and should optimally be placed behind barricades."
tier = SCRIPTURE_SCRIPT
one_per_tile = TRUE
+ space_allowed = TRUE
+ sort_priority = 11
/datum/clockwork_scripture/create_object/ocular_warden/check_special_requirements()
for(var/obj/structure/destructible/clockwork/ocular_warden/W in range(3, invoker))
@@ -481,6 +503,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
consumed_components = list("guvax_capacitor" = 1, "hierophant_ansible" = 1)
usage_tip = "If standing on a Sigil of Transmission, will transfer power to it. Augumented limbs will also be healed unless above a very high threshhold."
tier = SCRIPTURE_SCRIPT
+ sort_priority = 20
var/total_power_drained = 0
var/power_damage_threshhold = 3000
var/augument_damage_threshhold = 6000
@@ -488,47 +511,8 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
/datum/clockwork_scripture/channeled/volt_void/chant_effects(chant_number)
playsound(invoker, 'sound/effects/EMPulse.ogg', 50, 1)
var/power_drained = 0
- for(var/obj/machinery/power/apc/A in view(7, invoker))
- if(A.cell && A.cell.charge)
- playsound(A, "sparks", 50, 1)
- flick("apc-spark", A)
- power_drained += min(A.cell.charge, 500)
- A.cell.charge = max(0, A.cell.charge - 500) //Better than a power sink!
- if(!A.cell.charge && !A.shorted)
- A.shorted = 1
- A.visible_message("The [A.name]'s screen blurs with static.")
- A.update()
- A.update_icon()
- for(var/obj/machinery/power/smes/S in view(7, invoker))
- if(S.charge)
- power_drained += min(S.charge, 500)
- S.charge = max(0, S.charge - 50000)
- if(!S.charge && !S.panel_open)
- S.panel_open = TRUE
- S.icon_state = "[initial(S.icon_state)]-o"
- var/datum/effect_system/spark_spread/spks = new(get_turf(S))
- spks.set_up(10, 0, get_turf(S))
- spks.start()
- S.visible_message("[S]'s panel flies open with a flurry of sparks.")
- S.update_icon()
- for(var/obj/item/weapon/stock_parts/cell/C in view(7, invoker))
- if(C.charge)
- power_drained += min(C.charge, 500)
- C.charge = C.use(max(0, C.charge - 500))
- C.updateicon()
- for(var/obj/machinery/light/L in view(7, invoker))
- if(L.on)
- playsound(L, 'sound/effects/light_flicker.ogg', 50, 1)
- L.flicker(2)
- power_drained += 50
- for(var/mob/living/silicon/robot/R in view(7, invoker))
- if(!is_servant_of_ratvar(R) && R.cell && R.cell.charge)
- power_drained += min(R.cell.charge, 500)
- R.cell.charge = max(0, R.cell.charge - 500)
- R << "ERROR: Power loss detected!"
- var/datum/effect_system/spark_spread/spks = new(get_turf(R))
- spks.set_up(3, 0, get_turf(R))
- spks.start()
+ for(var/atom/movable/A in view(7, invoker))
+ power_drained += A.power_drain(TRUE)
var/obj/effect/clockwork/sigil/transmission/ST = locate(/obj/effect/clockwork/sigil/transmission) in get_turf(invoker)
if(ST && power_drained >= 50)
var/sigil_drain = 0
@@ -546,10 +530,12 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
var/mob/living/carbon/human/H = invoker
for(var/X in H.bodyparts)
var/obj/item/bodypart/BP = X
- if(ratvar_awakens || BP.status == ORGAN_ROBOTIC && total_power_drained < augument_damage_threshhold) //if ratvar is alive, it won't damage and will always heal augumented limbs
- BP.heal_damage(power_damage, power_damage, 1) //heals one point of burn and brute for every ~100W drained on augumented limbs
+ if(ratvar_awakens || (BP.status == BODYPART_ROBOTIC && total_power_drained < augument_damage_threshhold)) //if ratvar is alive, it won't damage and will always heal augumented limbs
+ if(BP.heal_damage(power_damage, power_damage, 1, 0)) //heals one point of burn and brute for every ~100W drained on augumented limbs
+ H.update_damage_overlays()
else
- BP.take_damage(0, power_damage)
+ if(BP.take_damage(0, power_damage))
+ H.update_damage_overlays()
else if(isanimal(invoker))
var/mob/living/simple_animal/A = invoker
A.adjustHealth(-power_damage) //if a simple animal is using volt void, just heal it
@@ -570,6 +556,8 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
creator_message = "You form a clockwork proselytizer, which is already pre-loaded with a small amount of replicant alloy."
usage_tip = "Clockwork walls cause adjacent tinkerer's caches to generate components passively, making them a vital tool. Clockwork floors heal servants standing on them."
tier = SCRIPTURE_SCRIPT
+ space_allowed = TRUE
+ sort_priority = 17
@@ -586,6 +574,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
tier = SCRIPTURE_SCRIPT
multiple_invokers_used = TRUE
multiple_invokers_optional = TRUE
+ sort_priority = 14
/datum/clockwork_scripture/fellowship_armory/run_scripture()
for(var/mob/living/L in range(1, invoker))
@@ -619,12 +608,13 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
whispered = TRUE
usage_tip = "You can impale human targets with the spear by pulling them, then attacking. Throwing the spear at a mob will do massive damage and stun them, but break the spear."
tier = SCRIPTURE_SCRIPT
+ sort_priority = 18
/datum/clockwork_scripture/function_call/check_special_requirements()
for(var/datum/action/innate/function_call/F in invoker.actions)
invoker << "You have already bound a Ratvarian spear to yourself!"
return 0
- return ishuman(invoker)
+ return invoker.can_hold_items()
/datum/clockwork_scripture/function_call/scripture_effects()
invoker.visible_message("A shimmer of yellow light infuses [invoker]!", \
@@ -647,6 +637,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
multiple_invokers_optional = TRUE
usage_tip = "This gateway is strictly one-way and will only allow things through the invoker's portal."
tier = SCRIPTURE_SCRIPT
+ sort_priority = 19
/datum/clockwork_scripture/spatial_gateway/check_special_requirements()
if(!isturf(invoker.loc))
@@ -682,7 +673,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
name = "Soul Vessel"
desc = "Forms an ancient positronic brain with an overriding directive to serve Ratvar."
invocations = list("Herd the souls of...", "...the blasphemous damned!")
- channel_time = 20
+ channel_time = 30
required_components = list("vanguard_cogwheel" = 1, "guvax_capacitor" = 2)
consumed_components = list("vanguard_cogwheel" = 1, "guvax_capacitor" = 1)
whispered = TRUE
@@ -690,6 +681,8 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
creator_message = "You form a soul vessel, which can be used in-hand to attract spirits, or used on an unconscious or dead human to extract their consciousness."
usage_tip = "The vessel can be used as a teleport target for Spatial Gateway, though it is generally better-used by placing it in a shell."
tier = SCRIPTURE_SCRIPT
+ space_allowed = TRUE
+ sort_priority = 16
@@ -698,7 +691,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
name = "Cogscarab"
desc = "Creates a small shell fitted for soul vessels. Adding an active soul vessel to it results in a small construct with tools and an inbuilt proselytizer."
invocations = list("Call forth...", "...the workers of Armorer.")
- channel_time = 50
+ channel_time = 60
required_components = list("belligerent_eye" = 2, "hierophant_ansible" = 1)
consumed_components = list("belligerent_eye" = 1, "hierophant_ansible" = 1)
object_path = /obj/structure/destructible/clockwork/shell/cogscarab
@@ -706,6 +699,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
observer_message = "The slab disgorges a puddle of black metal that contracts and forms into a strange shell!"
usage_tip = "Useless without a soul vessel and should not be created without one."
tier = SCRIPTURE_SCRIPT
+ sort_priority = 12
@@ -723,6 +717,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "This is not a primary conversion method - use Guvax for that. It is advantageous as a trap, however, as it will transmit the name of the newly-converted."
tier = SCRIPTURE_SCRIPT
one_per_tile = TRUE
+ sort_priority = 15
//////////////////
@@ -735,7 +730,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
desc = "Creates a large shell fitted for soul vessels. Adding an active soul vessel to it results in a powerful construct with decent health, notable melee power, \
and exceptional speed, though taking damage will temporarily slow it down."
invocations = list("Call forth...", "...the soldiers of Armorer.")
- channel_time = 70
+ channel_time = 80
required_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "replicant_alloy" = 3)
consumed_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "replicant_alloy" = 2)
object_path = /obj/structure/destructible/clockwork/shell/fragment
@@ -743,6 +738,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
observer_message = "The slab disgorges a puddle of black metal that expands and forms into a strange shell!"
usage_tip = "Useless without a soul vessel and should not be created without one."
tier = SCRIPTURE_APPLICATION
+ sort_priority = 25
@@ -762,6 +758,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "It will remain after converting a target, unless that target has a mindshield implant, which it will break to convert them, but consume itself in the process."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
+ sort_priority = 22
@@ -779,6 +776,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "Can be recharged by using Volt Void while standing on it."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
+ sort_priority = 26
@@ -797,14 +795,15 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "To revive a servant, the sigil must have 20 vitality plus the target servant's non-oxygen damage. It will still heal dead servants if it lacks the vitality to outright revive them."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
+ sort_priority = 23
/datum/clockwork_scripture/memory_allocation //Memory Allocation: Finds a willing ghost and makes them into a clockwork marauders for the invoker.
descname = "Guardian"
name = "Memory Allocation"
- desc = "Allocates part of your consciousness to a Clockwork Marauder, a vigilent fighter similar to the alien holoparasites employed by the Syndicate; It lives within you, able to be \
+ desc = "Allocates part of your consciousness to a Clockwork Marauder, a vigilent fighter that lives within you, able to be \
called forth by Speaking its True Name or if you become exceptionally low on health. \
- Unlike holoparasites, however, it does not transfer the damage it takes to you, instead simply gaining Fatigue as it is attacked. Marauders cannot move too far from their hosts, \
+ It gains Fatigue as it is attacked, weakening it. Marauders cannot move too far from their hosts, \
and will gain Fatigue at an increasing rate as they grow farther away. At maximum Fatigue, the marauder is forced to return to you and will be unable to manifest until its Fatigue is at zero."
invocations = list("Fright's will...", "...call forth...")
channel_time = 100
@@ -812,6 +811,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
consumed_components = list("belligerent_eye" = 1, "vanguard_cogwheel" = 1, "guvax_capacitor" = 2)
usage_tip = "Marauders are useful as personal bodyguards and frontline warriors, although they do little damage."
tier = SCRIPTURE_APPLICATION
+ sort_priority = 24
/datum/clockwork_scripture/memory_allocation/check_special_requirements()
for(var/mob/living/simple_animal/hostile/clockwork/marauder/M in living_mob_list)
@@ -882,6 +882,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "If it fails to funnel power into a nearby Sigil of Transmission and fails to disable even one thing, it will disable itself for two minutes."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
+ sort_priority = 29
@@ -901,6 +902,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "Powerful healing but power use is very inefficient, and its alloy use is little better."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
+ sort_priority = 27
@@ -920,6 +922,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "Producing a gateway has a high power cost. Gateways to or between clockwork obelisks recieve double duration and uses."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
+ sort_priority = 30
@@ -939,13 +942,14 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "Eligible human servants next to the motor will be converted at an additional power cost. It will also cure hallucinations and brain damage in nearby servants."
tier = SCRIPTURE_APPLICATION
one_per_tile = TRUE
+ sort_priority = 28
/datum/clockwork_scripture/create_object/tinkerers_daemon //Tinkerer's Daemon: Creates a shell that can be attached to a tinkerer's cache to grant it passive component creation.
descname = "Component Generator"
name = "Tinkerer's Daemon"
- desc = "Forms a daemon shell that can be attached to a tinkerer's cache to add new components at a healthy rate. It will only function if it is outnumbered by servants in a ratio of 5:1."
+ desc = "Forms a daemon shell that can be attached to a tinkerer's cache to add new components at a healthy rate. It will only function if it is outnumbered by servants by a ratio of 5:1."
invocations = list("Collect Engine parts...", "...that yet hold greatness!")
channel_time = 80
required_components = list("belligerent_eye" = 3, "vanguard_cogwheel" = 3, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 3)
@@ -954,6 +958,8 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
creator_message = "You form a daemon shell. Attach it to a tinkerer's cache to increase its rate of production."
usage_tip = "Vital to your success!"
tier = SCRIPTURE_APPLICATION
+ space_allowed = TRUE
+ sort_priority = 21
/datum/clockwork_scripture/create_object/tinkerers_daemon/check_special_requirements()
var/servants = 0
@@ -985,6 +991,9 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "Ocular wardens will become empowered, clockwork proselytizers will require no alloy, tinkerer's daemons will produce twice as quickly, \
and interdiction lenses, mending motors, mania motors, and clockwork obelisks will all require no power."
tier = SCRIPTURE_REVENANT
+ sort_priority = 33
+ invokers_required = 3
+ multiple_invokers_used = TRUE
/datum/clockwork_scripture/invoke_nezbere/check_special_requirements()
if(!slab.no_cost && clockwork_generals_invoked["nezbere"] > world.time)
@@ -1036,6 +1045,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
consumed_components = list("belligerent_eye" = 3, "vanguard_cogwheel" = 3, "guvax_capacitor" = 6, "hierophant_ansible" = 3)
usage_tip = "Causes brain damage, hallucinations, confusion, and dizziness in massive amounts."
tier = SCRIPTURE_REVENANT
+ sort_priority = 32
invokers_required = 3
multiple_invokers_used = TRUE
var/list/mindbreaksayings = list("\"Oh, great. I get to shatter some minds.\"", "\"More minds to crush.\"", \
@@ -1106,6 +1116,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
consumed_components = list("belligerent_eye" = 3, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 6)
usage_tip = "Struck targets will also be knocked down for about sixteen seconds."
tier = SCRIPTURE_REVENANT
+ sort_priority = 34
/datum/clockwork_scripture/invoke_nzcrentr/check_special_requirements()
if(!slab.no_cost && clockwork_generals_invoked["nzcrentr"] > world.time)
@@ -1135,7 +1146,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
for(var/mob/living/L in view(7, invoker))
if(is_servant_of_ratvar(L))
continue
- invoker.Beam(L, icon_state = "nzcrentrs_power", icon = 'icons/effects/beam.dmi', time = 10)
+ invoker.Beam(L, icon_state = "nzcrentrs_power", time = 10)
var/randdamage = rand(40, 60)
if(iscarbon(L))
L.electrocute_act(randdamage, "Nzcrentr's power", 1, randdamage)
@@ -1167,6 +1178,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
consumed_components = list("vanguard_cogwheel" = 6, "guvax_capacitor" = 3, "replicant_alloy" = 3, "hierophant_ansible" = 3)
usage_tip = "Those affected by this scripture are only weak to things that outright destroy bodies, such as bombs or the singularity."
tier = SCRIPTURE_REVENANT
+ sort_priority = 31
var/total_duration = 150
/datum/clockwork_scripture/invoke_inathneq/check_special_requirements()
@@ -1207,6 +1219,7 @@ Judgement: 10 servants, 100 CV, and any existing AIs are converted or destroyed
usage_tip = "The gateway is completely vulnerable to attack during its five-minute duration. It will periodically give indication of its general position to everyone on the station \
as well as being loud enough to be heard throughout the entire sector. Defend it with your life!"
tier = SCRIPTURE_JUDGEMENT
+ sort_priority = 35
/datum/clockwork_scripture/ark_of_the_clockwork_justiciar/New()
if(ticker && ticker.mode && ticker.mode.clockwork_objective != CLOCKCULT_GATEWAY)
diff --git a/code/game/gamemodes/clock_cult/clock_structures.dm b/code/game/gamemodes/clock_cult/clock_structures.dm
index 83477d09822..a543a5d2d3b 100644
--- a/code/game/gamemodes/clock_cult/clock_structures.dm
+++ b/code/game/gamemodes/clock_cult/clock_structures.dm
@@ -174,7 +174,7 @@
/obj/structure/destructible/clockwork/ocular_warden //Ocular warden: Low-damage, low-range turret. Deals constant damage to whoever it makes eye contact with.
name = "ocular warden"
desc = "A large brass eye with tendrils trailing below it and a wide red iris."
- clockwork_desc = "A stalwart turret that will deal sustained damage to any non-faithful it sees."
+ clockwork_desc = "A fragile turret that will deal sustained damage to any non-faithful it sees."
icon_state = "ocular_warden"
health = 25
max_health = 25
@@ -187,7 +187,7 @@
var/sight_range = 3
var/atom/movable/target
var/list/idle_messages = list(" sulkily glares around.", " lazily drifts from side to side.", " looks around for something to burn.", " slowly turns in circles.")
- var/mech_damage_cycle = 0 //only hits every few cycles so mechs have a chance against it
+ var/mech_damage_cycle = 0 //so that people in mechs don't get murderspammed with messages
/obj/structure/destructible/clockwork/ocular_warden/New()
..()
@@ -218,12 +218,14 @@
L.adjust_fire_stacks(damage_per_tick)
L.IgniteMob()
else if(istype(target,/obj/mecha))
- if(mech_damage_cycle)
- var/obj/mecha/M = target
- M.take_directional_damage(damage_per_tick, "fire", get_dir(src, M), 0) //does about half of standard damage to mechs * whatever their fire armor is
- mech_damage_cycle--
+ var/sending_message = FALSE
+ if(mech_damage_cycle > 1)
+ mech_damage_cycle = 0
+ sending_message = TRUE
else
mech_damage_cycle++
+ var/obj/mecha/M = target
+ M.take_directional_damage(damage_per_tick, "fire", get_dir(src, M), 0, 1, sending_message)
setDir(get_dir(get_turf(src), get_turf(target)))
if(!target)
if(validtargets.len)
@@ -331,15 +333,48 @@
/obj/item/clockwork/alloy_shards/medium = 4, \
/obj/item/clockwork/alloy_shards/small = 2) //slightly more debris than the default, totals 26 alloy
+/obj/structure/destructible/clockwork/wall_gear/displaced
+ anchored = FALSE
+
/obj/structure/destructible/clockwork/wall_gear/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/wrench))
default_unfasten_wrench(user, I, 10)
return 1
+ else if(istype(I, /obj/item/stack/sheet/brass))
+ var/obj/item/stack/sheet/brass/W = I
+ if(W.get_amount() < 1)
+ user << "You need one brass sheet to do this!"
+ return
+ var/turf/T = get_turf(src)
+ if(istype(T, /turf/closed/wall))
+ user << "There is already a wall present!"
+ return
+ if(!istype(T, /turf/open/floor))
+ user << "A floor must be present to build a [anchored ? "false ":""]wall!"
+ return
+ if(locate(/obj/structure/falsewall) in T.contents)
+ user << "There is already a false wall present!"
+ return
+ user << "You start adding [W] to [src]..."
+ if(do_after(user, 20, target = src))
+ var/brass_floor = FALSE
+ if(istype(T, /turf/open/floor/clockwork)) //if the floor is already brass, costs less to make(conservation of masssssss)
+ brass_floor = TRUE
+ if(W.use(2 - brass_floor))
+ if(anchored)
+ T.ChangeTurf(/turf/closed/wall/clockwork)
+ else
+ T.ChangeTurf(/turf/open/floor/clockwork)
+ new /obj/structure/falsewall/brass(T)
+ qdel(src)
+ else
+ user << "You need more brass to make a [anchored ? "false ":""]wall!"
+ return 1
return ..()
/obj/structure/destructible/clockwork/wall_gear/examine(mob/user)
..()
- user << "[src] is [anchored ? "secured to the floor":"mobile, and not secured"]."
+ user << "[src] is [anchored ? "":"not "]secured to the floor."
///////////////////////
// CLOCKWORK EFFECTS //
@@ -579,7 +614,7 @@
name = "clockwork wall"
icon = 'icons/turf/walls/clockwork_wall.dmi'
icon_state = "clockwork_wall"
- canSmoothWith = list(/obj/effect/clockwork/overlay/wall)
+ canSmoothWith = list(/obj/effect/clockwork/overlay/wall, /obj/structure/falsewall/brass)
smooth = SMOOTH_TRUE
layer = CLOSED_TURF_LAYER
@@ -711,10 +746,10 @@
color = "#FAE48C"
/obj/effect/clockwork/sigil/transgression/sigil_effects(mob/living/L)
- var/target_flashed = L.flash_eyes()
+ var/target_flashed = L.flash_act()
for(var/mob/living/M in viewers(5, src))
if(!is_servant_of_ratvar(M) && M != L)
- M.flash_eyes()
+ M.flash_act()
if(iscultist(L))
L << "\"Watch your step, wretch.\""
L.adjustBruteLoss(10)
diff --git a/code/game/gamemodes/cult/cult.dm b/code/game/gamemodes/cult/cult.dm
index 2676bc21aea..b80a7e692ea 100644
--- a/code/game/gamemodes/cult/cult.dm
+++ b/code/game/gamemodes/cult/cult.dm
@@ -150,7 +150,6 @@
return 0
else
mob << "You have a [item_name] in your [where]."
- mob.update_icons()
if(where == "backpack")
var/obj/item/weapon/storage/B = mob.back
B.orient2hud(mob)
diff --git a/code/game/gamemodes/cult/cult_comms.dm b/code/game/gamemodes/cult/cult_comms.dm
index accff66ebdd..13f1c4acf2a 100644
--- a/code/game/gamemodes/cult/cult_comms.dm
+++ b/code/game/gamemodes/cult/cult_comms.dm
@@ -30,9 +30,9 @@
if(!user)
return
if(!ishuman(user))
- user.say(message)
+ user.say(html_decode(message))
else
- user.whisper(message)
+ user.whisper(html_decode(message))
var/my_message = "[(ishuman(user) ? "Acolyte" : "Construct")] [user]: [message]"
for(var/mob/M in mob_list)
if(iscultist(M))
diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm
index 0f419ad2fec..499c09eca84 100644
--- a/code/game/gamemodes/cult/cult_items.dm
+++ b/code/game/gamemodes/cult/cult_items.dm
@@ -345,14 +345,14 @@
if(uses <= 0)
icon_state ="shifter_drained"
playsound(mobloc, "sparks", 50, 1)
- PoolOrNew(/obj/effect/overlay/temp/cult/phase/out, list(mobloc, C.dir))
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/cult/phase/out, list(mobloc, C.dir))
var/atom/movable/pulled = handle_teleport_grab(destination, C)
C.forceMove(destination)
if(pulled)
C.start_pulling(pulled) //forcemove resets pulls, so we need to re-pull
- PoolOrNew(/obj/effect/overlay/temp/cult/phase, list(destination, C.dir))
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/cult/phase, list(destination, C.dir))
playsound(destination, 'sound/effects/phasein.ogg', 25, 1)
playsound(destination, "sparks", 50, 1)
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index 405b6512001..980fbc9dd11 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -33,7 +33,7 @@
if(istype(M, /mob/living/simple_animal/hostile/construct/builder))
if(health < max_health)
health = min(max_health, health + 5)
- Beam(M, icon_state="sendbeam", icon='icons/effects/effects.dmi', time=4)
+ Beam(M, icon_state="sendbeam", time=4)
M.visible_message("[M] repairs \the [src].", \
"You repair [src], leaving it at [health]/[max_health] stability.")
else
diff --git a/code/game/gamemodes/cult/ritual.dm b/code/game/gamemodes/cult/ritual.dm
index fb375070f9d..0b1d11cd3c4 100644
--- a/code/game/gamemodes/cult/ritual.dm
+++ b/code/game/gamemodes/cult/ritual.dm
@@ -34,7 +34,7 @@ This file contains the arcane tome files.
M.reagents.add_reagent("unholywater",holy2unholy)
add_logs(user, M, "smacked", src, " removing the holy water from them")
return
- M.take_organ_damage(0, 15) //Used to be a random between 5 and 20
+ M.take_bodypart_damage(0, 15) //Used to be a random between 5 and 20
playsound(M, 'sound/weapons/sear.ogg', 50, 1)
M.visible_message("[user] strikes [M] with the arcane tome!", \
"[user] strikes you with the tome, searing your flesh!")
@@ -67,20 +67,15 @@ This file contains the arcane tome files.
invoking it and choosing which talisman you desire, the paper will be converted, after some delay into a talisman.
"
text += "Teleport This rune is unique in that it requires a keyword before the scribing can begin. When invoked, it will find any other Teleport runes; \
- If any are found, the user can choose which rune to send to. Upon activation, the rune teleports everything above it to the selected rune.
"
+ If any are found, the user can choose which rune to send to. Upon activation, the rune teleports everything above it to the selected rune, provided the selected rune is unblocked.
"
- text += "Convert This rune is critical to the success of the cult. It will allow you to convert normal crew members into cultists. \
- To do this, simply place the crew member upon the rune and invoke it. This rune requires two invokers to use. If the target to be converted is mindshield-implanted or a certain assignment, they will \
- be unable to be converted. People the Geometer wishes sacrificed will also be ineligible for conversion, and anyone with a shielding presence like the null rod will not be converted. \
- Successful conversions will produce a tome for the new cultist.
"
+ text += "Offer This rune is necessary to achieve your goals. Placing a noncultist above it will convert them if it can and sacrifice them otherwise. \
+ It requires two invokers to convert a target and three to sacrifice a living target or the sacrifice target. \
+ Successful conversions will produce a tome for the new cultist, in addition to healing them. \
+ Successful sacrifices will please the Geometer, can complete your objective if it sacrificed the sacrifice target, and will attempt to place the target into a soulstone.
"
- text += "Sacrifice This rune is necessary to achieve your goals. Simply place any dead creature upon the rune and invoke it (this will not \
- target cultists!). If this creature has a mind, a soulstone will be created and the creature's soul transported to it. Sacrificing the dead can be done alone, but sacrificing living crew or your cult's target will require 3 cultists. \
- Soulstones used on construct shells will move that soul into a powerful construct of your choice.
"
-
- text += "Raise Dead This rune requires two corpses. To perform the ritual, place the corpse you wish to revive onto \
- the rune and the offering body adjacent to it. When the rune is invoked, the body to be sacrificed will turn to dust, the life force flowing into the revival target. Assuming the target is not moved \
- within a few seconds, they will be brought back to life, healed of all ailments.
"
+ text += "Raise Dead This rune requires the corpse of a cultist placed upon the rune, and one person sacrificed for each revival you wish to do.\
+ Provided there are remaining revivals from those sacrificed, invoking the rune will revive the cultist placed upon it.
"
text += "Electromagnetic Disruption Robotic lifeforms have time and time again been the downfall of fledgling cults. This rune may allow you to gain the upper \
hand against these pests. By using the rune, a large electromagnetic pulse will be emitted from the rune's location. The size of the EMP will grow significantly for each additional adjacent cultist when the \
@@ -91,14 +86,14 @@ This file contains the arcane tome files.
The body will also take constant damage while in this form, and may even die. The user's spirit will contain their consciousness, and will allow them to freely wander the station as a ghost. This may \
also be used to commune with the dead.
"
- text += "Form Barrier While simple, this rune serves an important purpose in defense and hindering passage. When invoked, the \
- rune will draw a small amount of life force from the user and make the space above the rune completely dense, rendering it impassable to all but the most complex means. The rune may be invoked again to \
- undo this effect and allow passage again.
"
+ text += "Form Barrier While simple, this rune serves an important purpose in defense and hindering passage. When invoked, the rune will draw a small amount of blood from the user \
+ and make the space above the rune completely dense, rendering it impassable for about a minute and a half. This effect will spread to other nearby Barrier Runes. \
+ The rune may be invoked again to undo this effect and allow passage again.
"
text += "Summon Cultist This rune allows the cult to free other cultists with ease. When invoked, it will allow the user to summon a single cultist to the rune from \
any location. It requires two invokers, and will damage each invoker slightly.
"
- text += "Blood Boil When invoked, this rune will do a massive amount of damage to all non-cultist viewers, but it will also emit a small explosion upon invocation. \
+ text += "Blood Boil When invoked, this rune will rapidly do a massive amount of damage to all non-cultist viewers, but it will also emit a burst of flame once it finishes. \
It requires three invokers.
"
text += "Drain Life This rune will drain the life of every living creature above the rune, healing the invoker for each creature drained by it.
"
diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm
index abfdfa813d6..d42b1bdeaff 100644
--- a/code/game/gamemodes/cult/runes.dm
+++ b/code/game/gamemodes/cult/runes.dm
@@ -1,4 +1,4 @@
-/var/list/sacrificed = list()
+/var/list/sacrificed = list() //a mixed list of minds and mobs
var/list/non_revealed_runes = (subtypesof(/obj/effect/rune) - /obj/effect/rune/malformed)
/*
@@ -23,10 +23,11 @@ To draw a rune, use an arcane tome.
icon_state = "1"
unacidable = 1
layer = ABOVE_NORMAL_TURF_LAYER
- color = rgb(255,0,0)
+ color = "#FF0000"
var/invocation = "Aiy ele-mayo!" //This is said by cultists when the rune is invoked.
var/req_cultists = 1 //The amount of cultists required around the rune to invoke it. If only 1, any cultist can invoke it.
+ var/req_cultists_text //if we have a description override for required cultists to invoke
var/rune_in_use = 0 // Used for some runes, this is for when you want a rune to not be usable when in use.
var/scribe_delay = 50 //how long the rune takes to create
@@ -48,7 +49,7 @@ To draw a rune, use an arcane tome.
if(iscultist(user) || user.stat == DEAD) //If they're a cultist or a ghost, tell them the effects
user << "Name: [cultist_name]"
user << "Effects: [capitalize(cultist_desc)]"
- user << "Required Acolytes: [req_cultists]"
+ user << "Required Acolytes: [req_cultists_text ? "[req_cultists_text]":"[req_cultists]"]"
if(req_keyword && keyword)
user << "Keyword: [keyword]"
@@ -137,6 +138,9 @@ structure_check() searches for nearby cultist structures required for the invoca
for(var/M in invokers)
var/mob/living/L = M
L.say(invocation)
+ do_invoke_glow()
+
+/obj/effect/rune/proc/do_invoke_glow()
var/oldtransform = transform
spawn(0) //animate is a delay, we want to avoid being delayed
animate(src, transform = matrix()*2, alpha = 0, time = 5) //fade out
@@ -187,7 +191,7 @@ structure_check() searches for nearby cultist structures required for the invoca
cultist_desc = "transforms paper into powerful magic talismans."
invocation = "H'drak v'loso, mir'kanas verbot!"
icon_state = "3"
- color = rgb(0, 0, 255)
+ color = "#0000FF"
/obj/effect/rune/imbue/invoke(var/list/invokers)
var/mob/living/user = invokers[1] //the first invoker is always the user
@@ -296,6 +300,11 @@ var/list/teleport_runes = list()
return
var/turf/T = get_turf(src)
+ var/turf/target = get_turf(actual_selected_rune)
+ if(is_blocked_turf(target))
+ user << "The target rune is blocked. Attempting to teleport to it would be massively unwise."
+ fail_invoke()
+ return
var/movedsomething = 0
var/moveuserlater = 0
for(var/atom/movable/A in T)
@@ -305,158 +314,134 @@ var/list/teleport_runes = list()
continue
if(!A.anchored)
movedsomething = 1
- A.forceMove(get_turf(actual_selected_rune))
+ A.forceMove(target)
if(movedsomething)
..()
visible_message("There is a sharp crack of inrushing air, and everything above the rune disappears!")
user << "You[moveuserlater ? "r vision blurs, and you suddenly appear somewhere else":" send everything above the rune away"]."
if(moveuserlater)
- user.forceMove(get_turf(actual_selected_rune))
+ user.forceMove(target)
else
fail_invoke()
-//Rite of Enlightenment: Converts a normal crewmember to the cult.
+//Rite of Offering: Converts or sacrifices a target.
/obj/effect/rune/convert
- cultist_name = "Convert"
- cultist_desc = "converts a normal crewmember on top of it to the cult. Does not work on mindshield-implanted crew."
+ cultist_name = "Offer"
+ cultist_desc = "offers a noncultist above it to Nar-Sie, either converting them or sacrificing them."
+ req_cultists_text = "2 for conversion, 3 for living sacrifices and sacrifice targets."
invocation = "Mah'weyh pleggh at e'ntrath!"
icon_state = "3"
- color = rgb(200, 0, 0)
- req_cultists = 2
+ color = "#FFFFFF"
+ req_cultists = 1
+ allow_excess_invokers = 1
+ rune_in_use = FALSE
+
+/obj/effect/rune/convert/do_invoke_glow()
+ return
/obj/effect/rune/convert/invoke(var/list/invokers)
- var/list/convertees = list()
- var/turf/T = get_turf(src)
- for(var/mob/living/M in T)
- if(M.stat != DEAD && !iscultist(M) && is_convertable_to_cult(M.mind))
- convertees |= M
- else if(is_sacrifice_target(M.mind))
- for(var/C in invokers)
- C << "\"I desire this one for myself. SACRIFICE THEM!\""
- else if(is_servant_of_ratvar(M))
- M.visible_message("[M]'s eyes glow a defiant yellow!", \
- "\"Stop resisting. You will be mi-\"\"Give up and you will feel pain unlike anything you've ever felt!\"")
- M.Weaken(4)
- if(!convertees.len)
- fail_invoke()
- log_game("Convert rune failed - no eligible convertees")
- return
- var/mob/living/new_cultist = pick(convertees)
- if(new_cultist.null_rod_check())
- for(var/M in invokers)
- M << "Something is shielding [new_cultist]'s mind!"
- fail_invoke()
- log_game("Convert rune failed - convertee had null rod")
- return
- ..()
- new_cultist.visible_message("[new_cultist] writhes in pain as the markings below them glow a bloody red!", \
- "AAAAAAAAAAAAAA-")
- ticker.mode.add_cultist(new_cultist.mind, 1)
- new /obj/item/weapon/tome(get_turf(src))
- new_cultist.mind.special_role = "Cultist"
- new_cultist << "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \
- and something evil takes root."
- new_cultist << "Assist your new compatriots in their dark dealings. Your goal is theirs, and theirs is yours. You serve the Geometer above all else. Bring it back.\
- "
-
-//Rite of Tribute: Sacrifices a crew member to Nar-Sie. Places them into a soul shard if they're in their body.
-/obj/effect/rune/sacrifice
- cultist_name = "Sacrifice"
- cultist_desc = "sacrifices a crew member to the Geometer. May place them into a soul shard if their spirit remains in their body."
- icon_state = "3"
- allow_excess_invokers = 1
- invocation = "Barhah hra zar'garis!"
- color = rgb(255, 255, 255)
- rune_in_use = 0
-
-/obj/effect/rune/sacrifice/New()
- ..()
- icon_state = "[rand(1,7)]"
-
-/obj/effect/rune/sacrifice/invoke(var/list/invokers)
if(rune_in_use)
return
- rune_in_use = 1
- var/mob/living/user = invokers[1] //the first invoker is always the user
+ var/list/myriad_targets = list()
var/turf/T = get_turf(src)
- var/list/possible_targets = list()
- for(var/mob/living/M in T.contents)
- if(M.mind)
- if(M.mind in sacrificed)
- continue
+ for(var/mob/living/M in T)
if(!iscultist(M))
- possible_targets.Add(M)
- var/mob/offering
- if(possible_targets.len > 1) //If there's more than one target, allow choice
- offering = input(user, "Choose an offering to sacrifice.", "Unholy Tribute") as null|anything in possible_targets
- if(!Adjacent(user) || !src || qdeleted(src) || user.incapacitated())
- return
- else if(possible_targets.len) //Otherwise, if there's a target at all, pick the only one
- offering = possible_targets[possible_targets.len]
- if(!offering)
- rune_in_use = 0
- return
- /*var/obj/item/weapon/nullrod/N = offering.null_rod_check()
- if(N)
- user << "Something is blocking the Geometer's magic!"
- log_game("Sacrifice rune failed - target has \a [N]!")
+ myriad_targets |= M
+ if(!myriad_targets.len)
fail_invoke()
- rune_in_use = 0
- return*/
- if(((ishuman(offering) || isrobot(offering)) && offering.stat != DEAD) || is_sacrifice_target(offering.mind)) //Requires three people to sacrifice living targets
- if(invokers.len < 3)
- for(var/M in invokers)
- M << "[offering] is too greatly linked to the world! You need three acolytes!"
- fail_invoke()
- log_game("Sacrifice rune failed - not enough acolytes and target is living")
- rune_in_use = 0
- return
+ log_game("Offer rune failed - no eligible targets")
+ return
+ rune_in_use = TRUE
visible_message("[src] pulses blood red!")
- color = rgb(126, 23, 23)
- ..()
- sac(invokers, offering)
- color = initial(color)
+ color = "#7D1717"
+ var/mob/living/L = pick(myriad_targets)
+ var/is_clock = is_servant_of_ratvar(L)
+ var/is_convertable = is_convertable_to_cult(L.mind)
+ if(L.stat != DEAD && (is_clock || is_convertable))
+ invocation = "Mah'weyh pleggh at e'ntrath!"
+ ..()
+ if(is_clock)
+ L.visible_message("[L]'s eyes glow a defiant yellow!", \
+ "\"Stop resisting. You will be mi-\"\n\
+ \"Give up and you will feel pain unlike anything you've ever felt!\"")
+ L.Weaken(4)
+ else if(is_convertable)
+ do_convert(L, invokers)
+ else
+ invocation = "Barhah hra zar'garis!"
+ ..()
+ do_sacrifice(L, invokers)
+ animate(src, color = initial(color), time = 5)
+ rune_in_use = FALSE
-/obj/effect/rune/sacrifice/proc/sac(var/list/invokers, mob/living/T)
- var/sacrifice_fulfilled
- if(T)
- if(istype(T, /mob/living/simple_animal/pet/dog))
- for(var/M in invokers)
- var/mob/living/L = M
- L << "\"Even I have standards, such as they are!\""
- if(L.reagents)
- L.reagents.add_reagent("hell_water", 2)
- if(T.mind)
- sacrificed.Add(T.mind)
- if(is_sacrifice_target(T.mind))
- sacrifice_fulfilled = 1
- PoolOrNew(/obj/effect/overlay/temp/cult/sac, src.loc)
+/obj/effect/rune/convert/proc/do_convert(mob/living/convertee, list/invokers)
+ if(invokers.len < 2)
for(var/M in invokers)
- if(sacrifice_fulfilled)
- M << "\"Yes! This is the one I desire! You have done well.\""
- else
- if(ishuman(T) || isrobot(T))
- M << "\"I accept this sacrifice.\""
- else
- M << "\"I accept this meager sacrifice.\""
- if(T.mind)
- var/obj/item/device/soulstone/stone = new /obj/item/device/soulstone(get_turf(src))
- stone.invisibility = INVISIBILITY_MAXIMUM //so it's not picked up during transfer_soul()
- if(!stone.transfer_soul("FORCE", T, usr)) //If it cannot be added
- qdel(stone)
- if(stone)
- stone.invisibility = 0
- if(!T)
- rune_in_use = 0
- return
- if(isrobot(T))
- playsound(T, 'sound/magic/Disable_Tech.ogg', 100, 1)
- T.dust() //To prevent the MMI from remaining
+ M << "You need more invokers to convert [convertee]!"
+ log_game("Offer rune failed - tried conversion with one invoker")
+ return 0
+ if(convertee.null_rod_check())
+ for(var/M in invokers)
+ M << "Something is shielding [convertee]'s mind!"
+ log_game("Offer rune failed - convertee had null rod")
+ return 0
+ var/brutedamage = convertee.getBruteLoss()
+ var/burndamage = convertee.getFireLoss()
+ if(brutedamage || burndamage)
+ convertee.adjustBruteLoss(-(brutedamage * 0.75))
+ convertee.adjustFireLoss(-(burndamage * 0.75))
+ convertee.visible_message("[convertee] writhes in pain \
+ [brutedamage || burndamage ? "even as their wounds heal and close" : "as the markings below them glow a bloody red"]!", \
+ "AAAAAAAAAAAAAA-")
+ ticker.mode.add_cultist(convertee.mind, 1)
+ new /obj/item/weapon/tome(get_turf(src))
+ convertee.mind.special_role = "Cultist"
+ convertee << "Your blood pulses. Your head throbs. The world goes red. All at once you are aware of a horrible, horrible, truth. The veil of reality has been ripped away \
+ and something evil takes root."
+ convertee << "Assist your new compatriots in their dark dealings. Your goal is theirs, and theirs is yours. You serve the Geometer above all else. Bring it back.\
+ "
+ return 1
+
+/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers)
+ if((((ishuman(sacrificial) || isrobot(sacrificial)) && sacrificial.stat != DEAD) || is_sacrifice_target(sacrificial.mind)) && invokers.len < 3)
+ for(var/M in invokers)
+ M << "[sacrificial] is too greatly linked to the world! You need three acolytes!"
+ log_game("Offer rune failed - not enough acolytes and target is living or sac target")
+ return FALSE
+ var/sacrifice_fulfilled = FALSE
+
+ if(sacrificial.mind)
+ sacrificed += sacrificial.mind
+ if(is_sacrifice_target(sacrificial.mind))
+ sacrifice_fulfilled = TRUE
+ else
+ sacrificed += sacrificial
+
+ PoolOrNew(/obj/effect/overlay/temp/cult/sac, get_turf(src))
+ for(var/M in invokers)
+ if(sacrifice_fulfilled)
+ M << "\"Yes! This is the one I desire! You have done well.\""
else
- playsound(T, 'sound/magic/Disintegrate.ogg', 100, 1)
- T.gib()
- rune_in_use = 0
+ if(ishuman(sacrificial) || isrobot(sacrificial))
+ M << "\"I accept this sacrifice.\""
+ else
+ M << "\"I accept this meager sacrifice.\""
+
+ var/obj/item/device/soulstone/stone = new /obj/item/device/soulstone(get_turf(src))
+ if(sacrificial.mind)
+ stone.invisibility = INVISIBILITY_MAXIMUM //so it's not picked up during transfer_soul()
+ stone.transfer_soul("FORCE", sacrificial, usr)
+ stone.invisibility = 0
+
+ if(sacrificial)
+ if(isrobot(sacrificial))
+ playsound(sacrificial, 'sound/magic/Disable_Tech.ogg', 100, 1)
+ sacrificial.dust() //To prevent the MMI from remaining
+ else
+ playsound(sacrificial, 'sound/magic/Disintegrate.ogg', 100, 1)
+ sacrificial.gib()
+ return TRUE
//Ritual of Dimensional Rending: Calls forth the avatar of Nar-Sie upon the station.
/obj/effect/rune/narsie
@@ -465,7 +450,7 @@ var/list/teleport_runes = list()
invocation = "TOK-LYR RQA-NAP G'OLT-ULOFT!!"
req_cultists = 9
icon = 'icons/effects/96x96.dmi'
- color = rgb(125,23,23)
+ color = "#7D1717"
icon_state = "rune_large"
pixel_x = -32 //So the big ol' 96x96 sprite shows up right
pixel_y = -32
@@ -501,6 +486,7 @@ var/list/teleport_runes = list()
M << "Nar-Sie does not respond!"
fail_invoke()
log_game("Summon Nar-Sie rune failed - gametype is not cult")
+ return
if(locate(/obj/singularity/narsie) in poi_list)
for(var/M in invokers)
@@ -514,7 +500,7 @@ var/list/teleport_runes = list()
var/turf/T = get_turf(src)
sleep(40)
if(src)
- color = rgb(255, 0, 0)
+ color = "#FF0000"
new /obj/singularity/narsie/large(T) //Causes Nar-Sie to spawn even if the rune has been removed
if(cult_mode)
cult_mode.eldergod = 0
@@ -534,50 +520,47 @@ var/list/teleport_runes = list()
..()
return
-//Rite of Resurrection: Requires two corpses. Revives one and gibs the other.
+//Rite of Resurrection: Requires the corpse of a cultist and that there have been less revives than the number of people sacrificed
/obj/effect/rune/raise_dead
cultist_name = "Raise Dead"
- cultist_desc = "requires two corpses, one on the rune and one adjacent to the rune. The one on the rune is brought to life, the other is turned to ash."
+ cultist_desc = "requires the corpse of a cultist placed upon the rune. Provided there have been sufficient sacrifices, they will be revived."
invocation = null //Depends on the name of the user - see below
icon_state = "1"
- color = rgb(200, 0, 0)
+ color = "#C80000"
+ var/static/revives_used = 0
+
+/obj/effect/rune/raise_dead/examine(mob/user)
+ ..()
+ if(iscultist(user) || user.stat == DEAD)
+ var/revive_number = 0
+ if(sacrificed.len)
+ revive_number = sacrificed.len - revives_used
+ user << "Revives Remaining: [revive_number]"
/obj/effect/rune/raise_dead/invoke(var/list/invokers)
var/turf/T = get_turf(src)
- var/mob/living/mob_to_sacrifice
var/mob/living/mob_to_revive
- var/list/potential_sacrifice_mobs = list()
var/list/potential_revive_mobs = list()
var/mob/living/user = invokers[1]
if(rune_in_use)
return
- for(var/mob/living/M in orange(1,T))
- if(M.stat == DEAD && !iscultist(M))
- potential_sacrifice_mobs |= M
- if(!potential_sacrifice_mobs.len)
- user << "There are no eligible sacrifices nearby!"
- log_game("Raise Dead rune failed - no catalyst corpses")
- fail_invoke()
- return
for(var/mob/living/M in T.contents)
- if(M.stat == DEAD)
+ if(iscultist(M) && M.stat == DEAD)
potential_revive_mobs |= M
if(!potential_revive_mobs.len)
- user << "There is no eligible revival target on the rune!"
+ user << "There are no dead cultists on the rune!"
log_game("Raise Dead rune failed - no corpses to revive")
fail_invoke()
return
- if(potential_sacrifice_mobs.len > 1)
- mob_to_sacrifice = input(user, "Choose a corpse to sacrifice.", "Corpse to Sacrifice") as null|anything in potential_sacrifice_mobs
- else
- mob_to_sacrifice = potential_sacrifice_mobs[1]
- if(!src || qdeleted(src) || rune_in_use || !validness_checks(mob_to_sacrifice, user, TRUE))
+ if(!sacrificed.len || sacrificed.len <= revives_used)
+ user << "You have sacrificed too few people to revive a cultist!"
+ fail_invoke()
return
if(potential_revive_mobs.len > 1)
- mob_to_revive = input(user, "Choose a corpse to revive.", "Corpse to Revive") as null|anything in potential_revive_mobs
+ mob_to_revive = input(user, "Choose a cultist to revive.", "Cultist to Revive") as null|anything in potential_revive_mobs
else
mob_to_revive = potential_revive_mobs[1]
- if(!src || qdeleted(src) || rune_in_use || !validness_checks(mob_to_sacrifice, user, TRUE) || !validness_checks(mob_to_revive, user, FALSE))
+ if(!src || qdeleted(src) || rune_in_use || !validness_checks(mob_to_revive, user))
return
rune_in_use = 1
if(user.name == "Herbert West")
@@ -585,19 +568,7 @@ var/list/teleport_runes = list()
else
user.say("Pasnar val'keriam usinar. Savrae ines amutan. Yam'toth remium il'tarat!")
..()
- mob_to_sacrifice.visible_message("[mob_to_sacrifice]'s body rises into the air, connected to [mob_to_revive] by a glowing tendril!")
- mob_to_revive.Beam(mob_to_sacrifice,icon_state="sendbeam",icon='icons/effects/effects.dmi',time=20)
- sleep(20)
- if(!mob_to_sacrifice || !in_range(mob_to_sacrifice, src))
- rune_in_use = 0
- return
- if(!mob_to_revive || mob_to_revive.stat != DEAD)
- visible_message("The glowing tendril snaps against the rune with a shocking crack.")
- rune_in_use = 0
- fail_invoke()
- return
- mob_to_sacrifice.visible_message("[mob_to_sacrifice] disintegrates into a pile of bones.")
- mob_to_sacrifice.dust()
+ revives_used++
mob_to_revive.revive(1, 1) //This does remove disabilities and such, but the rune might actually see some use because of it!
mob_to_revive.grab_ghost()
mob_to_revive << "\"PASNAR SAVRAE YAM'TOTH. Arise.\""
@@ -605,7 +576,7 @@ var/list/teleport_runes = list()
"You awaken suddenly from the void. You're alive!")
rune_in_use = 0
-/obj/effect/rune/raise_dead/proc/validness_checks(mob/living/target_mob, mob/living/user, saccing)
+/obj/effect/rune/raise_dead/proc/validness_checks(mob/living/target_mob, mob/living/user)
var/turf/T = get_turf(src)
if(!user)
return 0
@@ -614,28 +585,28 @@ var/list/teleport_runes = list()
if(!target_mob)
fail_invoke()
return 0
- if(saccing)
- if(!in_range(target_mob, src))
- user << "The sacrificial target has been moved!"
- fail_invoke()
- log_game("Raise Dead rune failed - catalyst corpse moved")
- return 0
- if(target_mob.stat != DEAD)
- user << "The sacrificial target must be dead!"
- fail_invoke()
- log_game("Raise Dead rune failed - catalyst corpse is not dead")
- return 0
- else if(!(target_mob in T.contents))
- user << "The corpse to revive has been moved!"
+ if(!(target_mob in T.contents))
+ user << "The cultist to revive has been moved!"
fail_invoke()
log_game("Raise Dead rune failed - revival target moved")
return 0
+ var/mob/dead/observer/ghost = target_mob.get_ghost(TRUE)
+ if(!ghost)
+ user << "The corpse to revive has no spirit!"
+ fail_invoke()
+ log_game("Raise Dead rune failed - revival target has no ghost")
+ return 0
+ if(!sacrificed.len || sacrificed.len <= revives_used)
+ user << "You have sacrificed too few people to revive a cultist!"
+ fail_invoke()
+ log_game("Raise Dead rune failed - too few sacrificed")
+ return 0
return 1
/obj/effect/rune/raise_dead/fail_invoke()
..()
for(var/mob/living/M in range(1,src))
- if(M.stat == DEAD)
+ if(iscultist(M) && M.stat == DEAD)
M.visible_message("[M] twitches.")
@@ -646,7 +617,7 @@ var/list/teleport_runes = list()
invocation = "Ta'gh fara'qha fel d'amar det!"
icon_state = "5"
allow_excess_invokers = 1
- color = rgb(77, 148, 255)
+ color = "#4D94FF"
/obj/effect/rune/emp/invoke(var/list/invokers)
var/turf/E = get_turf(src)
@@ -676,7 +647,7 @@ var/list/teleport_runes = list()
cultist_desc = "severs the link between one's spirit and body. This effect is taxing and one's physical body will take damage while this is active."
invocation = "Fwe'sh mah erl nyag r'ya!"
icon_state = "7"
- color = rgb(126, 23, 23)
+ color = "#7D1717"
rune_in_use = 0 //One at a time, please!
construct_invoke = 0
var/mob/living/affecting = null
@@ -704,7 +675,7 @@ var/list/teleport_runes = list()
var/turf/T = get_turf(src)
rune_in_use = 1
affecting = user
- user.color = "#7e1717"
+ user.color = "#7D1717"
user.visible_message("[user] freezes statue-still, glowing an unearthly red.", \
"You see what lies beyond. All is revealed. While this is a wondrous experience, your physical form will waste away in this state. Hurry...")
user.ghostize(1)
@@ -717,7 +688,7 @@ var/list/teleport_runes = list()
affecting.apply_damage(0.1, BRUTE)
if(!(user in T))
user.visible_message("A spectral tendril wraps around [user] and pulls them back to the rune!")
- Beam(user,icon_state="drainbeam",icon='icons/effects/effects.dmi',time=2)
+ Beam(user,icon_state="drainbeam",time=2)
user.forceMove(get_turf(src)) //NO ESCAPE :^)
if(user.key)
user.visible_message("[user] slowly relaxes, the glow around them dimming.", \
@@ -742,13 +713,20 @@ var/list/teleport_runes = list()
rune_in_use = 0
+var/list/wall_runes = list()
//Rite of the Corporeal Shield: When invoked, becomes solid and cannot be passed. Invoke again to undo.
/obj/effect/rune/wall
cultist_name = "Form Barrier"
- cultist_desc = "when invoked, makes an invisible wall to block passage. Can be invoked again to reverse this."
+ cultist_desc = "when invoked, makes a temporary invisible wall to block passage. Can be invoked again to reverse this."
invocation = "Khari'd! Eske'te tannin!"
icon_state = "1"
- color = rgb(255, 0, 0)
+ color = "#C80000"
+ var/density_timer
+ var/recharging = FALSE
+
+/obj/effect/rune/wall/New()
+ ..()
+ wall_runes += src
/obj/effect/rune/wall/examine(mob/user)
..()
@@ -757,6 +735,7 @@ var/list/teleport_runes = list()
/obj/effect/rune/wall/Destroy()
density = 0
+ wall_runes -= src
air_update_turf(1)
return ..()
@@ -767,24 +746,55 @@ var/list/teleport_runes = list()
return density
/obj/effect/rune/wall/invoke(var/list/invokers)
+ if(recharging)
+ return
var/mob/living/user = invokers[1]
..()
density = !density
- air_update_turf(1)
+ update_state()
+ if(density)
+ spread_density()
user.visible_message("[user] [iscarbon(user) ? "places their hands on":"stares intently at"] [src], and [density ? "the air above it begins to shimmer" : "the shimmer above it fades"].", \
- "You channel your life energy into [src], [density ? "preventing" : "allowing"] passage above it.")
+ "You channel your life energy into [src], [density ? "temporarily preventing" : "allowing"] passage above it.")
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ C.apply_damage(2, BRUTE, pick("l_arm", "r_arm"))
+
+/obj/effect/rune/wall/proc/spread_density()
+ for(var/R in wall_runes)
+ var/obj/effect/rune/wall/W = R
+ if(W.z == z && get_dist(src, W) <= 2 && !W.density && !W.recharging)
+ W.density = TRUE
+ W.update_state()
+ W.spread_density()
+ density_timer = addtimer(src, "lose_density", 900)
+
+/obj/effect/rune/wall/proc/lose_density()
+ if(density)
+ recharging = TRUE
+ density = FALSE
+ update_state()
+ color = "#696969"
+ animate(src, color = initial(color), time = 50, easing = EASE_IN)
+ addtimer(src, "recharge", 50)
+
+/obj/effect/rune/wall/proc/recharge()
+ recharging = FALSE
+ color = initial(color)
+
+/obj/effect/rune/wall/proc/update_state()
+ deltimer(density_timer)
+ air_update_turf(1)
if(density)
var/image/I = image(layer = ABOVE_MOB_LAYER, icon = 'icons/effects/effects.dmi', icon_state = "barriershimmer")
I.appearance_flags = RESET_COLOR
I.alpha = 60
I.color = "#701414"
- overlays += I
+ add_overlay(I)
+ color = "#FF0000"
else
- overlays.Cut()
- if(iscarbon(user))
- var/mob/living/carbon/C = user
- C.apply_damage(2, BRUTE, pick("l_arm", "r_arm"))
-
+ cut_overlays()
+ color = "#C80000"
//Rite of Joined Souls: Summons a single cultist.
/obj/effect/rune/summon
@@ -794,7 +804,7 @@ var/list/teleport_runes = list()
req_cultists = 2
allow_excess_invokers = 1
icon_state = "5"
- color = rgb(0, 255, 0)
+ color = "#00FF00"
/obj/effect/rune/summon/invoke(var/list/invokers)
var/mob/living/user = invokers[1]
@@ -836,35 +846,67 @@ var/list/teleport_runes = list()
//Rite of Boiling Blood: Deals extremely high amounts of damage to non-cultists nearby
/obj/effect/rune/blood_boil
cultist_name = "Boil Blood"
- cultist_desc = "boils the blood of non-believers who can see the rune, dealing extreme amounts of damage. Requires 3 invokers."
+ cultist_desc = "boils the blood of non-believers who can see the rune, rapidly dealing extreme amounts of damage. Requires 3 invokers."
invocation = "Dedo ol'btoh!"
icon_state = "4"
- color = rgb(200, 0, 0)
+ color = "#C80000"
req_cultists = 3
construct_invoke = 0
+ var/tick_damage = 25
+ rune_in_use = FALSE
+
+/obj/effect/rune/blood_boil/do_invoke_glow()
+ return
/obj/effect/rune/blood_boil/invoke(var/list/invokers)
+ if(rune_in_use)
+ return
..()
+ rune_in_use = TRUE
var/turf/T = get_turf(src)
- visible_message("[src] briefly bubbles before exploding!")
- for(var/mob/living/carbon/C in viewers(T))
- if(!iscultist(C))
- var/obj/item/weapon/nullrod/N = C.null_rod_check()
- if(N)
- C << "\The [N] suddenly burns hotly before returning to normal!"
- continue
- C << "Your blood boils in your veins!"
- C.take_overall_damage(45,45)
- C.Stun(7)
- if(is_servant_of_ratvar(C))
- C << "You feel unholy darkness dimming the Justiciar's light!"
- C.adjustStaminaLoss(30)
+ visible_message("[src] turns a bright, glowing orange!")
+ SetLuminosity(6)
+ color = "#FC9B54"
for(var/M in invokers)
var/mob/living/L = M
- L.apply_damage(15, BRUTE, pick("l_arm", "r_arm"))
+ L.apply_damage(10, BRUTE, pick("l_arm", "r_arm"))
L << "[src] saps your strength!"
+ for(var/mob/living/L in viewers(T))
+ if(!iscultist(L) && L.blood_volume)
+ var/obj/item/weapon/nullrod/N = L.null_rod_check()
+ if(N)
+ L << "\The [N] suddenly burns hotly before returning to normal!"
+ continue
+ L << "Your blood boils in your veins!"
+ if(is_servant_of_ratvar(L))
+ L << "You feel an unholy darkness dimming the Justiciar's light!"
+ animate(src, color = "#FCB56D", time = 4)
+ sleep(4)
+ if(!src)
+ return
+ do_area_burn(T, 0.5)
+ animate(src, color = "#FFDF80", time = 5)
+ sleep(5)
+ if(!src)
+ return
+ do_area_burn(T, 1)
+ animate(src, color = "#FFFDF4", time = 6)
+ sleep(6)
+ if(!src)
+ return
+ do_area_burn(T, 1.5)
+ PoolOrNew(/obj/effect/hotspot, T)
qdel(src)
- explosion(T, -1, 0, 1, 5)
+
+/obj/effect/rune/blood_boil/proc/do_area_burn(turf/T, multiplier)
+ for(var/mob/living/L in viewers(T))
+ if(!iscultist(L) && L.blood_volume)
+ var/obj/item/weapon/nullrod/N = L.null_rod_check()
+ if(N)
+ continue
+ L.take_overall_damage(tick_damage*multiplier, tick_damage*multiplier)
+ if(is_servant_of_ratvar(L))
+ L.adjustStaminaLoss(tick_damage*0.5)
//Deals brute damage to all targets on the rune and heals the invoker for each target drained.
@@ -873,7 +915,7 @@ var/list/teleport_runes = list()
cultist_desc = "drains the life of all targets on the rune, restoring life to the user."
invocation = "Yu'gular faras desdae. Umathar uf'kal thenar!"
icon_state = "3"
- color = rgb(159, 28, 52)
+ color = "#9F1C34"
/obj/effect/rune/leeching/can_invoke(mob/living/user)
if(world.time <= user.next_move)
@@ -900,7 +942,7 @@ var/list/teleport_runes = list()
M.apply_damage(drained_amount, BRUTE, "chest")
user.adjustBruteLoss(-drained_amount)
M << "You feel extremely weak."
- user.Beam(T,icon_state="drainbeam",icon='icons/effects/effects.dmi',time=5)
+ user.Beam(T,icon_state="drainbeam",time=5)
user.visible_message("Blood flows from the rune into [user]!", \
"Blood flows into you, healing your wounds and revitalizing your spirit.")
@@ -912,7 +954,7 @@ var/list/teleport_runes = list()
invocation = "Gal'h'rfikk harfrandid mud'gib!" //how the fuck do you pronounce this
icon_state = "6"
construct_invoke = 0
- color = rgb(200, 0, 0)
+ color = "#C80000"
/obj/effect/rune/manifest/New(loc)
..()
diff --git a/code/game/gamemodes/cult/talisman.dm b/code/game/gamemodes/cult/talisman.dm
index 08e09f57fcb..9a27ad81c6c 100644
--- a/code/game/gamemodes/cult/talisman.dm
+++ b/code/game/gamemodes/cult/talisman.dm
@@ -149,9 +149,13 @@
var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
if(!actual_selected_rune)
return ..(user, 0)
+ var/turf/target = get_turf(actual_selected_rune)
+ if(is_blocked_turf(target))
+ user << "The target rune is blocked. Attempting to teleport to it would be massively unwise."
+ return ..(user, 0)
user.visible_message("Dust flows from [user]'s hand, and they disappear in a flash of red light!", \
"You speak the words of the talisman and find yourself somewhere else!")
- user.forceMove(get_turf(actual_selected_rune))
+ user.forceMove(target)
return ..()
@@ -253,7 +257,7 @@
else
target.Weaken(10)
target.Stun(10)
- target.flash_eyes(1,1)
+ target.flash_act(1,1)
if(issilicon(target))
var/mob/living/silicon/S = target
S.emp_act(1)
@@ -316,7 +320,7 @@
target << "You see a brief but horrible vision of Ratvar, rusted and scrapped, being torn apart."
target.emote("scream")
target.confused = max(0, target.confused + 3)
- target.flash_eyes()
+ target.flash_act()
qdel(src)
@@ -345,8 +349,8 @@
/obj/item/weapon/paper/talisman/construction/afterattack(obj/item/stack/sheet/target, mob/user, proximity_flag, click_parameters)
..()
if(proximity_flag && iscultist(user))
+ var/turf/T = get_turf(target)
if(istype(target, /obj/item/stack/sheet/metal))
- var/turf/T = get_turf(target)
if(target.use(25))
new /obj/structure/constructshell(T)
user << "The talisman clings to the metal and twists it into a construct shell!"
@@ -355,16 +359,16 @@
qdel(src)
else
user << "You need more metal to produce a construct shell!"
- if(istype(target, /obj/item/stack/sheet/plasteel))
- var/quantity = min(target.amount, uses)
- uses -= quantity
- new /obj/item/stack/sheet/runed_metal(T,quantity)
- target.use(quantity)
- user << "The talisman clings to the plasteel, transforming it into runed metal!"
- user << sound('sound/effects/magic.ogg',0,1,25)
- invoke(user, 1)
- if(uses <= 0)
- qdel(src)
+ else if(istype(target, /obj/item/stack/sheet/plasteel))
+ var/quantity = min(target.amount, uses)
+ uses -= quantity
+ new /obj/item/stack/sheet/runed_metal(T,quantity)
+ target.use(quantity)
+ user << "The talisman clings to the plasteel, transforming it into runed metal!"
+ user << sound('sound/effects/magic.ogg',0,1,25)
+ invoke(user, 1)
+ if(uses <= 0)
+ qdel(src)
else
user << "The talisman must be used on metal or plasteel!"
diff --git a/code/game/gamemodes/devil/true_devil/_true_devil.dm b/code/game/gamemodes/devil/true_devil/_true_devil.dm
index 8e91c964dab..22bb549558d 100644
--- a/code/game/gamemodes/devil/true_devil/_true_devil.dm
+++ b/code/game/gamemodes/devil/true_devil/_true_devil.dm
@@ -22,13 +22,20 @@
mob_size = MOB_SIZE_LARGE
var/mob/living/oldform
var/list/devil_overlays[DEVIL_TOTAL_LAYERS]
+ bodyparts = list(/obj/item/bodypart/chest/devil, /obj/item/bodypart/head/devil, /obj/item/bodypart/l_arm/devil,
+ /obj/item/bodypart/r_arm/devil, /obj/item/bodypart/r_leg/devil, /obj/item/bodypart/l_leg/devil)
+
+
/mob/living/carbon/true_devil/New()
- internal_organs += new /obj/item/organ/brain/
+ create_bodyparts() //initialize bodyparts
+
+ create_internal_organs()
+ ..()
+
+/mob/living/carbon/true_devil/create_internal_organs()
+ internal_organs += new /obj/item/organ/brain
internal_organs += new /obj/item/organ/tongue
- for(var/X in internal_organs)
- var/obj/item/organ/I = X
- I.Insert(src)
..()
@@ -95,11 +102,17 @@
/mob/living/carbon/true_devil/assess_threat()
return 666
-/mob/living/carbon/true_devil/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
+/mob/living/carbon/true_devil/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
if(mind && has_bane(BANE_LIGHT))
mind.disrupt_spells(-500)
return ..() //flashes don't stop devils UNLESS it's their bane.
+/mob/living/carbon/true_devil/soundbang_act()
+ return 0
+
+/mob/living/carbon/true_devil/get_ear_protection()
+ return 2
+
/mob/living/carbon/true_devil/attacked_by(obj/item/I, mob/living/user, def_zone)
var/weakness = check_weakness(I, user)
@@ -120,9 +133,6 @@
"[attack_message]")
return TRUE
-/mob/living/carbon/true_devil/UnarmedAttack(atom/A, proximity)
- A.attack_hand(src)
-
/mob/living/carbon/true_devil/Process_Spacemove(movement_dir = 0)
return 1
@@ -200,4 +210,14 @@
if(has_bane(BANE_LIGHT))
b_loss *=2
adjustBruteLoss(b_loss)
- return ..()
\ No newline at end of file
+ return ..()
+
+
+/mob/living/carbon/true_devil/update_body() //we don't use the bodyparts layer for devils.
+ return
+
+/mob/living/carbon/true_devil/update_body_parts()
+ return
+
+/mob/living/carbon/true_devil/update_damage_overlays() //devils don't have damage overlays.
+ return
\ No newline at end of file
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 09ca3b85fab..e4311624dc5 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -283,7 +283,7 @@
intercepttext += i_text.build(V)
if(station_goals.len)
- intercepttext += "Special Orders for [station_name()]:"
+ intercepttext += "Special Orders for [station_name()]:"
for(var/datum/station_goal/G in station_goals)
G.on_report()
intercepttext += G.get_report()
@@ -526,7 +526,7 @@
return max(0, enemy_minimum_age - C.player_age)
/datum/game_mode/proc/replace_jobbaned_player(mob/living/M, role_type, pref)
- var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [role_type]?", "[role_type]", null, pref, 100, M)
+ var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [role_type]?", "[role_type]", null, pref, 50, M)
var/mob/dead/observer/theghost = null
if(candidates.len)
theghost = pick(candidates)
@@ -539,7 +539,6 @@
ticker.mode.remove_cultist(newborgie, 0, 0)
ticker.mode.remove_revolutionary(newborgie, 0)
ticker.mode.remove_gangster(newborgie, 0, remove_bosses=1)
- ticker.mode.remove_hog_follower(newborgie, 0)
remove_servant_of_ratvar(newborgie.current, TRUE)
diff --git a/code/game/gamemodes/gang/gang.dm b/code/game/gamemodes/gang/gang.dm
index 241c16bf56e..eefbf5689f1 100644
--- a/code/game/gamemodes/gang/gang.dm
+++ b/code/game/gamemodes/gang/gang.dm
@@ -149,7 +149,6 @@ var/list/gang_colors_pool = list("red","orange","yellow","green","blue","purple"
. += 1
else
mob << "The chameleon security HUD in your [where4] will help you keep track of who is mindshield-implanted, and unable to be recruited."
- mob.update_icons()
return .
@@ -167,7 +166,7 @@ var/list/gang_colors_pool = list("red","orange","yellow","green","blue","purple"
if(iscarbon(gangster_mind.current))
var/mob/living/carbon/carbon_mob = gangster_mind.current
carbon_mob.silent = max(carbon_mob.silent, 5)
- carbon_mob.flash_eyes(1, 1)
+ carbon_mob.flash_act(1, 1)
gangster_mind.current.Stun(5)
gangster_mind.current << "You are now a member of the [G.name] Gang!"
gangster_mind.current << "Help your bosses take over the station by claiming territory with special spraycans only they can provide. Simply spray on any unclaimed area of the station."
diff --git a/code/game/gamemodes/handofgod/_handofgod.dm b/code/game/gamemodes/handofgod/_handofgod.dm
deleted file mode 100644
index 2de6b0f782d..00000000000
--- a/code/game/gamemodes/handofgod/_handofgod.dm
+++ /dev/null
@@ -1,476 +0,0 @@
-
-var/global/list/global_handofgod_traptypes = list()
-var/global/list/global_handofgod_structuretypes = list()
-
-#define CONDUIT_RANGE 15
-
-
-/datum/game_mode
- var/list/datum/mind/red_deities = list()
- var/list/datum/mind/red_deity_prophets = list()
- var/list/datum/mind/red_deity_followers = list()
-
- var/list/datum/mind/blue_deities = list()
- var/list/datum/mind/blue_deity_prophets = list()
- var/list/datum/mind/blue_deity_followers = list()
-
- var/list/datum/mind/unassigned_followers = list() //for roundstart team assigning
- var/list/datum/mind/assigned_to_red = list()
- var/list/datum/mind/assigned_to_blue = list()
-
-
-/datum/game_mode/hand_of_god
- name = "hand of god"
- config_tag = "handofgod"
- antag_flag = ROLE_HOG_CULTIST //Followers use ROLE_HOG_CULTIST, Gods are picked later on with ROLE_HOG_GOD
-
- required_players = 25
- required_enemies = 8
- recommended_enemies = 8
- restricted_jobs = list("Chaplain","AI", "Cyborg", "Security Officer", "Warden", "Detective", "Head of Security", "Captain", "Head of Personnel")
-
- announce_span = "danger"
- announce_text = "Two cults are trying to overthrow one another!\n\
- Gods: Protect your nexus and eliminate the enemy god.\n\
- Prophets: Lead your cult by your deity's will.\n\
- Followers: Follow your prophet's orders and lead your deity to victory.\n\
- Crew: Destroy both cults before they can grow in strength."
-
-
-/////////////
-//Pre setup//
-/////////////
-
-/datum/game_mode/hand_of_god/pre_setup()
- if(config.protect_roles_from_antagonist)
- restricted_jobs += protected_jobs
-
- if(config.protect_assistant_from_antagonist)
- restricted_jobs += "Assistant"
-
- for(var/F in 1 to recommended_enemies)
- if(!antag_candidates.len)
- break
- var/datum/mind/follower = pick_n_take(antag_candidates)
- unassigned_followers += follower
- follower.restricted_roles = restricted_jobs
- log_game("[follower.key] (ckey) has been selected as a follower, however teams have not been decided yet.")
-
- while(unassigned_followers.len > (required_enemies / 2))
- var/datum/mind/chosen = pick_n_take(unassigned_followers)
- add_hog_follower(chosen,"red")
-
- while(unassigned_followers.len)
- var/datum/mind/chosen = pick_n_take(unassigned_followers)
- add_hog_follower(chosen,"blue")
-
- return 1
-
-
-//////////////
-//Post Setup//
-//////////////
-
-//Pick a follower to uplift into a god
-/datum/game_mode/hand_of_god/post_setup()
-
- //Find viable red god
- var/list/red_god_possibilities = get_players_for_role(ROLE_HOG_GOD)
- red_god_possibilities &= red_deity_followers //followers only
- if(!red_god_possibilities.len) //No candidates? just pick any follower regardless of prefs
- red_god_possibilities = red_deity_followers
-
- //Make red god
- var/datum/mind/red_god = pick_n_take(red_god_possibilities)
- if(red_god)
- red_god.current.become_god("red")
- remove_hog_follower(red_god,0)
- add_god(red_god,"red")
-
- //Find viable blue god
- var/list/blue_god_possibilities = get_players_for_role(ROLE_HOG_GOD)
- blue_god_possibilities &= blue_deity_followers //followers only
- if(!blue_god_possibilities.len) //No candidates? just pick any follower regardless of prefs
- blue_god_possibilities = blue_deity_followers
-
- //Make blue god
- var/datum/mind/blue_god = pick_n_take(blue_god_possibilities)
- if(blue_god)
- blue_god.current.become_god("blue")
- remove_hog_follower(blue_god,0)
- add_god(blue_god,"blue")
-
-
- //Forge objectives
- //This is done here so that both gods exist
- if(red_god)
- ticker.mode.forge_deity_objectives(red_god)
- if(blue_god)
- ticker.mode.forge_deity_objectives(blue_god)
-
-
- ..()
-
-///////////////////
-//Objective Procs//
-///////////////////
-
-/datum/game_mode/proc/forge_deity_objectives(datum/mind/deity)
- switch(rand(1,100))
- if(1 to 30)
- var/datum/objective/deicide/deicide = new
- deicide.owner = deity
- if(deicide.find_target())//Hard to kill the other god if there is none
- deity.objectives += deicide
-
- if(!(locate(/datum/objective/escape_followers) in deity.objectives))
- var/datum/objective/escape_followers/recruit = new
- recruit.owner = deity
- deity.objectives += recruit
- recruit.gen_amount_goal(8, 12)
-
- if(31 to 60)
- var/datum/objective/sacrifice_prophet/sacrifice = new
- sacrifice.owner = deity
- deity.objectives += sacrifice
-
- if(!(locate(/datum/objective/escape_followers) in deity.objectives))
- var/datum/objective/escape_followers/recruit = new
- recruit.owner = deity
- deity.objectives += recruit
- recruit.gen_amount_goal(8, 12)
-
- if(61 to 85)
- var/datum/objective/build/build = new
- build.owner = deity
- deity.objectives += build
- build.gen_amount_goal(8, 16)
-
- var/datum/objective/sacrifice_prophet/sacrifice = new
- sacrifice.owner = deity
- deity.objectives += sacrifice
-
- if(!(locate(/datum/objective/escape_followers) in deity.objectives))
- var/datum/objective/escape_followers/recruit = new
- recruit.owner = deity
- deity.objectives += recruit
- recruit.gen_amount_goal(8, 12)
-
- else
- if (!locate(/datum/objective/follower_block) in deity.objectives)
- var/datum/objective/follower_block/block = new
- block.owner = deity
- deity.objectives += block
-
-///////////////
-//Greet procs//
-///////////////
-
-/datum/game_mode/proc/greet_hog_follower(datum/mind/follower_mind,colour)
- if(follower_mind in blue_deity_prophets || follower_mind in red_deity_prophets)
- follower_mind.current << "You have been appointed as the prophet of the [colour] deity! You are the only one who can communicate with your deity at will. Guide your followers, but be wary, for many will want you dead."
- else if(colour)
- follower_mind.current << "You are a follower of the [colour] cult's deity!"
- else
- follower_mind.current << "You are a follower of a cult's deity!"
-
-
-/////////////////
-//Convert procs//
-/////////////////
-
-/datum/game_mode/proc/add_hog_follower(datum/mind/follower_mind, colour = "No Colour")
- var/mob/living/carbon/human/H = follower_mind.current
- if(isloyal(H))
- H << "Your mindshield implant blocked the influence of the [colour] deity. "
- return 0
- if((follower_mind in red_deity_followers) || (follower_mind in red_deity_prophets) || (follower_mind in blue_deity_followers) || (follower_mind in blue_deity_prophets))
- H << "You already belong to a deity. Your strong faith has blocked out the conversion attempt by the followers of the [colour] deity."
- return 0
- var/obj/item/weapon/nullrod/N = H.null_rod_check()
- if(N)
- H << "Your holy weapon prevented the [colour] deity from brainwashing you."
- return 0
-
- if(colour == "red")
- red_deity_followers += follower_mind
- if(colour == "blue")
- blue_deity_followers += follower_mind
-
- H.faction |= "[colour] god"
- follower_mind.current << "You are now a follower of the [colour] deity! Follow your deity's prophet in order to complete your deity's objectives. Convert crewmembers to your cause by using your deity's nexus. And remember - there is no you, there is only the cult."
- update_hog_icons_added(follower_mind, colour)
- follower_mind.special_role = "Hand of God: [capitalize(colour)] Follower"
- follower_mind.current.attack_log += "\[[time_stamp()]\] Has been converted to the [colour] follower cult!"
- return 1
-
-
-/datum/game_mode/proc/add_god(datum/mind/god_mind, colour = "No Colour")
- remove_hog_follower(god_mind, announce = 0)
- if(colour == "red")
- red_deities += god_mind
- if(colour == "blue")
- blue_deities += god_mind
- god_mind.current.attack_log += "\[[time_stamp()]\] Has been made into a [colour] deity!"
- god_mind.special_role = "Hand of God: [colour] God"
- update_hog_icons_added(god_mind, colour)
-
-//////////////////
-//Deconvert proc//
-//////////////////
-
-/datum/game_mode/proc/remove_hog_follower(datum/mind/follower_mind, announce = 1)//deconverts both
- if(follower_mind.current)
- if(is_handofgod_cultist(follower_mind.current) || is_handofgod_prophet(follower_mind.current))
- follower_mind.remove_hog_follower_prophet()
- update_hog_icons_removed(follower_mind,"red")
- update_hog_icons_removed(follower_mind,"blue")
-
- var/mob/living/carbon/human/H = follower_mind.current
- H.faction -= "red god"
- H.faction -= "blue god"
-
- if(announce)
- follower_mind.current.attack_log += "\[[time_stamp()]\] Has been deconverted from a deity's cult!"
- follower_mind.current << "Your mind has been cleared from the brainwashing the followers have done to you. Now you serve yourself and the crew."
- for(var/mob/living/M in view(follower_mind.current))
- M << "[follower_mind.current] looks like their faith is shattered. They're no longer a cultist!"
-
-
-
-//////////////////////
-// Mob helper procs //
-//////////////////////
-
-/proc/is_handofgod_god(A)
- if(istype(A, /mob/camera/god))
- return 1
- return 0
-
-
-/proc/is_handofgod_bluecultist(A)
- if(ishuman(A))
- var/mob/living/carbon/human/H = A
- if(H.mind)
- if(H.mind in ticker.mode.blue_deity_followers|ticker.mode.blue_deity_prophets)
- return 1
- return 0
-
-
-/proc/is_handofgod_redcultist(A)
- if(ishuman(A))
- var/mob/living/carbon/human/H = A
- if(H.mind)
- if(H.mind in ticker.mode.red_deity_followers|ticker.mode.red_deity_prophets)
- return 1
- return 0
-
-
-/proc/is_handofgod_blueprophet(A)
- if(ishuman(A))
- var/mob/living/carbon/human/H = A
- if(H.mind)
- if(H.mind in ticker.mode.blue_deity_prophets)
- return 1
- return 0
-
-
-/proc/is_handofgod_redprophet(A)
- if(ishuman(A))
- var/mob/living/carbon/human/H = A
- if(H.mind)
- if(H.mind in ticker.mode.red_deity_prophets)
- return 1
- return 0
-
-
-
-/proc/is_handofgod_cultist(A) //any of them what so ever, blue, red, hot pink, whatever.
- if(is_handofgod_redcultist(A))
- return 1
- if(is_handofgod_bluecultist(A))
- return 1
- return 0
-
-
-/proc/is_handofgod_prophet(A) //any of them what so ever, blue, red, hot pink, whatever
- if(ishuman(A))
- var/mob/living/carbon/human/H = A
- if(H.mind)
- if(H.mind in ticker.mode.blue_deity_prophets|ticker.mode.red_deity_prophets)
- return 1
- return 0
-
-
-/mob/camera/god/proc/is_handofgod_myprophet(A)
- if(!ishuman(A))
- return 0
- var/mob/living/carbon/human/H = A
- if(!H.mind)
- return 0
- if(side == "red")
- if(H.mind in ticker.mode.red_deity_prophets)
- return 1
- else if(side == "blue")
- if(H.mind in ticker.mode.blue_deity_prophets)
- return 1
-
-
-/mob/camera/god/proc/is_handofgod_myfollowers(mob/A)
- if(!ishuman(A))
- return 0
- var/mob/living/carbon/human/H = A
- if(!H.mind)
- return 0
- if(side == "red")
- if(H.mind in ticker.mode.red_deity_prophets|ticker.mode.red_deity_followers)
- return 1
- else if(side == "blue")
- if(H.mind in ticker.mode.blue_deity_prophets|ticker.mode.blue_deity_followers)
- return 1
-
-//////////////////////
-//Roundend Reporting//
-//////////////////////
-
-
-/datum/game_mode/hand_of_god/declare_completion()
- if(red_deities.len)
- var/text = " The red cult:"
- for(var/datum/mind/red_god in red_deities)
- var/godwin = 1
-
- text += " [red_god.key] was the red deity, [red_god.name] ("
- if(red_god.current)
- if(red_god.current.stat == DEAD)
- text += "died"
- else
- text += "survived"
- else
- text += "ceased existing"
- text += ")"
- if(red_deity_prophets.len)
- for(var/datum/mind/red_prophet in red_deity_prophets)
- text += " The red prophet was [red_prophet.name] ([red_prophet.key])"
- else
- text += " the red prophet was killed for their beliefs."
-
- text += " Red follower count: [red_deity_followers.len]"
- text += " Red followers: "
- for(var/datum/mind/player in red_deity_followers)
- text += "[player.name] ([player.key]), "
-
- var/objectives = ""
- if(red_god.objectives.len)
- var/count = 1
- for(var/datum/objective/O in red_god.objectives)
- if(O.check_completion())
- objectives += " Objective #[count]: [O.explanation_text] Success!"
- feedback_add_details("god_objective","[O.type]|SUCCESS")
- else
- objectives += " Objective #[count]: [O.explanation_text] Fail."
- feedback_add_details("god_objective","[O.type]|FAIL")
- godwin = 0
- count++
-
- text += objectives
-
- if(godwin)
- text += " The red cult and deity were successful!"
- feedback_add_details("god_success","SUCCESS")
- else
- text += " The red cult and deity have failed!"
- feedback_add_details("god_success","FAIL")
-
- text += " "
-
- world << text
-
- if(blue_deities.len)
- var/text = " The blue cult:"
- for(var/datum/mind/blue_god in blue_deities)
- var/godwin = 1
-
- text += " [blue_god.key] was the blue deity, [blue_god.name] ("
- if(blue_god.current)
- if(blue_god.current.stat == DEAD)
- text += "died"
- else
- text += "survived"
- else
- text += "ceased existing"
- text += ")"
- if(blue_deity_prophets.len)
- for(var/datum/mind/blue_prophet in blue_deity_prophets)
- text += " The blue prophet was [blue_prophet.name] ([blue_prophet.key])"
- else
- text += " the blue prophet was killed for their beliefs."
-
- text += " Blue follower count: [blue_deity_followers.len]"
- text += " Blue followers: "
- for(var/datum/mind/player in blue_deity_followers)
- text += "[player.name] ([player.key])"
-
- var/objectives = ""
- if(blue_god.objectives.len)
- var/count = 1
- for(var/datum/objective/O in blue_god.objectives)
- if(O.check_completion())
- objectives += " Objective #[count]: [O.explanation_text] Success!"
- feedback_add_details("god_objective","[O.type]|SUCCESS")
- else
- objectives += " Objective #[count]: [O.explanation_text] Fail."
- feedback_add_details("god_objective","[O.type]|FAIL")
- godwin = 0
- count++
-
- text += objectives
-
- if(godwin)
- text += " The blue cult and deity were successful!"
- feedback_add_details("god_success","SUCCESS")
- else
- text += " The blue cult and deity have failed!"
- feedback_add_details("god_success","FAIL")
-
- text += " "
-
- world << text
-
- ..()
- return 1
-
-
-/datum/game_mode/proc/update_hog_icons_added(datum/mind/hog_mind,side)
- var/hud_key
- var/rank = 0
- if(side == "red")
- hud_key = ANTAG_HUD_HOG_RED
- if(is_handofgod_redprophet(hog_mind.current))
- rank = 1
-
- else if(side == "blue")
- hud_key = ANTAG_HUD_HOG_BLUE
- if(is_handofgod_blueprophet(hog_mind.current))
- rank = 1
-
- if(is_handofgod_god(hog_mind.current))
- rank = 2
-
- if(hud_key)
- var/datum/atom_hud/antag/hog_hud = huds[hud_key]
- hog_hud.join_hud(hog_mind.current)
- set_antag_hud(hog_mind.current, "hog-[side]-[rank]")
-
-
-/datum/game_mode/proc/update_hog_icons_removed(datum/mind/hog_mind,side)
- var/hud_key
- if(side == "red")
- hud_key = ANTAG_HUD_HOG_RED
- else if(side == "blue")
- hud_key = ANTAG_HUD_HOG_BLUE
-
- if(hud_key)
- var/datum/atom_hud/antag/hog_hud = huds[hud_key]
- hog_hud.leave_hud(hog_mind.current)
- set_antag_hud(hog_mind.current,null)
diff --git a/code/game/gamemodes/handofgod/actions.dm b/code/game/gamemodes/handofgod/actions.dm
deleted file mode 100644
index 766a2522fde..00000000000
--- a/code/game/gamemodes/handofgod/actions.dm
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Prophet's innate godspeak */
-/datum/action/innate/godspeak
- name = "Godspeak"
- button_icon_state = "godspeak"
- check_flags = AB_CHECK_CONSCIOUS
- var/mob/camera/god/god = null
-
-/datum/action/innate/godspeak/IsAvailable()
- if(..())
- if(god)
- return 1
- return 0
-
-/datum/action/innate/godspeak/Activate()
- var/msg = input(owner,"Speak to your god","Godspeak","") as null|text
- if(!msg)
- return
- var/rendered = "Prophet [owner]:[msg]"
- god << rendered
- owner << rendered
- for(var/mob/M in mob_list)
- if(isobserver(M))
- var/link = FOLLOW_LINK(M, owner)
- M << "[link] [rendered]"
-
-/datum/action/innate/godspeak/Destroy()
- god = null
- return ..()
diff --git a/code/game/gamemodes/handofgod/god.dm b/code/game/gamemodes/handofgod/god.dm
deleted file mode 100644
index 5a238736052..00000000000
--- a/code/game/gamemodes/handofgod/god.dm
+++ /dev/null
@@ -1,290 +0,0 @@
-
-/mob/camera/god
- name = "deity" //Auto changes to the player's deity name/random name
- real_name = "deity"
- icon = 'icons/mob/mob.dmi'
- icon_state = "marker"
- invisibility = 60
- see_in_dark = 0
- see_invisible = 55
- sight = SEE_TURFS | SEE_MOBS | SEE_OBJS | SEE_SELF
- languages_spoken = ALL
- languages_understood = ALL
- hud_possible = list(ANTAG_HUD)
- mouse_opacity = 0 //can't be clicked
-
- var/faith = 100 //For initial prophet appointing/stupid purchase
- var/max_faith = 100
- var/side = "neutral" //Red or Blue for the gamemode
- var/obj/structure/divine/nexus/god_nexus = null //The source of the god's power in this realm, kill it and the god is kill
- var/nexus_required = FALSE //If the god dies from losing it's nexus, defaults to off so that gods don't instantly die at roundstart
- var/followers_required = 0 //Same as above
- var/alive_followers = 0
- var/list/structures = list()
- var/list/conduits = list()
- var/prophets_sacrificed_in_name = 0
- var/image/ghostimage = null //For observer with darkness off visiblity
- var/list/prophets = list()
- var/datum/action/innate/godspeak/speak2god
-
-/mob/camera/god/New()
- ..()
- update_icons()
- build_hog_construction_lists()
-
- //Force nexuses after 15 minutes in hand of god mode
- if(ticker && ticker.mode && ticker.mode.name == "hand of god")
- addtimer(src, "forceplacenexus", 9000, FALSE)
-
-
-//Rebuilds the list based on the gamemode's lists
-//As they are the most accurate each tick
-/mob/camera/god/proc/get_my_followers()
- switch(side)
- if("red")
- . = ticker.mode.red_deity_followers|ticker.mode.red_deity_prophets
- if("blue")
- . = ticker.mode.blue_deity_followers|ticker.mode.blue_deity_prophets
- else
- . = list()
-
-
-/mob/camera/god/Destroy()
- var/list/followers = get_my_followers()
- for(var/datum/mind/F in followers)
- if(F.current)
- F.current << "Your god is DEAD!"
- for(var/X in prophets)
- speak2god.Remove(X)
- ghost_darkness_images -= ghostimage
- updateallghostimages()
- return ..()
-
-
-
-/mob/camera/god/proc/forceplacenexus()
- if(god_nexus)
- return
-
- if(ability_cost(0,1,0))
- place_nexus()
-
- else
- if(blobstart.len) //we're on invalid turf, try to pick from blobstart
- loc = pick(blobstart)
- place_nexus() //if blobstart fails, places on dense turf, but better than nothing
- src << "You failed to place your nexus, and it has been placed for you!"
-
-
-/mob/camera/god/update_icons()
- icon_state = "[initial(icon_state)]-[side]"
-
- if(ghostimage)
- ghost_darkness_images -= ghostimage
-
- ghostimage = image(src.icon,src,src.icon_state)
- ghost_darkness_images |= ghostimage
- updateallghostimages()
-
-
-/mob/camera/god/Stat()
- ..()
- if(statpanel("Status"))
- if(god_nexus)
- stat("Nexus health: ", god_nexus.health)
- stat("Followers: ", alive_followers)
- stat("Faith: ", "[faith]/[max_faith]")
-
-
-/mob/camera/god/Login()
- ..()
- sync_mind()
- src << "You are a deity!"
- src << "You are a deity and are worshipped by a cult! You are rather weak right now, but that will change as you gain more followers."
- src << "You will need to place an anchor to this world, a Nexus, in two minutes. If you don't, one will be placed immediately below you."
- src << "Your Follower count determines how many people believe in you and are a part of your cult."
- src << "Your Nexus Integrity tells you the condition of your nexus. If your nexus is destroyed, you will die. Place your Nexus on a safe, isolated place, that is still accessible to your followers."
- src << "Your Faith is used to interact with the world. This will regenerate on its own, and it goes faster when you have more followers and power pylons."
- src << "The first thing you should do after placing your nexus is to appoint a prophet. Only prophets can hear you talk, unless you use an expensive power."
- update_health_hud()
-
-
-/mob/camera/god/update_health_hud()
- if(god_nexus && hud_used && hud_used.healths)
- hud_used.healths.maptext = "
"
-
-
-
-/mob/camera/god/proc/place_nexus()
- if(god_nexus || (z != 1))
- return 0
-
- var/obj/structure/divine/nexus/N = new(get_turf(src))
- N.assign_deity(src)
- god_nexus = N
- nexus_required = TRUE
- verbs -= /mob/camera/god/verb/constructnexus
- //verbs += /mob/camera/god/verb/movenexus //Translocators have no sprite
- update_health_hud()
-
- var/area/A = get_area(src)
- if(A)
- var/areaname = A.name
- var/list/followers = get_my_followers()
- for(var/datum/mind/F in followers)
- if(F.current)
- F.current << "Your god's nexus is in \the [areaname]"
-
-
-/mob/camera/god/verb/freeturret()
- set category = "Deity"
- set name = "Free Turret (0)"
- set desc = "Place a single turret, for 0 faith."
-
- if(!ability_cost(0,1,1))
- return
- var/obj/structure/divine/defensepylon/DP = new(get_turf(src))
- DP.assign_deity(src)
- verbs -= /mob/camera/god/verb/freeturret
-
-
-
-/mob/camera/god/proc/update_followers()
- alive_followers = 0
- var/list/all_followers = get_my_followers()
- for(var/datum/mind/F in all_followers)
- if(F.current && F.current.stat != DEAD)
- alive_followers++
-
- if(hud_used && hud_used.deity_follower_display)
- hud_used.deity_follower_display.maptext = "
[alive_followers]
"
-
-
-/mob/camera/god/proc/check_death()
- if(!alive_followers)
- src << "You no longer have any followers. You shudder as you feel your existence cease..."
- if(god_nexus && !qdeleted(god_nexus))
- god_nexus.visible_message("\The [src] suddenly disappears!")
- qdel(god_nexus)
- qdel(src)
-
-
-/mob/camera/god/say(msg)
- if(!msg)
- return
- if(client)
- if(client.prefs.muted & MUTE_IC)
- src << "You cannot send IC messages (muted)."
- return
- if(src.client.handle_spam_prevention(msg,MUTE_IC))
- return
- if(stat)
- return
-
- god_speak(msg)
-
-
-/mob/camera/god/proc/god_speak(msg)
- log_say("Hand of God: [capitalize(side)] God/[key_name(src)] : [msg]")
- msg = trim(copytext(sanitize(msg), 1, MAX_MESSAGE_LEN))
- if(!msg)
- return
-
- msg = say_quote(msg, get_spans())
- var/rendered = "Divine Telepathy,[name][msg]"
- src << rendered
-
- for(var/mob/M in mob_list)
- if(is_handofgod_myfollowers(M))
- M << rendered
- if(isobserver(M))
- var/link = FOLLOW_LINK(M, src)
- M << "[link] [rendered]"
-
-
-/mob/camera/god/emote(act,m_type = 1 ,msg = null)
- return
-
-
-/mob/camera/god/Move(NewLoc, Dir = 0)
- loc = NewLoc
-
-
-
-/mob/camera/god/Topic(href, href_list)
- if(href_list["create_structure"])
- if(!ability_cost(75,1,1))
- return
-
- var/obj/structure/divine/construct_type = text2path(href_list["create_structure"]) //it's a path but we need to initial() some vars
- if(!construct_type)
- return
-
- add_faith(-75)
- var/obj/structure/divine/construction_holder/CH = new(get_turf(src))
- CH.assign_deity(src)
- CH.setup_construction(construct_type)
- CH.visible_message("[src] has created a transparent, unfinished [initial(construct_type.name)]. It can be finished by adding materials.")
- src << "You may click a construction site to cancel it, but only faith is refunded."
- structure_construction_ui(src)
- return
-
- if(href_list["place_trap"])
- if(!ability_cost(20,1,1))
- return
-
- var/atom/trap_type = text2path(href_list["place_trap"])
- if(!trap_type)
- return
-
- src << "You lay \a [initial(trap_type.name)]"
- add_faith(-20)
- new trap_type(get_turf(src))
- return
-
- ..()
-
-
-/mob/camera/god/proc/structure_construction_ui(mob/camera/god/user)
- var/dat = ""
- for(var/t in global_handofgod_structuretypes)
- if(global_handofgod_structuretypes[t])
- var/obj/structure/divine/apath = global_handofgod_structuretypes[t]
- dat += "
[capitalize(t)]
"
- var/imgstate = initial(apath.autocolours) ? "[initial(apath.icon_state)]-[side]" : "[initial(apath.icon_state)]"
- var/icon/I = icon('icons/obj/hand_of_god_structures.dmi',imgstate)
- var/img_component = lowertext(t)
- //I hate byond, but atleast it autocaches these so it's only 1*number_of_structures worth of actual calls
- user << browse_rsc(I,"hog_structure-[img_component].png")
- dat += "
"
- dat += "Description: [initial(apath.desc)] "
- dat += "
"
for(var/datum/mind/traitor in ticker.mode.traitors)
diff --git a/code/modules/admin/verbs/fps.dm b/code/modules/admin/verbs/fps.dm
index 0866a5859ea..901e6f636a4 100644
--- a/code/modules/admin/verbs/fps.dm
+++ b/code/modules/admin/verbs/fps.dm
@@ -7,18 +7,18 @@
if(!check_rights(R_DEBUG))
return
- var/fps = round(input("Sets game frames-per-second. Can potentially break the game","FPS", config.fps) as num|null)
+ var/new_fps = round(input("Sets game frames-per-second. Can potentially break the game (default: [config.fps])","FPS", world.fps) as num|null)
- if(fps <= 0)
- src << "Error: ticklag(): Invalid world.ticklag value. No changes made."
+ if(new_fps <= 0)
+ src << "Error: set_server_fps(): Invalid world.fps value. No changes made."
return
- if(fps > config.fps)
- if(alert(src, "You are setting fps to a high value:\n\t[fps] frames-per-second\n\tconfig.fps = [config.fps]","Warning!","Confirm","ABORT-ABORT-ABORT") != "Confirm")
+ if(new_fps > config.fps*1.5)
+ if(alert(src, "You are setting fps to a high value:\n\t[new_fps] frames-per-second\n\tconfig.fps = [config.fps]","Warning!","Confirm","ABORT-ABORT-ABORT") != "Confirm")
return
- var/msg = "[key_name(src)] has modified world.fps to [fps]"
+ var/msg = "[key_name(src)] has modified world.fps to [new_fps]"
log_admin(msg, 0)
message_admins(msg, 0)
feedback_add_details("admin_verb","TICKLAG") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- world.fps = fps
\ No newline at end of file
+ world.fps = new_fps
\ No newline at end of file
diff --git a/code/modules/admin/verbs/manipulate_organs.dm b/code/modules/admin/verbs/manipulate_organs.dm
index 82703edaa3e..289d1b6cd7d 100644
--- a/code/modules/admin/verbs/manipulate_organs.dm
+++ b/code/modules/admin/verbs/manipulate_organs.dm
@@ -26,7 +26,8 @@
organ.implant(C)
if("drop organ/implant", "remove organ/implant")
- for(var/obj/item/organ/I in C.internal_organs)
+ for(var/X in C.internal_organs)
+ var/obj/item/organ/I = X
organs["[I.name] ([I.type])"] = I
for(var/obj/item/weapon/implant/I in C)
diff --git a/code/modules/admin/verbs/onlyone.dm b/code/modules/admin/verbs/onlyone.dm
index affb6b57bc9..fa8998008d6 100644
--- a/code/modules/admin/verbs/onlyone.dm
+++ b/code/modules/admin/verbs/onlyone.dm
@@ -1,60 +1,78 @@
-/client/proc/only_one()
+var/highlander = FALSE
+/client/proc/only_one() //Gives everyone kilts, berets, claymores, and pinpointers, with the objective to hijack the emergency shuttle.
if(!ticker || !ticker.mode)
alert("The game hasn't started yet!")
return
+ highlander = TRUE
world << "THERE CAN BE ONLY ONE!!!"
world << sound('sound/misc/highlander.ogg')
+ for(var/obj/item/weapon/disk/nuclear/N in poi_list)
+ N.relocate() //Gets it out of bags and such
+
for(var/mob/living/carbon/human/H in player_list)
- if(H.stat == DEAD || !(H.client)) continue
-
- ticker.mode.traitors += H.mind
- H.mind.special_role = "highlander"
-
- H.dna.species.specflags |= NOGUNS //nice try jackass
-
- var/datum/objective/steal/steal_objective = new
- steal_objective.owner = H.mind
- steal_objective.set_target(new /datum/objective_item/steal/nukedisc)
- H.mind.objectives += steal_objective
-
- var/datum/objective/hijack/hijack_objective = new
- hijack_objective.explanation_text = "Escape on the shuttle alone. Ensure nobody else makes it out."
- hijack_objective.owner = H.mind
- H.mind.objectives += hijack_objective
-
- H.mind.announce_objectives()
-
- for (var/obj/item/I in H)
- if (istype(I, /obj/item/weapon/implant))
- continue
- qdel(I)
-
- H.equip_to_slot_or_del(new /obj/item/clothing/under/kilt/highlander(H), slot_w_uniform)
- H.equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(H), slot_ears)
- H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(H), slot_head)
- H.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(H), slot_shoes)
- H.equip_to_slot_or_del(new /obj/item/weapon/pinpointer(H.loc), slot_l_store)
-
- var/obj/item/weapon/card/id/W = new(H)
- W.icon_state = "centcom"
- W.access = get_all_accesses()
- W.access += get_all_centcom_access()
- W.assignment = "Highlander"
- W.registered_name = H.real_name
- W.flags |= NODROP
- W.update_label(H.real_name)
- H.equip_to_slot_or_del(W, slot_wear_id)
-
- var/obj/item/weapon/claymore/highlander/H1 = new(H)
- H.put_in_hands(H1)
- H1.pickup(H)
+ if(H.stat == DEAD || !(H.client))
+ continue
+ H.make_scottish()
message_admins("[key_name_admin(usr)] used THERE CAN BE ONLY ONE!")
log_admin("[key_name(usr)] used THERE CAN BE ONLY ONE.")
addtimer(SSshuttle.emergency, "request", 50, FALSE, null, 1)
+/mob/living/carbon/human/proc/make_scottish()
+ ticker.mode.traitors += mind
+ mind.special_role = "highlander"
+ dna.species.specflags |= NOGUNS //nice try jackass
+
+ var/datum/objective/steal/steal_objective = new
+ steal_objective.owner = mind
+ steal_objective.set_target(new /datum/objective_item/steal/nukedisc)
+ mind.objectives += steal_objective
+
+ var/datum/objective/hijack/hijack_objective = new
+ hijack_objective.explanation_text = "Escape on the shuttle alone. Ensure that nobody else makes it out."
+ hijack_objective.owner = mind
+ mind.objectives += hijack_objective
+
+ mind.announce_objectives()
+
+ for(var/obj/item/I in src)
+ if(istype(I, /obj/item/weapon/implant))
+ continue
+ qdel(I)
+ equip_to_slot_or_del(new /obj/item/clothing/under/kilt/highlander(src), slot_w_uniform)
+ equip_to_slot_or_del(new /obj/item/device/radio/headset/heads/captain(src), slot_ears)
+ equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(src), slot_head)
+ equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(src), slot_shoes)
+ equip_to_slot_or_del(new /obj/item/weapon/pinpointer(src), slot_l_store)
+ for(var/obj/item/weapon/pinpointer/P in src)
+ P.attack_self(src)
+ var/obj/item/weapon/card/id/W = new(src)
+ W.icon_state = "centcom"
+ W.access = get_all_accesses()
+ W.access += get_all_centcom_access()
+ W.assignment = "Highlander"
+ W.registered_name = real_name
+ W.flags |= NODROP
+ W.update_label(real_name)
+ equip_to_slot_or_del(W, slot_wear_id)
+
+ var/obj/item/weapon/claymore/highlander/H1 = new(src)
+ if(!highlander)
+ H1.admin_spawned = TRUE //To prevent announcing
+ put_in_hands(H1)
+ H1.pickup(src) //For the stun shielding
+
+ var/obj/item/weapon/bloodcrawl/antiwelder = new(src)
+ antiwelder.name = "compulsion of honor"
+ antiwelder.desc = "You are unable to hold anything in this hand until you're the last one left!"
+ antiwelder.icon_state = "bloodhand_right"
+ put_in_hands(antiwelder)
+
+ src << "Your [H1.name] cries out for blood. Join in the slaughter, lest you be claimed yourself...\n\
+ Activate it in your hand, and it will lead to the nearest target. Attack the nuclear authentication disk with it, and you will store it."
+
/proc/only_me()
if(!ticker || !ticker.mode)
alert("The game hasn't started yet!")
diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm
index 7190bb3f945..ba2ccc76d6d 100644
--- a/code/modules/admin/verbs/pray.dm
+++ b/code/modules/admin/verbs/pray.dm
@@ -20,13 +20,13 @@
var/image/cross = image('icons/obj/storage.dmi',"bible")
var/font_color = "purple"
var/prayer_type = "PRAYER"
- var/deity = "Space Jesus" // y'all need space jesus by default
- if (ticker && ticker.Bible_deity_name)
- deity = ticker.Bible_deity_name
+ var/deity
if(usr.job == "Chaplain")
cross = image('icons/obj/storage.dmi',"kingyellow")
font_color = "blue"
prayer_type = "CHAPLAIN PRAYER"
+ if (ticker && ticker.Bible_deity_name)
+ deity = ticker.Bible_deity_name
else if(iscultist(usr))
cross = image('icons/obj/storage.dmi',"tome")
font_color = "red"
@@ -34,7 +34,7 @@
deity = "Nar-Sie"
msg = "\icon[cross] \
- [prayer_type] (to [deity]): \
+ [prayer_type][deity ? " (to [deity])" : ""]: \
[ADMIN_FULLMONTY(src)] [ADMIN_SC(src)]: \
[msg]"
diff --git a/code/modules/admin/verbs/randomverbs.dm b/code/modules/admin/verbs/randomverbs.dm
index 1008453f85b..a229b10f337 100644
--- a/code/modules/admin/verbs/randomverbs.dm
+++ b/code/modules/admin/verbs/randomverbs.dm
@@ -441,7 +441,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
var/datum/round_event/ion_storm/ion = new(0, announce_ion_laws, input)
ion.start()
-
+
feedback_add_details("admin_verb","IONC") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
/client/proc/cmd_admin_rejuvenate(mob/living/M in mob_list)
@@ -595,7 +595,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
message_admins("[key_name_admin(usr)] has gibbed [key_name_admin(M)]")
if(istype(M, /mob/dead/observer))
- gibs(M.loc, M.viruses)
+ new /obj/effect/gibspawner/generic(M.loc, M.viruses)
return
if(confirm == "Yes")
M.gib()
@@ -612,7 +612,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
log_admin("[key_name(usr)] used gibself.")
message_admins("[key_name_admin(usr)] used gibself.")
feedback_add_details("admin_verb","GIBS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
- mob.gib(1, 1)
+ mob.gib(1, 1, 1)
/client/proc/cmd_admin_check_contents(mob/living/M in mob_list)
set category = "Special Verbs"
@@ -1152,4 +1152,4 @@ var/list/datum/outfit/custom_outfits = list() //Admin created outfits
for(var/datum/station_goal/S in ticker.mode.station_goals)
dat += "[S.name] - Announce | Remove "
dat += " Add New Goal"
- usr << browse(dat, "window=goals;size=400x400")
\ No newline at end of file
+ usr << browse(dat, "window=goals;size=400x400")
diff --git a/code/modules/assembly/flash.dm b/code/modules/assembly/flash.dm
index 2ca23434053..f174129c534 100644
--- a/code/modules/assembly/flash.dm
+++ b/code/modules/assembly/flash.dm
@@ -85,7 +85,7 @@
if(user && targeted)
if(M.weakeyes)
M.Weaken(3) //quick weaken bypasses eye protection but has no eye flash
- if(M.flash_eyes(1, 1))
+ if(M.flash_act(1, 1))
M.confused += power
terrible_conversion_proc(M, user)
M.Stun(1)
@@ -100,7 +100,7 @@
user << "You fail to blind [M] with the flash!"
M << "[user] fails to blind you with the flash!"
else
- if(M.flash_eyes())
+ if(M.flash_act())
M.confused += power
/obj/item/device/assembly/flash/attack(mob/living/M, mob/user)
@@ -117,7 +117,7 @@
update_icon(1)
M.Weaken(6)
R.confused += 5
- R.flash_eyes(affect_silicon = 1)
+ R.flash_act(affect_silicon = 1)
user.visible_message("[user] overloads [R]'s sensors with the flash!", "You overload [R]'s sensors with the flash!")
return 1
@@ -173,26 +173,15 @@
/obj/item/device/assembly/flash/cyborg/attack(mob/living/M, mob/user)
..()
- cyborg_flash_animation(user)
+ PoolOrNew(/obj/effect/overlay/temp/borgflash, get_turf(src))
/obj/item/device/assembly/flash/cyborg/attack_self(mob/user)
..()
- cyborg_flash_animation(user)
+ PoolOrNew(/obj/effect/overlay/temp/borgflash, get_turf(src))
/obj/item/device/assembly/flash/cyborg/attackby(obj/item/weapon/W, mob/user, params)
return
-/obj/item/device/assembly/flash/cyborg/proc/cyborg_flash_animation(mob/living/user)
- var/atom/movable/overlay/animation = new(user.loc)
- animation.layer = user.layer + 1
- animation.icon_state = "blank"
- animation.icon = 'icons/mob/mob.dmi'
- animation.master = user
- flick("blspell", animation)
- sleep(5)
- qdel(animation)
-
-
/obj/item/device/assembly/flash/memorizer
name = "memorizer"
desc = "If you see this, you're not likely to remember it any time soon."
@@ -201,3 +190,32 @@
item_state = "nullrod"
/obj/item/device/assembly/flash/handheld //this is now the regular pocket flashes
+
+/obj/item/device/assembly/flash/armimplant
+ name = "photon projector"
+ desc = "A high-powered photon projector implant normally used for lighting purposes, but also doubles as a flashbulb weapon. Self-repair protocals fix the flashbulb if it ever burns out."
+ var/flashcd = 20
+ var/overheat = 0
+ var/obj/item/organ/cyberimp/arm/flash/I = null
+
+/obj/item/device/assembly/flash/armimplant/burn_out()
+ if(I && I.owner)
+ I.owner << "Your photon projector implant overheats and deactivates!"
+ I.Retract()
+ overheat = FALSE
+ addtimer(src, "cooldown", flashcd * 2)
+
+/obj/item/device/assembly/flash/armimplant/try_use_flash(mob/user = null)
+ if(overheat)
+ if(I && I.owner)
+ I.owner << "Your photon projector is running too hot to be used again so quickly!"
+ return FALSE
+ overheat = TRUE
+ addtimer(src, "cooldown", flashcd)
+ playsound(src.loc, 'sound/weapons/flash.ogg', 100, 1)
+ update_icon(1)
+ return TRUE
+
+
+/obj/item/device/assembly/flash/armimplant/proc/cooldown()
+ overheat = FALSE
diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm
index 30adb230404..31ecea937bd 100644
--- a/code/modules/assembly/mousetrap.dm
+++ b/code/modules/assembly/mousetrap.dm
@@ -60,8 +60,7 @@
H.Stun(3)
if(affecting)
if(affecting.take_damage(1, 0))
- H.update_damage_overlays(0)
- H.updatehealth()
+ H.update_damage_overlays()
else if(ismouse(target))
var/mob/living/simple_animal/mouse/M = target
visible_message("SPLAT!")
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
index 8208ada42d7..b61e862502c 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
@@ -65,7 +65,7 @@ Acts like a normal vent, but has an input AND output.
..()
if(!on)
- return 0
+ return FALSE
var/datum/gas_mixture/air1 = AIR1
var/datum/gas_mixture/air2 = AIR2
@@ -85,6 +85,9 @@ Acts like a normal vent, but has an input AND output.
var/transfer_moles = pressure_delta*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
+ //Removed can be null if there is no atmosphere in air1
+ if(!removed)
+ return FALSE
loc.assume_air(removed)
air_update_turf()
@@ -105,6 +108,9 @@ Acts like a normal vent, but has an input AND output.
var/transfer_moles = pressure_delta*air2.volume/(environment.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
+ //removed can be null if there is no air in the location
+ if(!removed)
+ return FALSE
air2.merge(removed)
air_update_turf()
@@ -112,7 +118,7 @@ Acts like a normal vent, but has an input AND output.
var/datum/pipeline/parent2 = PARENT2
parent2.update = 1
- return 1
+ return TRUE
//Radio remote control
@@ -195,4 +201,4 @@ Acts like a normal vent, but has an input AND output.
#undef EXT_BOUND
#undef INPUT_MIN
-#undef OUTPUT_MAX
\ No newline at end of file
+#undef OUTPUT_MAX
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
index f95900688ec..b39fe29c0ff 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
@@ -184,9 +184,10 @@
//Take a gas sample
var/datum/gas_mixture/removed = tile.remove_air(transfer_moles)
- var/list/removed_gases = removed.gases
- if (isnull(removed)) //in space
+ //Nothing left to remove from the tile
+ if (isnull(removed))
return
+ var/list/removed_gases = removed.gases
//Filter it
var/datum/gas_mixture/filtered_out = new
diff --git a/code/modules/awaymissions/capture_the_flag.dm b/code/modules/awaymissions/capture_the_flag.dm
index e6cb0ad5723..c6c4e545d42 100644
--- a/code/modules/awaymissions/capture_the_flag.dm
+++ b/code/modules/awaymissions/capture_the_flag.dm
@@ -463,31 +463,27 @@
-/obj/structure/divine/trap/ctf
+/obj/structure/trap/ctf
name = "Spawn protection"
desc = "Stay outta the enemy spawn!"
icon_state = "trap"
- health = INFINITY
- maxhealth = INFINITY
var/team = WHITE_TEAM
- constructable = FALSE
time_between_triggers = 1
alpha = 255
-/obj/structure/divine/trap/examine(mob/user)
+/obj/structure/trap/examine(mob/user)
return
-/obj/structure/divine/trap/ctf/trap_effect(mob/living/L)
+/obj/structure/trap/ctf/trap_effect(mob/living/L)
if(!(src.team in L.faction))
L << "Stay out of the enemy spawn!"
L.death()
-
-/obj/structure/divine/trap/ctf/red
+/obj/structure/trap/ctf/red
team = RED_TEAM
icon_state = "trap-fire"
-/obj/structure/divine/trap/ctf/blue
+/obj/structure/trap/ctf/blue
team = BLUE_TEAM
icon_state = "trap-frost"
diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm
index 5764994c628..b1ed528cb40 100644
--- a/code/modules/cargo/packs.dm
+++ b/code/modules/cargo/packs.dm
@@ -5,6 +5,7 @@ datum/supply_pack
var/contraband = FALSE
var/cost = 700 // Minimum cost, or infinite points are possible.
var/access = FALSE
+ var/access_any = FALSE
var/list/contains = null
var/crate_name = "crate"
var/crate_type = /obj/structure/closet/crate
@@ -17,6 +18,8 @@ datum/supply_pack
C.name = crate_name
if(access)
C.req_access = list(access)
+ if(access_any)
+ C.req_one_access = access_any
fill(C)
@@ -452,6 +455,35 @@ datum/supply_pack
crate_name = "fuel tank crate"
crate_type = /obj/structure/closet/crate/large
+/datum/supply_pack/engineering/oxygen
+ name = "Oxygen Canister"
+ cost = 1500
+ contains = list(/obj/machinery/portable_atmospherics/canister/oxygen)
+ crate_name = "oxygen canister crate"
+ crate_type = /obj/structure/closet/crate/large
+
+/datum/supply_pack/engineering/nitrogen
+ name = "Nitrogen Canister"
+ cost = 2000
+ contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen)
+ crate_name = "nitrogen canister crate"
+ crate_type = /obj/structure/closet/crate/large
+
+/datum/supply_pack/engineering/carbon_dio
+ name = "Carbon Dioxide Canister"
+ cost = 3000
+ contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide)
+ crate_name = "carbon dioxide canister crate"
+ crate_type = /obj/structure/closet/crate/large
+
+/datum/supply_pack/science/nitrous_oxide_canister
+ name = "Nitrous Oxide Canister"
+ cost = 3000
+ access = access_atmospherics
+ contains = list(/obj/machinery/portable_atmospherics/canister/nitrous_oxide)
+ crate_name = "nitrous oxide canister crate"
+ crate_type = /obj/structure/closet/crate/secure
+
/datum/supply_pack/engineering/tools
name = "Toolbox Crate"
contains = list(/obj/item/weapon/storage/toolbox/electrical,
@@ -829,6 +861,24 @@ datum/supply_pack
crate_type = /obj/structure/closet/crate/secure
dangerous = TRUE
+/datum/supply_pack/science/bz_canister
+ name = "BZ Canister"
+ cost = 4000
+ access_any = list(access_rd, access_atmospherics)
+ contains = list(/obj/machinery/portable_atmospherics/canister/bz)
+ crate_name = "bz canister crate"
+ crate_type = /obj/structure/closet/crate/secure
+ dangerous = TRUE
+
+/datum/supply_pack/science/freon_canister
+ name = "Freon Canister"
+ cost = 6000
+ access_any = list(access_rd, access_atmospherics)
+ contains = list(/obj/machinery/portable_atmospherics/canister/freon)
+ crate_name = "freon canister crate"
+ crate_type = /obj/structure/closet/crate/secure
+ dangerous = TRUE
+
/datum/supply_pack/science/research
name = "Machine Prototype Crate"
cost = 8000
@@ -1201,6 +1251,13 @@ datum/supply_pack
crate_name = "high-capacity water tank crate"
crate_type = /obj/structure/closet/crate/large
+/datum/supply_pack/misc/water_vapor
+ name = "Water Vapor Canister"
+ cost = 2500
+ contains = list(/obj/machinery/portable_atmospherics/canister/water_vapor)
+ crate_name = "water vapor canister crate"
+ crate_type = /obj/structure/closet/crate/large
+
/datum/supply_pack/misc/lasertag
name = "Laser Tag Crate"
cost = 1500
diff --git a/code/modules/client/client_colour.dm b/code/modules/client/client_colour.dm
index 8073b0abebf..7e78032f467 100644
--- a/code/modules/client/client_colour.dm
+++ b/code/modules/client/client_colour.dm
@@ -27,7 +27,7 @@
colour_type - a typepath (subtyped from /datum/client_colour)
*/
/mob/proc/add_client_colour(colour_type)
- if(!ispath(/datum/client_colour))
+ if(!ispath(colour_type, /datum/client_colour))
return
var/datum/client_colour/CC = new colour_type()
@@ -41,7 +41,7 @@
colour_type - a typepath (subtyped from /datum/client_colour)
*/
/mob/proc/remove_client_colour(colour_type)
- if(!ispath(/datum/client_colour))
+ if(!ispath(colour_type, /datum/client_colour))
return
for(var/cc in client_colours)
@@ -70,3 +70,39 @@
+/datum/client_colour/glass_colour
+ priority = 0
+ colour = "red"
+
+/datum/client_colour/glass_colour/green
+ colour = "#aaffaa"
+
+/datum/client_colour/glass_colour/lightgreen
+ colour = "#ccffcc"
+
+/datum/client_colour/glass_colour/blue
+ colour = "#aaaaff"
+
+/datum/client_colour/glass_colour/lightblue
+ colour = "#ccccff"
+
+/datum/client_colour/glass_colour/yellow
+ colour = "#ffff66"
+
+/datum/client_colour/glass_colour/red
+ colour = "#ffaaaa"
+
+/datum/client_colour/glass_colour/darkred
+ colour = "#bb5555"
+
+/datum/client_colour/glass_colour/orange
+ colour = "#ffbb99"
+
+/datum/client_colour/glass_colour/lightorange
+ colour = "#ffddaa"
+
+/datum/client_colour/glass_colour/purple
+ colour = "#ff99ff"
+
+/datum/client_colour/glass_colour/gray
+ colour = "#cccccc"
\ No newline at end of file
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index d594f9bae4c..b1c2b33657a 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -41,6 +41,8 @@ var/list/preferences_datums = list()
var/allow_midround_antag = 1
var/preferred_map = null
+ var/uses_glasses_colour = 0
+
//character preferences
var/real_name //our character's name
var/be_random_name = 0 //whether we'll have a random name every round
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 5042ae817ba..eabce84b226 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -97,7 +97,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
ignoring = list()
if(current_version < 15)
toggles |= SOUND_ANNOUNCEMENTS
-
+
//should this proc get fairly long (say 3 versions long),
//just increase SAVEFILE_VERSION_MIN so it's not as far behind
@@ -123,7 +123,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
joblessrole = BERANDOMJOB
else
joblessrole = BEASSISTANT
-
+
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
@@ -171,6 +171,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["ignoring"] >> ignoring
S["ghost_hud"] >> ghost_hud
S["inquisitive_ghost"] >> inquisitive_ghost
+ S["uses_glasses_colour"]>> uses_glasses_colour
//try to fix any outdated data if necessary
if(needs_update >= 0)
@@ -222,6 +223,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["ignoring"] << ignoring
S["ghost_hud"] << ghost_hud
S["inquisitive_ghost"] << inquisitive_ghost
+ S["uses_glasses_colour"]<< uses_glasses_colour
return 1
diff --git a/code/modules/client/verbs/suicide.dm b/code/modules/client/verbs/suicide.dm
index cb6120efe3d..659fe3f3c8d 100644
--- a/code/modules/client/verbs/suicide.dm
+++ b/code/modules/client/verbs/suicide.dm
@@ -53,7 +53,7 @@
adjustOxyLoss(max(200 - getToxLoss() - getFireLoss() - getBruteLoss() - getOxyLoss(), 0))
death(0)
-/mob/living/carbon/brain/verb/suicide()
+/mob/living/brain/verb/suicide()
set hidden = 1
if(!canSuicide())
return
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 55721e470d2..3a848e8d52a 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -47,7 +47,7 @@
M.put_in_hand(src, H.held_index)
add_fingerprint(usr)
-/obj/item/clothing/throw_at(atom/target, range, speed, mob/thrower, spin)
+/obj/item/clothing/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0)
if(pockets)
pockets.close_all()
return ..()
diff --git a/code/modules/clothing/glasses/glasses.dm b/code/modules/clothing/glasses/glasses.dm
index 1c5375434f2..8ca4bf66cc4 100644
--- a/code/modules/clothing/glasses/glasses.dm
+++ b/code/modules/clothing/glasses/glasses.dm
@@ -1,6 +1,7 @@
/obj/item/clothing/glasses
name = "glasses"
materials = list(MAT_GLASS = 250)
+ var/glass_colour_type = null //colors your vision when worn
//called when thermal glasses are emped.
/obj/item/clothing/glasses/proc/thermal_overload()
@@ -9,7 +10,7 @@
if(!(H.disabilities & BLIND))
if(H.glasses == src)
H << "The [src] overloads and blinds you!"
- H.flash_eyes(visual = 1)
+ H.flash_act(visual = 1)
H.blind_eyes(3)
H.blur_eyes(5)
H.adjust_eye_damage(5)
@@ -23,6 +24,7 @@
darkness_view = 2
vision_flags = SEE_TURFS
invis_view = SEE_INVISIBLE_MINIMUM
+ glass_colour_type = /datum/client_colour/glass_colour/lightgreen
/obj/item/clothing/glasses/meson/night
name = "Night Vision Optical Meson Scanner"
@@ -31,6 +33,7 @@
item_state = "nvgmeson"
origin_tech = "magnets=4;engineering=5;plasmatech=4"
darkness_view = 8
+ glass_colour_type = /datum/client_colour/glass_colour/green
/obj/item/clothing/glasses/meson/gar
name = "gar mesons"
@@ -52,6 +55,7 @@
origin_tech = "magnets=2;engineering=1"
scan_reagents = 1 //You can see reagents while wearing science goggles
actions_types = list(/datum/action/item_action/toggle_research_scanner)
+ glass_colour_type = /datum/client_colour/glass_colour/purple
/obj/item/clothing/glasses/science/item_action_slot_check(slot)
if(slot == slot_glasses)
@@ -65,6 +69,7 @@
origin_tech = "materials=4;magnets=4;plasmatech=4;engineering=4"
darkness_view = 8
invis_view = SEE_INVISIBLE_MINIMUM
+ glass_colour_type = /datum/client_colour/glass_colour/green
/obj/item/clothing/glasses/eyepatch
name = "eyepatch"
@@ -85,6 +90,7 @@
item_state = "glasses"
origin_tech = "magnets=3;engineering=3"
vision_flags = SEE_OBJS
+ glass_colour_type = /datum/client_colour/glass_colour/lightblue
/obj/item/clothing/glasses/material/mining
name = "Optical Material Scanner"
@@ -105,6 +111,7 @@
attack_verb = list("sliced")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ glass_colour_type = /datum/client_colour/glass_colour/lightgreen
/obj/item/clothing/glasses/regular
name = "Prescription Glasses"
@@ -133,7 +140,7 @@
darkness_view = 1
flash_protect = 1
tint = 1
-
+ glass_colour_type = /datum/client_colour/glass_colour/gray
dog_fashion = /datum/dog_fashion/head
/obj/item/clothing/glasses/sunglasses/reagent
@@ -173,6 +180,7 @@
attack_verb = list("sliced")
hitsound = 'sound/weapons/bladeslice.ogg'
sharpness = IS_SHARP
+ glass_colour_type = /datum/client_colour/glass_colour/orange
/obj/item/clothing/glasses/sunglasses/gar/supergar
desc = "We evolve past the person we were a minute before. Little by little we advance with each turn. That's how a drill works!"
@@ -181,6 +189,7 @@
item_state = "gar"
force = 12
throwforce = 12
+ glass_colour_type = /datum/client_colour/glass_colour/red
/obj/item/clothing/glasses/welding
name = "welding goggles"
@@ -193,6 +202,7 @@
tint = 2
flags_cover = GLASSESCOVERSEYES
visor_flags_inv = HIDEEYES
+ glass_colour_type = /datum/client_colour/glass_colour/gray
/obj/item/clothing/glasses/welding/attack_self()
@@ -230,6 +240,7 @@
vision_flags = SEE_MOBS
invis_view = 2
flash_protect = 0
+ glass_colour_type = /datum/client_colour/glass_colour/red
/obj/item/clothing/glasses/thermal/emp_act(severity)
thermal_overload()
@@ -273,12 +284,14 @@
desc = "A sweet pair of orange shades."
icon_state = "orangeglasses"
item_state = "orangeglasses"
+ glass_colour_type = /datum/client_colour/glass_colour/lightorange
/obj/item/clothing/glasses/red
name = "red glasses"
desc = "A sweet pair of red shades."
icon_state = "redglasses"
item_state = "redglasses"
+ glass_colour_type = /datum/client_colour/glass_colour/red
/obj/item/clothing/glasses/godeye
name = "eye of god"
@@ -356,3 +369,35 @@
icon_state = "gar"
item_state = "gar"
+
+/obj/item/clothing/glasses/AltClick(mob/user)
+ if(glass_colour_type && ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.client)
+ if(H.client.prefs)
+ if(src == H.glasses)
+ H.client.prefs.uses_glasses_colour = !H.client.prefs.uses_glasses_colour
+ if(H.client.prefs.uses_glasses_colour)
+ H << "You will now see glasses colors."
+ else
+ H << "You will no longer see glasses colors."
+ H.update_glasses_color(src, 1)
+ else
+ return ..()
+
+/obj/item/clothing/glasses/proc/change_glass_color(mob/living/carbon/human/H, datum/client_colour/glass_colour/new_color_type)
+ var/old_colour_type = glass_colour_type
+ if(!new_color_type || ispath(new_color_type)) //the new glass colour type must be null or a path.
+ glass_colour_type = new_color_type
+ if(H && H.glasses == src)
+ if(old_colour_type)
+ H.remove_client_colour(old_colour_type)
+ if(glass_colour_type)
+ H.update_glasses_color(src, 1)
+
+
+/mob/living/carbon/human/proc/update_glasses_color(obj/item/clothing/glasses/G, glasses_equipped)
+ if(client && client.prefs.uses_glasses_colour && glasses_equipped)
+ add_client_colour(G.glass_colour_type)
+ else
+ remove_client_colour(G.glass_colour_type)
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index ba07bdd1aba..847208a09f4 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -6,6 +6,7 @@
var/hud_type = null
/obj/item/clothing/glasses/hud/equipped(mob/living/carbon/human/user, slot)
+ ..()
if(hud_type && slot == slot_glasses)
var/datum/atom_hud/H = huds[hud_type]
H.add_hud_to(user)
@@ -33,6 +34,7 @@
icon_state = "healthhud"
origin_tech = "magnets=3;biotech=2"
hud_type = DATA_HUD_MEDICAL_ADVANCED
+ glass_colour_type = /datum/client_colour/glass_colour/lightblue
/obj/item/clothing/glasses/hud/health/night
name = "Night Vision Health Scanner HUD"
@@ -42,6 +44,7 @@
origin_tech = "magnets=4;biotech=4;plasmatech=4;engineering=5"
darkness_view = 8
invis_view = SEE_INVISIBLE_MINIMUM
+ glass_colour_type = /datum/client_colour/glass_colour/green
/obj/item/clothing/glasses/hud/diagnostic
name = "Diagnostic HUD"
@@ -49,6 +52,7 @@
icon_state = "diagnostichud"
origin_tech = "magnets=2;engineering=2"
hud_type = DATA_HUD_DIAGNOSTIC
+ glass_colour_type = /datum/client_colour/glass_colour/lightorange
/obj/item/clothing/glasses/hud/diagnostic/night
name = "Night Vision Diagnostic HUD"
@@ -58,6 +62,7 @@
origin_tech = "magnets=4;powerstorage=4;plasmatech=4;engineering=5"
darkness_view = 8
invis_view = SEE_INVISIBLE_MINIMUM
+ glass_colour_type = /datum/client_colour/glass_colour/green
/obj/item/clothing/glasses/hud/security
name = "Security HUD"
@@ -65,6 +70,7 @@
icon_state = "securityhud"
origin_tech = "magnets=3;combat=2"
hud_type = DATA_HUD_SECURITY_ADVANCED
+ glass_colour_type = /datum/client_colour/glass_colour/red
/obj/item/clothing/glasses/hud/security/chameleon
name = "Chamleon Security HUD"
@@ -88,6 +94,7 @@
darkness_view = 1
flash_protect = 1
tint = 1
+ glass_colour_type = /datum/client_colour/glass_colour/darkred
/obj/item/clothing/glasses/hud/security/night
name = "Night Vision Security HUD"
@@ -96,6 +103,7 @@
origin_tech = "magnets=4;combat=4;plasmatech=4;engineering=5"
darkness_view = 8
invis_view = SEE_INVISIBLE_MINIMUM
+ glass_colour_type = /datum/client_colour/glass_colour/green
/obj/item/clothing/glasses/hud/security/sunglasses/gars
name = "HUD gar glasses"
@@ -151,16 +159,20 @@
hud_type = DATA_HUD_SECURITY_ADVANCED
vision_flags = SEE_MOBS
invis_view = 2
+ glass_colour_type = /datum/client_colour/glass_colour/red
/obj/item/clothing/glasses/hud/toggle/thermal/attack_self(mob/user)
..()
switch (hud_type)
if (DATA_HUD_MEDICAL_ADVANCED)
icon_state = "meson"
+ change_glass_color(user, /datum/client_colour/glass_colour/green)
if (DATA_HUD_SECURITY_ADVANCED)
icon_state = "thermal"
+ change_glass_color(user, /datum/client_colour/glass_colour/red)
else
icon_state = "purple"
+ change_glass_color(user, /datum/client_colour/glass_colour/purple)
user.update_inv_glasses()
/obj/item/clothing/glasses/hud/toggle/thermal/emp_act(severity)
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index f17cb08415b..11e77d18c1f 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -85,6 +85,10 @@
jetpack = new jetpack(src)
..()
+/obj/item/clothing/suit/space/hardsuit/attack_self(mob/user)
+ user.changeNext_move(CLICK_CD_MELEE)
+ ..()
+
/obj/item/clothing/suit/space/hardsuit/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/weapon/tank/jetpack/suit))
if(jetpack)
@@ -486,6 +490,28 @@
armor = list(melee = 45, bullet = 25, laser = 30, energy = 10, bomb = 25, bio = 100, rad = 50)
helmettype = /obj/item/clothing/head/helmet/space/hardsuit/security/hos
+ //Captain
+/obj/item/clothing/head/helmet/space/hardsuit/captain
+ name = "captain's hardsuit helmet"
+ icon_state = "capspace"
+ item_state = "capspacehelmet"
+ desc = "A special hardsuit helmet designed for only the most fashionable of military figureheads."
+ armor = list(melee = 40, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50)
+ actions_types = list()
+ flags_inv = HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDEFACIALHAIR //we want to see the mask
+
+/obj/item/clothing/head/helmet/space/hardsuit/captain/attack_self()
+ return //Sprites required for flashlight
+
+/obj/item/clothing/suit/space/hardsuit/captain
+ name = "captain's hardsuit"
+ desc = "A bulky, heavy-duty piece of exclusive Nanotrasen hardsuit armor. YOU are in charge!"
+ icon_state = "caparmor"
+ item_state = "capspacesuit"
+ allowed = list(/obj/item/weapon/tank/internals, /obj/item/device/flashlight,/obj/item/weapon/gun/energy, /obj/item/weapon/gun/projectile, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs)
+ armor = list(melee = 40, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50)
+ helmettype = /obj/item/clothing/head/helmet/space/hardsuit/captain
+
//Clown
/obj/item/clothing/head/helmet/space/hardsuit/clown
name = "cosmohonk hardsuit helmet"
diff --git a/code/modules/clothing/spacesuits/miscellaneous.dm b/code/modules/clothing/spacesuits/miscellaneous.dm
index 1b902d27fe4..10bdf923bbb 100644
--- a/code/modules/clothing/spacesuits/miscellaneous.dm
+++ b/code/modules/clothing/spacesuits/miscellaneous.dm
@@ -14,26 +14,6 @@ Contains:
- Carp hardsuit
*/
- //Captain's space suit, not hardsuits because no flashlight!
-/obj/item/clothing/head/helmet/space/captain
- name = "captain's space helmet"
- icon_state = "capspace"
- item_state = "capspacehelmet"
- desc = "A special helmet designed for only the most fashionable of military figureheads."
- flags_inv = HIDEFACE|HIDEEARS|HIDEHAIR
- permeability_coefficient = 0.01
- armor = list(melee = 40, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50)
-
-/obj/item/clothing/suit/space/captain
- name = "captain's space suit"
- desc = "A bulky, heavy-duty piece of exclusive Nanotrasen armor. YOU are in charge!"
- icon_state = "caparmor"
- item_state = "capspacesuit"
- w_class = 4
- allowed = list(/obj/item/weapon/tank/internals, /obj/item/device/flashlight,/obj/item/weapon/gun/energy, /obj/item/weapon/gun/projectile, /obj/item/ammo_box, /obj/item/ammo_casing, /obj/item/weapon/melee/baton,/obj/item/weapon/restraints/handcuffs)
- armor = list(melee = 40, bullet = 50, laser = 50, energy = 25, bomb = 50, bio = 100, rad = 50)
-
-
//Death squad armored space suits, not hardsuits!
/obj/item/clothing/head/helmet/space/hardsuit/deathsquad
name = "deathsquad helmet"
diff --git a/code/modules/clothing/suits/armor.dm b/code/modules/clothing/suits/armor.dm
index 1531c6780a0..5a77d9f2f7f 100644
--- a/code/modules/clothing/suits/armor.dm
+++ b/code/modules/clothing/suits/armor.dm
@@ -279,7 +279,7 @@
for(var/mob/living/M in view(6, owner))
if(M == owner)
continue
- owner.Beam(M,icon_state="lightning[rand(1, 12)]",icon='icons/effects/effects.dmi',time=5)
+ owner.Beam(M,icon_state="lightning[rand(1, 12)]",time=5)
M.adjustFireLoss(25)
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
reactivearmor_cooldown = world.time + reactivearmor_cooldown_duration
diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm
index 0bd4fff922f..5dcbeb7c63b 100644
--- a/code/modules/crafting/recipes.dm
+++ b/code/modules/crafting/recipes.dm
@@ -94,17 +94,17 @@
/datum/crafting_recipe/ed209
name = "ED209"
result = /mob/living/simple_animal/bot/ed209
- reqs = list(/obj/item/robot_parts/robot_suit = 1,
+ reqs = list(/obj/item/robot_suit = 1,
/obj/item/clothing/head/helmet = 1,
/obj/item/clothing/suit/armor/vest = 1,
- /obj/item/robot_parts/l_leg = 1,
- /obj/item/robot_parts/r_leg = 1,
+ /obj/item/bodypart/l_leg/robot = 1,
+ /obj/item/bodypart/r_leg/robot = 1,
/obj/item/stack/sheet/metal = 5,
/obj/item/stack/cable_coil = 5,
/obj/item/weapon/gun/energy/gun/advtaser = 1,
/obj/item/weapon/stock_parts/cell = 1,
/obj/item/device/assembly/prox_sensor = 1,
- /obj/item/robot_parts/r_arm = 1)
+ /obj/item/bodypart/r_arm/robot = 1)
tools = list(/obj/item/weapon/weldingtool, /obj/item/weapon/screwdriver)
time = 60
category = CAT_ROBOT
@@ -116,7 +116,7 @@
/obj/item/clothing/head/helmet/sec = 1,
/obj/item/weapon/melee/baton = 1,
/obj/item/device/assembly/prox_sensor = 1,
- /obj/item/robot_parts/r_arm = 1)
+ /obj/item/bodypart/r_arm/robot = 1)
tools = list(/obj/item/weapon/weldingtool)
time = 60
category = CAT_ROBOT
@@ -126,7 +126,7 @@
result = /mob/living/simple_animal/bot/cleanbot
reqs = list(/obj/item/weapon/reagent_containers/glass/bucket = 1,
/obj/item/device/assembly/prox_sensor = 1,
- /obj/item/robot_parts/r_arm = 1)
+ /obj/item/bodypart/r_arm/robot = 1)
time = 40
category = CAT_ROBOT
@@ -136,7 +136,7 @@
reqs = list(/obj/item/weapon/storage/toolbox/mechanical = 1,
/obj/item/stack/tile/plasteel = 1,
/obj/item/device/assembly/prox_sensor = 1,
- /obj/item/robot_parts/r_arm = 1)
+ /obj/item/bodypart/r_arm/robot = 1)
time = 40
category = CAT_ROBOT
@@ -146,7 +146,7 @@
reqs = list(/obj/item/device/healthanalyzer = 1,
/obj/item/weapon/storage/firstaid = 1,
/obj/item/device/assembly/prox_sensor = 1,
- /obj/item/robot_parts/r_arm = 1)
+ /obj/item/bodypart/r_arm/robot = 1)
time = 40
category = CAT_ROBOT
diff --git a/code/modules/events/anomaly_bluespace.dm b/code/modules/events/anomaly_bluespace.dm
index 19b3ac4abfa..a2b2dbf31bc 100644
--- a/code/modules/events/anomaly_bluespace.dm
+++ b/code/modules/events/anomaly_bluespace.dm
@@ -44,7 +44,7 @@
var/list/flashers = list()
for(var/mob/living/carbon/C in viewers(TO, null))
- if(C.flash_eyes())
+ if(C.flash_act())
flashers += C
var/y_distance = TO.y - FROM.y
diff --git a/code/modules/food_and_drinks/food/snacks/meat.dm b/code/modules/food_and_drinks/food/snacks/meat.dm
index d006bfb6ee7..ae777bcbcd1 100644
--- a/code/modules/food_and_drinks/food/snacks/meat.dm
+++ b/code/modules/food_and_drinks/food/snacks/meat.dm
@@ -190,6 +190,22 @@
icon_state = "meatwheat_clump"
bitesize = 4
+/obj/item/weapon/reagent_containers/food/snacks/meat/rawbacon
+ name = "raw piece of bacon"
+ desc = "A raw piece of bacon."
+ icon_state = "bacon"
+ cooked_type = /obj/item/weapon/reagent_containers/food/snacks/meat/bacon
+ bitesize = 2
+ list_reagents = list("nutriment" = 1)
+ filling_color = "#B22222"
+
+/obj/item/weapon/reagent_containers/food/snacks/meat/bacon
+ name = "piece of bacon"
+ desc = "A delicious piece of bacon."
+ icon_state = "baconcooked"
+ list_reagents = list("nutriment" = 2)
+ bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+
////////////////////////////////////// MEAT STEAKS ///////////////////////////////////////////////////////////
@@ -272,7 +288,6 @@
name = "raw spider cutlet"
cooked_type = /obj/item/weapon/reagent_containers/food/snacks/meat/cutlet/spider
-
//Cooked cutlets
/obj/item/weapon/reagent_containers/food/snacks/meat/cutlet
@@ -298,5 +313,4 @@
name = "xeno cutlet"
/obj/item/weapon/reagent_containers/food/snacks/meat/cutlet/spider
- name = "spider cutlet"
-
+ name = "spider cutlet"
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/food/snacks_burgers.dm b/code/modules/food_and_drinks/food/snacks_burgers.dm
index 4cab54e9891..77e04689317 100644
--- a/code/modules/food_and_drinks/food/snacks_burgers.dm
+++ b/code/modules/food_and_drinks/food/snacks_burgers.dm
@@ -203,3 +203,9 @@
desc = "It's still warm. The steam coming off of it looks like baseball."
icon_state = "baseball"
bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+
+/obj/item/weapon/reagent_containers/food/snacks/burger/baconburger
+ name = "bacon burger"
+ desc = "The perfect combination of all things American."
+ icon_state = "baconburger"
+ bonus_reagents = list("nutriment" = 8, "vitamin" = 1)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/processor.dm b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
index ebbe4b1e4d2..41b3b987986 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/processor.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
@@ -3,7 +3,7 @@
name = "food processor"
desc = "An industrial grinder used to process meat and other foods. Keep hands clear of intake area while operating."
icon = 'icons/obj/kitchen.dmi'
- icon_state = "processor"
+ icon_state = "processor1"
layer = BELOW_OBJ_LAYER
density = 1
anchored = 1
@@ -90,6 +90,10 @@
input = /obj/item/weapon/reagent_containers/food/snacks/meat/slab
output = /obj/item/weapon/reagent_containers/food/snacks/faggot
+/datum/food_processor_process/bacon
+ input = /obj/item/weapon/reagent_containers/food/snacks/meat/rawcutlet
+ output = /obj/item/weapon/reagent_containers/food/snacks/meat/rawbacon
+
/datum/food_processor_process/sweetpotato
input = /obj/item/weapon/reagent_containers/food/snacks/grown/potato/sweet
output = /obj/item/weapon/reagent_containers/food/snacks/yakiimo
@@ -185,7 +189,7 @@
if(src.processing)
user << "The processor is in the process of processing!"
return 1
- if(default_deconstruction_screwdriver(user, "processor1", "processor", O))
+ if(default_deconstruction_screwdriver(user, "processor", "processor1", O))
return
if(exchange_parts(user, O))
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_burger.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_burger.dm
index 94b40722664..573574f4e9c 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_burger.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_burger.dm
@@ -262,3 +262,14 @@
)
result = /obj/item/weapon/reagent_containers/food/snacks/burger/baseball
category = CAT_BURGER
+
+/datum/crafting_recipe/food/baconburger
+ name = "Bacon Burger"
+ reqs = list(
+ /obj/item/weapon/reagent_containers/food/snacks/meat/bacon = 3,
+ /obj/item/weapon/reagent_containers/food/snacks/cheesewedge = 1,
+ /obj/item/weapon/reagent_containers/food/snacks/bun = 1
+ )
+
+ result = /obj/item/weapon/reagent_containers/food/snacks/burger/baconburger
+ category = CAT_BURGER
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
index 8229391e50e..439db2986b0 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_cake.dm
@@ -111,7 +111,7 @@
/obj/item/weapon/reagent_containers/food/snacks/meat/slab = 3,
/datum/reagent/blood = 30,
/datum/reagent/consumable/sprinkles = 5,
- /datum/reagent/toxin/teslium = 1 //To shock the whole thing into life
+ /datum/reagent/teslium = 1 //To shock the whole thing into life
)
result = /mob/living/simple_animal/pet/cat/cak
category = CAT_CAKE //Cat! Haha, get it? CAT? GET IT???
diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm
index 0dd97c68a36..be78c4ef8b2 100644
--- a/code/modules/hydroponics/grown/nettle.dm
+++ b/code/modules/hydroponics/grown/nettle.dm
@@ -51,16 +51,13 @@
if(!iscarbon(user))
return 0
var/mob/living/carbon/C = user
- if(ishuman(user))
- var/mob/living/carbon/human/H = C
- if(H.gloves)
- return 0
- var/organ = (H.held_index_to_dir(H.active_hand_index) == "l" ? "l_":"r_") + "arm"
- var/obj/item/bodypart/affecting = H.get_bodypart(organ)
- if(affecting && affecting.take_damage(0, force))
- H.update_damage_overlays(0)
- else
- C.take_organ_damage(0,force)
+ if(C.gloves)
+ return 0
+ var/hit_zone = (C.held_index_to_dir(C.active_hand_index) == "l" ? "l_":"r_") + "arm"
+ var/obj/item/bodypart/affecting = C.get_bodypart(hit_zone)
+ if(affecting)
+ if(affecting.take_damage(0, force))
+ C.update_damage_overlays()
C << "The nettle burns your bare hand!"
return 1
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 0fcfa4992c1..afcf5b0e83d 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -857,6 +857,10 @@
user.visible_message("[user] digs out the plants in [src]!", "You dig out all of [src]'s plants!")
playsound(src, 'sound/effects/shovel_dig.ogg', 50, 1)
if(myseed) //Could be that they're just using it as a de-weeder
+ age = 0
+ health = 0
+ if(harvest)
+ harvest = FALSE //To make sure they can't just put in another seed and insta-harvest it
qdel(myseed)
myseed = null
weedlevel = 0 //Has a side effect of cleaning up those nasty weeds
diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm
index 40c2a19addb..9109ddefc76 100644
--- a/code/modules/mining/abandoned_crates.dm
+++ b/code/modules/mining/abandoned_crates.dm
@@ -11,12 +11,12 @@
/obj/structure/closet/crate/secure/loot/New()
..()
- var/list/digits = list("1", "2", "3", "4", "5", "6", "7", "8", "9", "z")
+ var/list/digits = list("1", "2", "3", "4", "5", "6", "7", "8", "9", "0")
code = ""
for(var/i = 0, i < codelen, i++)
var/dig = pick(digits)
code += dig
- digits -= dig //Player can enter codes with matching digits, but there are never matching digits in the answer
+ digits -= dig //there are never matching digits in the answer
var/loot = rand(1,100) //100 different crates with varying chances of spawning
switch(loot)
@@ -153,18 +153,26 @@
/obj/structure/closet/crate/secure/loot/attack_hand(mob/user)
if(locked)
user << "The crate is locked with a Deca-code lock."
- var/input = input(usr, "Enter [codelen] digits.", "Deca-Code Lock", "") as text
+ var/input = input(usr, "Enter [codelen] digits. All digits must be unique.", "Deca-Code Lock", "") as text
if(user.canUseTopic(src, 1))
+ var/list/sanitised = list()
+ var/sanitycheck = 1
+ for(var/i=1,i<=length(input),i++) //put the guess into a list
+ sanitised += text2num(copytext(input,i,i+1))
+ for(var/i=1,i<=(length(input)-1),i++) //compare each digit in the guess to all those following it
+ for(var/j=(i+1),j<=length(input),j++)
+ if(sanitised[i] == sanitised[j])
+ sanitycheck = null //if a digit is repeated, reject the input
if (input == code)
user << "The crate unlocks!"
locked = 0
cut_overlays()
add_overlay("securecrateg")
- else if (input == null || length(input) != codelen)
+ else if (input == null || sanitycheck == null || length(input) != codelen)
user << "You leave the crate alone."
else
user << "A red light flashes."
- lastattempt = replacetext(input, 0, "z")
+ lastattempt = input
attempts--
if(attempts == 0)
boom(user)
@@ -192,19 +200,21 @@
user << "* Anti-Tamper Bomb will activate after [src.attempts] failed access attempts."
if(lastattempt != null)
var/list/guess = list()
+ var/list/answer = list()
var/bulls = 0
var/cows = 0
- for(var/i = 1, i < codelen + 1, i++)
- var/a = copytext(lastattempt, i, i+1) //Stuff the code into the list
- guess += a
- guess[a] = i
- for(var/i in guess) //Go through list and count matches
- var/a = findtext(code, i)
- if(a == guess[i])
- ++bulls
- else if(a)
+ for(var/i=1,i<=length(lastattempt),i++)
+ guess += text2num(copytext(lastattempt,i,i+1))
+ for(var/i=1,i<=length(lastattempt),i++)
+ answer += text2num(copytext(code,i,i+1))
+ for(var/i = 1, i < codelen + 1, i++) // Go through list and count matches
+ if( answer.Find(guess[i],1,codelen+1))
++cows
- user << "Last code attempt had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions."
+ if( answer[i] == guess[i])
+ ++bulls
+ --cows
+
+ user << "Last code attempt, [lastattempt], had [bulls] correct digits at correct positions and [cows] correct digits at incorrect positions."
return
return ..()
diff --git a/code/modules/mining/equipment.dm b/code/modules/mining/equipment.dm
index 1b8e9a56612..adcd2b4762c 100644
--- a/code/modules/mining/equipment.dm
+++ b/code/modules/mining/equipment.dm
@@ -507,7 +507,7 @@
range = 6
var/obj/item/weapon/twohanded/required/mining_hammer/hammer_synced = null
-/obj/item/projectile/destabilizer/on_hit(atom/target, blocked = 0, hit_zone)
+/obj/item/projectile/destabilizer/on_hit(atom/target, blocked = 0)
if(hammer_synced)
if(hammer_synced.mark == target)
return ..()
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 066ae8d47a7..365e3ade3f6 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -48,7 +48,7 @@
if(16)
new /obj/item/weapon/guardiancreator(src)
if(17)
- new /obj/item/borg/upgrade/modkit/aoe/mobs(src)
+ new /obj/item/borg/upgrade/modkit/aoe/turfs/andmobs(src)
if(18)
new /obj/item/device/warp_cube/red(src)
if(19)
@@ -195,7 +195,7 @@
/obj/item/projectile/hook/fire(setAngle)
if(firer)
- chain = Beam(firer, icon_state = "chain", icon = 'icons/obj/lavaland/artefacts.dmi', time = INFINITY, maxdistance = INFINITY)
+ chain = firer.Beam(src, icon_state = "chain", time = INFINITY, maxdistance = INFINITY)
..()
/obj/item/projectile/hook/on_hit(atom/target)
@@ -704,15 +704,13 @@
/obj/structure/closet/crate/necropolis/bubblegum/New()
..()
- var/loot = rand(1,4)
+ var/loot = rand(1,3)
switch(loot)
if(1)
- new /obj/item/weapon/antag_spawner/slaughter_demon(src)
- if(2)
new /obj/item/mayhem(src)
- if(3)
+ if(2)
new /obj/item/blood_contract(src)
- if(4)
+ if(3)
new /obj/item/weapon/gun/magic/staff/spellblade(src)
/obj/item/blood_contract
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index fdb907cac4b..6c9143d943e 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -38,13 +38,14 @@
new /datum/data/mining_equipment("Mining Hardsuit", /obj/item/clothing/suit/space/hardsuit/mining, 2000),
new /datum/data/mining_equipment("Diamond Pickaxe", /obj/item/weapon/pickaxe/diamond, 2000),
new /datum/data/mining_equipment("Super Resonator", /obj/item/weapon/resonator/upgraded, 2500),
- new /datum/data/mining_equipment("KA White Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer, 200),
- new /datum/data/mining_equipment("KA Adjustable Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer/adjustable, 300),
- new /datum/data/mining_equipment("KA Super Chassis", /obj/item/borg/upgrade/modkit/chassis_mod, 400),
- new /datum/data/mining_equipment("KA Hyper Chassis", /obj/item/borg/upgrade/modkit/chassis_mod/orange, 500),
+ new /datum/data/mining_equipment("KA White Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer, 100),
+ new /datum/data/mining_equipment("KA Adjustable Tracer Rounds", /obj/item/borg/upgrade/modkit/tracer/adjustable, 150),
+ new /datum/data/mining_equipment("KA Super Chassis", /obj/item/borg/upgrade/modkit/chassis_mod, 250),
+ new /datum/data/mining_equipment("KA Hyper Chassis", /obj/item/borg/upgrade/modkit/chassis_mod/orange, 300),
new /datum/data/mining_equipment("KA Range Increase", /obj/item/borg/upgrade/modkit/range, 1000),
new /datum/data/mining_equipment("KA Damage Increase", /obj/item/borg/upgrade/modkit/damage, 1000),
new /datum/data/mining_equipment("KA Cooldown Decrease",/obj/item/borg/upgrade/modkit/cooldown, 1000),
+ new /datum/data/mining_equipment("KA AoE Damage", /obj/item/borg/upgrade/modkit/aoe/mobs, 2000),
new /datum/data/mining_equipment("Point Transfer Card", /obj/item/weapon/card/mining_point_card, 500),
new /datum/data/mining_equipment("Mining Drone", /mob/living/simple_animal/hostile/mining_drone, 800),
new /datum/data/mining_equipment("Drone Melee Upgrade", /obj/item/device/mine_bot_ugprade, 400),
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index bf154f66071..1bd06bab451 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -313,7 +313,6 @@
desc = "An easily-compressable wall used for temporary shelter."
icon = 'icons/turf/walls/survival_pod_walls.dmi'
icon_state = "smooth"
- walltype = "shuttle"
smooth = SMOOTH_MORE|SMOOTH_DIAGONAL
canSmoothWith = list(/turf/closed/wall/shuttle/survival, /obj/machinery/door/airlock/survival_pod, /obj/structure/window/shuttle/survival_pod, /obj/structure/shuttle/engine)
diff --git a/code/modules/mob/interactive.dm b/code/modules/mob/interactive.dm
index ab0aa56e1c0..7be2862b0fc 100644
--- a/code/modules/mob/interactive.dm
+++ b/code/modules/mob/interactive.dm
@@ -137,13 +137,14 @@
retal = 1
retal_target = user
-/mob/living/carbon/human/interactive/bullet_act(var/obj/item/projectile/P)
+/mob/living/carbon/human/interactive/bullet_act(obj/item/projectile/P, def_zone)
var/potentialAssault = locate(/mob/living) in view(2,P.starting)
if(potentialAssault)
retal = 1
retal_target = potentialAssault
..()
+
/client/proc/resetSNPC(var/mob/A in SSnpc.botPool_l)
set name = "Reset SNPC"
set desc = "Reset the SNPC"
@@ -296,9 +297,9 @@
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
if(prob((FUZZY_CHANCE_LOW+FUZZY_CHANCE_HIGH)/4))
- BP.change_bodypart_status(ORGAN_ROBOTIC)
+ BP.change_bodypart_status(BODYPART_ROBOTIC)
update_icons()
- update_damage_overlays(0)
+ update_damage_overlays()
functions = list("nearbyscan","combat","shitcurity","chatter") // stop customize adding multiple copies of a function
//job specific favours
switch(myjob.title)
@@ -422,10 +423,6 @@
if(C)
retalTarget(C)
-/mob/living/carbon/human/interactive/bullet_act(obj/item/projectile/P, def_zone)
- ..(P,def_zone)
- retalTarget(P.firer)
-
/mob/living/carbon/human/interactive/attack_hand(mob/living/carbon/human/M)
..(M)
retalTarget(M)
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index ecaf9f1c75f..377d8ac3b15 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -266,6 +266,7 @@
if(client)
client.screen -= I
I.layer = initial(I.layer)
+ I.appearance_flags &= ~NO_CLIENT_COLOR
I.forceMove(loc)
I.dropped(src)
return TRUE
diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm
similarity index 92%
rename from code/modules/mob/living/carbon/brain/MMI.dm
rename to code/modules/mob/living/brain/MMI.dm
index 0e6e1ee5b03..4979cbd6c7d 100644
--- a/code/modules/mob/living/carbon/brain/MMI.dm
+++ b/code/modules/mob/living/brain/MMI.dm
@@ -1,198 +1,197 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
-
-/obj/item/device/mmi
- name = "Man-Machine Interface"
- desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity, that nevertheless has become standard-issue on Nanotrasen stations."
- icon = 'icons/obj/assemblies.dmi'
- icon_state = "mmi_empty"
- w_class = 3
- origin_tech = "biotech=2;programming=3;engineering=2"
- var/braintype = "Cyborg"
- var/obj/item/device/radio/radio = null //Let's give it a radio.
- var/hacked = 0 //Whether or not this is a Syndicate MMI
- var/mob/living/carbon/brain/brainmob = null //The current occupant.
- var/mob/living/silicon/robot = null //Appears unused.
- var/obj/mecha = null //This does not appear to be used outside of reference in mecha.dm.
- var/obj/item/organ/brain/brain = null //The actual brain
- var/clockwork = FALSE //If this is a soul vessel
-
-/obj/item/device/mmi/update_icon()
- if(brain)
- if(istype(brain,/obj/item/organ/brain/alien))
- if(brainmob && brainmob.stat == DEAD)
- icon_state = "mmi_alien_dead"
- else
- icon_state = "mmi_alien"
- braintype = "Xenoborg" //HISS....Beep.
- else
- if(brainmob && brainmob.stat == DEAD)
- icon_state = "mmi_dead"
- else
- icon_state = "mmi_full"
- braintype = "Cyborg"
- else
- icon_state = "mmi_empty"
-
-/obj/item/device/mmi/New()
- ..()
- radio = new(src) //Spawns a radio inside the MMI.
- radio.broadcasting = 0 //researching radio mmis turned the robofabs into radios because this didnt start as 0.
-
-
-
-/obj/item/device/mmi/attackby(obj/item/O, mob/user, params)
- user.changeNext_move(CLICK_CD_MELEE)
- if(istype(O,/obj/item/organ/brain)) //Time to stick a brain in it --NEO
- var/obj/item/organ/brain/newbrain = O
- if(brain)
- user << "There's already a brain in the MMI!"
- return
- if(!newbrain.brainmob)
- user << "You aren't sure where this brain came from, but you're pretty sure it's a useless brain!"
- return
-
- if(!user.unEquip(O))
- return
- var/mob/living/carbon/brain/B = newbrain.brainmob
- if(!B.key)
- B.notify_ghost_cloning("Someone has put your brain in a MMI!", source = src)
- visible_message("[user] sticks \a [newbrain] into \the [src].")
-
- brainmob = newbrain.brainmob
- newbrain.brainmob = null
- brainmob.loc = src
- brainmob.container = src
- if(!newbrain.damaged_brain) // the brain organ hasn't been beaten to death.
- brainmob.stat = CONSCIOUS //we manually revive the brain mob
- dead_mob_list -= brainmob
- living_mob_list += brainmob
-
- brainmob.reset_perspective()
- if(clockwork)
- add_servant_of_ratvar(brainmob, TRUE)
- newbrain.loc = src //P-put your brain in it
- brain = newbrain
-
- name = "Man-Machine Interface: [brainmob.real_name]"
- update_icon()
-
- feedback_inc("cyborg_mmis_filled",1)
-
- return
-
- else if(brainmob)
- O.attack(brainmob, user) //Oh noooeeeee
- return
- ..()
-
-/obj/item/device/mmi/attack_self(mob/user)
- if(!brain)
- radio.on = !radio.on
- user << "You toggle the MMI's radio system [radio.on==1 ? "on" : "off"]."
- else
- user << "You unlock and upend the MMI, spilling the brain onto the floor."
-
- brainmob.container = null //Reset brainmob mmi var.
- brainmob.loc = brain //Throw mob into brain.
- brainmob.stat = DEAD
- brainmob.emp_damage = 0
- brainmob.reset_perspective() //so the brainmob follows the brain organ instead of the mmi. And to update our vision
- living_mob_list -= brainmob //Get outta here
- dead_mob_list += brainmob
- brain.brainmob = brainmob //Set the brain to use the brainmob
- brainmob = null //Set mmi brainmob var to null
-
- user.put_in_hands(brain) //puts brain in the user's hand or otherwise drops it on the user's turf
- brain = null //No more brain in here
-
- update_icon()
- name = "Man-Machine Interface"
-
-/obj/item/device/mmi/proc/transfer_identity(mob/living/L) //Same deal as the regular brain proc. Used for human-->robot people.
- if(!brainmob)
- brainmob = new(src)
- brainmob.name = L.real_name
- brainmob.real_name = L.real_name
- if(L.has_dna())
- var/mob/living/carbon/C = L
- if(!brainmob.dna)
- brainmob.dna = new /datum/dna(brainmob)
- C.dna.copy_dna(brainmob.dna)
- brainmob.container = src
-
- if(ishuman(L))
- var/mob/living/carbon/human/H = L
- var/obj/item/organ/brain/newbrain = H.getorgan(/obj/item/organ/brain)
- newbrain.loc = src
- brain = newbrain
- else if(!brain)
- brain = new(src)
- brain.name = "[L.real_name]'s brain"
-
- name = "Man-Machine Interface: [brainmob.real_name]"
- update_icon()
- return
-
-
-/obj/item/device/mmi/verb/Toggle_Listening()
- set name = "Toggle Listening"
- set desc = "Toggle listening channel on or off."
- set category = "MMI"
- set src = usr.loc
- set popup_menu = 0
-
- if(brainmob.stat)
- brainmob << "Can't do that while incapacitated or dead!"
- if(!radio.on)
- brainmob << "Your radio is disabled!"
- return
-
- radio.listening = radio.listening==1 ? 0 : 1
- brainmob << "Radio is [radio.listening==1 ? "now" : "no longer"] receiving broadcast."
-
-/obj/item/device/mmi/emp_act(severity)
- if(!brainmob)
- return
- else
- switch(severity)
- if(1)
- brainmob.emp_damage = min(brainmob.emp_damage + rand(20,30), 30)
- if(2)
- brainmob.emp_damage = min(brainmob.emp_damage + rand(10,20), 30)
- if(3)
- brainmob.emp_damage = min(brainmob.emp_damage + rand(0,10), 30)
- brainmob.emote("alarm")
- ..()
-
-/obj/item/device/mmi/Destroy()
- if(isrobot(loc))
- var/mob/living/silicon/robot/borg = loc
- borg.mmi = null
- if(brainmob)
- qdel(brainmob)
- brainmob = null
- return ..()
-
-/obj/item/device/mmi/examine(mob/user)
- ..()
- if(brainmob)
- var/mob/living/carbon/brain/B = brainmob
- if(!B.key || !B.mind || B.stat == DEAD)
- user << "The MMI indicates the brain is completely unresponsive."
-
- else if(!B.client)
- user << "The MMI indicates the brain is currently inactive; it might change."
-
- else
- user << "The MMI indicates the brain is active."
-
-
-/obj/item/device/mmi/syndie
- name = "Syndicate Man-Machine Interface"
- desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs created with it, but doesn't fit in Nanotrasen AI cores."
- origin_tech = "biotech=4;programming=4;syndicate=2"
- hacked = 1
-
-/obj/item/device/mmi/syndie/New()
- ..()
- radio.on = 0
+//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
+
+/obj/item/device/mmi
+ name = "Man-Machine Interface"
+ desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity, that nevertheless has become standard-issue on Nanotrasen stations."
+ icon = 'icons/obj/assemblies.dmi'
+ icon_state = "mmi_empty"
+ w_class = 3
+ origin_tech = "biotech=2;programming=3;engineering=2"
+ var/braintype = "Cyborg"
+ var/obj/item/device/radio/radio = null //Let's give it a radio.
+ var/hacked = 0 //Whether or not this is a Syndicate MMI
+ var/mob/living/brain/brainmob = null //The current occupant.
+ var/mob/living/silicon/robot = null //Appears unused.
+ var/obj/mecha = null //This does not appear to be used outside of reference in mecha.dm.
+ var/obj/item/organ/brain/brain = null //The actual brain
+ var/clockwork = FALSE //If this is a soul vessel
+
+/obj/item/device/mmi/update_icon()
+ if(brain)
+ if(istype(brain,/obj/item/organ/brain/alien))
+ if(brainmob && brainmob.stat == DEAD)
+ icon_state = "mmi_alien_dead"
+ else
+ icon_state = "mmi_alien"
+ braintype = "Xenoborg" //HISS....Beep.
+ else
+ if(brainmob && brainmob.stat == DEAD)
+ icon_state = "mmi_dead"
+ else
+ icon_state = "mmi_full"
+ braintype = "Cyborg"
+ else
+ icon_state = "mmi_empty"
+
+/obj/item/device/mmi/New()
+ ..()
+ radio = new(src) //Spawns a radio inside the MMI.
+ radio.broadcasting = 0 //researching radio mmis turned the robofabs into radios because this didnt start as 0.
+
+
+
+/obj/item/device/mmi/attackby(obj/item/O, mob/user, params)
+ user.changeNext_move(CLICK_CD_MELEE)
+ if(istype(O,/obj/item/organ/brain)) //Time to stick a brain in it --NEO
+ var/obj/item/organ/brain/newbrain = O
+ if(brain)
+ user << "There's already a brain in the MMI!"
+ return
+ if(!newbrain.brainmob)
+ user << "You aren't sure where this brain came from, but you're pretty sure it's a useless brain!"
+ return
+
+ if(!user.unEquip(O))
+ return
+ var/mob/living/brain/B = newbrain.brainmob
+ if(!B.key)
+ B.notify_ghost_cloning("Someone has put your brain in a MMI!", source = src)
+ visible_message("[user] sticks \a [newbrain] into \the [src].")
+
+ brainmob = newbrain.brainmob
+ newbrain.brainmob = null
+ brainmob.loc = src
+ brainmob.container = src
+ if(!newbrain.damaged_brain) // the brain organ hasn't been beaten to death.
+ brainmob.stat = CONSCIOUS //we manually revive the brain mob
+ dead_mob_list -= brainmob
+ living_mob_list += brainmob
+
+ brainmob.reset_perspective()
+ if(clockwork)
+ add_servant_of_ratvar(brainmob, TRUE)
+ newbrain.loc = src //P-put your brain in it
+ brain = newbrain
+
+ name = "Man-Machine Interface: [brainmob.real_name]"
+ update_icon()
+
+ feedback_inc("cyborg_mmis_filled",1)
+
+ else if(brainmob)
+ O.attack(brainmob, user) //Oh noooeeeee
+ else
+ return ..()
+
+
+/obj/item/device/mmi/attack_self(mob/user)
+ if(!brain)
+ radio.on = !radio.on
+ user << "You toggle the MMI's radio system [radio.on==1 ? "on" : "off"]."
+ else
+ user << "You unlock and upend the MMI, spilling the brain onto the floor."
+
+ brainmob.container = null //Reset brainmob mmi var.
+ brainmob.loc = brain //Throw mob into brain.
+ brainmob.stat = DEAD
+ brainmob.emp_damage = 0
+ brainmob.reset_perspective() //so the brainmob follows the brain organ instead of the mmi. And to update our vision
+ living_mob_list -= brainmob //Get outta here
+ dead_mob_list += brainmob
+ brain.brainmob = brainmob //Set the brain to use the brainmob
+ brainmob = null //Set mmi brainmob var to null
+
+ user.put_in_hands(brain) //puts brain in the user's hand or otherwise drops it on the user's turf
+ brain = null //No more brain in here
+
+ update_icon()
+ name = "Man-Machine Interface"
+
+/obj/item/device/mmi/proc/transfer_identity(mob/living/L) //Same deal as the regular brain proc. Used for human-->robot people.
+ if(!brainmob)
+ brainmob = new(src)
+ brainmob.name = L.real_name
+ brainmob.real_name = L.real_name
+ if(L.has_dna())
+ var/mob/living/carbon/C = L
+ if(!brainmob.stored_dna)
+ brainmob.stored_dna = new /datum/dna/stored(brainmob)
+ C.dna.copy_dna(brainmob.stored_dna)
+ brainmob.container = src
+
+ if(ishuman(L))
+ var/mob/living/carbon/human/H = L
+ var/obj/item/organ/brain/newbrain = H.getorgan(/obj/item/organ/brain)
+ newbrain.loc = src
+ brain = newbrain
+ else if(!brain)
+ brain = new(src)
+ brain.name = "[L.real_name]'s brain"
+
+ name = "Man-Machine Interface: [brainmob.real_name]"
+ update_icon()
+ return
+
+
+/obj/item/device/mmi/verb/Toggle_Listening()
+ set name = "Toggle Listening"
+ set desc = "Toggle listening channel on or off."
+ set category = "MMI"
+ set src = usr.loc
+ set popup_menu = 0
+
+ if(brainmob.stat)
+ brainmob << "Can't do that while incapacitated or dead!"
+ if(!radio.on)
+ brainmob << "Your radio is disabled!"
+ return
+
+ radio.listening = radio.listening==1 ? 0 : 1
+ brainmob << "Radio is [radio.listening==1 ? "now" : "no longer"] receiving broadcast."
+
+/obj/item/device/mmi/emp_act(severity)
+ if(!brainmob)
+ return
+ else
+ switch(severity)
+ if(1)
+ brainmob.emp_damage = min(brainmob.emp_damage + rand(20,30), 30)
+ if(2)
+ brainmob.emp_damage = min(brainmob.emp_damage + rand(10,20), 30)
+ if(3)
+ brainmob.emp_damage = min(brainmob.emp_damage + rand(0,10), 30)
+ brainmob.emote("alarm")
+ ..()
+
+/obj/item/device/mmi/Destroy()
+ if(isrobot(loc))
+ var/mob/living/silicon/robot/borg = loc
+ borg.mmi = null
+ if(brainmob)
+ qdel(brainmob)
+ brainmob = null
+ return ..()
+
+/obj/item/device/mmi/examine(mob/user)
+ ..()
+ if(brainmob)
+ var/mob/living/brain/B = brainmob
+ if(!B.key || !B.mind || B.stat == DEAD)
+ user << "The MMI indicates the brain is completely unresponsive."
+
+ else if(!B.client)
+ user << "The MMI indicates the brain is currently inactive; it might change."
+
+ else
+ user << "The MMI indicates the brain is active."
+
+
+/obj/item/device/mmi/syndie
+ name = "Syndicate Man-Machine Interface"
+ desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs created with it, but doesn't fit in Nanotrasen AI cores."
+ origin_tech = "biotech=4;programming=4;syndicate=2"
+ hacked = 1
+
+/obj/item/device/mmi/syndie/New()
+ ..()
+ radio.on = 0
diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
similarity index 50%
rename from code/modules/mob/living/carbon/brain/brain.dm
rename to code/modules/mob/living/brain/brain.dm
index a089a58bd77..dfdf30fb3c5 100644
--- a/code/modules/mob/living/carbon/brain/brain.dm
+++ b/code/modules/mob/living/brain/brain.dm
@@ -1,63 +1,67 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
-
-/mob/living/carbon/brain
- languages_spoken = HUMAN
- languages_understood = HUMAN
- var/obj/item/device/mmi/container = null
- var/timeofhostdeath = 0
- var/emp_damage = 0//Handles a type of MMI damage
- has_limbs = 0
- stat = DEAD //we start dead by default
- see_invisible = SEE_INVISIBLE_MINIMUM
-
-/mob/living/carbon/brain/New(loc)
- ..()
- if(isturf(loc)) //not spawned in an MMI or brain organ (most likely adminspawned)
- var/obj/item/organ/brain/OB = new(loc) //we create a new brain organ for it.
- src.loc = OB
- OB.brainmob = src
-
-
-/mob/living/carbon/brain/Destroy()
- if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting.
- if(stat!=DEAD) //If not dead.
- death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA
- ghostize() //Ghostize checks for key so nothing else is necessary.
- container = null
- return ..()
-
-/mob/living/carbon/brain/update_canmove()
- if(in_contents_of(/obj/mecha))
- canmove = 1
- else
- canmove = 0
- return canmove
-
-/mob/living/carbon/brain/toggle_throw_mode()
- return
-
-/mob/living/carbon/brain/ex_act() //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up.
- return
-
-/mob/living/carbon/brain/blob_act(obj/effect/blob/B)
- return
-
-/mob/living/carbon/brain/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default
- return
-
-/mob/living/carbon/brain/check_ear_prot()
- return 1
-
-/mob/living/carbon/brain/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
- return // no eyes, no flashing
-
-/mob/living/carbon/brain/update_damage_hud()
- return //no red circles for brain
-
-/mob/living/carbon/brain/can_be_revived()
- . = 1
- if(!container || health <= HEALTH_THRESHOLD_DEAD)
- return 0
-
-/mob/living/carbon/brain/update_sight()
- return
+//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
+
+/mob/living/brain
+ languages_spoken = HUMAN
+ languages_understood = HUMAN
+ var/obj/item/device/mmi/container = null
+ var/timeofhostdeath = 0
+ var/emp_damage = 0//Handles a type of MMI damage
+ var/datum/dna/stored/stored_dna // dna var for brain. Used to store dna, brain dna is not considered like actual dna, brain.has_dna() returns FALSE.
+ stat = DEAD //we start dead by default
+ see_invisible = SEE_INVISIBLE_MINIMUM
+
+/mob/living/brain/New(loc)
+ ..()
+ create_dna(src)
+ stored_dna.initialize_dna(random_blood_type())
+ if(isturf(loc)) //not spawned in an MMI or brain organ (most likely adminspawned)
+ var/obj/item/organ/brain/OB = new(loc) //we create a new brain organ for it.
+ src.loc = OB
+ OB.brainmob = src
+
+
+/mob/living/brain/proc/create_dna()
+ stored_dna = new /datum/dna/stored(src)
+ if(!stored_dna.species)
+ var/rando_race = pick(config.roundstart_races)
+ stored_dna.species = new rando_race()
+
+/mob/living/brain/Destroy()
+ if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting.
+ if(stat!=DEAD) //If not dead.
+ death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA
+ ghostize() //Ghostize checks for key so nothing else is necessary.
+ container = null
+ return ..()
+
+/mob/living/brain/update_canmove()
+ if(in_contents_of(/obj/mecha))
+ canmove = 1
+ else
+ canmove = 0
+ return canmove
+
+/mob/living/brain/ex_act() //you cant blow up brainmobs because it makes transfer_to() freak out when borgs blow up.
+ return
+
+/mob/living/brain/blob_act(obj/effect/blob/B)
+ return
+
+/mob/living/brain/get_eye_protection()//no eyes
+ return 2
+
+/mob/living/brain/get_ear_protection()//no ears
+ return 2
+
+/mob/living/brain/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
+ return // no eyes, no flashing
+
+/mob/living/brain/can_be_revived()
+ . = 1
+ if(!container || health <= HEALTH_THRESHOLD_DEAD)
+ return 0
+
+/mob/living/brain/fully_replace_character_name(oldname,newname)
+ ..()
+ if(stored_dna)
+ stored_dna.real_name = real_name
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
similarity index 65%
rename from code/modules/mob/living/carbon/brain/brain_item.dm
rename to code/modules/mob/living/brain/brain_item.dm
index e5e7d511fc0..4bccb03c2d8 100644
--- a/code/modules/mob/living/carbon/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -1,127 +1,122 @@
-/obj/item/organ/brain
- name = "brain"
- desc = "A piece of juicy meat found in a person's head."
- icon_state = "brain"
- throw_speed = 3
- throw_range = 5
- layer = ABOVE_MOB_LAYER
- zone = "head"
- slot = "brain"
- vital = 1
- origin_tech = "biotech=5"
- attack_verb = list("attacked", "slapped", "whacked")
- var/mob/living/carbon/brain/brainmob = null
- var/damaged_brain = 0 //whether the brain organ is damaged.
-
-/obj/item/organ/brain/Insert(mob/living/carbon/M, special = 0)
- ..()
- name = "brain"
- if(brainmob)
- if(M.key)
- M.ghostize()
-
- if(brainmob.mind)
- brainmob.mind.transfer_to(M)
- else
- M.key = brainmob.key
-
- qdel(brainmob)
-
- //Update the body's icon so it doesnt appear debrained anymore
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- H.update_hair(0)
-
-/obj/item/organ/brain/Remove(mob/living/carbon/M, special = 0)
- ..()
- if(!special)
- transfer_identity(M)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- H.update_hair(0)
-
-/obj/item/organ/brain/prepare_eat()
- return // Too important to eat.
-
-/obj/item/organ/brain/proc/transfer_identity(mob/living/L)
- name = "[L.name]'s brain"
- brainmob = new(src)
- brainmob.name = L.real_name
- brainmob.real_name = L.real_name
- brainmob.timeofhostdeath = L.timeofdeath
- if(L.has_dna())
- var/mob/living/carbon/C = L
- if(!brainmob.dna)
- brainmob.dna = new /datum/dna(brainmob)
- C.dna.copy_dna(brainmob.dna)
- if(L.mind && L.mind.current && (L.mind.current.stat == DEAD))
- L.mind.transfer_to(brainmob)
- brainmob << "You feel slightly disoriented. That's normal when you're just a brain."
-
-/obj/item/organ/brain/attackby(obj/item/O, mob/user, params)
- user.changeNext_move(CLICK_CD_MELEE)
- if(brainmob)
- O.attack(brainmob, user) //Oh noooeeeee
-
-/obj/item/organ/brain/examine(mob/user)
- ..()
-
- if(brainmob)
- if(brainmob.client)
- if(brainmob.health <= HEALTH_THRESHOLD_DEAD)
- user << "It's lifeless and severely damaged."
- else
- user << "You can feel the small spark of life still left in this one."
- else
- user << "This one seems particularly lifeless. Perhaps it will regain some of its luster later."
- else
- user << "This one is completely devoid of life."
-
-/obj/item/organ/brain/attack(mob/living/carbon/M, mob/user)
- if(!istype(M))
- return ..()
-
- add_fingerprint(user)
-
- if(user.zone_selected != "head")
- return ..()
-
- var/mob/living/carbon/human/H = M
- if(istype(H) && ((H.head && H.head.flags_cover & HEADCOVERSEYES) || (H.wear_mask && H.wear_mask.flags_cover & MASKCOVERSEYES) || (H.glasses && H.glasses.flags & GLASSESCOVERSEYES)))
- user << "You're going to need to remove their head cover first!"
- return
-
-//since these people will be dead M != usr
-
- if(!M.getorgan(/obj/item/organ/brain))
- if(istype(H) && !H.get_bodypart("head"))
- return
- user.drop_item()
- var/msg = "[M] has [src] inserted into \his head by [user]."
- if(M == user)
- msg = "[user] inserts [src] into \his head!"
-
- M.visible_message("[msg]",
- "[msg]")
-
- if(M != user)
- M << "[user] inserts [src] into your head."
- user << "You insert [src] into [M]'s head."
- else
- user << "You insert [src] into your head." //LOL
-
- Insert(M)
- else
- ..()
-
-/obj/item/organ/brain/Destroy() //copypasted from MMIs.
- if(brainmob)
- qdel(brainmob)
- brainmob = null
- return ..()
-
-/obj/item/organ/brain/alien
- name = "alien brain"
- desc = "We barely understand the brains of terrestial animals. Who knows what we may find in the brain of such an advanced species?"
- icon_state = "brain-x"
- origin_tech = "biotech=6"
+/obj/item/organ/brain
+ name = "brain"
+ desc = "A piece of juicy meat found in a person's head."
+ icon_state = "brain"
+ throw_speed = 3
+ throw_range = 5
+ layer = ABOVE_MOB_LAYER
+ zone = "head"
+ slot = "brain"
+ vital = 1
+ origin_tech = "biotech=5"
+ attack_verb = list("attacked", "slapped", "whacked")
+ var/mob/living/brain/brainmob = null
+ var/damaged_brain = 0 //whether the brain organ is damaged.
+
+/obj/item/organ/brain/Insert(mob/living/carbon/C, special = 0)
+ ..()
+ name = "brain"
+ if(brainmob)
+ if(C.key)
+ C.ghostize()
+
+ if(brainmob.mind)
+ brainmob.mind.transfer_to(C)
+ else
+ C.key = brainmob.key
+
+ qdel(brainmob)
+
+ //Update the body's icon so it doesnt appear debrained anymore
+ C.update_hair()
+
+/obj/item/organ/brain/Remove(mob/living/carbon/C, special = 0)
+ ..()
+ if(!special)
+ transfer_identity(C)
+ C.update_hair()
+
+/obj/item/organ/brain/prepare_eat()
+ return // Too important to eat.
+
+/obj/item/organ/brain/proc/transfer_identity(mob/living/L)
+ name = "[L.name]'s brain"
+ brainmob = new(src)
+ brainmob.name = L.real_name
+ brainmob.real_name = L.real_name
+ brainmob.timeofhostdeath = L.timeofdeath
+ if(L.has_dna())
+ var/mob/living/carbon/C = L
+ if(!brainmob.stored_dna)
+ brainmob.stored_dna = new /datum/dna/stored(brainmob)
+ C.dna.copy_dna(brainmob.stored_dna)
+ if(L.mind && L.mind.current && (L.mind.current.stat == DEAD))
+ L.mind.transfer_to(brainmob)
+ brainmob << "You feel slightly disoriented. That's normal when you're just a brain."
+
+/obj/item/organ/brain/attackby(obj/item/O, mob/user, params)
+ user.changeNext_move(CLICK_CD_MELEE)
+ if(brainmob)
+ O.attack(brainmob, user) //Oh noooeeeee
+
+/obj/item/organ/brain/examine(mob/user)
+ ..()
+
+ if(brainmob)
+ if(brainmob.client)
+ if(brainmob.health <= HEALTH_THRESHOLD_DEAD)
+ user << "It's lifeless and severely damaged."
+ else
+ user << "You can feel the small spark of life still left in this one."
+ else
+ user << "This one seems particularly lifeless. Perhaps it will regain some of its luster later."
+ else
+ user << "This one is completely devoid of life."
+
+/obj/item/organ/brain/attack(mob/living/carbon/C, mob/user)
+ if(!istype(C))
+ return ..()
+
+ add_fingerprint(user)
+
+ if(user.zone_selected != "head")
+ return ..()
+
+ if((C.head && (C.head.flags_cover & HEADCOVERSEYES)) || (C.wear_mask && (C.wear_mask.flags_cover & MASKCOVERSEYES)) || (C.glasses && (C.glasses.flags & GLASSESCOVERSEYES)))
+ user << "You're going to need to remove their head cover first!"
+ return
+
+//since these people will be dead M != usr
+
+ if(!C.getorgan(/obj/item/organ/brain))
+ if(!C.get_bodypart("head"))
+ return
+ user.drop_item()
+ var/msg = "[C] has [src] inserted into \his head by [user]."
+ if(C == user)
+ msg = "[user] inserts [src] into \his head!"
+
+ C.visible_message("[msg]",
+ "[msg]")
+
+ if(C != user)
+ C << "[user] inserts [src] into your head."
+ user << "You insert [src] into [C]'s head."
+ else
+ user << "You insert [src] into your head." //LOL
+
+ Insert(C)
+ else
+ ..()
+
+/obj/item/organ/brain/Destroy() //copypasted from MMIs.
+ if(brainmob)
+ qdel(brainmob)
+ brainmob = null
+ return ..()
+
+/obj/item/organ/brain/alien
+ name = "alien brain"
+ desc = "We barely understand the brains of terrestial animals. Who knows what we may find in the brain of such an advanced species?"
+ icon_state = "brain-x"
+ origin_tech = "biotech=6"
diff --git a/code/modules/mob/living/carbon/brain/death.dm b/code/modules/mob/living/brain/death.dm
similarity index 83%
rename from code/modules/mob/living/carbon/brain/death.dm
rename to code/modules/mob/living/brain/death.dm
index 67b700b2b08..e98859b90ff 100644
--- a/code/modules/mob/living/carbon/brain/death.dm
+++ b/code/modules/mob/living/brain/death.dm
@@ -1,20 +1,20 @@
-/mob/living/carbon/brain/death(gibbed)
- if(stat == DEAD)
- return
- stat = DEAD
-
- if(!gibbed && container)//If not gibbed but in a container.
- var/obj/item/device/mmi = container
- mmi.visible_message("[src]'s MMI flatlines!", \
- "You hear something flatline.")
- mmi.update_icon()
-
- return ..()
-
-/mob/living/carbon/brain/gib()
- if(container)
- qdel(container)//Gets rid of the MMI if there is one
- if(loc)
- if(istype(loc,/obj/item/organ/brain))
- qdel(loc)//Gets rid of the brain item
+/mob/living/brain/death(gibbed)
+ if(stat == DEAD)
+ return
+ stat = DEAD
+
+ if(!gibbed && container)//If not gibbed but in a container.
+ var/obj/item/device/mmi = container
+ mmi.visible_message("[src]'s MMI flatlines!", \
+ "You hear something flatline.")
+ mmi.update_icon()
+
+ return ..()
+
+/mob/living/brain/gib()
+ if(container)
+ qdel(container)//Gets rid of the MMI if there is one
+ if(loc)
+ if(istype(loc,/obj/item/organ/brain))
+ qdel(loc)//Gets rid of the brain item
..()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/brain/emote.dm b/code/modules/mob/living/brain/emote.dm
similarity index 91%
rename from code/modules/mob/living/carbon/brain/emote.dm
rename to code/modules/mob/living/brain/emote.dm
index bd4be7c66f9..8ab505f7a9e 100644
--- a/code/modules/mob/living/carbon/brain/emote.dm
+++ b/code/modules/mob/living/brain/emote.dm
@@ -1,71 +1,71 @@
-/mob/living/carbon/brain/emote(act,m_type=1,message = null)
- if(!(container && istype(container, /obj/item/device/mmi)))//No MMI, no emotes
- return
-
- if (findtext(act, "-", 1, null))
- var/t1 = findtext(act, "-", 1, null)
- act = copytext(act, 1, t1)
-
-
- if(src.stat == DEAD)
- return
- switch(act)
- if ("alarm")
- src << "You sound an alarm."
- message = "[src] sounds an alarm."
- m_type = 2
-
- if ("alert")
- src << "You let out a distressed noise."
- message = "[src] lets out a distressed noise."
- m_type = 2
-
- if ("beep","beeps")
- src << "You beep."
- message = "[src] beeps."
- m_type = 2
-
- if ("blink","blinks")
- message = "[src] blinks."
- m_type = 1
-
- if ("boop","boops")
- src << "You boop."
- message = "[src] boops."
- m_type = 2
-
- if ("flash")
- message = "The lights on [src] flash quickly."
- m_type = 1
-
- if ("notice")
- src << "You play a loud tone."
- message = "[src] plays a loud tone."
- m_type = 2
-
- if ("whistle","whistles")
- src << "You whistle."
- message = "[src] whistles."
- m_type = 2
-
- if ("help")
- src << "Help for MMI emotes. You can use these emotes with say \"*emote\":\nalarm, alert, beep, blink, boop, flash, notice, whistle"
-
- else
- src << "Unusable emote '[act]'. Say *help for a list."
- return
-
- if (message)
- log_emote("[name]/[key] : [message]")
-
- for(var/mob/M in dead_mob_list)
- if (!M.client || istype(M, /mob/new_player))
- continue //skip monkeys, leavers, and new_players
- if(M.stat == DEAD && (M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT)) && !(M in viewers(src,null)))
- M.show_message(message)
-
-
- if (m_type & 1)
- visible_message(message)
- else if (m_type & 2)
+/mob/living/brain/emote(act,m_type=1,message = null)
+ if(!(container && istype(container, /obj/item/device/mmi)))//No MMI, no emotes
+ return
+
+ if (findtext(act, "-", 1, null))
+ var/t1 = findtext(act, "-", 1, null)
+ act = copytext(act, 1, t1)
+
+
+ if(src.stat == DEAD)
+ return
+ switch(act)
+ if ("alarm")
+ src << "You sound an alarm."
+ message = "[src] sounds an alarm."
+ m_type = 2
+
+ if ("alert")
+ src << "You let out a distressed noise."
+ message = "[src] lets out a distressed noise."
+ m_type = 2
+
+ if ("beep","beeps")
+ src << "You beep."
+ message = "[src] beeps."
+ m_type = 2
+
+ if ("blink","blinks")
+ message = "[src] blinks."
+ m_type = 1
+
+ if ("boop","boops")
+ src << "You boop."
+ message = "[src] boops."
+ m_type = 2
+
+ if ("flash")
+ message = "The lights on [src] flash quickly."
+ m_type = 1
+
+ if ("notice")
+ src << "You play a loud tone."
+ message = "[src] plays a loud tone."
+ m_type = 2
+
+ if ("whistle","whistles")
+ src << "You whistle."
+ message = "[src] whistles."
+ m_type = 2
+
+ if ("help")
+ src << "Help for MMI emotes. You can use these emotes with say \"*emote\":\nalarm, alert, beep, blink, boop, flash, notice, whistle"
+
+ else
+ src << "Unusable emote '[act]'. Say *help for a list."
+ return
+
+ if (message)
+ log_emote("[name]/[key] : [message]")
+
+ for(var/mob/M in dead_mob_list)
+ if (!M.client || istype(M, /mob/new_player))
+ continue //skip monkeys, leavers, and new_players
+ if(M.stat == DEAD && (M.client && (M.client.prefs.chat_toggles & CHAT_GHOSTSIGHT)) && !(M in viewers(src,null)))
+ M.show_message(message)
+
+
+ if (m_type & 1)
+ visible_message(message)
+ else if (m_type & 2)
audible_message(message)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/brain/life.dm
similarity index 57%
rename from code/modules/mob/living/carbon/brain/life.dm
rename to code/modules/mob/living/brain/life.dm
index 75f731b6e69..9d87f412e8d 100644
--- a/code/modules/mob/living/carbon/brain/life.dm
+++ b/code/modules/mob/living/brain/life.dm
@@ -1,60 +1,49 @@
-
-/mob/living/carbon/brain/Life()
- set invisibility = 0
- set background = BACKGROUND_ENABLED
-
- if (notransform)
- return
- if(!loc)
- return
- . = ..()
- handle_emp_damage()
-
-/mob/living/carbon/brain/handle_breathing()
- return
-
-/mob/living/carbon/brain/handle_mutations_and_radiation()
- return
-
-/mob/living/carbon/brain/handle_environment(datum/gas_mixture/environment)
- return
-
-/mob/living/carbon/brain/update_stat()
- if(status_flags & GODMODE)
- return
- if(health <= HEALTH_THRESHOLD_DEAD)
- if(stat != DEAD)
- death()
- var/obj/item/organ/brain/BR
- if(container && container.brain)
- BR = container.brain
- else if(istype(loc, /obj/item/organ/brain))
- BR = loc
- if(BR)
- BR.damaged_brain = 1 //beaten to a pulp
-
-/* //currently unused feature, since brain outside a mmi is always dead.
-/mob/living/carbon/brain/proc/handle_brain_revival_life()
- if(stat != DEAD)
- if(config.revival_brain_life != -1)
- if( !container && (world.time - timeofhostdeath) > config.revival_brain_life)
- death()
-*/
-
-/mob/living/carbon/brain/proc/handle_emp_damage()
- if(emp_damage)
- if(stat == DEAD)
- emp_damage = 0
- else
- emp_damage = max(emp_damage-1, 0)
-
-/mob/living/carbon/brain/handle_status_effects()
- return
-
-/mob/living/carbon/brain/handle_disabilities()
- return
-
-/mob/living/carbon/brain/handle_changeling()
- return
-
-
+
+/mob/living/brain/Life()
+ set invisibility = 0
+ set background = BACKGROUND_ENABLED
+
+ if (notransform)
+ return
+ if(!loc)
+ return
+ . = ..()
+ handle_emp_damage()
+
+/mob/living/brain/update_stat()
+ if(status_flags & GODMODE)
+ return
+ if(health <= HEALTH_THRESHOLD_DEAD)
+ if(stat != DEAD)
+ death()
+ var/obj/item/organ/brain/BR
+ if(container && container.brain)
+ BR = container.brain
+ else if(istype(loc, /obj/item/organ/brain))
+ BR = loc
+ if(BR)
+ BR.damaged_brain = 1 //beaten to a pulp
+
+/* //currently unused feature, since brain outside a mmi is always dead.
+/mob/living/brain/proc/handle_brain_revival_life()
+ if(stat != DEAD)
+ if(config.revival_brain_life != -1)
+ if( !container && (world.time - timeofhostdeath) > config.revival_brain_life)
+ death()
+*/
+
+/mob/living/brain/proc/handle_emp_damage()
+ if(emp_damage)
+ if(stat == DEAD)
+ emp_damage = 0
+ else
+ emp_damage = max(emp_damage-1, 0)
+
+/mob/living/brain/handle_status_effects()
+ return
+
+/mob/living/brain/handle_disabilities()
+ return
+
+
+
diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/brain/posibrain.dm
similarity index 98%
rename from code/modules/mob/living/carbon/brain/posibrain.dm
rename to code/modules/mob/living/brain/posibrain.dm
index 229f2b52fce..f7ad95798a5 100644
--- a/code/modules/mob/living/carbon/brain/posibrain.dm
+++ b/code/modules/mob/living/brain/posibrain.dm
@@ -80,11 +80,10 @@ var/global/posibrain_notif_cooldown = 0
name = "[initial(name)] ([C])"
brainmob.name = C.real_name
brainmob.real_name = C.real_name
- brainmob.dna = C.dna
if(C.has_dna())
- if(!brainmob.dna)
- brainmob.dna = new /datum/dna(brainmob)
- C.dna.copy_dna(brainmob.dna)
+ if(!brainmob.stored_dna)
+ brainmob.stored_dna = new /datum/dna/stored(brainmob)
+ C.dna.copy_dna(brainmob.stored_dna)
brainmob.timeofhostdeath = C.timeofdeath
brainmob.stat = CONSCIOUS
if(brainmob.mind)
diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/brain/say.dm
similarity index 70%
rename from code/modules/mob/living/carbon/brain/say.dm
rename to code/modules/mob/living/brain/say.dm
index 77f72d484a7..0aeb312ee0f 100644
--- a/code/modules/mob/living/carbon/brain/say.dm
+++ b/code/modules/mob/living/brain/say.dm
@@ -1,23 +1,23 @@
-/mob/living/carbon/brain/say(message)
- if(!(container && istype(container, /obj/item/device/mmi)))
- return //No MMI, can't speak, bucko./N
- else
- if(prob(emp_damage*4))
- if(prob(10))//10% chane to drop the message entirely
- return
- else
- message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher
- ..()
-
-/mob/living/carbon/brain/radio(message, message_mode, list/spans)
- if(message_mode && istype(container, /obj/item/device/mmi))
- var/obj/item/device/mmi/R = container
- if(R.radio)
- R.radio.talk_into(src, message, , spans)
- return ITALICS | REDUCE_RANGE
-
-/mob/living/carbon/brain/lingcheck()
- return 0
-
-/mob/living/carbon/brain/treat_message(message)
+/mob/living/brain/say(message)
+ if(!(container && istype(container, /obj/item/device/mmi)))
+ return //No MMI, can't speak, bucko./N
+ else
+ if(prob(emp_damage*4))
+ if(prob(10))//10% chane to drop the message entirely
+ return
+ else
+ message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher
+ ..()
+
+/mob/living/brain/radio(message, message_mode, list/spans)
+ if(message_mode && istype(container, /obj/item/device/mmi))
+ var/obj/item/device/mmi/R = container
+ if(R.radio)
+ R.radio.talk_into(src, message, , spans)
+ return ITALICS | REDUCE_RANGE
+
+/mob/living/brain/lingcheck()
+ return 0
+
+/mob/living/brain/treat_message(message)
return message
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/brain/status_procs.dm b/code/modules/mob/living/brain/status_procs.dm
similarity index 52%
rename from code/modules/mob/living/carbon/brain/status_procs.dm
rename to code/modules/mob/living/brain/status_procs.dm
index dc8ff6ffc1e..caf2bfe22c4 100644
--- a/code/modules/mob/living/carbon/brain/status_procs.dm
+++ b/code/modules/mob/living/brain/status_procs.dm
@@ -4,35 +4,30 @@
/////////////////////////////////// EAR DAMAGE ////////////////////////////////////
-/mob/living/carbon/brain/adjustEarDamage()
+/mob/living/brain/adjustEarDamage()
return
-/mob/living/carbon/brain/setEarDamage() // no ears to damage or heal
+/mob/living/brain/setEarDamage() // no ears to damage or heal
return
/////////////////////////////////// EYE_BLIND ////////////////////////////////////
-/mob/living/carbon/brain/blind_eyes() // no eyes to damage or heal
+/mob/living/brain/blind_eyes() // no eyes to damage or heal
return
-/mob/living/carbon/brain/adjust_blindness()
+/mob/living/brain/adjust_blindness()
return
-/mob/living/carbon/brain/set_blindness()
+/mob/living/brain/set_blindness()
return
/////////////////////////////////// EYE_BLURRY ////////////////////////////////////
-/mob/living/carbon/brain/blur_eyes()
+/mob/living/brain/blur_eyes()
return
-/mob/living/carbon/brain/adjust_blurriness()
+/mob/living/brain/adjust_blurriness()
return
-/mob/living/carbon/brain/set_blurriness()
+/mob/living/brain/set_blurriness()
return
-
-/////////////////////////////////// BLIND DISABILITY ////////////////////////////////////
-
-/mob/living/carbon/brain/become_blind()
- return
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/alien.dm b/code/modules/mob/living/carbon/alien/alien.dm
index c8f7ce99a22..42572b1c03c 100644
--- a/code/modules/mob/living/carbon/alien/alien.dm
+++ b/code/modules/mob/living/carbon/alien/alien.dm
@@ -37,35 +37,22 @@
verbs += /mob/living/proc/mob_sleep
verbs += /mob/living/proc/lay_down
- internal_organs += new /obj/item/organ/brain/alien
- internal_organs += new /obj/item/organ/alien/hivenode
- internal_organs += new /obj/item/organ/tongue/alien
+ create_bodyparts() //initialize bodyparts
- for(var/obj/item/organ/I in internal_organs)
- I.Insert(src)
+ create_internal_organs()
AddAbility(new/obj/effect/proc_holder/alien/nightvisiontoggle(null))
..()
+/mob/living/carbon/alien/create_internal_organs()
+ internal_organs += new /obj/item/organ/brain/alien
+ internal_organs += new /obj/item/organ/alien/hivenode
+ internal_organs += new /obj/item/organ/tongue/alien
+ ..()
+
/mob/living/carbon/alien/assess_threat() // beepsky won't hunt aliums
return -10
-/mob/living/carbon/alien/adjustToxLoss(amount)
- return 0
-
-/mob/living/carbon/alien/adjustFireLoss(amount) // Weak to Fire
- if(amount > 0)
- ..(amount * 2)
- else
- ..(amount)
- return
-
-/mob/living/carbon/alien/check_eye_prot()
- return ..() + 2
-
-/mob/living/carbon/alien/getToxLoss()
- return 0
-
/mob/living/carbon/alien/handle_environment(datum/gas_mixture/environment)
if(!environment)
return
@@ -100,35 +87,6 @@
else
clear_alert("alien_fire")
-
-/mob/living/carbon/alien/ex_act(severity, target)
- ..()
-
- switch (severity)
- if (1)
- gib()
- return
-
- if (2)
- adjustBruteLoss(60)
- adjustFireLoss(60)
- adjustEarDamage(30,120)
-
- if(3)
- adjustBruteLoss(30)
- if (prob(50))
- Paralyse(1)
- adjustEarDamage(15,60)
-
- updatehealth()
-
-
-/mob/living/carbon/alien/handle_fire()//Aliens on fire code
- if(..())
- return
- bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up!
- return
-
/mob/living/carbon/alien/reagent_check(datum/reagent/R) //can metabolize all reagents
return 0
diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm
index d9f5ef6fa98..0d934446366 100644
--- a/code/modules/mob/living/carbon/alien/alien_defense.dm
+++ b/code/modules/mob/living/carbon/alien/alien_defense.dm
@@ -1,3 +1,10 @@
+
+/mob/living/carbon/alien/get_eye_protection()
+ return ..() + 2 //potential cyber implants + natural eye protection
+
+/mob/living/carbon/alien/get_ear_protection()
+ return 2 //no ears
+
/mob/living/carbon/alien/hitby(atom/movable/AM, skipcatch, hitpush)
..(AM, skipcatch = 1, hitpush = 0)
@@ -40,7 +47,6 @@ In all, this is a lot like the monkey code. /N
updatehealth()
else
M << "[name] is too injured for that."
- return
/mob/living/carbon/alien/attack_larva(mob/living/carbon/alien/larva/L)
@@ -65,9 +71,10 @@ In all, this is a lot like the monkey code. /N
/mob/living/carbon/alien/attack_paw(mob/living/carbon/monkey/M)
if(..())
if (stat != DEAD)
- adjustBruteLoss(rand(1, 3))
- updatehealth()
- return
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ apply_damage(rand(1, 3), BRUTE, affecting)
+
+
/mob/living/carbon/alien/attack_animal(mob/living/simple_animal/M)
@@ -96,3 +103,22 @@ In all, this is a lot like the monkey code. /N
adjustBruteLoss(damage)
add_logs(M, src, "attacked")
updatehealth()
+
+/mob/living/carbon/alien/ex_act(severity, target)
+ ..()
+ switch (severity)
+ if (1)
+ gib()
+
+ if (2)
+ take_overall_damage(60, 60)
+ adjustEarDamage(30,120)
+
+ if(3)
+ take_overall_damage(30,0)
+ if(prob(50))
+ Paralyse(1)
+ adjustEarDamage(15,60)
+
+/mob/living/carbon/alien/soundbang_act(intensity = 1, stun_pwr = 1, damage_pwr = 5, deafen_pwr = 15)
+ return 0
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/damage_procs.dm b/code/modules/mob/living/carbon/alien/damage_procs.dm
new file mode 100644
index 00000000000..7857c0b565e
--- /dev/null
+++ b/code/modules/mob/living/carbon/alien/damage_procs.dm
@@ -0,0 +1,22 @@
+
+
+/mob/living/carbon/alien/getToxLoss()
+ return 0
+
+/mob/living/carbon/alien/adjustToxLoss(amount) //alien immune to tox damage
+ return 0
+
+/mob/living/carbon/alien/adjustFireLoss(amount) // Weak to Fire
+ if(amount > 0)
+ ..(amount * 2)
+ else
+ ..(amount)
+
+
+
+//aliens are immune to stamina damage.
+/mob/living/carbon/alien/adjustStaminaLoss(amount, updating_stamina = 1)
+ return
+
+/mob/living/carbon/alien/setStaminaLoss(amount, updating_stamina = 1)
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/death.dm b/code/modules/mob/living/carbon/alien/death.dm
index 7583d0afaa7..6211dc83493 100644
--- a/code/modules/mob/living/carbon/alien/death.dm
+++ b/code/modules/mob/living/carbon/alien/death.dm
@@ -1,5 +1,8 @@
-/mob/living/carbon/alien/spawn_gibs()
- xgibs(loc, viruses)
+/mob/living/carbon/alien/spawn_gibs(with_bodyparts)
+ if(with_bodyparts)
+ new /obj/effect/gibspawner/xeno(loc,viruses)
+ else
+ new /obj/effect/gibspawner/xenobodypartless(loc,viruses)
/mob/living/carbon/alien/gib_animation()
PoolOrNew(/obj/effect/overlay/temp/gib_animation, list(loc, "gibbed-a"))
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
index 8e078e4ed7c..5f0dbd5635e 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/drone.dm
@@ -7,11 +7,14 @@
/mob/living/carbon/alien/humanoid/drone/New()
+ AddAbility(new/obj/effect/proc_holder/alien/evolve(null))
+ ..()
+
+
+/mob/living/carbon/alien/humanoid/drone/create_internal_organs()
internal_organs += new /obj/item/organ/alien/plasmavessel/large
internal_organs += new /obj/item/organ/alien/resinspinner
internal_organs += new /obj/item/organ/alien/acid
-
- AddAbility(new/obj/effect/proc_holder/alien/evolve(null))
..()
/mob/living/carbon/alien/humanoid/drone/movement_delay()
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
index 379500f5002..3a9e938df39 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/hunter.dm
@@ -6,7 +6,7 @@
icon_state = "alienh_s"
var/obj/screen/leap_icon = null
-/mob/living/carbon/alien/humanoid/hunter/New()
+/mob/living/carbon/alien/humanoid/hunter/create_internal_organs()
internal_organs += new /obj/item/organ/alien/plasmavessel/small
..()
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm
index 8da5304ff77..d16c06bea53 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/praetorian.dm
@@ -11,14 +11,18 @@
real_name = name
+ AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno(src))
+ AddAbility(new /obj/effect/proc_holder/alien/royal/praetorian/evolve())
+ ..()
+
+/mob/living/carbon/alien/humanoid/royal/praetorian/create_internal_organs()
internal_organs += new /obj/item/organ/alien/plasmavessel/large
internal_organs += new /obj/item/organ/alien/resinspinner
internal_organs += new /obj/item/organ/alien/acid
internal_organs += new /obj/item/organ/alien/neurotoxin
- AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno(src))
- AddAbility(new /obj/effect/proc_holder/alien/royal/praetorian/evolve())
..()
+
/mob/living/carbon/alien/humanoid/royal/praetorian/movement_delay()
. = ..()
. += 1
diff --git a/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm b/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm
index a22ab106dd4..dacd4ff7d4a 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/caste/sentinel.dm
@@ -7,11 +7,15 @@
/mob/living/carbon/alien/humanoid/sentinel/New()
- internal_organs += new /obj/item/organ/alien/plasmavessel
- internal_organs += new /obj/item/organ/alien/acid
- internal_organs += new /obj/item/organ/alien/neurotoxin
AddAbility(new /obj/effect/proc_holder/alien/sneak)
..()
+/mob/living/carbon/alien/humanoid/sentinel/create_internal_organs()
+ internal_organs += new /obj/item/organ/alien/plasmavessel
+ internal_organs += new /obj/item/organ/alien/acid
+ internal_organs += new /obj/item/organ/alien/neurotoxin
+ ..()
+
+
/mob/living/carbon/alien/humanoid/sentinel/movement_delay()
. = ..()
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
index 89acb9ab91c..98c1df7b382 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid.dm
@@ -15,75 +15,19 @@
var/custom_pixel_y_offset = 0
var/sneaking = 0 //For sneaky-sneaky mode and appropriate slowdown
var/drooling = 0 //For Neruotoxic spit overlays
+ bodyparts = list(/obj/item/bodypart/chest/alien, /obj/item/bodypart/head/alien, /obj/item/bodypart/l_arm/alien,
+ /obj/item/bodypart/r_arm/alien, /obj/item/bodypart/r_leg/alien, /obj/item/bodypart/l_leg/alien)
+
//This is fine right now, if we're adding organ specific damage this needs to be updated
/mob/living/carbon/alien/humanoid/New()
AddAbility(new/obj/effect/proc_holder/alien/regurgitate(null))
..()
-
/mob/living/carbon/alien/humanoid/movement_delay()
. = ..()
. += move_delay_add + config.alien_delay + sneaking //move_delay_add is used to slow aliens with stuns
-/mob/living/carbon/alien/humanoid/emp_act(severity)
- if(r_store) r_store.emp_act(severity)
- if(l_store) l_store.emp_act(severity)
- ..()
-
-/mob/living/carbon/alien/humanoid/attack_hulk(mob/living/carbon/human/user)
- if(user.a_intent == "harm")
- ..(user, 1)
- adjustBruteLoss(15)
- var/hitverb = "punched"
- if(mob_size < MOB_SIZE_LARGE)
- step_away(src,user,15)
- sleep(1)
- step_away(src,user,15)
- hitverb = "slammed"
- playsound(loc, "punch", 25, 1, -1)
- visible_message("[user] has [hitverb] [src]!", \
- "[user] has [hitverb] [src]!")
- return 1
-
-/mob/living/carbon/alien/humanoid/attack_hand(mob/living/carbon/human/M)
- if(..())
- switch(M.a_intent)
- if ("harm")
- var/damage = rand(1, 9)
- if (prob(90))
- playsound(loc, "punch", 25, 1, -1)
- visible_message("[M] has punched [src]!", \
- "[M] has punched [src]!")
- if ((stat != DEAD) && (damage > 9 || prob(5)))//Regular humans have a very small chance of weakening an alien.
- Paralyse(2)
- visible_message("[M] has weakened [src]!", \
- "[M] has weakened [src]!")
- adjustBruteLoss(damage)
- add_logs(M, src, "attacked")
- updatehealth()
- else
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to punch [src]!")
-
- if ("disarm")
- if (!lying)
- if (prob(5))
- Paralyse(2)
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- add_logs(M, src, "pushed")
- visible_message("[M] has pushed down [src]!", \
- "[M] has pushed down [src]!")
- else
- if (prob(50))
- drop_item()
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- visible_message("[M] has disarmed [src]!", \
- "[M] has disarmed [src]!")
- else
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to disarm [src]!")
-
/mob/living/carbon/alien/humanoid/restrained(ignore_grab)
. = handcuffed
@@ -150,9 +94,6 @@
else
return initial(pixel_x)
-/mob/living/carbon/alien/humanoid/check_ear_prot()
- return 1
-
/mob/living/carbon/alien/humanoid/get_permeability_protection()
return 0.8
@@ -179,9 +120,3 @@ proc/get_alien_type(var/alienpath)
if(breath && breath.total_moles() > 0 && !sneaking)
playsound(get_turf(src), pick('sound/voice/lowHiss2.ogg', 'sound/voice/lowHiss3.ogg', 'sound/voice/lowHiss4.ogg'), 50, 0, -5)
..()
-
-/mob/living/carbon/alien/humanoid/grabbedby(mob/living/carbon/user, supress_message = 0)
- if(user == src && pulling && grab_state >= GRAB_AGGRESSIVE && !pulling.anchored && iscarbon(pulling))
- devour_mob(pulling, devour_time = 60)
- else
- ..()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
new file mode 100644
index 00000000000..4f08997c40f
--- /dev/null
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
@@ -0,0 +1,59 @@
+
+/mob/living/carbon/alien/humanoid/grabbedby(mob/living/carbon/user, supress_message = 0)
+ if(user == src && pulling && grab_state >= GRAB_AGGRESSIVE && !pulling.anchored && iscarbon(pulling))
+ devour_mob(pulling, devour_time = 60)
+ else
+ ..()
+
+/mob/living/carbon/alien/humanoid/attack_hulk(mob/living/carbon/human/user)
+ if(user.a_intent == "harm")
+ ..(user, 1)
+ adjustBruteLoss(15)
+ var/hitverb = "punched"
+ if(mob_size < MOB_SIZE_LARGE)
+ step_away(src,user,15)
+ sleep(1)
+ step_away(src,user,15)
+ hitverb = "slammed"
+ playsound(loc, "punch", 25, 1, -1)
+ visible_message("[user] has [hitverb] [src]!", \
+ "[user] has [hitverb] [src]!")
+ return 1
+
+/mob/living/carbon/alien/humanoid/attack_hand(mob/living/carbon/human/M)
+ if(..())
+ switch(M.a_intent)
+ if ("harm")
+ var/damage = rand(1, 9)
+ if (prob(90))
+ playsound(loc, "punch", 25, 1, -1)
+ visible_message("[M] has punched [src]!", \
+ "[M] has punched [src]!")
+ if ((stat != DEAD) && (damage > 9 || prob(5)))//Regular humans have a very small chance of weakening an alien.
+ Paralyse(2)
+ visible_message("[M] has weakened [src]!", \
+ "[M] has weakened [src]!")
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ apply_damage(damage, BRUTE, affecting)
+ add_logs(M, src, "attacked")
+ else
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ visible_message("[M] has attempted to punch [src]!")
+
+ if ("disarm")
+ if (!lying)
+ if (prob(5))
+ Paralyse(2)
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ add_logs(M, src, "pushed")
+ visible_message("[M] has pushed down [src]!", \
+ "[M] has pushed down [src]!")
+ else
+ if (prob(50))
+ drop_item()
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ visible_message("[M] has disarmed [src]!", \
+ "[M] has disarmed [src]!")
+ else
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ visible_message("[M] has attempted to disarm [src]!")
diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
index 5f48d88c55d..5559ebffe01 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm
@@ -57,14 +57,17 @@
real_name = src.name
+ AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno(src))
+ AddAbility(new/obj/effect/proc_holder/alien/royal/queen/promote())
+ smallsprite.Grant(src)
+ ..()
+
+/mob/living/carbon/alien/humanoid/royal/queen/create_internal_organs()
internal_organs += new /obj/item/organ/alien/plasmavessel/large/queen
internal_organs += new /obj/item/organ/alien/resinspinner
internal_organs += new /obj/item/organ/alien/acid
internal_organs += new /obj/item/organ/alien/neurotoxin
internal_organs += new /obj/item/organ/alien/eggsac
- AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/repulse/xeno(src))
- AddAbility(new/obj/effect/proc_holder/alien/royal/queen/promote())
- smallsprite.Grant(src)
..()
/mob/living/carbon/alien/humanoid/royal/queen/movement_delay()
diff --git a/code/modules/mob/living/carbon/alien/larva/death.dm b/code/modules/mob/living/carbon/alien/larva/death.dm
index 136572fb5c5..43a2f196255 100644
--- a/code/modules/mob/living/carbon/alien/larva/death.dm
+++ b/code/modules/mob/living/carbon/alien/larva/death.dm
@@ -8,3 +8,18 @@
visible_message("[src] lets out a waning high-pitched cry.")
return ..(gibbed)
+
+/mob/living/carbon/alien/larva/spawn_gibs(with_bodyparts)
+ if(with_bodyparts)
+ new /obj/effect/gibspawner/larva(loc,viruses)
+ else
+ new /obj/effect/gibspawner/larvabodypartless(loc,viruses)
+
+/mob/living/carbon/alien/larva/gib_animation()
+ PoolOrNew(/obj/effect/overlay/temp/gib_animation, list(loc, "gibbed-l"))
+
+/mob/living/carbon/alien/larva/spawn_dust()
+ new /obj/effect/decal/remains/xeno(loc)
+
+/mob/living/carbon/alien/larva/dust_animation()
+ PoolOrNew(/obj/effect/overlay/temp/dust_animation, list(loc, "dust-l"))
diff --git a/code/modules/mob/living/carbon/alien/larva/larva.dm b/code/modules/mob/living/carbon/alien/larva/larva.dm
index 887cf139996..f6ceff4774a 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva.dm
@@ -14,16 +14,20 @@
var/time_of_birth
rotate_on_lying = 0
+ bodyparts = list(/obj/item/bodypart/chest/larva, /obj/item/bodypart/head/larva)
+
//This is fine right now, if we're adding organ specific damage this needs to be updated
/mob/living/carbon/alien/larva/New()
- regenerate_icons()
- internal_organs += new /obj/item/organ/alien/plasmavessel/small/tiny
AddAbility(new/obj/effect/proc_holder/alien/hide(null))
AddAbility(new/obj/effect/proc_holder/alien/larva_evolve(null))
..()
+/mob/living/carbon/alien/larva/create_internal_organs()
+ internal_organs += new /obj/item/organ/alien/plasmavessel/small/tiny
+ ..()
+
//This needs to be fixed
/mob/living/carbon/alien/larva/Stat()
..()
@@ -39,36 +43,6 @@
/mob/living/carbon/alien/larva/attack_ui(slot_id)
return
-/mob/living/carbon/alien/larva/attack_hulk(mob/living/carbon/human/user)
- if(user.a_intent == "harm")
- ..(user, 1)
- adjustBruteLoss(5 + rand(1,9))
- spawn()
- step_away(src,user,15)
- sleep(1)
- step_away(src,user,15)
- return 1
-
-/mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/M)
- if(..())
- var/damage = rand(1, 9)
- if (prob(90))
- playsound(loc, "punch", 25, 1, -1)
- add_logs(M, src, "attacked")
- visible_message("[M] has kicked [src]!", \
- "[M] has kicked [src]!")
- if ((stat != DEAD) && (damage > 4.9))
- Paralyse(rand(5,10))
-
- adjustBruteLoss(damage)
- updatehealth()
- else
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to kick [src]!", \
- "[M] has attempted to kick [src]!")
-
- return
-
/mob/living/carbon/alien/larva/restrained(ignore_grab)
. = 0
diff --git a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
new file mode 100644
index 00000000000..77bab6cdf04
--- /dev/null
+++ b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
@@ -0,0 +1,29 @@
+
+
+/mob/living/carbon/alien/larva/attack_hand(mob/living/carbon/human/M)
+ if(..())
+ var/damage = rand(1, 9)
+ if (prob(90))
+ playsound(loc, "punch", 25, 1, -1)
+ add_logs(M, src, "attacked")
+ visible_message("[M] has kicked [src]!", \
+ "[M] has kicked [src]!")
+ if ((stat != DEAD) && (damage > 4.9))
+ Paralyse(rand(5,10))
+
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ apply_damage(damage, BRUTE, affecting)
+ else
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ visible_message("[M] has attempted to kick [src]!", \
+ "[M] has attempted to kick [src]!")
+
+/mob/living/carbon/alien/larva/attack_hulk(mob/living/carbon/human/user)
+ if(user.a_intent == "harm")
+ ..(user, 1)
+ adjustBruteLoss(5 + rand(1,9))
+ spawn()
+ step_away(src,user,15)
+ sleep(1)
+ step_away(src,user,15)
+ return 1
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/larva/life.dm b/code/modules/mob/living/carbon/alien/larva/life.dm
index 0f4de4b6890..0ff617d7532 100644
--- a/code/modules/mob/living/carbon/alien/larva/life.dm
+++ b/code/modules/mob/living/carbon/alien/larva/life.dm
@@ -6,7 +6,7 @@
if (notransform)
return
- if(..())
+ if(..()) //not dead
// GROW!
if(amount_grown < max_grown)
amount_grown++
diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm
index 91bddef2cde..f0192cf2a96 100644
--- a/code/modules/mob/living/carbon/alien/life.dm
+++ b/code/modules/mob/living/carbon/alien/life.dm
@@ -45,4 +45,10 @@
move_delay_add = max(0, move_delay_add - rand(1, 2))
/mob/living/carbon/alien/handle_changeling()
+ return
+
+/mob/living/carbon/alien/handle_fire()//Aliens on fire code
+ if(..())
+ return
+ bodytemperature += BODYTEMP_HEATING_MAX //If you're on fire, you heat up!
return
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 9a531fdf956..f2382721cff 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -41,7 +41,7 @@ var/const/ALIEN_AFK_BRACKET = 450 // 45 seconds
if(prob(4))
owner << "Your muscles ache."
if(prob(20))
- owner.take_organ_damage(1)
+ owner.take_bodypart_damage(1)
if(prob(4))
owner << "Your stomach hurts."
if(prob(20))
diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm
index a1292a9c9ab..58551f671e1 100644
--- a/code/modules/mob/living/carbon/alien/special/facehugger.dm
+++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm
@@ -68,7 +68,6 @@ var/const/MAX_ACTIVE_TIME = 400
/obj/item/clothing/mask/facehugger/bullet_act(obj/item/projectile/P)
if(P.damage)
Die()
- return
/obj/item/clothing/mask/facehugger/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
if(exposed_temperature > 300)
@@ -92,7 +91,7 @@ var/const/MAX_ACTIVE_TIME = 400
return Attach(AM)
return 0
-/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed, mob/thrower, spin)
+/obj/item/clothing/mask/facehugger/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0)
if(!..())
return
if(stat == CONSCIOUS)
@@ -124,7 +123,7 @@ var/const/MAX_ACTIVE_TIME = 400
return 0
if(stat != CONSCIOUS)
return 0
- if(!sterile) M.take_organ_damage(strength,0) //done here so that even borgs and humans in helmets take damage
+ if(!sterile) M.take_bodypart_damage(strength,0) //done here so that even borgs and humans in helmets take damage
M.visible_message("[src] leaps at [M]'s face!", \
"[src] leaps at [M]'s face!")
if(ishuman(M))
@@ -180,7 +179,7 @@ var/const/MAX_ACTIVE_TIME = 400
icon_state = "[initial(icon_state)]_impregnated"
var/obj/item/bodypart/chest/LC = target.get_bodypart("chest")
- if((!LC || LC.status != ORGAN_ROBOTIC) && !target.getorgan(/obj/item/organ/body_egg/alien_embryo))
+ if((!LC || LC.status != BODYPART_ROBOTIC) && !target.getorgan(/obj/item/organ/body_egg/alien_embryo))
new /obj/item/organ/body_egg/alien_embryo(target)
if(iscorgi(target))
diff --git a/code/modules/mob/living/carbon/alien/update_icons.dm b/code/modules/mob/living/carbon/alien/update_icons.dm
new file mode 100644
index 00000000000..ec3753e6979
--- /dev/null
+++ b/code/modules/mob/living/carbon/alien/update_icons.dm
@@ -0,0 +1,11 @@
+
+
+
+/mob/living/carbon/alien/update_damage_overlays() //aliens don't have damage overlays.
+ return
+
+/mob/living/carbon/alien/update_body() // we don't use the bodyparts or body layers for aliens.
+ return
+
+/mob/living/carbon/alien/update_body_parts()//we don't use the bodyparts layer for aliens.
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 8175cf4e862..94ee29b74b0 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -3,10 +3,11 @@
/mob/living/carbon/New()
create_reagents(1000)
+ update_body_parts() //to update the carbon's new bodyparts appearance
..()
/mob/living/carbon/Destroy()
- for(var/atom/movable/guts in internal_organs)
+ for(var/guts in internal_organs)
qdel(guts)
for(var/atom/movable/food in stomach_contents)
qdel(food)
@@ -28,16 +29,9 @@
var/obj/item/I = user.get_active_held_item()
if(I && I.force)
var/d = rand(round(I.force / 4), I.force)
- if(istype(src, /mob/living/carbon/human))
- var/mob/living/carbon/human/H = src
- var/organ = H.get_bodypart("chest")
- if (istype(organ, /obj/item/bodypart))
- var/obj/item/bodypart/temp = organ
- if(temp.take_damage(d, 0))
- H.update_damage_overlays(0)
- H.updatehealth()
- else
- src.take_organ_damage(d)
+ var/obj/item/bodypart/BP = get_bodypart("chest")
+ if(BP.take_damage(d, 0))
+ update_damage_overlays()
visible_message("[user] attacks [src]'s stomach wall with the [I.name]!", \
"[user] attacks your stomach wall with the [I.name]!")
playsound(user.loc, 'sound/effects/attackblob.ogg', 50, 1)
@@ -49,36 +43,6 @@
src.gib()
-/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, override = 0, tesla_shock = 0)
- shock_damage *= siemens_coeff
- if(dna && dna.species)
- shock_damage *= dna.species.siemens_coeff
- if(shock_damage<1 && !override)
- return 0
- if(reagents.has_reagent("teslium"))
- shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging!
- take_overall_damage(0,shock_damage)
- visible_message(
- "[src] was shocked by \the [source]!", \
- "You feel a powerful shock coursing through your body!", \
- "You hear a heavy electrical crack." \
- )
- jitteriness += 1000 //High numbers for violent convulsions
- do_jitter_animation(jitteriness)
- stuttering += 2
- if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5))
- Stun(2)
- spawn(20)
- jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
- if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5))
- Stun(3)
- Weaken(3)
- if(override)
- return override
- else
- return shock_damage
-
-
/mob/living/carbon/swap_hand(held_index)
if(!held_index)
held_index = (active_hand_index % held_items.len)+1
@@ -117,73 +81,27 @@
else
mode() // Activate held item
-/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
- if(on_fire)
- M << "You can't put them out with just your bare hands!"
- return
+/mob/living/carbon/attackby(obj/item/I, mob/user, params)
+ if(lying && surgeries.len)
+ if(user != src && user.a_intent == "help")
+ for(var/datum/surgery/S in surgeries)
+ if(S.next_step(user))
+ return 1
+ return ..()
- if(health >= 0 && !(status_flags & FAKEDEATH))
-
- if(lying)
- M.visible_message("[M] shakes [src] trying to get them up!", \
- "You shake [src] trying to get them up!")
- else
- M.visible_message("[M] hugs [src] to make them feel better!", \
- "You hug [src] to make them feel better!")
- AdjustSleeping(-5)
- AdjustParalysis(-3)
- AdjustStunned(-3)
- AdjustWeakened(-3)
- if(resting)
- resting = 0
- update_canmove()
-
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
-
-/mob/living/carbon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
+/mob/living/carbon/throw_impact(atom/hit_atom)
. = ..()
-
- var/damage = intensity - check_eye_prot()
- if(.) // we've been flashed
- if(visual)
- return
- if(weakeyes)
- Stun(2)
-
- if (damage == 1)
- src << "Your eyes sting a little."
- if(prob(40))
- adjust_eye_damage(1)
-
- else if (damage == 2)
- src << "Your eyes burn."
- adjust_eye_damage(rand(2, 4))
-
- else if( damage > 3)
- src << "Your eyes itch and burn severely!"
- adjust_eye_damage(rand(12, 16))
-
- if(eye_damage > 10)
- blind_eyes(damage)
- blur_eyes(damage * rand(3, 6))
-
- if(eye_damage > 20)
- if(prob(eye_damage - 20))
- if(become_nearsighted())
- src << "Your eyes start to burn badly!"
- else if(prob(eye_damage - 25))
- if(become_blind())
- src << "You can't see anything!"
- else
- src << "Your eyes are really starting to hurt. This can't be good for you!"
- if(has_bane(BANE_LIGHT))
- mind.disrupt_spells(-500)
- return 1
- else if(damage == 0) // just enough protection
- if(prob(20))
- src << "Something bright flashes in the corner of your vision!"
- if(has_bane(BANE_LIGHT))
- mind.disrupt_spells(0)
+ if(hit_atom.density && isturf(hit_atom))
+ Weaken(1)
+ take_bodypart_damage(10)
+ if(iscarbon(hit_atom))
+ var/mob/living/carbon/victim = hit_atom
+ victim.Weaken(1)
+ Weaken(1)
+ victim.take_bodypart_damage(10)
+ take_bodypart_damage(10)
+ visible_message("[src] crashes into [victim], knocking them both over!", "You violently crash into [victim]!")
+ playsound(src,'sound/weapons/punch1.ogg',50,1)
//Throwing stuff
@@ -308,13 +226,6 @@
/mob/living/carbon/is_muzzled()
return(istype(src.wear_mask, /obj/item/clothing/mask/muzzle))
-/mob/living/carbon/blob_act(obj/effect/blob/B)
- if (stat == DEAD)
- return
- else
- show_message("The blob attacks!")
- adjustBruteLoss(10)
-
/mob/living/carbon/proc/spin(spintime, speed)
set waitfor = 0
var/D = dir
@@ -467,10 +378,6 @@
else
return initial(pixel_y)
-/mob/living/carbon/check_ear_prot()
- if(head && (head.flags & HEADBANGPROTECT))
- return 1
-
/mob/living/carbon/proc/accident(obj/item/I)
if(!I || (I.flags & (NODROP|ABSTRACT)))
return
@@ -499,17 +406,6 @@
var/turf/target = get_turf(loc)
I.throw_at(target,I.throw_range,I.throw_speed,src)
-/mob/living/carbon/emp_act(severity)
- for(var/obj/item/organ/O in internal_organs)
- O.emp_act(severity)
- ..()
-
-/mob/living/carbon/check_eye_prot()
- var/number = ..()
- for(var/obj/item/organ/cyberimp/eyes/EFP in internal_organs)
- number += EFP.flash_protect
- return number
-
/mob/living/carbon/proc/AddAbility(obj/effect/proc_holder/alien/A)
abilities.Add(A)
A.on_gain(src)
@@ -538,6 +434,11 @@
add_abilities_to_panel()
+/mob/living/carbon/attack_ui(slot)
+ if(!has_hand_for_held_index(active_hand_index))
+ return 0
+ return ..()
+
/mob/living/carbon/proc/vomit(var/lost_nutrition = 10, var/blood = 0, var/stun = 1, var/distance = 0, var/message = 1, var/toxic = 0)
if(nutrition < 100 && !blood)
if(message)
@@ -578,12 +479,29 @@
return 1
-
/mob/living/carbon/fully_replace_character_name(oldname,newname)
..()
if(dna)
dna.real_name = real_name
+//Updates the mob's health from bodyparts and mob damage variables
+/mob/living/carbon/updatehealth()
+ if(status_flags & GODMODE)
+ return
+ var/total_burn = 0
+ var/total_brute = 0
+ for(var/X in bodyparts) //hardcoded to streamline things a bit
+ var/obj/item/bodypart/BP = X
+ total_brute += BP.brute_dam
+ total_burn += BP.burn_dam
+ health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
+ update_stat()
+ if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
+ become_husk()
+ if(on_fire)
+ shred_clothing()
+ med_hud_set_health()
+
/mob/living/carbon/update_sight()
if(!client)
return
@@ -754,8 +672,10 @@
if(B)
B.damaged_brain = 0
for(var/datum/disease/D in viruses)
- D.cure(0)
+ if (D.severity != NONTHREAT)
+ D.cure(0)
if(admin_revive)
+ regenerate_limbs()
handcuffed = initial(handcuffed)
for(var/obj/item/weapon/restraints/R in contents) //actually remove cuffs from inventory
qdel(R)
@@ -773,7 +693,8 @@
if(qdeleted(src))
return
var/organs_amt = 0
- for(var/obj/item/organ/O in internal_organs)
+ for(var/X in internal_organs)
+ var/obj/item/organ/O = X
if(prob(50))
organs_amt++
O.Remove(src)
@@ -783,15 +704,6 @@
..()
-/mob/living/carbon/adjustToxLoss(amount, updating_health=1)
- if(has_dna() && TOXINLOVER in dna.species.specflags) //damage becomes healing and healing becomes damage
- amount = -amount
- if(amount > 0)
- blood_volume -= 5*amount
- else
- blood_volume -= amount
- return ..()
-
/mob/living/carbon/fakefire(var/fire_icon = "Generic_mob_burning")
overlays_standing[FIRE_LAYER] = image("icon"='icons/mob/OnFire.dmi', "icon_state"= fire_icon, "layer"=-FIRE_LAYER)
apply_overlay(FIRE_LAYER)
@@ -799,3 +711,34 @@
/mob/living/carbon/fakefireextinguish()
remove_overlay(FIRE_LAYER)
+
+/mob/living/carbon/proc/devour_mob(mob/living/carbon/C, devour_time = 130)
+ C.visible_message("[src] is attempting to devour [C]!", \
+ "[src] is attempting to devour you!")
+ if(!do_mob(src, C, devour_time))
+ return
+ if(pulling && pulling == C && grab_state >= GRAB_AGGRESSIVE && a_intent == "grab")
+ C.visible_message("[src] devours [C]!", \
+ "[src] devours you!")
+ C.forceMove(src)
+ stomach_contents.Add(C)
+ add_logs(src, C, "devoured")
+
+/mob/living/carbon/proc/create_bodyparts()
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/O = new X()
+ O.owner = src
+ bodyparts.Remove(X)
+ bodyparts.Add(O)
+ if(O.body_part == ARM_LEFT)
+ O.held_index = 1
+ hand_bodyparts += O
+ else if(O.body_part == ARM_RIGHT)
+ O.held_index = 2
+ hand_bodyparts += O
+
+
+/mob/living/carbon/proc/create_internal_organs()
+ for(var/X in internal_organs)
+ var/obj/item/organ/I = X
+ I.Insert(src)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 6a82174e41e..4de7733bd26 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -1,3 +1,19 @@
+
+/mob/living/carbon/get_eye_protection()
+ var/number = ..()
+ for(var/obj/item/organ/cyberimp/eyes/EFP in internal_organs)
+ number += EFP.flash_protect
+ return number
+
+/mob/living/carbon/get_ear_protection()
+ if(head && (head.flags & HEADBANGPROTECT))
+ return 1
+
+/mob/living/carbon/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
+ var/obj/item/bodypart/affecting = get_bodypart(def_zone)
+ if(affecting && affecting.dismemberable && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
+ affecting.dismember(P.damtype)
+
/mob/living/carbon/hitby(atom/movable/AM, skipcatch, hitpush = 1, blocked = 0)
if(!skipcatch) //ugly, but easy
if(in_throw_mode && !get_active_held_item()) //empty active hand and we're in throw mode
@@ -11,32 +27,42 @@
return 1
..()
-/mob/living/carbon/throw_impact(atom/hit_atom)
- . = ..()
- if(hit_atom.density && isturf(hit_atom))
- Weaken(1)
- take_organ_damage(10)
- if(iscarbon(hit_atom))
- var/mob/living/carbon/victim = hit_atom
- victim.Weaken(1)
- Weaken(1)
- victim.take_organ_damage(10)
- take_organ_damage(10)
- visible_message("[src] crashes into [victim], knocking them both over!", "You violently crash into [victim]!")
- playsound(src,'sound/weapons/punch1.ogg',50,1)
-/mob/living/carbon/attackby(obj/item/I, mob/user, params)
- if(lying && surgeries.len)
- if(user != src && user.a_intent == "help")
- for(var/datum/surgery/S in surgeries)
- if(S.next_step(user))
- return 1
- return ..()
+/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(user.zone_selected))
+ if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest)
+ affecting = bodyparts[1]
+ send_item_attack_message(I, user, affecting.name)
+ if(I.force)
+ apply_damage(I.force, I.damtype, affecting)
+ if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
+ if(prob(33))
+ I.add_mob_blood(src)
+ var/turf/location = get_turf(src)
+ add_splatter_floor(location)
+ if(get_dist(user, src) <= 1) //people with TK won't get smeared with blood
+ user.add_mob_blood(src)
+ if(affecting.body_zone == "head")
+ if(wear_mask)
+ wear_mask.add_mob_blood(src)
+ update_inv_wear_mask()
+ if(head)
+ head.add_mob_blood(src)
+ update_inv_head()
+
+ //dismemberment
+ var/probability = I.get_dismemberment_chance(affecting)
+ if(prob(probability))
+ if(affecting.dismember(I.damtype))
+ I.add_mob_blood(src)
+ playsound(get_turf(src), I.get_dismember_sound(), 80, 1)
+ return TRUE //successful attack
+
+/mob/living/carbon/attack_drone(mob/living/simple_animal/drone/user)
+ return //so we don't call the carbon's attack_hand().
/mob/living/carbon/attack_hand(mob/living/carbon/human/user)
- if(!iscarbon(user))
- return
for(var/datum/disease/D in viruses)
if(D.IsSpreadByTouch())
@@ -55,9 +81,6 @@
/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
- if(!istype(M, /mob/living/carbon))
- return 0
-
for(var/datum/disease/D in viruses)
if(D.IsSpreadByTouch())
M.ContractDisease(D)
@@ -101,20 +124,8 @@
updatehealth()
return 1
-/mob/living/carbon/proc/devour_mob(mob/living/carbon/C, devour_time = 130)
- C.visible_message("[src] is attempting to devour [C]!", \
- "[src] is attempting to devour you!")
- if(!do_mob(src, C, devour_time))
- return
- if(pulling && pulling == C && grab_state >= GRAB_AGGRESSIVE && a_intent == "grab")
- C.visible_message("[src] devours [C]!", \
- "[src] devours you!")
- C.forceMove(src)
- stomach_contents.Add(C)
- add_logs(src, C, "devoured")
-
/mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone)
- if(!attacker.limb_destroyer || !has_limbs)
+ if(!attacker.limb_destroyer)
return dam_zone
var/obj/item/bodypart/affecting
if(dam_zone && attacker.client)
@@ -134,3 +145,136 @@
return null
return affecting.body_zone
return dam_zone
+
+
+/mob/living/carbon/blob_act(obj/effect/blob/B)
+ if (stat == DEAD)
+ return
+ else
+ show_message("The blob attacks!")
+ adjustBruteLoss(10)
+
+/mob/living/carbon/emp_act(severity)
+ for(var/X in internal_organs)
+ var/obj/item/organ/O = X
+ O.emp_act(severity)
+ ..()
+
+/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, override = 0, tesla_shock = 0)
+ shock_damage *= siemens_coeff
+ if(dna && dna.species)
+ shock_damage *= dna.species.siemens_coeff
+ if(shock_damage<1 && !override)
+ return 0
+ if(reagents.has_reagent("teslium"))
+ shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging!
+ take_overall_damage(0,shock_damage)
+ visible_message(
+ "[src] was shocked by \the [source]!", \
+ "You feel a powerful shock coursing through your body!", \
+ "You hear a heavy electrical crack." \
+ )
+ jitteriness += 1000 //High numbers for violent convulsions
+ do_jitter_animation(jitteriness)
+ stuttering += 2
+ if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5))
+ Stun(2)
+ spawn(20)
+ jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
+ if(!tesla_shock || (tesla_shock && siemens_coeff > 0.5))
+ Stun(3)
+ Weaken(3)
+ if(override)
+ return override
+ else
+ return shock_damage
+
+/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
+ if(on_fire)
+ M << "You can't put them out with just your bare hands!"
+ return
+
+ if(health >= 0 && !(status_flags & FAKEDEATH))
+
+ if(lying)
+ M.visible_message("[M] shakes [src] trying to get them up!", \
+ "You shake [src] trying to get them up!")
+ else
+ M.visible_message("[M] hugs [src] to make them feel better!", \
+ "You hug [src] to make them feel better!")
+ AdjustSleeping(-5)
+ AdjustParalysis(-3)
+ AdjustStunned(-3)
+ AdjustWeakened(-3)
+ if(resting)
+ resting = 0
+ update_canmove()
+
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+
+
+/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
+ . = ..()
+
+ var/damage = intensity - get_eye_protection()
+ if(.) // we've been flashed
+ if(visual)
+ return
+ if(weakeyes)
+ Stun(2)
+
+ if (damage == 1)
+ src << "Your eyes sting a little."
+ if(prob(40))
+ adjust_eye_damage(1)
+
+ else if (damage == 2)
+ src << "Your eyes burn."
+ adjust_eye_damage(rand(2, 4))
+
+ else if( damage > 3)
+ src << "Your eyes itch and burn severely!"
+ adjust_eye_damage(rand(12, 16))
+
+ if(eye_damage > 10)
+ blind_eyes(damage)
+ blur_eyes(damage * rand(3, 6))
+
+ if(eye_damage > 20)
+ if(prob(eye_damage - 20))
+ if(become_nearsighted())
+ src << "Your eyes start to burn badly!"
+ else if(prob(eye_damage - 25))
+ if(become_blind())
+ src << "You can't see anything!"
+ else
+ src << "Your eyes are really starting to hurt. This can't be good for you!"
+ if(has_bane(BANE_LIGHT))
+ mind.disrupt_spells(-500)
+ return 1
+ else if(damage == 0) // just enough protection
+ if(prob(20))
+ src << "Something bright flashes in the corner of your vision!"
+ if(has_bane(BANE_LIGHT))
+ mind.disrupt_spells(0)
+
+
+/mob/living/carbon/soundbang_act(intensity = 1, stun_pwr = 1, damage_pwr = 5, deafen_pwr = 15)
+ var/ear_safety = get_ear_protection()
+ if(ear_safety < 2) //has ears
+ var/effect_amount = intensity - ear_safety
+ if(effect_amount > 0)
+ if(stun_pwr)
+ Stun(stun_pwr*effect_amount)
+ Weaken(stun_pwr*effect_amount)
+ if(deafen_pwr || damage_pwr)
+ setEarDamage(ear_damage + damage_pwr*effect_amount, max(ear_deaf, deafen_pwr*effect_amount))
+ if (ear_damage >= 15)
+ src << "Your ears start to ring badly!"
+ if(prob(ear_damage - 5))
+ src << "You can't hear anything!"
+ disabilities |= DEAF
+ else if(ear_damage >= 5)
+ src << "Your ears start to ring!"
+ src << sound('sound/weapons/flash_ring.ogg',0,1,0,250)
+ return effect_amount //how soundbanged we are
diff --git a/code/modules/mob/living/carbon/carbon_defines.dm b/code/modules/mob/living/carbon/carbon_defines.dm
index 103fcbe50d7..f73ad1053c1 100644
--- a/code/modules/mob/living/carbon/carbon_defines.dm
+++ b/code/modules/mob/living/carbon/carbon_defines.dm
@@ -16,6 +16,11 @@
var/obj/item/weapon/tank/internal = null
var/obj/item/head = null
+ var/obj/item/gloves = null //only used by humans
+ var/obj/item/shoes = null //only used by humans.
+ var/obj/item/clothing/glasses/glasses = null //only used by humans.
+ var/obj/item/ears = null //only used by humans.
+
var/datum/dna/dna = null//Carbon
var/failed_last_breath = 0 //This is used to determine if the mob failed a breath. If they did fail a brath, they will attempt to breathe each tick, otherwise just once per 4 ticks.
@@ -32,4 +37,8 @@
var/tinttotal = 0 // Total level of visualy impairing items
- var/list/bodyparts = list() //Gets filled up in the constructor (New() proc in human.dm and monkey.dm)
+ var/list/bodyparts = list(/obj/item/bodypart/chest, /obj/item/bodypart/head, /obj/item/bodypart/l_arm,
+ /obj/item/bodypart/r_arm, /obj/item/bodypart/r_leg, /obj/item/bodypart/l_leg)
+ //Gets filled up in create_bodyparts()
+
+ var/list/hand_bodyparts = list() //a collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm
index 479e9459c5c..6b2e19c1959 100644
--- a/code/modules/mob/living/carbon/carbon_movement.dm
+++ b/code/modules/mob/living/carbon/carbon_movement.dm
@@ -1,6 +1,13 @@
/mob/living/carbon/movement_delay()
. = ..()
- . += grab_state * 3
+ . += grab_state * 3 //can't go fast while grabbing something.
+
+ if(!get_leg_ignore()) //ignore the fact we lack legs
+ var/leg_amount = get_num_legs()
+ . += 6 - 3*leg_amount //the fewer the legs, the slower the mob
+ if(!leg_amount)
+ . += 6 - 3*get_num_arms() //crawling is harder with fewer arms
+
if(legcuffed)
. += legcuffed.slowdown
diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm
new file mode 100644
index 00000000000..6da20373f62
--- /dev/null
+++ b/code/modules/mob/living/carbon/damage_procs.dm
@@ -0,0 +1,191 @@
+
+
+/mob/living/carbon/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked = 0)
+ var/hit_percent = (100-blocked)/100
+ if(!damage || hit_percent <= 0)
+ return 0
+
+ var/obj/item/bodypart/BP = null
+ if(islimb(def_zone)) //we specified a bodypart object
+ BP = def_zone
+ else
+ if(!def_zone)
+ def_zone = ran_zone(def_zone)
+ BP = get_bodypart(check_zone(def_zone))
+ if(!BP)
+ BP = bodyparts[1]
+
+ switch(damagetype)
+ if(BRUTE)
+ if(BP)
+ if(BP.take_damage(damage * hit_percent, 0))
+ update_damage_overlays()
+ else //no bodypart, we deal damage with a more general method.
+ adjustBruteLoss(damage * hit_percent)
+ if(BURN)
+ if(BP)
+ if(BP.take_damage(0, damage * hit_percent))
+ update_damage_overlays()
+ else
+ adjustFireLoss(damage * hit_percent)
+ if(TOX)
+ adjustToxLoss(damage * hit_percent)
+ if(OXY)
+ adjustOxyLoss(damage * hit_percent)
+ if(CLONE)
+ adjustCloneLoss(damage * hit_percent)
+ if(STAMINA)
+ adjustStaminaLoss(damage * hit_percent)
+ return 1
+
+
+//These procs fetch a cumulative total damage from all bodyparts
+/mob/living/carbon/getBruteLoss()
+ var/amount = 0
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ amount += BP.brute_dam
+ return amount
+
+/mob/living/carbon/getFireLoss()
+ var/amount = 0
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ amount += BP.burn_dam
+ return amount
+
+
+/mob/living/carbon/adjustBruteLoss(amount, updating_health = 1)
+ if(status_flags & GODMODE)
+ return 0
+ if(amount > 0)
+ take_overall_damage(amount, 0)
+ else
+ heal_overall_damage(-amount, 0, 0, 1, updating_health)
+
+/mob/living/carbon/adjustFireLoss(amount)
+ if(status_flags & GODMODE)
+ return 0
+ if(amount > 0)
+ take_overall_damage(0, amount)
+ else
+ heal_overall_damage(0, -amount)
+
+
+/mob/living/carbon/adjustToxLoss(amount, updating_health=1)
+ if(has_dna() && TOXINLOVER in dna.species.specflags) //damage becomes healing and healing becomes damage
+ amount = -amount
+ if(amount > 0)
+ blood_volume -= 5*amount
+ else
+ blood_volume -= amount
+ return ..()
+
+////////////////////////////////////////////
+
+//Returns a list of damaged bodyparts
+/mob/living/carbon/proc/get_damaged_bodyparts(brute, burn)
+ var/list/obj/item/bodypart/parts = list()
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ if((brute && BP.brute_dam) || (burn && BP.burn_dam))
+ parts += BP
+ return parts
+
+//Returns a list of damageable bodyparts
+/mob/living/carbon/proc/get_damageable_bodyparts()
+ var/list/obj/item/bodypart/parts = list()
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ if(BP.brute_dam + BP.burn_dam < BP.max_damage)
+ parts += BP
+ return parts
+
+//Heals ONE bodypart randomly selected from damaged ones.
+//It automatically updates damage overlays if necessary
+//It automatically updates health status
+/mob/living/carbon/heal_bodypart_damage(brute, burn, only_robotic = 0, only_organic = 1)
+ var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn)
+ if(!parts.len)
+ return
+ var/obj/item/bodypart/picked = pick(parts)
+ if(picked.heal_damage(brute, burn, only_robotic, only_organic))
+ update_damage_overlays()
+
+//Damages ONE bodypart randomly selected from damagable ones.
+//It automatically updates damage overlays if necessary
+//It automatically updates health status
+/mob/living/carbon/take_bodypart_damage(brute, burn)
+ var/list/obj/item/bodypart/parts = get_damageable_bodyparts()
+ if(!parts.len)
+ return
+ var/obj/item/bodypart/picked = pick(parts)
+ if(picked.take_damage(brute,burn))
+ update_damage_overlays()
+
+
+//Heal MANY bodyparts, in random order
+/mob/living/carbon/heal_overall_damage(brute, burn, only_robotic = 0, only_organic = 1, updating_health = 1)
+ var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn)
+
+ var/update = 0
+ while(parts.len && (brute>0 || burn>0) )
+ var/obj/item/bodypart/picked = pick(parts)
+
+ var/brute_was = picked.brute_dam
+ var/burn_was = picked.burn_dam
+
+ update |= picked.heal_damage(brute,burn, only_robotic, only_organic, 0)
+
+ brute -= (brute_was-picked.brute_dam)
+ burn -= (burn_was-picked.burn_dam)
+
+ parts -= picked
+ if(updating_health)
+ updatehealth()
+ if(update)
+ update_damage_overlays()
+
+// damage MANY bodyparts, in random order
+/mob/living/carbon/take_overall_damage(brute, burn, updating_health = 1)
+ if(status_flags & GODMODE)
+ return //godmode
+
+ var/list/obj/item/bodypart/parts = get_damageable_bodyparts()
+ var/update = 0
+ while(parts.len && (brute>0 || burn>0) )
+ var/obj/item/bodypart/picked = pick(parts)
+ var/brute_per_part = round(brute/parts.len, 0.01)
+ var/burn_per_part = round(burn/parts.len, 0.01)
+
+ var/brute_was = picked.brute_dam
+ var/burn_was = picked.burn_dam
+
+
+ update |= picked.take_damage(brute_per_part,burn_per_part, 0)
+
+ brute -= (picked.brute_dam - brute_was)
+ burn -= (picked.burn_dam - burn_was)
+
+ parts -= picked
+ if(updating_health)
+ updatehealth()
+ if(update)
+ update_damage_overlays()
+
+
+
+/mob/living/carbon/adjustStaminaLoss(amount, updating_stamina = 1)
+ if(status_flags & GODMODE)
+ return 0
+ staminaloss = Clamp(staminaloss + amount, 0, maxHealth*2)
+ if(updating_stamina)
+ update_stamina()
+
+
+/mob/living/carbon/setStaminaLoss(amount, updating_stamina = 1)
+ if(status_flags & GODMODE)
+ return 0
+ staminaloss = amount
+ if(updating_stamina)
+ update_stamina()
diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm
index 3db1d738a96..f1a2a526a7a 100644
--- a/code/modules/mob/living/carbon/death.dm
+++ b/code/modules/mob/living/carbon/death.dm
@@ -3,19 +3,43 @@
losebreath = 0
..()
-/mob/living/carbon/gib(no_brain, no_organs)
+/mob/living/carbon/gib(no_brain, no_organs, no_bodyparts)
for(var/mob/M in src)
if(M in stomach_contents)
stomach_contents.Remove(M)
- M.loc = loc
+ M.forceMove(loc)
visible_message("[M] bursts out of [src]!")
..()
-/mob/living/carbon/spill_organs(no_brain)
- for(var/obj/item/organ/I in internal_organs)
- if(no_brain && istype(I, /obj/item/organ/brain))
- continue
- if(I)
+/mob/living/carbon/spill_organs(no_brain, no_organs, no_bodyparts)
+ if(!no_bodyparts)
+ if(no_organs)//so the organs don't get transfered inside the bodyparts we'll drop.
+ for(var/X in internal_organs)
+ qdel(X)
+ else //we're going to drop all bodyparts except chest, so the only organs that needs spilling are those inside it.
+ for(var/X in internal_organs)
+ var/obj/item/organ/O = X
+ if(no_brain && istype(O, /obj/item/organ/brain))
+ qdel(O) //so the brain isn't transfered to the head when the head drops.
+ continue
+ var/org_zone = check_zone(O.zone) //both groin and chest organs.
+ if(org_zone == "chest")
+ O.Remove(src)
+ O.forceMove(get_turf(src))
+ O.throw_at_fast(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5)
+ else
+ for(var/X in internal_organs)
+ var/obj/item/organ/I = X
+ if(no_brain && istype(I, /obj/item/organ/brain))
+ qdel(I)
+ continue
I.Remove(src)
- I.loc = get_turf(src)
+ I.forceMove(get_turf(src))
I.throw_at_fast(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5)
+
+
+/mob/living/carbon/spread_bodyparts()
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ BP.drop_limb()
+ BP.throw_at_fast(get_edge_target_turf(src,pick(alldirs)),rand(1,3),5)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm
index 1be55c38a12..61d30f7b8e9 100644
--- a/code/modules/mob/living/carbon/examine.dm
+++ b/code/modules/mob/living/carbon/examine.dm
@@ -2,7 +2,7 @@
var/msg = "*---------*\nThis is \icon[src] \a [src]!\n"
if (handcuffed)
- msg += "It is \icon[src.handcuffed] handcuffed!\n"
+ msg += "It is \icon[src.handcuffed] handcuffed!\n"
if (head)
msg += "It has \icon[src.head] \a [src.head] on its head. \n"
if (wear_mask)
@@ -17,52 +17,65 @@
if (back)
msg += "It has \icon[src.back] \a [src.back] on its back.\n"
+ var/appears_dead = 0
if (stat == DEAD)
- msg += "It is limp and unresponsive, with no signs of life.\n"
- else
- msg += ""
- var/temp = getBruteLoss()
- if(temp)
- if (temp < 30)
- msg += "It has minor bruising.\n"
- else
- msg += "It has severe bruising!\n"
+ appears_dead = 1
+ if(getorgan(/obj/item/organ/brain))
+ msg += "It is limp and unresponsive, with no signs of life.\n"
+ else if(get_bodypart("head"))
+ msg += "It appears that it's brain is missing...\n"
- temp = getFireLoss()
- if(temp)
- if (temp < 30)
- msg += "It has minor burns.\n"
- else
- msg += "It has severe burns!\n"
+ var/list/missing = get_missing_limbs()
+ for(var/t in missing)
+ if(t=="head")
+ msg += "Its [parse_zone(t)] is missing!\n"
+ continue
+ msg += "<Its [parse_zone(t)] is missing!\n"
- temp = getCloneLoss()
- if(temp)
- if(getCloneLoss() < 30)
- msg += "It is slightly deformed.\n"
- else
- msg += "It is severely deformed.\n"
+ msg += ""
+ var/temp = getBruteLoss()
+ if(temp)
+ if (temp < 30)
+ msg += "It has minor bruising.\n"
+ else
+ msg += "It has severe bruising!\n"
- if(getBrainLoss() > 60)
- msg += "It seems to be clumsy and unable to think.\n"
+ temp = getFireLoss()
+ if(temp)
+ if (temp < 30)
+ msg += "It has minor burns.\n"
+ else
+ msg += "It has severe burns!\n"
- if(fire_stacks > 0)
- msg += "It's covered in something flammable.\n"
- if(fire_stacks < 0)
- msg += "It's soaked in water.\n"
+ temp = getCloneLoss()
+ if(temp)
+ if(getCloneLoss() < 30)
+ msg += "It is slightly deformed.\n"
+ else
+ msg += "It is severely deformed.\n"
- if(pulledby && pulledby.grab_state)
- msg += "It's restrained by [pulledby]'s grip.\n"
+ if(getBrainLoss() > 60)
+ msg += "It seems to be clumsy and unable to think.\n"
+ if(fire_stacks > 0)
+ msg += "It's covered in something flammable.\n"
+ if(fire_stacks < 0)
+ msg += "It's soaked in water.\n"
+
+ if(pulledby && pulledby.grab_state)
+ msg += "It's restrained by [pulledby]'s grip.\n"
+
+ msg += ""
+
+ if(!appears_dead)
if(stat == UNCONSCIOUS)
msg += "It isn't responding to anything around it; it seems to be asleep.\n"
- msg += ""
- if(digitalcamo)
- msg += "It is moving its body in an unnatural and blatantly unsimian manner.\n"
+ if(digitalcamo)
+ msg += "It is moving its body in an unnatural and blatantly unsimian manner.\n"
+
- if(!getorgan(/obj/item/organ/brain))
- msg += "It appears that it's brain is missing...\n"
msg += "*---------*"
- user << msg
\ No newline at end of file
+ user << msg
diff --git a/code/modules/mob/living/carbon/human/damage_procs.dm b/code/modules/mob/living/carbon/human/damage_procs.dm
new file mode 100644
index 00000000000..aa49718753f
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/damage_procs.dm
@@ -0,0 +1,5 @@
+
+
+/mob/living/carbon/human/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0)
+ // depending on the species, it will run the corresponding apply_damage code there
+ return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src)
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index d1b085ca3b9..83bf44f8e14 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -4,8 +4,11 @@
/mob/living/carbon/human/dust_animation()
PoolOrNew(/obj/effect/overlay/temp/dust_animation, list(loc, "dust-h"))
-/mob/living/carbon/human/spawn_gibs()
- hgibs(loc, viruses, dna)
+/mob/living/carbon/human/spawn_gibs(with_bodyparts)
+ if(with_bodyparts)
+ new /obj/effect/gibspawner/human(loc, viruses, dna)
+ else
+ new /obj/effect/gibspawner/humanbodypartless(loc, viruses, dna)
/mob/living/carbon/human/spawn_dust()
new /obj/effect/decal/remains/human(loc)
@@ -40,21 +43,9 @@
set_species(/datum/species/skeleton)
return 1
-/mob/living/carbon/proc/ChangeToHusk()
- if(disabilities & HUSK)
- return
- disabilities |= HUSK
- status_flags |= DISFIGURED //makes them unknown without fucking up other stuff like admintools
- return 1
-
-/mob/living/carbon/human/ChangeToHusk()
- . = ..()
- if(.)
- update_hair()
- update_body()
/mob/living/carbon/proc/Drain()
- ChangeToHusk()
+ become_husk()
disabilities |= NOCLONE
blood_volume = 0
return 1
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 6aae26c14c5..7b71530d27f 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -191,18 +191,26 @@
for(var/obj/item/I in BP.embedded_objects)
msg += "[t_He] [t_has] \a \icon[I] [I] embedded in [t_his] [BP.name]!\n"
- //stores how many left limbs are missing
+ //stores missing limbs
var/l_limbs_missing = 0
+ var/r_limbs_missing = 0
for(var/t in missing)
if(t=="head")
msg += "[capitalize(t_his)] [parse_zone(t)] is missing!\n"
continue
if(t == "l_arm" || t == "l_leg")
l_limbs_missing++
+ else if(t == "r_arm" || t == "r_leg")
+ r_limbs_missing++
+
msg += "[capitalize(t_his)] [parse_zone(t)] is missing!\n"
- if(l_limbs_missing >= 2)
+ if(l_limbs_missing >= 2 && r_limbs_missing == 0)
msg += "[t_He] looks all right now.\n"
+ else if(l_limbs_missing == 0 && r_limbs_missing >= 2)
+ msg += "[t_He] really keeps to the left.\n"
+ else if(l_limbs_missing >= 2 && r_limbs_missing >= 2)
+ msg += "[t_He] doesn't seem all there.\n"
if(temp)
if(temp < 30)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 48f191b4e74..1c7a02138df 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -3,7 +3,7 @@
real_name = "Unknown"
voice_name = "Unknown"
icon = 'icons/mob/human.dmi'
- icon_state = "caucasian1_m_s"
+ icon_state = "caucasian_m_s"
@@ -18,18 +18,7 @@
verbs += /mob/living/proc/lay_down
//initialize limbs first
- bodyparts = newlist(/obj/item/bodypart/chest, /obj/item/bodypart/head, /obj/item/bodypart/r_leg, /obj/item/bodypart/l_leg)
- var/obj/item/bodypart/l_arm/l_arm = new()
- var/obj/item/bodypart/r_arm/r_arm = new()
- bodyparts += l_arm
- bodyparts += r_arm
- l_arm.held_index = 1
- r_arm.held_index = 2
- hand_bodyparts += l_arm
- hand_bodyparts += r_arm
- for(var/X in bodyparts)
- var/obj/item/bodypart/O = X
- O.owner = src
+ create_bodyparts()
//initialize dna. for spawned humans; overwritten by other code
create_dna(src)
@@ -40,21 +29,7 @@
set_species(dna.species.type)
//initialise organs
- if(!(NOHUNGER in dna.species.specflags))
- internal_organs += new /obj/item/organ/appendix
-
- if(!(NOBREATH in dna.species.specflags))
- internal_organs += new /obj/item/organ/lungs
-
- if(!(NOBLOOD in dna.species.specflags))
- internal_organs += new /obj/item/organ/heart
-
- internal_organs += new /obj/item/organ/brain
-
- //Note: Additional organs are generated/replaced on the dna.species level
-
- for(var/obj/item/organ/I in internal_organs)
- I.Insert(src)
+ create_internal_organs()
martial_art = default_martial_art
@@ -62,6 +37,16 @@
..()
+/mob/living/carbon/human/create_internal_organs()
+ if(!(NOHUNGER in dna.species.specflags))
+ internal_organs += new /obj/item/organ/appendix
+ if(!(NOBREATH in dna.species.specflags))
+ internal_organs += new /obj/item/organ/lungs
+ if(!(NOBLOOD in dna.species.specflags))
+ internal_organs += new /obj/item/organ/heart
+ internal_organs += new /obj/item/organ/brain
+ ..()
+
/mob/living/carbon/human/OpenCraftingMenu()
handcrafting.ui_interact(src)
@@ -123,87 +108,6 @@
stat("*", "[D.name], Type: [D.spread_text], Stage: [D.stage]/[D.max_stages], Possible Cure: [D.cure_text]")
-/mob/living/carbon/human/ex_act(severity, ex_target)
- var/b_loss = null
- var/f_loss = null
- var/bomb_armor = getarmor(null, "bomb")
- if(istype(ex_target, /datum/spacevine_mutation) && isvineimmune(src))
- return
-
- switch (severity)
- if (1)
- b_loss += 500
- if (prob(bomb_armor))
- shred_clothing(1,150)
- var/atom/target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src)))
- throw_at(target, 200, 4)
- else
- gib()
- return
-
- if (2)
- b_loss += 60
-
- f_loss += 60
- if (prob(bomb_armor))
- b_loss = b_loss/1.5
- f_loss = f_loss/1.5
- shred_clothing(1,25)
- else
- shred_clothing(1,50)
-
- if (!istype(ears, /obj/item/clothing/ears/earmuffs))
- adjustEarDamage(30, 120)
- if (prob(70))
- Paralyse(10)
-
- if(3)
- b_loss += 30
- if (prob(bomb_armor))
- b_loss = b_loss/2
- if (!istype(ears, /obj/item/clothing/ears/earmuffs))
- adjustEarDamage(15,60)
- if (prob(50))
- Paralyse(10)
-
- take_overall_damage(b_loss,f_loss)
- //attempt to dismember bodyparts
- if(severity <= 2 || !bomb_armor)
- var/max_limb_loss = round(4/severity) //so you don't lose four limbs at severity 3.
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- if(prob(50/severity) && !prob(getarmor(BP, "bomb")) && BP.body_zone != "head" && BP.body_zone != "chest")
- BP.brute_dam = BP.max_damage
- BP.dismember()
- max_limb_loss--
- if(!max_limb_loss)
- break
- ..()
-
-/mob/living/carbon/human/blob_act(obj/effect/blob/B)
- if(stat == DEAD)
- return
- show_message("The blob attacks you!")
- var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
- apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee"))
- return
-
-/mob/living/carbon/human/bullet_act()
- if(martial_art && martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
- if(!prob(martial_art.deflection_chance))
- return ..()
- if(!src.lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
- src.visible_message("[src] deflects the projectile; they can't be hit with ranged weapons!", "You deflect the projectile!")
- playsound(src, pick("sound/weapons/bulletflyby.ogg","sound/weapons/bulletflyby2.ogg","sound/weapons/bulletflyby3.ogg"), 75, 1)
- return 0
- ..()
-
-/mob/living/carbon/human/attack_ui(slot)
- if(!has_hand_for_held_index(active_hand_index))
- return 0
- return ..()
-
/mob/living/carbon/human/show_inv(mob/user)
user.set_machine(src)
var/has_breathable_mask = istype(wear_mask, /obj/item/clothing/mask)
@@ -300,35 +204,6 @@
spreadFire(AM)
-//Added a safety check in case you want to shock a human mob directly through electrocute_act.
-/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0)
- if(tesla_shock)
- var/total_coeff = 1
- if(gloves)
- var/obj/item/clothing/gloves/G = gloves
- if(G.siemens_coefficient <= 0)
- total_coeff -= 0.5
- if(wear_suit)
- var/obj/item/clothing/suit/S = wear_suit
- if(S.siemens_coefficient <= 0)
- total_coeff -= 0.95
- siemens_coeff = total_coeff
- else if(!safety)
- var/gloves_siemens_coeff = 1
- if(gloves)
- var/obj/item/clothing/gloves/G = gloves
- gloves_siemens_coeff = G.siemens_coefficient
- siemens_coeff = gloves_siemens_coeff
- if(heart_attack)
- if(shock_damage * siemens_coeff >= 1 && prob(25))
- heart_attack = 0
- if(stat == CONSCIOUS)
- src << "You feel your heart beating again!"
- . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock)
- if(.)
- electrocution_animation(40)
-
-
/mob/living/carbon/human/Topic(href, href_list)
if(usr.canUseTopic(src, BE_CLOSE, NO_DEXTERY))
@@ -734,17 +609,6 @@
update_body()
update_hair()
-/mob/living/carbon/human/singularity_act()
- var/gain = 20
- if(mind)
- if((mind.assigned_role == "Station Engineer") || (mind.assigned_role == "Chief Engineer") )
- gain = 100
- if(mind.assigned_role == "Clown")
- gain = rand(-300, 300)
- investigate_log("([key_name(src)]) has been consumed by the singularity.","singulo") //Oh that's where the clown ended up!
- gib()
- return(gain)
-
/mob/living/carbon/human/singularity_pull(S, current_size)
if(current_size >= STAGE_THREE)
for(var/obj/item/hand in held_items)
@@ -756,71 +620,6 @@
return
..()
-
-/mob/living/carbon/human/help_shake_act(mob/living/carbon/M)
- if(!istype(M))
- return
-
- if(health >= 0)
- if(src == M)
- visible_message( \
- "[src] examines \himself.", \
- "You check yourself for injuries.")
-
- var/list/missing = list("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg")
- for(var/X in bodyparts)
- var/obj/item/bodypart/LB = X
- missing -= LB.body_zone
- var/status = ""
- var/brutedamage = LB.brute_dam
- var/burndamage = LB.burn_dam
- if(hallucination)
- if(prob(30))
- brutedamage += rand(30,40)
- if(prob(30))
- burndamage += rand(30,40)
-
- if(brutedamage > 0)
- status = "bruised"
- if(brutedamage > 20)
- status = "battered"
- if(brutedamage > 40)
- status = "mangled"
- if(brutedamage > 0 && burndamage > 0)
- status += " and "
- if(burndamage > 40)
- status += "peeling away"
-
- else if(burndamage > 10)
- status += "blistered"
- else if(burndamage > 0)
- status += "numb"
- if(status == "")
- status = "OK"
- src << "\t [status == "OK" ? "\blue" : "\red"] Your [LB.name] is [status]."
-
- for(var/obj/item/I in LB.embedded_objects)
- src << "\t \red There is \a [I] embedded in your [LB.name]!"
-
- for(var/t in missing)
- src << "Your [parse_zone(t)] is missing!"
-
- if(bleed_rate)
- src << "You are bleeding!"
- if(staminaloss)
- if(staminaloss > 30)
- src << "You're completely exhausted."
- else
- src << "You feel fatigued."
- else
- if(wear_suit)
- wear_suit.add_fingerprint(M)
- else if(w_uniform)
- w_uniform.add_fingerprint(M)
-
- ..()
-
-
/mob/living/carbon/human/proc/do_cpr(mob/living/carbon/C)
CHECK_DNA_AND_SPECIES(C)
@@ -1010,7 +809,6 @@
hud_used.healthdoll.icon_state = "healthdoll_DEAD"
/mob/living/carbon/human/fully_heal(admin_revive = 0)
- CHECK_DNA_AND_SPECIES(src)
if(admin_revive)
regenerate_limbs()
diff --git a/code/modules/mob/living/carbon/human/human_attackalien.dm b/code/modules/mob/living/carbon/human/human_attackalien.dm
deleted file mode 100644
index b407a2881a9..00000000000
--- a/code/modules/mob/living/carbon/human/human_attackalien.dm
+++ /dev/null
@@ -1,39 +0,0 @@
-/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(check_shields(0, M.name))
- visible_message("[M] attempted to touch [src]!")
- return 0
-
- if(..())
- if(M.a_intent == "harm")
- if (w_uniform)
- w_uniform.add_fingerprint(M)
- var/damage = prob(90) ? 20 : 0
- if(!damage)
- playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
- visible_message("[M] has lunged at [src]!", \
- "[M] has lunged at [src]!")
- return 0
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
- var/armor_block = run_armor_check(affecting, "melee","","",10)
-
- playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- visible_message("[M] has slashed at [src]!", \
- "[M] has slashed at [src]!")
- if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful
- return 1
- apply_damage(damage, BRUTE, affecting, armor_block)
- add_logs(M, src, "attacked")
- updatehealth()
-
- if(M.a_intent == "disarm") //Always drop item in hand, if no item, get stunned instead.
- if(get_active_held_item() && drop_item())
- playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
- visible_message("[M] disarmed [src]!", \
- "[M] disarmed [src]!")
- else
- playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
- Weaken(5)
- add_logs(M, src, "tackled")
- visible_message("[M] has tackled down [src]!", \
- "[M] has tackled down [src]!")
- return
diff --git a/code/modules/mob/living/carbon/human/human_attackhand.dm b/code/modules/mob/living/carbon/human/human_attackhand.dm
deleted file mode 100644
index 43e4dfaae76..00000000000
--- a/code/modules/mob/living/carbon/human/human_attackhand.dm
+++ /dev/null
@@ -1,14 +0,0 @@
-/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user)
- if(user.a_intent == "harm")
- ..(user, 1)
- playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
- var/hulk_verb = pick("smash","pummel")
- visible_message("[user] has [hulk_verb]ed [src]!", \
- "[user] has [hulk_verb]ed [src]!")
- adjustBruteLoss(15)
- return 1
-
-/mob/living/carbon/human/attack_hand(mob/living/carbon/human/M)
- if(..()) //to allow surgery to return properly.
- return
- dna.species.spec_attack_hand(M, src)
diff --git a/code/modules/mob/living/carbon/human/human_attackpaw.dm b/code/modules/mob/living/carbon/human/human_attackpaw.dm
deleted file mode 100644
index 4c666a86799..00000000000
--- a/code/modules/mob/living/carbon/human/human_attackpaw.dm
+++ /dev/null
@@ -1,18 +0,0 @@
-/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M)
- var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
-
- if(M.a_intent == "help")
- ..() //shaking
- return 0
-
- if(M.limb_destroyer)
- dismembering_strike(M, affecting.body_zone)
-
- if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites.
- if(..()) //successful monkey bite, this handles disease contraction.
- var/damage = rand(1, 3)
- if(stat != DEAD)
- apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee"))
- updatehealth()
- return 1
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm
deleted file mode 100644
index c218fbb8445..00000000000
--- a/code/modules/mob/living/carbon/human/human_damage.dm
+++ /dev/null
@@ -1,161 +0,0 @@
-//Updates the mob's health from bodyparts and mob damage variables
-/mob/living/carbon/human/updatehealth()
- if(status_flags & GODMODE)
- return
- var/total_burn = 0
- var/total_brute = 0
- for(var/X in bodyparts) //hardcoded to streamline things a bit
- var/obj/item/bodypart/BP = X
- total_brute += BP.brute_dam
- total_burn += BP.burn_dam
- health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
- update_stat()
- if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
- ChangeToHusk()
- if(on_fire)
- shred_clothing()
- med_hud_set_health()
- med_hud_set_status()
-
-
-//These procs fetch a cumulative total damage from all bodyparts
-/mob/living/carbon/human/getBruteLoss()
- var/amount = 0
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- amount += BP.brute_dam
- return amount
-
-/mob/living/carbon/human/getFireLoss()
- var/amount = 0
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- amount += BP.burn_dam
- return amount
-
-
-/mob/living/carbon/human/adjustBruteLoss(amount)
- if(status_flags & GODMODE)
- return 0
- if(amount > 0)
- take_overall_damage(amount, 0)
- else
- heal_overall_damage(-amount, 0)
-
-/mob/living/carbon/human/adjustFireLoss(amount)
- if(status_flags & GODMODE)
- return 0
- if(amount > 0)
- take_overall_damage(0, amount)
- else
- heal_overall_damage(0, -amount)
-
-/mob/living/carbon/human/proc/hat_fall_prob()
- var/multiplier = 1
- var/obj/item/clothing/head/H = head
- var/loose = 40
- if(stat || (status_flags & FAKEDEATH))
- multiplier = 2
- if(H.flags_cover & (HEADCOVERSEYES | HEADCOVERSMOUTH) || H.flags_inv & (HIDEEYES | HIDEFACE))
- loose = 0
- return loose * multiplier
-
-////////////////////////////////////////////
-
-//Returns a list of damaged bodyparts
-/mob/living/carbon/human/proc/get_damaged_bodyparts(brute, burn)
- var/list/obj/item/bodypart/parts = list()
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- if((brute && BP.brute_dam) || (burn && BP.burn_dam))
- parts += BP
- return parts
-
-//Returns a list of damageable bodyparts
-/mob/living/carbon/human/proc/get_damageable_bodyparts()
- var/list/obj/item/bodypart/parts = list()
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- if(BP.brute_dam + BP.burn_dam < BP.max_damage)
- parts += BP
- return parts
-
-//Heals ONE external organ, organ gets randomly selected from damaged ones.
-//It automatically updates damage overlays if necesary
-//It automatically updates health status
-/mob/living/carbon/human/heal_organ_damage(brute, burn)
- var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn)
- if(!parts.len)
- return
- var/obj/item/bodypart/picked = pick(parts)
- if(picked.heal_damage(brute,burn,0))
- update_damage_overlays(0)
- updatehealth()
-
-//Damages ONE external organ, organ gets randomly selected from damagable ones.
-//It automatically updates damage overlays if necesary
-//It automatically updates health status
-/mob/living/carbon/human/take_organ_damage(brute, burn)
- var/list/obj/item/bodypart/parts = get_damageable_bodyparts()
- if(!parts.len)
- return
- var/obj/item/bodypart/picked = pick(parts)
- if(picked.take_damage(brute,burn))
- update_damage_overlays(0)
- updatehealth()
-
-
-//Heal MANY bodyparts, in random order
-/mob/living/carbon/human/heal_overall_damage(brute, burn, updating_health=1)
- var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn)
-
- var/update = 0
- while(parts.len && (brute>0 || burn>0) )
- var/obj/item/bodypart/picked = pick(parts)
-
- var/brute_was = picked.brute_dam
- var/burn_was = picked.burn_dam
-
- update |= picked.heal_damage(brute,burn,0)
-
- brute -= (brute_was-picked.brute_dam)
- burn -= (burn_was-picked.burn_dam)
-
- parts -= picked
- if(updating_health)
- updatehealth()
- if(update)
- update_damage_overlays(0)
-
-// damage MANY bodyparts, in random order
-/mob/living/carbon/human/take_overall_damage(brute, burn)
- if(status_flags & GODMODE)
- return //godmode
-
- var/list/obj/item/bodypart/parts = get_damageable_bodyparts()
- var/update = 0
- while(parts.len && (brute>0 || burn>0) )
- var/obj/item/bodypart/picked = pick(parts)
- var/brute_per_part = brute/parts.len
- var/burn_per_part = burn/parts.len
-
- var/brute_was = picked.brute_dam
- var/burn_was = picked.burn_dam
-
-
- update |= picked.take_damage(brute_per_part,burn_per_part)
-
- brute -= (picked.brute_dam - brute_was)
- burn -= (picked.burn_dam - burn_was)
-
- parts -= picked
- updatehealth()
- if(update)
- update_damage_overlays(0)
-
-////////////////////////////////////////////
-
-
-/mob/living/carbon/human/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0)
- // depending on the species, it will run the corresponding apply_damage code there
- return dna.species.apply_damage(damage, damagetype, def_zone, blocked, src)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index f19d0567565..535f7f39ffb 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -31,10 +31,36 @@
protection += C.armor[type]
return protection
+///checkeyeprot()
+///Returns a number between -1 to 2
+/mob/living/carbon/human/get_eye_protection()
+ var/number = ..()
+ if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head
+ var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item
+ number += HFP.flash_protect
+ if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses
+ var/obj/item/clothing/glasses/GFP = src.glasses
+ number += GFP.flash_protect
+ if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask
+ var/obj/item/clothing/mask/MFP = src.wear_mask
+ number += MFP.flash_protect
+ return number
+
+/mob/living/carbon/human/get_ear_protection()
+ if((ears && (ears.flags & EARBANGPROTECT)) || (head && (head.flags & HEADBANGPROTECT)))
+ return 1
+
/mob/living/carbon/human/on_hit(proj_type)
dna.species.on_hit(proj_type, src)
+
/mob/living/carbon/human/bullet_act(obj/item/projectile/P, def_zone)
+ if(martial_art && martial_art.deflection_chance) //Some martial arts users can deflect projectiles!
+ if(prob(martial_art.deflection_chance))
+ if(!lying && dna && !dna.check_mutation(HULK)) //But only if they're not lying down, and hulks can't do it
+ visible_message("[src] deflects the projectile; they can't be hit with ranged weapons!", "You deflect the projectile!")
+ playsound(src, pick("sound/weapons/bulletflyby.ogg","sound/weapons/bulletflyby2.ogg","sound/weapons/bulletflyby3.ogg"), 75, 1)
+ return 0
if(!(P.original == src && P.firer == src)) //can't block or reflect when shooting yourself
if(istype(P, /obj/item/projectile/energy) || istype(P, /obj/item/projectile/beam))
if(check_reflect(def_zone)) // Checks if you've passed a reflection% check
@@ -63,11 +89,6 @@
return (..(P , def_zone))
-/mob/living/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
- var/obj/item/bodypart/affecting = get_bodypart(def_zone)
- if(affecting && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
- affecting.dismember(P.damtype)
-
/mob/living/carbon/human/proc/check_reflect(def_zone) //Reflection checks for anything in your l_hand, r_hand, or wear_suit based on the reflection chance of the object
if(wear_suit)
if(wear_suit.IsReflect(def_zone) == 1)
@@ -96,22 +117,309 @@
return 0
+/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
+ var/obj/item/I
+ var/throwpower = 30
+ if(istype(AM, /obj/item))
+ I = AM
+ throwpower = I.throwforce
+ if(I.thrownby == src) //No throwing stuff at yourself to trigger hit reactions
+ return ..()
+ if(check_shields(throwpower, "\the [AM.name]", AM, THROWN_PROJECTILE_ATTACK))
+ hitpush = 0
+ skipcatch = 1
+ blocked = 1
+ else if(I)
+ if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD)
+ if(can_embed(I))
+ if(prob(I.embed_chance) && !(dna && (PIERCEIMMUNE in dna.species.specflags)))
+ throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
+ var/obj/item/bodypart/L = pick(bodyparts)
+ L.embedded_objects |= I
+ I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
+ I.loc = src
+ L.take_damage(I.w_class*I.embedded_impact_pain_multiplier)
+ visible_message("\the [I.name] embeds itself in [src]'s [L.name]!","\the [I.name] embeds itself in your [L.name]!")
+ hitpush = 0
+ skipcatch = 1 //can't catch the now embedded item
+
+ return ..()
+
+/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
+ if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (disabilities & FAT) && ismonkey(pulling))
+ devour_mob(pulling)
+ else
+ ..()
+
+/mob/living/carbon/human/grippedby(mob/living/user)
+ if(w_uniform)
+ w_uniform.add_fingerprint(user)
+ ..()
+
+
/mob/living/carbon/human/attacked_by(obj/item/I, mob/living/user)
if(!I || !user)
return 0
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(user.zone_selected))
- var/target_area = parse_zone(check_zone(user.zone_selected))
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(user.zone_selected)) //what we're actually ending up trying to hit.
+ var/target_area = parse_zone(check_zone(user.zone_selected)) //our intended target
feedback_add_details("item_used_for_combat","[I.type]|[I.force]")
feedback_add_details("zone_targeted","[target_area]")
// the attacked_by code varies among species
- return dna.species.spec_attacked_by(I, user, affecting, a_intent, target_area, src)
+ return dna.species.spec_attacked_by(I, user, affecting, a_intent, src)
+
+
+/mob/living/carbon/human/attack_hulk(mob/living/carbon/human/user)
+ if(user.a_intent == "harm")
+ ..(user, 1)
+ playsound(loc, user.dna.species.attack_sound, 25, 1, -1)
+ var/hulk_verb = pick("smash","pummel")
+ visible_message("[user] has [hulk_verb]ed [src]!", \
+ "[user] has [hulk_verb]ed [src]!")
+ adjustBruteLoss(15)
+ return 1
+
+/mob/living/carbon/human/attack_hand(mob/living/carbon/human/M)
+ if(..()) //to allow surgery to return properly.
+ return
+ dna.species.spec_attack_hand(M, src)
+
+
+/mob/living/carbon/human/attack_paw(mob/living/carbon/monkey/M)
+ var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
+
+ if(M.a_intent == "help")
+ ..() //shaking
+ return 0
+
+ if(M.limb_destroyer)
+ dismembering_strike(M, affecting.body_zone)
+
+ if(can_inject(M, 1, affecting))//Thick suits can stop monkey bites.
+ if(..()) //successful monkey bite, this handles disease contraction.
+ var/damage = rand(1, 3)
+ if(stat != DEAD)
+ apply_damage(damage, BRUTE, affecting, run_armor_check(affecting, "melee"))
+ return 1
+
+/mob/living/carbon/human/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if(check_shields(0, M.name))
+ visible_message("[M] attempted to touch [src]!")
+ return 0
+
+ if(..())
+ if(M.a_intent == "harm")
+ if (w_uniform)
+ w_uniform.add_fingerprint(M)
+ var/damage = prob(90) ? 20 : 0
+ if(!damage)
+ playsound(loc, 'sound/weapons/slashmiss.ogg', 50, 1, -1)
+ visible_message("[M] has lunged at [src]!", \
+ "[M] has lunged at [src]!")
+ return 0
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ var/armor_block = run_armor_check(affecting, "melee","","",10)
+
+ playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
+ visible_message("[M] has slashed at [src]!", \
+ "[M] has slashed at [src]!")
+ add_logs(M, src, "attacked")
+ if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful
+ return 1
+ apply_damage(damage, BRUTE, affecting, armor_block)
+
+ if(M.a_intent == "disarm") //Always drop item in hand, if no item, get stunned instead.
+ if(get_active_held_item() && drop_item())
+ playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
+ visible_message("[M] disarmed [src]!", \
+ "[M] disarmed [src]!")
+ else
+ playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
+ Weaken(5)
+ add_logs(M, src, "tackled")
+ visible_message("[M] has tackled down [src]!", \
+ "[M] has tackled down [src]!")
+
+
+/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L)
+
+ if(..()) //successful larva bite.
+ var/damage = rand(1, 3)
+ if(check_shields(damage, "the [L.name]"))
+ return 0
+ if(stat != DEAD)
+ L.amount_grown = min(L.amount_grown + damage, L.max_grown)
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
+ var/armor_block = run_armor_check(affecting, "melee")
+ apply_damage(damage, BRUTE, affecting, armor_block)
+
+
+/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
+ if(..())
+ var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
+ if(check_shields(damage, "the [M.name]", null, MELEE_ATTACK, M.armour_penetration))
+ return 0
+ var/dam_zone = dismembering_strike(M, pick("chest", "l_hand", "r_hand", "l_leg", "r_leg"))
+ if(!dam_zone) //Dismemberment successful
+ return 1
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
+ var/armor = run_armor_check(affecting, "melee", armour_penetration = M.armour_penetration)
+ apply_damage(damage, M.melee_damage_type, affecting, armor)
+
+
+
+/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M)
+ if(..()) //successful slime attack
+ var/damage = rand(5, 25)
+ if(M.is_adult)
+ damage = rand(10, 35)
+
+ if(check_shields(damage, "the [M.name]"))
+ return 0
+
+ var/dam_zone = dismembering_strike(M, pick("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg"))
+ if(!dam_zone) //Dismemberment successful
+ return 1
+
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
+ var/armor_block = run_armor_check(affecting, "melee")
+ apply_damage(damage, BRUTE, affecting, armor_block)
+
+/mob/living/carbon/human/mech_melee_attack(obj/mecha/M)
+
+ if(M.occupant.a_intent == "harm")
+ M.do_attack_animation(src)
+ if(M.damtype == "brute")
+ step_away(src,M,15)
+ var/obj/item/bodypart/temp = get_bodypart(pick("chest", "chest", "chest", "head"))
+ if(temp)
+ var/update = 0
+ switch(M.damtype)
+ if("brute")
+ if(M.force > 20)
+ Paralyse(1)
+ update |= temp.take_damage(rand(M.force/2, M.force), 0)
+ playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
+ if("fire")
+ update |= temp.take_damage(0, rand(M.force/2, M.force))
+ playsound(src, 'sound/items/Welder.ogg', 50, 1)
+ if("tox")
+ M.mech_toxin_damage(src)
+ else
+ return
+ if(update)
+ update_damage_overlays()
+ updatehealth()
+
+ visible_message("[M.name] has hit [src]!", \
+ "[M.name] has hit [src]!")
+ add_logs(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])")
+
+ else
+ ..()
+
+
+/mob/living/carbon/human/ex_act(severity, ex_target)
+ var/b_loss = null
+ var/f_loss = null
+ var/bomb_armor = getarmor(null, "bomb")
+ if(istype(ex_target, /datum/spacevine_mutation) && isvineimmune(src))
+ return
+
+ switch (severity)
+ if (1)
+ b_loss += 500
+ if (prob(bomb_armor))
+ shred_clothing(1,150)
+ var/atom/target = get_edge_target_turf(src, get_dir(src, get_step_away(src, src)))
+ throw_at(target, 200, 4)
+ else
+ gib()
+ return
+
+ if (2)
+ b_loss += 60
+
+ f_loss += 60
+ if (prob(bomb_armor))
+ b_loss = b_loss/1.5
+ f_loss = f_loss/1.5
+ shred_clothing(1,25)
+ else
+ shred_clothing(1,50)
+
+ if (!istype(ears, /obj/item/clothing/ears/earmuffs))
+ adjustEarDamage(30, 120)
+ if (prob(70))
+ Paralyse(10)
+
+ if(3)
+ b_loss += 30
+ if (prob(bomb_armor))
+ b_loss = b_loss/2
+ if (!istype(ears, /obj/item/clothing/ears/earmuffs))
+ adjustEarDamage(15,60)
+ if (prob(50))
+ Paralyse(8)
+
+ take_overall_damage(b_loss,f_loss)
+ //attempt to dismember bodyparts
+ if(severity <= 2 || !bomb_armor)
+ var/max_limb_loss = round(4/severity) //so you don't lose four limbs at severity 3.
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ if(prob(50/severity) && !prob(getarmor(BP, "bomb")) && BP.body_zone != "head" && BP.body_zone != "chest")
+ BP.brute_dam = BP.max_damage
+ BP.dismember()
+ max_limb_loss--
+ if(!max_limb_loss)
+ break
+ ..()
+
+/mob/living/carbon/human/blob_act(obj/effect/blob/B)
+ if(stat == DEAD)
+ return
+ show_message("The blob attacks you!")
+ var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
+ apply_damage(5, BRUTE, affecting, run_armor_check(affecting, "melee"))
+
+
+//Added a safety check in case you want to shock a human mob directly through electrocute_act.
+/mob/living/carbon/human/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0)
+ if(tesla_shock)
+ var/total_coeff = 1
+ if(gloves)
+ var/obj/item/clothing/gloves/G = gloves
+ if(G.siemens_coefficient <= 0)
+ total_coeff -= 0.5
+ if(wear_suit)
+ var/obj/item/clothing/suit/S = wear_suit
+ if(S.siemens_coefficient <= 0)
+ total_coeff -= 0.95
+ siemens_coeff = total_coeff
+ else if(!safety)
+ var/gloves_siemens_coeff = 1
+ if(gloves)
+ var/obj/item/clothing/gloves/G = gloves
+ gloves_siemens_coeff = G.siemens_coefficient
+ siemens_coeff = gloves_siemens_coeff
+ if(heart_attack)
+ if(shock_damage * siemens_coeff >= 1 && prob(25))
+ heart_attack = 0
+ if(stat == CONSCIOUS)
+ src << "You feel your heart beating again!"
+ . = ..(shock_damage,source,siemens_coeff,safety,override,tesla_shock)
+ if(.)
+ electrocution_animation(40)
+
/mob/living/carbon/human/emp_act(severity)
var/informed = 0
for(var/obj/item/bodypart/L in src.bodyparts)
- if(L.status == ORGAN_ROBOTIC)
+ if(L.status == BODYPART_ROBOTIC)
if(!informed)
src << "You feel a sharp pain as your robotic limbs overload."
informed = 1
@@ -264,123 +572,76 @@
acid_volume_left = max(acid_volume_left - acid_decay, 0)
-/mob/living/carbon/human/attack_animal(mob/living/simple_animal/M)
- if(..())
- var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- if(check_shields(damage, "the [M.name]", null, MELEE_ATTACK, M.armour_penetration))
- return 0
- var/dam_zone = dismembering_strike(M, pick("chest", "l_hand", "r_hand", "l_leg", "r_leg"))
- if(!dam_zone) //Dismemberment successful
- return 1
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
- var/armor = run_armor_check(affecting, "melee", armour_penetration = M.armour_penetration)
- apply_damage(damage, M.melee_damage_type, affecting, armor)
- updatehealth()
+/mob/living/carbon/human/singularity_act()
+ var/gain = 20
+ if(mind)
+ if((mind.assigned_role == "Station Engineer") || (mind.assigned_role == "Chief Engineer") )
+ gain = 100
+ if(mind.assigned_role == "Clown")
+ gain = rand(-300, 300)
+ investigate_log("([key_name(src)]) has been consumed by the singularity.","singulo") //Oh that's where the clown ended up!
+ gib()
+ return(gain)
+/mob/living/carbon/human/help_shake_act(mob/living/carbon/M)
+ if(!istype(M))
+ return
-/mob/living/carbon/human/attack_larva(mob/living/carbon/alien/larva/L)
+ if(health >= 0)
+ if(src == M)
+ visible_message( \
+ "[src] examines \himself.", \
+ "You check yourself for injuries.")
- if(..()) //successful larva bite.
- var/damage = rand(1, 3)
- if(check_shields(damage, "the [L.name]"))
- return 0
- if(stat != DEAD)
- L.amount_grown = min(L.amount_grown + damage, L.max_grown)
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
- var/armor_block = run_armor_check(affecting, "melee")
- apply_damage(damage, BRUTE, affecting, armor_block)
- updatehealth()
+ var/list/missing = list("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg")
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/LB = X
+ missing -= LB.body_zone
+ var/status = ""
+ var/brutedamage = LB.brute_dam
+ var/burndamage = LB.burn_dam
+ if(hallucination)
+ if(prob(30))
+ brutedamage += rand(30,40)
+ if(prob(30))
+ burndamage += rand(30,40)
+ if(brutedamage > 0)
+ status = "bruised"
+ if(brutedamage > 20)
+ status = "battered"
+ if(brutedamage > 40)
+ status = "mangled"
+ if(brutedamage > 0 && burndamage > 0)
+ status += " and "
+ if(burndamage > 40)
+ status += "peeling away"
-/mob/living/carbon/human/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime attack
- var/damage = rand(5, 25)
- if(M.is_adult)
- damage = rand(10, 35)
+ else if(burndamage > 10)
+ status += "blistered"
+ else if(burndamage > 0)
+ status += "numb"
+ if(status == "")
+ status = "OK"
+ src << "\t [status == "OK" ? "\blue" : "\red"] Your [LB.name] is [status]."
- if(check_shields(damage, "the [M.name]"))
- return 0
+ for(var/obj/item/I in LB.embedded_objects)
+ src << "\t \red There is \a [I] embedded in your [LB.name]!"
- var/dam_zone = dismembering_strike(M, pick("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg"))
- if(!dam_zone) //Dismemberment successful
- return 1
+ for(var/t in missing)
+ src << "Your [parse_zone(t)] is missing!"
- var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
- var/armor_block = run_armor_check(affecting, "melee")
- apply_damage(damage, BRUTE, affecting, armor_block)
-
-/mob/living/carbon/human/mech_melee_attack(obj/mecha/M)
-
- if(M.occupant.a_intent == "harm")
- M.do_attack_animation(src)
- if(M.damtype == "brute")
- step_away(src,M,15)
- var/obj/item/bodypart/temp = get_bodypart(pick("chest", "chest", "chest", "head"))
- if(temp)
- var/update = 0
- switch(M.damtype)
- if("brute")
- if(M.force > 20)
- Paralyse(1)
- update |= temp.take_damage(rand(M.force/2, M.force), 0)
- playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
- if("fire")
- update |= temp.take_damage(0, rand(M.force/2, M.force))
- playsound(src, 'sound/items/Welder.ogg', 50, 1)
- if("tox")
- M.mech_toxin_damage(src)
+ if(bleed_rate)
+ src << "You are bleeding!"
+ if(staminaloss)
+ if(staminaloss > 30)
+ src << "You're completely exhausted."
else
- return
- if(update)
- update_damage_overlays(0)
- updatehealth()
+ src << "You feel fatigued."
+ else
+ if(wear_suit)
+ wear_suit.add_fingerprint(M)
+ else if(w_uniform)
+ w_uniform.add_fingerprint(M)
- visible_message("[M.name] has hit [src]!", \
- "[M.name] has hit [src]!")
- add_logs(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])")
-
- else
- ..()
-
-/mob/living/carbon/human/hitby(atom/movable/AM, skipcatch = 0, hitpush = 1, blocked = 0)
- var/obj/item/I
- var/throwpower = 30
- if(istype(AM, /obj/item))
- I = AM
- throwpower = I.throwforce
- if(I.thrownby == src) //No throwing stuff at yourself to trigger hit reactions
- return ..()
- if(check_shields(throwpower, "\the [AM.name]", AM, THROWN_PROJECTILE_ATTACK))
- hitpush = 0
- skipcatch = 1
- blocked = 1
- else if(I)
- if(I.throw_speed >= EMBED_THROWSPEED_THRESHOLD)
- if(can_embed(I))
- if(prob(I.embed_chance) && !(dna && (PIERCEIMMUNE in dna.species.specflags)))
- throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
- var/obj/item/bodypart/L = pick(bodyparts)
- L.embedded_objects |= I
- I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
- I.loc = src
- L.take_damage(I.w_class*I.embedded_impact_pain_multiplier)
- visible_message("\the [I.name] embeds itself in [src]'s [L.name]!","\the [I.name] embeds itself in your [L.name]!")
- hitpush = 0
- skipcatch = 1 //can't catch the now embedded item
-
- return ..()
-
-/mob/living/carbon/human/grabbedby(mob/living/carbon/user, supress_message = 0)
- if(user == src && pulling && !pulling.anchored && grab_state >= GRAB_AGGRESSIVE && (disabilities & FAT) && ismonkey(pulling))
- devour_mob(pulling)
- else
- ..()
-
-/mob/living/carbon/human/grippedby(mob/living/user)
- if(w_uniform)
- w_uniform.add_fingerprint(user)
- ..()
-
-/mob/living/carbon/human/Stun(amount, updating_canmove = 1)
- amount = dna.species.spec_stun(src,amount)
- ..()
\ No newline at end of file
+ ..()
diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm
index 2bccce619fa..abf9dffc00c 100644
--- a/code/modules/mob/living/carbon/human/human_defines.dm
+++ b/code/modules/mob/living/carbon/human/human_defines.dm
@@ -30,11 +30,7 @@ var/global/default_martial_art = new/datum/martial_art
//Equipment slots
var/obj/item/wear_suit = null
var/obj/item/w_uniform = null
- var/obj/item/shoes = null
var/obj/item/belt = null
- var/obj/item/gloves = null
- var/obj/item/clothing/glasses/glasses = null
- var/obj/item/ears = null
var/obj/item/wear_id = null
var/obj/item/r_store = null
var/obj/item/l_store = null
@@ -53,5 +49,3 @@ var/global/default_martial_art = new/datum/martial_art
var/drunkenness = 0 //Overall drunkenness - check handle_alcohol() in life.dm for effects
var/datum/personal_crafting/handcrafting
-
- var/list/hand_bodyparts = list() //a collection of arms (or actually whatever the fug /bodyparts you monsters use to wreck my systems)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm
index 69863d41b9b..98426060462 100644
--- a/code/modules/mob/living/carbon/human/human_helpers.dm
+++ b/code/modules/mob/living/carbon/human/human_helpers.dm
@@ -81,24 +81,6 @@
if(wear_id)
return wear_id.GetID()
-///checkeyeprot()
-///Returns a number between -1 to 2
-/mob/living/carbon/human/check_eye_prot()
- var/number = ..()
- if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head
- var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item
- number += HFP.flash_protect
- if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses
- var/obj/item/clothing/glasses/GFP = src.glasses
- number += GFP.flash_protect
- if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask
- var/obj/item/clothing/mask/MFP = src.wear_mask
- number += MFP.flash_protect
- return number
-
-/mob/living/carbon/human/check_ear_prot()
- if((ears && (ears.flags & EARBANGPROTECT)) || (head && (head.flags & HEADBANGPROTECT)))
- return 1
/mob/living/carbon/human/abiotic(full_body = 0)
var/abiotic_hands = FALSE
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index 98d53ef104f..3bb4c433f4c 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -15,7 +15,7 @@
return 0
return ..()
-/mob/living/carbon/human/has_gravity()
+/mob/living/carbon/human/mob_has_gravity()
. = ..()
if(!.)
if(mob_negates_gravity())
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index cf9504df710..7a0cb8e246a 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -69,6 +69,8 @@
if(slot_glasses)
glasses = I
var/obj/item/clothing/glasses/G = I
+ if(G.glass_colour_type)
+ update_glasses_color(G, 1)
if(G.tint)
update_tint()
if(G.vision_correction)
@@ -144,6 +146,8 @@
else if(I == glasses)
glasses = null
var/obj/item/clothing/glasses/G = I
+ if(G.glass_colour_type)
+ update_glasses_color(G, 0)
if(G.tint)
update_tint()
if(G.vision_correction)
@@ -200,7 +204,16 @@
//Cycles through all clothing slots and tests them for destruction
-/mob/living/carbon/human/proc/shred_clothing(bomb,shock)
+/mob/living/carbon/proc/shred_clothing(bomb,shock)
+ if(back)
+ back.shred(bomb,shock-20,src)
+ if(head)
+ head.shred(bomb,shock,src)
+ if(wear_mask)
+ wear_mask.shred(bomb,shock,src)
+
+
+/mob/living/carbon/human/shred_clothing(bomb,shock)
var/covered_parts = 0 //The body parts that are protected by exterior clothing/armor
var/head_absorbed = 0 //How much of the shock the headgear absorbs when it is shredded. -1=it survives
var/suit_absorbed = 0 //How much of the shock the exosuit absorbs when it is shredded. -1=it survives
diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm
index 0c3b27ba8d1..5d7003106aa 100644
--- a/code/modules/mob/living/carbon/human/life.dm
+++ b/code/modules/mob/living/carbon/human/life.dm
@@ -29,20 +29,26 @@
if (notransform)
return
- if(..())
+ if(..()) //not dead
for(var/datum/mutation/human/HM in dna.mutations)
HM.on_life(src)
+ if(stat != DEAD)
//heart attack stuff
handle_heart()
+ if(stat != DEAD)
//Stuff jammed in your limbs hurts
handle_embedded_objects()
+
//Update our name based on whether our face is obscured/disfigured
name = get_visible_name()
dna.species.spec_life(src) // for mutantraces
+ if(stat != DEAD)
+ return 1
+
/mob/living/carbon/human/calculate_affecting_pressure(pressure)
if((wear_suit && (wear_suit.flags & STOPSPRESSUREDMAGE)) && (head && (head.flags & STOPSPRESSUREDMAGE)))
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 619e9a7e139..852a19fd1ab 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -54,7 +54,7 @@
var/punchdamagehigh = 9 //highest possible punch damage
var/punchstunthreshold = 9//damage at which punches from this race will stun //yes it should be to the attacked race but it's not useful that way even if it's logical
var/siemens_coeff = 1 //base electrocution coefficient
- var/exotic_damage_overlay = ""
+ var/damage_overlay_type = "human" //what kind of damage overlays (if any) appear on our species when wounded?
var/fixed_mut_color = "" //to use MUTCOLOR with a fixed color that's independent of dna.feature["mcolor"]
var/invis_sight = SEE_INVISIBLE_LIVING
@@ -132,8 +132,6 @@
var/obj/item/thing = C.get_item_by_slot(slot_id)
if(thing && (!thing.species_exception || !is_type_in_list(src,thing.species_exception)))
C.unEquip(thing)
- if(NODISMEMBER in specflags)
- C.regenerate_limbs() //if we don't handle dismemberment, we grow our missing limbs back
var/obj/item/organ/heart/heart = C.getorganslot("heart")
var/obj/item/organ/lungs/lungs = C.getorganslot("lungs")
@@ -226,7 +224,8 @@
hair_hidden = 1
if(!hair_hidden)
if(!H.getorgan(/obj/item/organ/brain)) //Applies the debrained overlay if there is no brain
- standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER)
+ if(!(NOBLOOD in specflags))
+ standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER)
else if(H.hair_style && (HAIR in specflags))
S = hair_styles_list[H.hair_style]
@@ -263,17 +262,18 @@
var/obj/item/bodypart/head/HD = H.get_bodypart("head")
- // lipstick
- if(H.lip_style && (LIPS in specflags) && HD)
- var/image/lips = image("icon"='icons/mob/human_face.dmi', "icon_state"="lips_[H.lip_style]_s", "layer" = -BODY_LAYER)
- lips.color = H.lip_color
- standing += lips
+ if(!(H.disabilities & HUSK))
+ // lipstick
+ if(H.lip_style && (LIPS in specflags) && HD)
+ var/image/lips = image("icon"='icons/mob/human_face.dmi', "icon_state"="lips_[H.lip_style]_s", "layer" = -BODY_LAYER)
+ lips.color = H.lip_color
+ standing += lips
- // eyes
- if((EYECOLOR in specflags) && HD)
- var/image/img_eyes_s = image("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[eyes]_s", "layer" = -BODY_LAYER)
- img_eyes_s.color = "#" + H.eye_color
- standing += img_eyes_s
+ // eyes
+ if((EYECOLOR in specflags) && HD)
+ var/image/img_eyes_s = image("icon" = 'icons/mob/human_face.dmi', "icon_state" = "[eyes]_s", "layer" = -BODY_LAYER)
+ img_eyes_s.color = "#" + H.eye_color
+ standing += img_eyes_s
//Underwear, Undershirts & Socks
if(H.underwear)
@@ -346,19 +346,19 @@
bodyparts_to_add -= "waggingspines"
if("snout" in mutant_bodyparts) //Take a closer look at that snout!
- if((H.wear_mask && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE)) || !HD || HD.status == ORGAN_ROBOTIC)
+ if((H.wear_mask && (H.wear_mask.flags_inv & HIDEFACE)) || (H.head && (H.head.flags_inv & HIDEFACE)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "snout"
if("frills" in mutant_bodyparts)
- if(!H.dna.features["frills"] || H.dna.features["frills"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || !HD || HD.status == ORGAN_ROBOTIC)
+ if(!H.dna.features["frills"] || H.dna.features["frills"] == "None" || H.head && (H.head.flags_inv & HIDEEARS) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "frills"
if("horns" in mutant_bodyparts)
- if(!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == ORGAN_ROBOTIC)
+ if(!H.dna.features["horns"] || H.dna.features["horns"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "horns"
if("ears" in mutant_bodyparts)
- if(!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == ORGAN_ROBOTIC)
+ if(!H.dna.features["ears"] || H.dna.features["ears"] == "None" || H.head && (H.head.flags_inv & HIDEHAIR) || (H.wear_mask && (H.wear_mask.flags_inv & HIDEHAIR)) || !HD || HD.status == BODYPART_ROBOTIC)
bodyparts_to_add -= "ears"
if("wings" in mutant_bodyparts)
@@ -830,7 +830,7 @@
if(75 to 100)
if(prob(1))
H << "You mutate!"
- randmutb(H)
+ H.randmutb()
H.emote("gasp")
H.domutcheck()
return 0
@@ -894,13 +894,6 @@
if(H.bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT)
. += (BODYTEMP_COLD_DAMAGE_LIMIT - H.bodytemperature) / COLD_SLOWDOWN_FACTOR
- if(!(FLYING in specflags))
- var/leg_amount = H.get_num_legs()
- . += 6 - 3*leg_amount //the fewer the legs, the slower the mob
- if(!leg_amount)
- . += 6 - 3*H.get_num_arms() //crawling is harder with fewer arms
-
-
. += speedmod
//////////////////
@@ -1027,10 +1020,9 @@
"[M] attemped to disarm [H]!")
return
-/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, target_area, mob/living/carbon/human/H)
+/datum/species/proc/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
// Allows you to put in item-specific reactions based on species
if(user != H)
- user.do_attack_animation(H)
if(H.check_shields(I.force, "the [I.name]", I, MELEE_ATTACK, I.armour_penetration))
return 0
@@ -1062,7 +1054,7 @@
var/bloody = 0
if(((I.damtype == BRUTE) && I.force && prob(25 + (I.force * 2))))
- if(affecting.status == ORGAN_ORGANIC)
+ if(affecting.status == BODYPART_ORGANIC)
I.add_mob_blood(H) //Make the weapon bloody, not the person.
if(prob(I.force * 2)) //blood spatter!
bloody = 1
@@ -1112,39 +1104,43 @@
return TRUE
/datum/species/proc/apply_damage(damage, damagetype = BRUTE, def_zone = null, blocked, mob/living/carbon/human/H)
- blocked = (100-(blocked+armor))/100
- if(!damage || blocked <= 0)
+ var/hit_percent = (100-(blocked+armor))/100
+ if(!damage || hit_percent <= 0)
return 0
- var/obj/item/bodypart/organ = null
+ var/obj/item/bodypart/BP = null
if(islimb(def_zone))
- organ = def_zone
+ BP = def_zone
else
if(!def_zone)
def_zone = ran_zone(def_zone)
- organ = H.get_bodypart(check_zone(def_zone))
- if(!organ)
- return 0
-
- damage = (damage * blocked)
+ BP = H.get_bodypart(check_zone(def_zone))
+ if(!BP)
+ BP = H.bodyparts[1]
switch(damagetype)
if(BRUTE)
H.damageoverlaytemp = 20
- if(organ.take_damage(damage*brutemod, 0))
- H.update_damage_overlays(0)
+ if(BP)
+ if(BP.take_damage(damage * hit_percent * brutemod, 0))
+ H.update_damage_overlays()
+ else//no bodypart, we deal damage with a more general method.
+ H.adjustBruteLoss(damage * hit_percent * brutemod)
if(BURN)
H.damageoverlaytemp = 20
- if(organ.take_damage(0, damage*burnmod))
- H.update_damage_overlays(0)
+ if(BP)
+ if(BP.take_damage(0, damage * hit_percent * burnmod))
+ H.update_damage_overlays()
+ else
+ H.adjustFireLoss(damage * hit_percent* burnmod)
if(TOX)
- H.adjustToxLoss(damage)
+ H.adjustToxLoss(damage * hit_percent)
if(OXY)
- H.adjustOxyLoss(damage)
+ H.adjustOxyLoss(damage * hit_percent)
if(CLONE)
- H.adjustCloneLoss(damage)
+ H.adjustCloneLoss(damage * hit_percent)
if(STAMINA)
- H.adjustStaminaLoss(damage)
+ H.adjustStaminaLoss(damage * hit_percent)
return 1
/datum/species/proc/on_hit(obj/item/projectile/proj_type, mob/living/carbon/human/H)
diff --git a/code/modules/mob/living/carbon/human/species_types.dm b/code/modules/mob/living/carbon/human/species_types.dm
index 9677c1b0bfc..9029f98e207 100644
--- a/code/modules/mob/living/carbon/human/species_types.dm
+++ b/code/modules/mob/living/carbon/human/species_types.dm
@@ -146,9 +146,9 @@
H.Weaken(5)
H.visible_message("[H] writhes in pain as \his vacuoles boil.", "You writhe in pain as your vacuoles boil!", "You hear the crunching of leaves.")
if(prob(80))
- randmutb(H)
+ H.randmutb()
else
- randmutg(H)
+ H.randmutg()
H.domutcheck()
else
H.adjustFireLoss(rand(5,15))
@@ -172,6 +172,34 @@
meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/mutant/shadow
specflags = list(NOBREATH,NOBLOOD,RADIMMUNE,VIRUSIMMUNE)
dangerous_existence = 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.see_in_dark < 8)
+ H.see_in_dark = 8
+ H.see_invisible = SEE_INVISIBLE_MINIMUM
+ H << "You adjust your vision to pierce the darkness."
+ else
+ H.see_in_dark = 2
+ H.see_invisible = SEE_INVISIBLE_LIVING
+ H << "You adjust your vision to recognize the shadows."
+
+/datum/species/shadow/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ . = ..()
+ vision_toggle = new
+ vision_toggle.Grant(C)
+
+/datum/species/shadow/on_species_loss(mob/living/carbon/C)
+ . = ..()
+ if(vision_toggle)
+ vision_toggle.Remove(C)
/datum/species/shadow/spec_life(mob/living/carbon/human/H)
var/light_amount = 0
@@ -642,6 +670,7 @@
meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/human/mutant/skeleton
specflags = list(NOBREATH,RESISTTEMP,NOBLOOD,RADIMMUNE,VIRUSIMMUNE,PIERCEIMMUNE,NOHUNGER,EASYDISMEMBER,EASYLIMBATTACHMENT)
mutant_organs = list(/obj/item/organ/tongue/bone)
+ damage_overlay_type = ""//let's not show bloody wounds or burns over bones.
/*
ZOMBIES
@@ -730,6 +759,7 @@ var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_
burnmod = 2
heatmod = 2
speedmod = 1
+ damage_overlay_type = ""//let's not show bloody wounds or burns over bones.
/datum/species/plasmaman/spec_life(mob/living/carbon/human/H)
var/datum/gas_mixture/environment = H.loc.return_air()
@@ -781,7 +811,7 @@ var/global/image/plasmaman_on_fire = image("icon"='icons/mob/OnFire.dmi', "icon_
dangerous_existence = 1
blacklisted = 1
meat = null
- exotic_damage_overlay = "synth"
+ damage_overlay_type = "synth"
limbs_id = "synth"
var/list/initial_specflags = list(NOTRANSSTING,NOBREATH,VIRUSIMMUNE,NODISMEMBER,NOHUNGER) //for getting these values back for assume_disguise()
var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm
new file mode 100644
index 00000000000..adcf57433c4
--- /dev/null
+++ b/code/modules/mob/living/carbon/human/status_procs.dm
@@ -0,0 +1,15 @@
+
+/mob/living/carbon/human/Stun(amount, updating = 1, ignore_canstun = 0)
+ amount = dna.species.spec_stun(src,amount)
+ ..()
+
+
+/mob/living/carbon/human/cure_husk()
+ . = ..()
+ if(.)
+ update_hair()
+
+/mob/living/carbon/human/become_husk()
+ . = ..()
+ if(.)
+ update_hair()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index cb7289a7ef5..4bbde09513d 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -48,28 +48,6 @@ There are several things that need to be remembered:
*/
-//DAMAGE OVERLAYS
-//constructs damage icon for each organ from mask * damage field and saves it in our overlays_ lists
-/mob/living/carbon/human/update_damage_overlays()
- remove_overlay(DAMAGE_LAYER)
-
- var/image/standing = image("icon"='icons/mob/dam_human.dmi', "icon_state"="blank", "layer"=-DAMAGE_LAYER)
- overlays_standing[DAMAGE_LAYER] = standing
-
- var/dmgoverlaytype = ""
- if(dna.species.exotic_damage_overlay)
- dmgoverlaytype = dna.species.exotic_damage_overlay + "_"
-
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- if(BP.brutestate)
- standing.overlays += "[dmgoverlaytype][BP.body_zone]_[BP.brutestate]0" //we're adding icon_states of the base image as overlays
- if(BP.burnstate)
- standing.overlays += "[dmgoverlaytype][BP.body_zone]_0[BP.burnstate]"
-
- apply_overlay(DAMAGE_LAYER)
-
-
//HAIR OVERLAY
/mob/living/carbon/human/update_hair()
dna.species.handle_hair(src)
@@ -79,47 +57,14 @@ There are several things that need to be remembered:
dna.species.handle_mutant_bodyparts(src)
-/mob/living/carbon/human/proc/update_body()
+/mob/living/carbon/human/update_body()
remove_overlay(BODY_LAYER)
dna.species.handle_body(src)
- update_body_parts()
+ ..()
/mob/living/carbon/human/update_fire()
..("Standing")
-/mob/living/carbon/human/proc/update_body_parts()
- //CHECK FOR UPDATE
- var/oldkey = icon_render_key
- icon_render_key = generate_icon_render_key()
- if(oldkey == icon_render_key)
- return
-
- remove_overlay(BODYPARTS_LAYER)
-
- //LOAD ICONS
- if(limb_icon_cache[icon_render_key])
- load_limb_from_cache()
- update_damage_overlays()
- update_mutant_bodyparts()
- update_hair()
- return
-
- //GENERATE NEW LIMBS
- var/list/new_limbs = list()
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- if(!BP.no_update)
- BP.update_limb()
- var/image/temp = BP.get_limb_icon()
- if(temp)
- new_limbs += temp
- if(new_limbs.len)
- overlays_standing[BODYPARTS_LAYER] = new_limbs
- limb_icon_cache[icon_render_key] = new_limbs
-
- apply_overlay(BODYPARTS_LAYER)
- update_damage_overlays()
-
/* --------------------------------------- */
//For legacy support.
@@ -219,9 +164,16 @@ There are several things that need to be remembered:
remove_overlay(GLOVES_LAYER)
if(get_num_arms() <2)
+ if(!gloves && blood_DNA)
+ if(has_left_hand())
+ overlays_standing[GLOVES_LAYER] = image("icon"='icons/effects/blood.dmi', "icon_state"="bloodyhands_left", "layer"=-GLOVES_LAYER)
+ apply_overlay(GLOVES_LAYER)
+ else if(has_right_hand())
+ overlays_standing[GLOVES_LAYER] = image("icon"='icons/effects/blood.dmi', "icon_state"="bloodyhands_right", "layer"=-GLOVES_LAYER)
+ apply_overlay(GLOVES_LAYER)
return
- if(client && hud_used)
+ if(client && hud_used && hud_used.inv_slots[slot_gloves])
var/obj/screen/inventory/inv = hud_used.inv_slots[slot_gloves]
inv.update_icon()
@@ -246,7 +198,6 @@ There are several things that need to be remembered:
apply_overlay(GLOVES_LAYER)
-
/mob/living/carbon/human/update_inv_glasses()
remove_overlay(GLASSES_LAYER)
@@ -336,19 +287,10 @@ There are several things that need to be remembered:
apply_overlay(SUIT_STORE_LAYER)
-
/mob/living/carbon/human/update_inv_head()
- remove_overlay(HEAD_LAYER)
- if(!get_bodypart("head")) //Decapitated
- return
..()
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[slot_head]
- inv.update_icon()
-
update_mutant_bodyparts()
-
/mob/living/carbon/human/update_inv_belt()
remove_overlay(BELT_LAYER)
@@ -382,16 +324,16 @@ There are several things that need to be remembered:
inv.update_icon()
if(istype(wear_suit, /obj/item/clothing/suit))
- wear_suit.screen_loc = ui_oclothing //TODO //Todo what?
+ wear_suit.screen_loc = ui_oclothing
if(client && hud_used && hud_used.hud_shown)
- if(hud_used.inventory_shown) //if the inventory is open ...
- client.screen += wear_suit //Either way, add the item to the HUD
+ if(hud_used.inventory_shown)
+ client.screen += wear_suit
update_observer_view(wear_suit,1)
var/image/standing = wear_suit.build_worn_icon(state = wear_suit.icon_state, default_layer = SUIT_LAYER, default_icon_file = 'icons/mob/suit.dmi')
overlays_standing[SUIT_LAYER] = standing
- if(istype(wear_suit, /obj/item/clothing/suit/straight_jacket))
+ if(wear_suit.breakouttime) //suit is restraining
drop_all_held_items()
update_hair()
@@ -423,22 +365,10 @@ There are several things that need to be remembered:
update_observer_view(r_store)
-
/mob/living/carbon/human/update_inv_wear_mask()
- remove_overlay(FACEMASK_LAYER)
- if(!get_bodypart("head")) //Decapitated
- return
..()
- if(client && hud_used)
- var/obj/screen/inventory/inv = hud_used.inv_slots[slot_wear_mask]
- inv.update_icon()
- update_mutant_bodyparts()
+ update_mutant_bodyparts() //e.g. upgate needed because mask now hides lizard snout
-/mob/living/carbon/human/update_inv_handcuffed()
- remove_overlay(HANDCUFF_LAYER)
- if(handcuffed)
- overlays_standing[HANDCUFF_LAYER] = image("icon"='icons/mob/mob.dmi', "icon_state"="handcuff1", "layer"=-HANDCUFF_LAYER)
- apply_overlay(HANDCUFF_LAYER)
/mob/living/carbon/human/update_inv_legcuffed()
remove_overlay(LEGCUFF_LAYER)
@@ -492,6 +422,8 @@ There are several things that need to be remembered:
update_observer_view(I)
+
+
/*
Does everything in relation to building the /image used in the mob's overlays list
covers:
@@ -581,31 +513,8 @@ generate/load female uniform sprites matching all previously decided variables
-
-
-
-/////////////////////
-// Limb Icon Cache //
-/////////////////////
-/*
- Called from update_body_parts() these procs handle the limb icon cache.
- the limb icon cache adds an icon_render_key to a human mob, it represents:
- - skin_tone (if applicable)
- - gender
- - limbs (stores as the limb name and whether it is removed/fine, organic/robotic)
- These procs only store limbs as to increase the number of matching icon_render_keys
- This cache exists because drawing 6/7 icons for humans constantly is quite a waste
- See RemieRichards on irc.rizon.net #coderbus
-*/
-
-var/global/list/limb_icon_cache = list()
-
-/mob/living/carbon/human
- var/icon_render_key = ""
-
-
//produces a key based on the human's limbs
-/mob/living/carbon/human/proc/generate_icon_render_key()
+/mob/living/carbon/human/generate_icon_render_key()
. = "[dna.species.limbs_id]"
if(dna.check_mutation(HULK))
@@ -624,7 +533,7 @@ var/global/list/limb_icon_cache = list()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
. += "-[BP.body_zone]"
- if(BP.status == ORGAN_ORGANIC)
+ if(BP.status == BODYPART_ORGANIC)
. += "-organic"
else
. += "-robotic"
@@ -632,16 +541,14 @@ var/global/list/limb_icon_cache = list()
if(disabilities & HUSK)
. += "-husk"
-
-//change the human's icon to the one matching it's key
-/mob/living/carbon/human/proc/load_limb_from_cache()
- if(limb_icon_cache[icon_render_key])
- remove_overlay(BODYPARTS_LAYER)
- overlays_standing[BODYPARTS_LAYER] = limb_icon_cache[icon_render_key]
- apply_overlay(BODYPARTS_LAYER)
+/mob/living/carbon/human/load_limb_from_cache()
+ ..()
+ update_mutant_bodyparts()
+ update_hair()
-/mob/living/carbon/human/proc/update_observer_view(var/obj/item/I,var/inventory)
+
+/mob/living/carbon/human/proc/update_observer_view(obj/item/I, inventory)
if(observers && observers.len)
for(var/M in observers)
var/mob/dead/observe = M
diff --git a/code/modules/mob/living/carbon/inventory.dm b/code/modules/mob/living/carbon/inventory.dm
index e44a4bad371..e399110909f 100644
--- a/code/modules/mob/living/carbon/inventory.dm
+++ b/code/modules/mob/living/carbon/inventory.dm
@@ -37,6 +37,7 @@
observe.client.screen -= I
I.loc = src
I.layer = ABOVE_HUD_LAYER
+ I.appearance_flags |= NO_CLIENT_COLOR
var/not_handled = FALSE
switch(slot)
if(slot_back)
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 2f4ca6da119..aa898296f9a 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -9,17 +9,20 @@
damageoverlaytemp = 0
update_damage_hud()
- if(..())
- . = 1
-
+ if(..()) //not dead
handle_blood()
- for(var/obj/item/organ/O in internal_organs)
+ if(stat != DEAD)
+ for(var/X in internal_organs)
+ var/obj/item/organ/O = X
O.on_life()
//Updates the number of stored chemicals for powers
handle_changeling()
+ if(stat != DEAD)
+ return 1
+
///////////////
// BREATHING //
///////////////
diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm
index d3e541143b0..3e87fa5c1ab 100644
--- a/code/modules/mob/living/carbon/monkey/life.dm
+++ b/code/modules/mob/living/carbon/monkey/life.dm
@@ -39,7 +39,7 @@
if(75 to 100)
if(prob(1))
src << "You mutate!"
- randmutb(src)
+ randmutb()
emote("gasp")
domutcheck()
..()
@@ -83,29 +83,29 @@
switch(bodytemperature)
if(360 to 400)
throw_alert("temp", /obj/screen/alert/hot, 1)
- adjustFireLoss(2)
+ apply_damage(HEAT_DAMAGE_LEVEL_1, BURN)
if(400 to 460)
throw_alert("temp", /obj/screen/alert/hot, 2)
- adjustFireLoss(3)
+ apply_damage(HEAT_DAMAGE_LEVEL_2, BURN)
if(460 to INFINITY)
throw_alert("temp", /obj/screen/alert/hot, 3)
if(on_fire)
- adjustFireLoss(8)
+ apply_damage(HEAT_DAMAGE_LEVEL_3, BURN)
else
- adjustFireLoss(3)
+ apply_damage(HEAT_DAMAGE_LEVEL_2, BURN)
else if(bodytemperature < BODYTEMP_COLD_DAMAGE_LIMIT)
if(!istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
switch(bodytemperature)
if(200 to 260)
throw_alert("temp", /obj/screen/alert/cold, 1)
- adjustFireLoss(0.5)
+ apply_damage(COLD_DAMAGE_LEVEL_1, BURN)
if(120 to 200)
throw_alert("temp", /obj/screen/alert/cold, 2)
- adjustFireLoss(1.5)
+ apply_damage(COLD_DAMAGE_LEVEL_2, BURN)
if(-INFINITY to 120)
throw_alert("temp", /obj/screen/alert/cold, 3)
- adjustFireLoss(3)
+ apply_damage(COLD_DAMAGE_LEVEL_3, BURN)
else
clear_alert("temp")
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index 6ae41f3c859..33cbce3edb1 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -3,7 +3,7 @@
voice_name = "monkey"
verb_say = "chimpers"
icon = 'icons/mob/monkey.dmi'
- icon_state = "monkey1"
+ icon_state = ""
gender = NEUTER
pass_flags = PASSTABLE
languages_spoken = MONKEY
@@ -13,6 +13,10 @@
type_of_meat = /obj/item/weapon/reagent_containers/food/snacks/meat/slab/monkey
gib_type = /obj/effect/decal/cleanable/blood/gibs
unique_name = 1
+ bodyparts = list(/obj/item/bodypart/chest/monkey, /obj/item/bodypart/head/monkey, /obj/item/bodypart/l_arm/monkey,
+ /obj/item/bodypart/r_arm/monkey, /obj/item/bodypart/r_leg/monkey, /obj/item/bodypart/l_leg/monkey)
+
+
/mob/living/carbon/monkey/New()
verbs += /mob/living/proc/mob_sleep
@@ -22,24 +26,13 @@
gender = pick(MALE, FEMALE)
real_name = name
- //initialize limbs, currently only used to handle cavity implant surgery, no dismemberment.
- bodyparts = newlist(/obj/item/bodypart/chest, /obj/item/bodypart/head, /obj/item/bodypart/l_arm,
- /obj/item/bodypart/r_arm, /obj/item/bodypart/r_leg, /obj/item/bodypart/l_leg)
- for(var/X in bodyparts)
- var/obj/item/bodypart/O = X
- O.owner = src
+ //initialize limbs
+ create_bodyparts()
if(good_mutations.len) //genetic mutations have been set up.
- initialize()
+ initialize() //initialize monkey dna
- internal_organs += new /obj/item/organ/appendix
- internal_organs += new /obj/item/organ/lungs
- internal_organs += new /obj/item/organ/heart
- internal_organs += new /obj/item/organ/brain
- internal_organs += new /obj/item/organ/tongue
-
- for(var/obj/item/organ/I in internal_organs)
- I.Insert(src)
+ create_internal_organs()
..()
@@ -47,6 +40,15 @@
create_dna(src)
dna.initialize_dna(random_blood_type())
+
+/mob/living/carbon/monkey/create_internal_organs()
+ internal_organs += new /obj/item/organ/appendix
+ internal_organs += new /obj/item/organ/lungs
+ internal_organs += new /obj/item/organ/heart
+ internal_organs += new /obj/item/organ/brain
+ internal_organs += new /obj/item/organ/tongue
+ ..()
+
/mob/living/carbon/monkey/movement_delay()
if(reagents)
if(reagents.has_reagent("morphine"))
@@ -64,133 +66,6 @@
. += (283.222 - bodytemperature) / 10 * 1.75
return . + config.monkey_delay
-/mob/living/carbon/monkey/attack_paw(mob/living/M)
- if(..()) //successful monkey bite.
- var/damage = rand(1, 5)
- if (stat != DEAD)
- adjustBruteLoss(damage)
- updatehealth()
- return
-
-/mob/living/carbon/monkey/attack_larva(mob/living/carbon/alien/larva/L)
- if(..()) //successful larva bite.
- var/damage = rand(1, 3)
- if(stat != DEAD)
- L.amount_grown = min(L.amount_grown + damage, L.max_grown)
- adjustBruteLoss(damage)
- updatehealth()
-
-/mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M)
- if(..()) //To allow surgery to return properly.
- return
-
- switch(M.a_intent)
- if("help")
- help_shake_act(M)
- if("grab")
- grabbedby(M)
- if("harm")
- M.do_attack_animation(src)
- if (prob(75))
- visible_message("[M] has punched [name]!", \
- "[M] has punched [name]!")
-
- playsound(loc, "punch", 25, 1, -1)
- var/damage = rand(5, 10)
- if (prob(40))
- damage = rand(10, 15)
- if ( (paralysis < 5) && (health > 0) )
- Paralyse(rand(10, 15))
- visible_message("[M] has knocked out [name]!", \
- "[M] has knocked out [name]!")
- adjustBruteLoss(damage)
- add_logs(M, src, "attacked")
- updatehealth()
- else
- playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to punch [name]!", \
- "[M] has attempted to punch [name]!")
- if("disarm")
- if (!( paralysis ))
- M.do_attack_animation(src)
- if (prob(25))
- Paralyse(2)
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- add_logs(M, src, "pushed")
- visible_message("[M] has pushed down [src]!", \
- "[M] has pushed down [src]!")
- else
- if(drop_item())
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
- visible_message("[M] has disarmed [src]!", \
- "[M] has disarmed [src]!")
-
-/mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(..()) //if harm or disarm intent.
- if (M.a_intent == "harm")
- if ((prob(95) && health > 0))
- playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- var/damage = rand(15, 30)
- if (damage >= 25)
- damage = rand(20, 40)
- if (paralysis < 15)
- Paralyse(rand(10, 15))
- visible_message("[M] has wounded [name]!", \
- "[M] has wounded [name]!")
- else
- visible_message("[M] has slashed [name]!", \
- "[M] has slashed [name]!")
-
- if (stat != DEAD)
- adjustBruteLoss(damage)
- updatehealth()
- add_logs(M, src, "attacked")
- else
- playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
- visible_message("[M] has attempted to lunge at [name]!", \
- "[M] has attempted to lunge at [name]!")
-
- if (M.a_intent == "disarm")
- playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
- if(prob(95))
- Weaken(10)
- visible_message("[M] has tackled down [name]!", \
- "[M] has tackled down [name]!")
- else
- if(drop_item())
- visible_message("[M] has disarmed [name]!", \
- "[M] has disarmed [name]!")
- add_logs(M, src, "disarmed")
- updatehealth()
- return
-
-/mob/living/carbon/monkey/attack_animal(mob/living/simple_animal/M)
- if(..())
- var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- switch(M.melee_damage_type)
- if(BRUTE)
- adjustBruteLoss(damage)
- if(BURN)
- adjustFireLoss(damage)
- if(TOX)
- adjustToxLoss(damage)
- if(OXY)
- adjustOxyLoss(damage)
- if(CLONE)
- adjustCloneLoss(damage)
- if(STAMINA)
- adjustStaminaLoss(damage)
- updatehealth()
-
-
-/mob/living/carbon/monkey/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime attack
- var/damage = rand(5, 35)
- if(M.is_adult)
- damage = rand(20, 40)
- adjustBruteLoss(damage)
- updatehealth()
-
/mob/living/carbon/monkey/Stat()
..()
if(statpanel("Status"))
@@ -209,24 +84,6 @@
internal = null
return
-/mob/living/carbon/monkey/ex_act(severity, target)
- ..()
- switch(severity)
- if(1)
- gib()
- return
- if(2)
- adjustBruteLoss(60)
- adjustFireLoss(60)
- adjustEarDamage(30,120)
- if(3)
- adjustBruteLoss(30)
- if (prob(50))
- Paralyse(10)
- adjustEarDamage(15,60)
-
- updatehealth()
- return
/mob/living/carbon/monkey/IsAdvancedToolUser()//Unless its monkey mode monkeys cant use advanced tools
return 0
@@ -270,24 +127,6 @@
return threatcount
-/mob/living/carbon/monkey/acid_act(acidpwr, toxpwr, acid_volume)
- if(wear_mask)
- if(!wear_mask.unacidable)
- wear_mask.acid_act(acidpwr)
- update_inv_wear_mask()
- else
- src << "Your mask protects you from the acid."
- return
-
- take_organ_damage(min(6*toxpwr, acid_volume * acidpwr/10))
-
-/mob/living/carbon/monkey/help_shake_act(mob/living/carbon/M)
- if(health < 0 && ishuman(M))
- var/mob/living/carbon/human/H = M
- H.do_cpr(src)
- else
- ..()
-
/mob/living/carbon/monkey/get_permeability_protection()
var/protection = 0
if(head)
@@ -297,13 +136,6 @@
protection = protection/7 //the rest of the body isn't covered.
return protection
-/mob/living/carbon/monkey/check_eye_prot()
- var/number = ..()
- if(istype(src.wear_mask, /obj/item/clothing/mask))
- var/obj/item/clothing/mask/MFP = src.wear_mask
- number += MFP.flash_protect
- return number
-
/mob/living/carbon/monkey/fully_heal(admin_revive = 0)
if(!getorganslot("lungs"))
var/obj/item/organ/lungs/L = new()
diff --git a/code/modules/mob/living/carbon/monkey/monkey_defense.dm b/code/modules/mob/living/carbon/monkey/monkey_defense.dm
new file mode 100644
index 00000000000..c3a1818b242
--- /dev/null
+++ b/code/modules/mob/living/carbon/monkey/monkey_defense.dm
@@ -0,0 +1,188 @@
+
+/mob/living/carbon/monkey/get_eye_protection()
+ var/number = ..()
+ if(istype(src.wear_mask, /obj/item/clothing/mask))
+ var/obj/item/clothing/mask/MFP = src.wear_mask
+ number += MFP.flash_protect
+ return number
+
+/mob/living/carbon/monkey/help_shake_act(mob/living/carbon/M)
+ if(health < 0 && ishuman(M))
+ var/mob/living/carbon/human/H = M
+ H.do_cpr(src)
+ else
+ ..()
+
+/mob/living/carbon/monkey/attack_paw(mob/living/M)
+ if(..()) //successful monkey bite.
+ var/dam_zone = pick("chest", "l_hand", "r_hand", "l_leg", "r_leg")
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
+ if(M.limb_destroyer)
+ dismembering_strike(M, affecting.body_zone)
+ if(stat != DEAD)
+ apply_damage(rand(1, 5), BRUTE, affecting)
+
+
+
+/mob/living/carbon/monkey/attack_larva(mob/living/carbon/alien/larva/L)
+ if(..()) //successful larva bite.
+ var/damage = rand(1, 3)
+ if(stat != DEAD)
+ L.amount_grown = min(L.amount_grown + damage, L.max_grown)
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected))
+ apply_damage(damage, BRUTE, affecting)
+
+/mob/living/carbon/monkey/attack_hand(mob/living/carbon/human/M)
+ if(..()) //To allow surgery to return properly.
+ return
+
+ switch(M.a_intent)
+ if("help")
+ help_shake_act(M)
+ if("grab")
+ grabbedby(M)
+ if("harm")
+ M.do_attack_animation(src)
+ if (prob(75))
+ visible_message("[M] has punched [name]!", \
+ "[M] has punched [name]!")
+
+ playsound(loc, "punch", 25, 1, -1)
+ var/damage = rand(5, 10)
+ if (prob(40))
+ damage = rand(10, 15)
+ if ( (paralysis < 5) && (health > 0) )
+ Paralyse(rand(10, 15))
+ visible_message("[M] has knocked out [name]!", \
+ "[M] has knocked out [name]!")
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ apply_damage(damage, BRUTE, affecting)
+ add_logs(M, src, "attacked")
+
+ else
+ playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
+ visible_message("[M] has attempted to punch [name]!", \
+ "[M] has attempted to punch [name]!")
+ if("disarm")
+ if (!( paralysis ))
+ M.do_attack_animation(src)
+ if (prob(25))
+ Paralyse(2)
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ add_logs(M, src, "pushed")
+ visible_message("[M] has pushed down [src]!", \
+ "[M] has pushed down [src]!")
+ else
+ if(drop_item())
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+ visible_message("[M] has disarmed [src]!", \
+ "[M] has disarmed [src]!")
+
+/mob/living/carbon/monkey/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if(..()) //if harm or disarm intent.
+ if (M.a_intent == "harm")
+ if ((prob(95) && health > 0))
+ playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
+ var/damage = rand(15, 30)
+ if (damage >= 25)
+ damage = rand(20, 40)
+ if (paralysis < 15)
+ Paralyse(rand(10, 15))
+ visible_message("[M] has wounded [name]!", \
+ "[M] has wounded [name]!")
+ else
+ visible_message("[M] has slashed [name]!", \
+ "[M] has slashed [name]!")
+
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected))
+ add_logs(M, src, "attacked")
+ if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful
+ return 1
+ apply_damage(damage, BRUTE, affecting)
+
+ else
+ playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
+ visible_message("[M] has attempted to lunge at [name]!", \
+ "[M] has attempted to lunge at [name]!")
+
+ if (M.a_intent == "disarm")
+ playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
+ if(prob(95))
+ Weaken(10)
+ visible_message("[M] has tackled down [name]!", \
+ "[M] has tackled down [name]!")
+ else
+ if(drop_item())
+ visible_message("[M] has disarmed [name]!", \
+ "[M] has disarmed [name]!")
+ add_logs(M, src, "disarmed")
+ updatehealth()
+
+
+/mob/living/carbon/monkey/attack_animal(mob/living/simple_animal/M)
+ if(..())
+ var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
+ var/dam_zone = dismembering_strike(M, pick("chest", "l_hand", "r_hand", "l_leg", "r_leg"))
+ if(!dam_zone) //Dismemberment successful
+ return 1
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
+ apply_damage(damage, M.melee_damage_type, affecting)
+
+
+
+/mob/living/carbon/monkey/attack_slime(mob/living/simple_animal/slime/M)
+ if(..()) //successful slime attack
+ var/damage = rand(5, 35)
+ if(M.is_adult)
+ damage = rand(20, 40)
+ var/dam_zone = dismembering_strike(M, pick("head", "chest", "l_arm", "r_arm", "l_leg", "r_leg"))
+ if(!dam_zone) //Dismemberment successful
+ return 1
+ var/obj/item/bodypart/affecting = get_bodypart(ran_zone(dam_zone))
+ apply_damage(damage, BRUTE, affecting)
+
+
+/mob/living/carbon/monkey/acid_act(acidpwr, toxpwr, acid_volume)
+ if(wear_mask)
+ if(!wear_mask.unacidable)
+ wear_mask.acid_act(acidpwr)
+ update_inv_wear_mask()
+ else
+ src << "Your mask protects you from the acid."
+ return
+
+ take_bodypart_damage(min(6*toxpwr, acid_volume * acidpwr/10))
+
+
+/mob/living/carbon/monkey/ex_act(severity, target)
+ ..()
+
+ switch (severity)
+ if (1)
+ gib()
+
+ if (2)
+ take_overall_damage(60, 60)
+ shred_clothing(1,50)
+ adjustEarDamage(30, 120)
+ if(prob(70))
+ Paralyse(10)
+
+ if(3)
+ take_overall_damage(30, 0)
+ adjustEarDamage(15,60)
+ if (prob(50))
+ Paralyse(8)
+
+
+ //attempt to dismember bodyparts
+ if(severity <= 2)
+ var/max_limb_loss = round(4/severity) //so you don't lose four limbs at severity 3.
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ if(prob(50/severity) && BP.body_zone != "chest")
+ BP.brute_dam = BP.max_damage
+ BP.dismember()
+ max_limb_loss--
+ if(!max_limb_loss)
+ break
diff --git a/code/modules/mob/living/carbon/monkey/punpun.dm b/code/modules/mob/living/carbon/monkey/punpun.dm
index d892512aecb..995c30f6fed 100644
--- a/code/modules/mob/living/carbon/monkey/punpun.dm
+++ b/code/modules/mob/living/carbon/monkey/punpun.dm
@@ -11,10 +11,6 @@
/mob/living/carbon/monkey/punpun/New()
Read_Memory()
- if(relic_hat)
- equip_to_slot_or_del(new relic_hat, slot_head)
- if(relic_mask)
- equip_to_slot_or_del(new relic_mask, slot_wear_mask)
if(ancestor_name)
name = ancestor_name
if(ancestor_chain > 1)
@@ -27,6 +23,14 @@
gender = pick(MALE, FEMALE)
..()
+ //These have to be after the parent new to ensure that the monkey
+ //bodyparts are actually created before we try to equip things to
+ //those slots
+ if(relic_hat)
+ equip_to_slot_or_del(new relic_hat, slot_head)
+ if(relic_mask)
+ equip_to_slot_or_del(new relic_mask, slot_wear_mask)
+
/mob/living/carbon/monkey/punpun/Life()
if(ticker.current_state == GAME_STATE_FINISHED && !memory_saved)
Write_Memory(0)
diff --git a/code/modules/mob/living/carbon/monkey/update_icons.dm b/code/modules/mob/living/carbon/monkey/update_icons.dm
index b342ace1e79..b7ca5044398 100644
--- a/code/modules/mob/living/carbon/monkey/update_icons.dm
+++ b/code/modules/mob/living/carbon/monkey/update_icons.dm
@@ -1,29 +1,47 @@
/mob/living/carbon/monkey/regenerate_icons()
if(!..())
+ update_body_parts()
+ update_hair()
update_inv_wear_mask()
update_inv_head()
update_inv_back()
- update_icons()
update_transform()
-/mob/living/carbon/monkey/update_icons()
- cut_overlays()
- icon_state = "monkey1"
- for(var/image/I in overlays_standing)
- add_overlay(I)
////////
+
+/mob/living/carbon/monkey/update_hair()
+ remove_overlay(HAIR_LAYER)
+
+ var/obj/item/bodypart/head/HD = get_bodypart("head")
+ if(!HD) //Decapitated
+ return
+
+ if(disabilities & HUSK)
+ return
+
+ var/hair_hidden = 0
+
+ if(head)
+ var/obj/item/I = head
+ if(I.flags_inv & HIDEHAIR)
+ hair_hidden = 1
+ if(wear_mask)
+ var/obj/item/clothing/mask/M = wear_mask
+ if(M.flags_inv & HIDEHAIR)
+ hair_hidden = 1
+ if(!hair_hidden)
+ if(!getorgan(/obj/item/organ/brain)) //Applies the debrained overlay if there is no brain
+ var/image/I = image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER)
+ overlays_standing[HAIR_LAYER] = I
+ apply_overlay(HAIR_LAYER)
+
+
/mob/living/carbon/monkey/update_fire()
..("Monkey_burning")
-/mob/living/carbon/monkey/update_inv_handcuffed()
- remove_overlay(HANDCUFF_LAYER)
- if(handcuffed)
- overlays_standing[HANDCUFF_LAYER] = image("icon"='icons/mob/mob.dmi', "icon_state"="handcuff1", "layer"=-HANDCUFF_LAYER)
- apply_overlay(HANDCUFF_LAYER)
-
/mob/living/carbon/monkey/update_inv_legcuffed()
remove_overlay(LEGCUFF_LAYER)
if(legcuffed)
diff --git a/code/modules/mob/living/carbon/say.dm b/code/modules/mob/living/carbon/say.dm
index 0b6c2cae108..8b1e3b65298 100644
--- a/code/modules/mob/living/carbon/say.dm
+++ b/code/modules/mob/living/carbon/say.dm
@@ -24,3 +24,7 @@
var/obj/item/organ/tongue/T = getorganslot("tongue")
if(T)
. |= T.get_spans()
+
+ var/obj/item/I = get_active_held_item()
+ if(I)
+ . |= I.get_held_item_speechspans(src)
diff --git a/code/modules/mob/living/carbon/status_procs.dm b/code/modules/mob/living/carbon/status_procs.dm
index 24c9305aa15..abfe312c48b 100644
--- a/code/modules/mob/living/carbon/status_procs.dm
+++ b/code/modules/mob/living/carbon/status_procs.dm
@@ -1,6 +1,6 @@
//Here are the procs used to modify status effects of a mob.
//The effects include: stunned, weakened, paralysis, sleeping, resting, jitteriness, dizziness, ear damage,
-// eye damage, eye_blind, eye_blurry, druggy, BLIND disability, and NEARSIGHT disability.
+// eye damage, eye_blind, eye_blurry, druggy, BLIND disability, NEARSIGHT disability, and HUSK disability.
/mob/living/carbon/damage_eyes(amount)
if(amount>0)
@@ -76,4 +76,19 @@
if(!(disabilities & NEARSIGHT))
disabilities |= NEARSIGHT
overlay_fullscreen("nearsighted", /obj/screen/fullscreen/impaired, 1)
- return 1
\ No newline at end of file
+ return 1
+
+/mob/living/carbon/cure_husk()
+ if(disabilities & HUSK)
+ disabilities &= ~HUSK
+ status_flags &= ~DISFIGURED
+ update_body()
+ return 1
+
+/mob/living/carbon/become_husk()
+ if(disabilities & HUSK)
+ return
+ disabilities |= HUSK
+ status_flags |= DISFIGURED //makes them unknown
+ update_body()
+ return 1
diff --git a/code/modules/mob/living/carbon/update_icons.dm b/code/modules/mob/living/carbon/update_icons.dm
index 05f410fafe2..dcd5b1a59b2 100644
--- a/code/modules/mob/living/carbon/update_icons.dm
+++ b/code/modules/mob/living/carbon/update_icons.dm
@@ -40,10 +40,18 @@
overlays -= overlays_standing[cache_index]
overlays_standing[cache_index] = null
+/mob/living/carbon/regenerate_icons()
+ if(notransform)
+ return 1
+ update_inv_hands()
+ update_inv_handcuffed()
+ update_inv_legcuffed()
+ update_fire()
+
/mob/living/carbon/update_inv_hands()
remove_overlay(HANDS_LAYER)
- if(handcuffed)
+ if (handcuffed)
drop_all_held_items()
return
@@ -85,23 +93,44 @@
apply_overlay(FIRE_LAYER)
-/mob/living/carbon/regenerate_icons()
- if(notransform)
- return 1
- update_inv_hands()
- update_inv_handcuffed()
- update_inv_legcuffed()
- update_fire()
+
+
+/mob/living/carbon/update_damage_overlays()
+ remove_overlay(DAMAGE_LAYER)
+
+ var/image/standing = image("icon"='icons/mob/dam_mob.dmi', "icon_state"="blank", "layer"=-DAMAGE_LAYER)
+ overlays_standing[DAMAGE_LAYER] = standing
+
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ if(BP.dmg_overlay_type)
+ if(BP.brutestate)
+ standing.overlays += "[BP.dmg_overlay_type]_[BP.body_zone]_[BP.brutestate]0" //we're adding icon_states of the base image as overlays
+ if(BP.burnstate)
+ standing.overlays += "[BP.dmg_overlay_type]_[BP.body_zone]_0[BP.burnstate]"
+
+ apply_overlay(DAMAGE_LAYER)
+
/mob/living/carbon/update_inv_wear_mask()
remove_overlay(FACEMASK_LAYER)
- if(istype(wear_mask, /obj/item/clothing/mask))
+
+ if(!get_bodypart("head")) //Decapitated
+ return
+
+ if(client && hud_used && hud_used.inv_slots[slot_wear_mask])
+ var/obj/screen/inventory/inv = hud_used.inv_slots[slot_wear_mask]
+ inv.update_icon()
+
+ if(wear_mask)
if(!(head && (head.flags_inv & HIDEMASK)))
var/image/standing = wear_mask.build_worn_icon(state = wear_mask.icon_state, default_layer = FACEMASK_LAYER, default_icon_file = 'icons/mob/mask.dmi')
overlays_standing[FACEMASK_LAYER] = standing
update_hud_wear_mask(wear_mask)
+
apply_overlay(FACEMASK_LAYER)
+
/mob/living/carbon/update_inv_back()
remove_overlay(BACK_LAYER)
@@ -117,14 +146,27 @@
/mob/living/carbon/update_inv_head()
remove_overlay(HEAD_LAYER)
+
+ if(!get_bodypart("head")) //Decapitated
+ return
+
+ if(client && hud_used && hud_used.inv_slots[slot_back])
+ var/obj/screen/inventory/inv = hud_used.inv_slots[slot_head]
+ inv.update_icon()
+
if(head)
var/image/standing = head.build_worn_icon(state = head.icon_state, default_layer = HEAD_LAYER, default_icon_file = 'icons/mob/head.dmi')
overlays_standing[HEAD_LAYER] = standing
update_hud_head(head)
+
apply_overlay(HEAD_LAYER)
+
/mob/living/carbon/update_inv_handcuffed()
- return
+ remove_overlay(HANDCUFF_LAYER)
+ if(handcuffed)
+ overlays_standing[HANDCUFF_LAYER] = image("icon"='icons/mob/mob.dmi', "icon_state"="handcuff1", "layer"=-HANDCUFF_LAYER)
+ apply_overlay(HANDCUFF_LAYER)
//mob HUD updates for items in our inventory
@@ -150,12 +192,92 @@
return
+
//Overlays for the worn overlay so you can overlay while you overlay
//eg: ammo counters, primed grenade flashing, etc.
-/obj/item/proc/worn_overlays(var/isinhands = FALSE)
+/obj/item/proc/worn_overlays(isinhands = FALSE)
. = list()
+/mob/living/carbon/update_body()
+ update_body_parts()
+
+/mob/living/carbon/proc/update_body_parts()
+ //CHECK FOR UPDATE
+ var/oldkey = icon_render_key
+ icon_render_key = generate_icon_render_key()
+ if(oldkey == icon_render_key)
+ return
+
+ remove_overlay(BODYPARTS_LAYER)
+
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ if(!BP.no_update)
+ BP.update_limb()
+
+ //LOAD ICONS
+ if(limb_icon_cache[icon_render_key])
+ load_limb_from_cache()
+ return
+
+ //GENERATE NEW LIMBS
+ var/list/new_limbs = list()
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ var/image/temp = BP.get_limb_icon()
+ if(temp)
+ new_limbs += temp
+ if(new_limbs.len)
+ overlays_standing[BODYPARTS_LAYER] = new_limbs
+ limb_icon_cache[icon_render_key] = new_limbs
+
+ apply_overlay(BODYPARTS_LAYER)
+ update_damage_overlays()
+/////////////////////
+// Limb Icon Cache //
+/////////////////////
+/*
+ Called from update_body_parts() these procs handle the limb icon cache.
+ the limb icon cache adds an icon_render_key to a human mob, it represents:
+ - skin_tone (if applicable)
+ - gender
+ - limbs (stores as the limb name and whether it is removed/fine, organic/robotic)
+ These procs only store limbs as to increase the number of matching icon_render_keys
+ This cache exists because drawing 6/7 icons for humans constantly is quite a waste
+ See RemieRichards on irc.rizon.net #coderbus
+*/
+
+var/global/list/limb_icon_cache = list()
+
+/mob/living/carbon
+ var/icon_render_key = ""
+
+
+//produces a key based on the mob's limbs
+
+/mob/living/carbon/proc/generate_icon_render_key()
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ . += "-[BP.body_zone]"
+ if(BP.animal_origin)
+ . += "-[BP.animal_origin]"
+ if(BP.status == BODYPART_ORGANIC)
+ . += "-organic"
+ else
+ . += "-robotic"
+
+ if(disabilities & HUSK)
+ . += "-husk"
+
+
+//change the mob's icon to the one matching its key
+/mob/living/carbon/proc/load_limb_from_cache()
+ if(limb_icon_cache[icon_render_key])
+ remove_overlay(BODYPARTS_LAYER)
+ overlays_standing[BODYPARTS_LAYER] = limb_icon_cache[icon_render_key]
+ apply_overlay(BODYPARTS_LAYER)
+ update_damage_overlays()
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index 0690e8b11fd..f0fcda0dcf9 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -9,23 +9,22 @@
standard 0 if fail
*/
/mob/living/proc/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0)
- blocked = (100-blocked)/100
- if(!damage || (blocked <= 0))
+ var/hit_percent = (100-blocked)/100
+ if(!damage || (hit_percent <= 0))
return 0
switch(damagetype)
if(BRUTE)
- adjustBruteLoss(damage * blocked)
+ adjustBruteLoss(damage * hit_percent)
if(BURN)
- adjustFireLoss(damage * blocked)
+ adjustFireLoss(damage * hit_percent)
if(TOX)
- adjustToxLoss(damage * blocked)
+ adjustToxLoss(damage * hit_percent)
if(OXY)
- adjustOxyLoss(damage * blocked)
+ adjustOxyLoss(damage * hit_percent)
if(CLONE)
- adjustCloneLoss(damage * blocked)
+ adjustCloneLoss(damage * hit_percent)
if(STAMINA)
- adjustStaminaLoss(damage * blocked)
- updatehealth()
+ adjustStaminaLoss(damage * hit_percent)
return 1
@@ -49,30 +48,30 @@
/mob/living/proc/apply_effect(effect = 0,effecttype = STUN, blocked = 0)
- blocked = (100-blocked)/100
- if(!effect || (blocked <= 0))
+ var/hit_percent = (100-blocked)/100
+ if(!effect || (hit_percent <= 0))
return 0
switch(effecttype)
if(STUN)
- Stun(effect * blocked)
+ Stun(effect * hit_percent)
if(WEAKEN)
- Weaken(effect * blocked)
+ Weaken(effect * hit_percent)
if(PARALYZE)
- Paralyse(effect * blocked)
+ Paralyse(effect * hit_percent)
if(IRRADIATE)
- radiation += max(effect * blocked, 0)
+ radiation += max(effect * hit_percent, 0)
if(SLUR)
- slurring = max(slurring,(effect * blocked))
+ slurring = max(slurring,(effect * hit_percent))
if(STUTTER)
if(status_flags & CANSTUN) // stun is usually associated with stutter
- stuttering = max(stuttering,(effect * blocked))
+ stuttering = max(stuttering,(effect * hit_percent))
if(EYE_BLUR)
- blur_eyes(effect * blocked)
+ blur_eyes(effect * hit_percent)
if(DROWSY)
- drowsyness = max(drowsyness,(effect * blocked))
+ drowsyness = max(drowsyness,(effect * hit_percent))
if(JITTER)
if(status_flags & CANSTUN)
- jitteriness = max(jitteriness,(effect * blocked))
+ jitteriness = max(jitteriness,(effect * hit_percent))
return 1
@@ -99,4 +98,128 @@
apply_damage(stamina, STAMINA, null, blocked)
if(jitter)
apply_effect(jitter, JITTER, blocked)
- return 1
\ No newline at end of file
+ return 1
+
+
+/mob/living/proc/getBruteLoss()
+ return bruteloss
+
+/mob/living/proc/adjustBruteLoss(amount, updating_health=1)
+ if(status_flags & GODMODE)
+ return 0
+ bruteloss = Clamp((bruteloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
+ if(updating_health)
+ updatehealth()
+
+/mob/living/proc/getOxyLoss()
+ return oxyloss
+
+/mob/living/proc/adjustOxyLoss(amount, updating_health=1)
+ if(status_flags & GODMODE)
+ return 0
+ oxyloss = Clamp((oxyloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
+ if(updating_health)
+ updatehealth()
+
+/mob/living/proc/setOxyLoss(amount, updating_health=1)
+ if(status_flags & GODMODE)
+ return 0
+ oxyloss = amount
+ if(updating_health)
+ updatehealth()
+
+/mob/living/proc/getToxLoss()
+ return toxloss
+
+/mob/living/proc/adjustToxLoss(amount, updating_health=1)
+ if(status_flags & GODMODE)
+ return 0
+ toxloss = Clamp((toxloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
+ if(updating_health)
+ updatehealth()
+ return amount
+
+/mob/living/proc/setToxLoss(amount, updating_health=1)
+ if(status_flags & GODMODE)
+ return 0
+ toxloss = amount
+ if(updating_health)
+ updatehealth()
+
+/mob/living/proc/getFireLoss()
+ return fireloss
+
+/mob/living/proc/adjustFireLoss(amount, updating_health=1)
+ if(status_flags & GODMODE)
+ return 0
+ fireloss = Clamp((fireloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
+ if(updating_health)
+ updatehealth()
+
+/mob/living/proc/getCloneLoss()
+ return cloneloss
+
+/mob/living/proc/adjustCloneLoss(amount, updating_health=1)
+ if(status_flags & GODMODE)
+ return 0
+ cloneloss = Clamp((cloneloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
+ if(updating_health)
+ updatehealth()
+
+/mob/living/proc/setCloneLoss(amount, updating_health=1)
+ if(status_flags & GODMODE)
+ return 0
+ cloneloss = amount
+ if(updating_health)
+ updatehealth()
+
+/mob/living/proc/getBrainLoss()
+ return brainloss
+
+/mob/living/proc/adjustBrainLoss(amount)
+ if(status_flags & GODMODE)
+ return 0
+ brainloss = Clamp((brainloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
+
+/mob/living/proc/setBrainLoss(amount)
+ if(status_flags & GODMODE)
+ return 0
+ brainloss = amount
+
+/mob/living/proc/getStaminaLoss()
+ return staminaloss
+
+/mob/living/proc/adjustStaminaLoss(amount, updating_stamina = 1)
+ return
+
+/mob/living/proc/setStaminaLoss(amount, updating_stamina = 1)
+ return
+
+
+// heal ONE external organ, organ gets randomly selected from damaged ones.
+/mob/living/proc/heal_bodypart_damage(brute, burn, updating_health = 1)
+ adjustBruteLoss(-brute, 0) //zero as argument for no instant health update
+ adjustFireLoss(-burn, 0)
+ if(updating_health)
+ updatehealth()
+
+// damage ONE external organ, organ gets randomly selected from damaged ones.
+/mob/living/proc/take_bodypart_damage(brute, burn, updating_health = 1)
+ adjustBruteLoss(brute, 0) //zero as argument for no instant health update
+ adjustFireLoss(burn, 0)
+ if(updating_health)
+ updatehealth()
+
+// heal MANY bodyparts, in random order
+/mob/living/proc/heal_overall_damage(brute, burn, only_robotic = 0, only_organic = 1, updating_health = 1)
+ adjustBruteLoss(-brute, 0) //zero as argument for no instant health update
+ adjustFireLoss(-burn, 0)
+ if(updating_health)
+ updatehealth()
+
+// damage MANY bodyparts, in random order
+/mob/living/proc/take_overall_damage(brute, burn, updating_health = 1)
+ adjustBruteLoss(brute, 0) //zero as argument for no instant health update
+ adjustFireLoss(burn, 0)
+ if(updating_health)
+ updatehealth()
\ No newline at end of file
diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm
index fc1bf88240b..6695c4a1271 100644
--- a/code/modules/mob/living/death.dm
+++ b/code/modules/mob/living/death.dm
@@ -1,27 +1,30 @@
-/mob/living/gib(no_brain, no_organs)
+/mob/living/gib(no_brain, no_organs, no_bodyparts)
var/prev_lying = lying
if(stat != DEAD)
death(1)
- if(buckled)
- buckled.unbuckle_mob(src,force=1) //to update alien nest overlay, forced because we don't exist anymore
-
if(!prev_lying)
gib_animation()
- if(!no_organs)
- spill_organs(no_brain)
- spawn_gibs()
+
+ spill_organs(no_brain, no_organs, no_bodyparts)
+
+ if(!no_bodyparts)
+ spread_bodyparts(no_brain, no_organs)
+
+ spawn_gibs(no_bodyparts)
qdel(src)
/mob/living/proc/gib_animation()
return
/mob/living/proc/spawn_gibs()
- gibs(loc, viruses)
+ new /obj/effect/gibspawner/generic(loc, viruses)
-/mob/living/proc/spill_organs(no_brain)
+/mob/living/proc/spill_organs()
return
+/mob/living/proc/spread_bodyparts()
+ return
/mob/living/dust()
death(1)
@@ -57,8 +60,6 @@
living_mob_list -= src
if(!gibbed)
dead_mob_list += src
- else if(buckled)
- buckled.unbuckle_mob(src,force=1)
paralysis = 0
stunned = 0
weakened = 0
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index f44ca1855ba..19cca48a15b 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -19,21 +19,18 @@
var/datum/gas_mixture/environment = loc.return_air()
if(stat != DEAD)
-
//Breathing, if applicable
handle_breathing()
-
+ if(stat != DEAD)
//Mutations and radiation
handle_mutations_and_radiation()
-
+ if(stat != DEAD)
//Chemicals in the body
handle_chemicals_in_body()
-
+ if(stat != DEAD)
//Random events (vomiting etc)
handle_random_events()
- . = 1
-
//Handle temperature/pressure differences between body and environment
if(environment)
handle_environment(environment)
@@ -43,16 +40,19 @@
//stuff in the stomach
handle_stomach()
- update_gravity(has_gravity())
+ update_gravity(mob_has_gravity())
if(machine)
machine.check_eye(src)
-
if(stat != DEAD)
handle_disabilities() // eye, ear, brain damages
+ if(stat != DEAD)
handle_status_effects() //all special effects, stunned, weakened, jitteryness, hallucination, sleeping, etc
+ if(stat != DEAD)
+ return 1
+
/mob/living/proc/handle_breathing()
return
@@ -78,6 +78,23 @@
/mob/living/proc/handle_environment(datum/gas_mixture/environment)
return
+/mob/living/proc/handle_fire()
+ if(fire_stacks < 0) //If we've doused ourselves in water to avoid fire, dry off slowly
+ fire_stacks = min(0, fire_stacks + 1)//So we dry ourselves back to default, nonflammable.
+ if(!on_fire)
+ return 1
+ if(fire_stacks > 0)
+ adjust_fire_stacks(-0.1) //the fire is slowly consumed
+ else
+ ExtinguishMob()
+ return
+ var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
+ if(!G.gases["o2"] || G.gases["o2"][MOLES] < 1)
+ ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
+ return
+ var/turf/location = get_turf(src)
+ location.hotspot_expose(700, 50, 1)
+
/mob/living/proc/handle_stomach()
return
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index d5d566211d1..74a24079251 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -29,6 +29,9 @@
/mob/living/Destroy()
..()
+ if(buckled)
+ buckled.unbuckle_mob(src,force=1)
+
for(var/mob/living/simple_animal/drone/D in player_list)
for(var/image/I in staticOverlays)
D.staticOverlays.Remove(I)
@@ -212,22 +215,13 @@
src << "You have given up life and succumbed to death."
death()
+/mob/living/incapacitated(ignore_restraints, ignore_grab)
+ if(stat || paralysis || stunned || weakened || (!ignore_restraints && restrained(ignore_grab)))
+ return 1
+
/mob/living/proc/InCritical()
return (src.health < 0 && src.health > -95 && stat == UNCONSCIOUS)
-/mob/living/ex_act(severity, origin)
- if(istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
- return
- ..()
- flash_eyes()
-
-/mob/living/proc/updatehealth()
- if(status_flags & GODMODE)
- return
- health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss()
- update_stat()
- med_hud_set_health()
-
//This proc is used for mobs which are affected by pressure to calculate the amount of pressure that actually
//affects them once clothing is factored in. ~Errorage
/mob/living/proc/calculate_affecting_pressure(pressure)
@@ -255,120 +249,6 @@
return temperature
-// MOB PROCS
-/mob/living/proc/getBruteLoss()
- return bruteloss
-
-/mob/living/proc/adjustBruteLoss(amount, updating_health=1)
- if(status_flags & GODMODE)
- return 0
- bruteloss = Clamp((bruteloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
- if(updating_health)
- updatehealth()
-
-/mob/living/proc/getOxyLoss()
- return oxyloss
-
-/mob/living/proc/adjustOxyLoss(amount, updating_health=1)
- if(status_flags & GODMODE)
- return 0
- oxyloss = Clamp((oxyloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
- if(updating_health)
- updatehealth()
-
-/mob/living/proc/setOxyLoss(amount, updating_health=1)
- if(status_flags & GODMODE)
- return 0
- oxyloss = amount
- if(updating_health)
- updatehealth()
-
-/mob/living/proc/getToxLoss()
- return toxloss
-
-/mob/living/proc/adjustToxLoss(amount, updating_health=1)
- if(status_flags & GODMODE)
- return 0
- toxloss = Clamp((toxloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
- if(updating_health)
- updatehealth()
- return amount
-
-/mob/living/proc/setToxLoss(amount, updating_health=1)
- if(status_flags & GODMODE)
- return 0
- toxloss = amount
- if(updating_health)
- updatehealth()
-
-/mob/living/proc/getFireLoss()
- return fireloss
-
-/mob/living/proc/adjustFireLoss(amount, updating_health=1)
- if(status_flags & GODMODE)
- return 0
- fireloss = Clamp((fireloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
- if(updating_health)
- updatehealth()
-
-/mob/living/proc/getCloneLoss()
- return cloneloss
-
-/mob/living/proc/adjustCloneLoss(amount, updating_health=1)
- if(status_flags & GODMODE)
- return 0
- cloneloss = Clamp((cloneloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
- if(updating_health)
- updatehealth()
-
-/mob/living/proc/setCloneLoss(amount, updating_health=1)
- if(status_flags & GODMODE)
- return 0
- cloneloss = amount
- if(updating_health)
- updatehealth()
-
-/mob/living/proc/getBrainLoss()
- return brainloss
-
-/mob/living/proc/adjustBrainLoss(amount)
- if(status_flags & GODMODE)
- return 0
- brainloss = Clamp((brainloss + (amount * config.damage_multiplier)), 0, maxHealth*2)
-
-/mob/living/proc/setBrainLoss(amount)
- if(status_flags & GODMODE)
- return 0
- brainloss = amount
-
-/mob/living/proc/getStaminaLoss()
- return staminaloss
-
-/mob/living/proc/adjustStaminaLoss(amount, updating_stamina = 1)
- return
-
-/mob/living/carbon/adjustStaminaLoss(amount, updating_stamina = 1)
- if(status_flags & GODMODE)
- return 0
- staminaloss = Clamp(staminaloss + amount, 0, maxHealth*2)
- if(updating_stamina)
- update_stamina()
-
-/mob/living/carbon/alien/adjustStaminaLoss(amount, updating_stamina = 1)
- return
-
-/mob/living/proc/setStaminaLoss(amount, updating_stamina = 1)
- return
-
-/mob/living/carbon/setStaminaLoss(amount, updating_stamina = 1)
- if(status_flags & GODMODE)
- return 0
- staminaloss = amount
- if(updating_stamina)
- update_stamina()
-
-/mob/living/carbon/alien/setStaminaLoss(amount, updating_stamina = 1)
- return
/mob/living/proc/getMaxHealth()
return maxHealth
@@ -425,23 +305,6 @@
return 1
return 0
-
-/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0)
- if(shock_damage > 0)
- adjustFireLoss(shock_damage)
- visible_message(
- "[src] was shocked by \the [source]!", \
- "You feel a powerful shock coursing through your body!", \
- "You hear a heavy electrical crack." \
- )
- return shock_damage
-
-/mob/living/emp_act(severity)
- var/list/L = src.get_contents()
- for(var/obj/O in L)
- O.emp_act(severity)
- ..()
-
/mob/living/proc/can_inject()
return 1
@@ -453,33 +316,14 @@
var/def_zone = ran_zone(t)
return def_zone
-// heal ONE external organ, organ gets randomly selected from damaged ones.
-/mob/living/proc/heal_organ_damage(brute, burn, updating_health=1)
- adjustBruteLoss(-brute, updating_health)
- adjustFireLoss(-burn, updating_health)
- if(updating_health)
- updatehealth()
-// damage ONE external organ, organ gets randomly selected from damaged ones.
-/mob/living/proc/take_organ_damage(brute, burn, updating_health=1)
- adjustBruteLoss(brute)
- adjustFireLoss(burn)
- if(updating_health)
- updatehealth()
-
-// heal MANY bodyparts, in random order
-/mob/living/proc/heal_overall_damage(brute, burn, updating_health=1)
- adjustBruteLoss(-brute, updating_health)
- adjustFireLoss(-burn, updating_health)
- if(updating_health)
- updatehealth()
-
-// damage MANY bodyparts, in random order
-/mob/living/proc/take_overall_damage(brute, burn, updating_health=1)
- adjustBruteLoss(brute, updating_health)
- adjustFireLoss(burn, updating_health)
- if(updating_health)
- updatehealth()
+/mob/living/proc/updatehealth()
+ if(status_flags & GODMODE)
+ return
+ health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss()
+ update_stat()
+ med_hud_set_health()
+ med_hud_set_status()
//proc used to ressuscitate a mob
/mob/living/proc/revive(full_heal = 0, admin_revive = 0)
@@ -500,7 +344,7 @@
//proc used to completely heal a mob.
/mob/living/proc/fully_heal(admin_revive = 0)
restore_blood()
- setToxLoss(0, 0)
+ setToxLoss(0, 0) //zero as second argument not automatically call updatehealth().
setOxyLoss(0, 0)
setCloneLoss(0, 0)
setBrainLoss(0)
@@ -517,14 +361,14 @@
set_eye_damage(0)
cure_nearsighted()
cure_blind()
+ cure_husk()
disabilities = 0
ear_deaf = 0
ear_damage = 0
hallucination = 0
- heal_overall_damage(100000, 100000)
+ heal_overall_damage(100000, 100000, 0, 0, 1) //heal brute and burn dmg on both organic and robotic limbs, and update health right away.
ExtinguishMob()
fire_stacks = 0
- updatehealth()
update_canmove()
@@ -758,21 +602,6 @@
animate(src, pixel_y = get_standard_pixel_y_offset(lying), time = 10)
floating = 0
-//called when the mob receives a bright flash
-/mob/living/proc/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash)
- if(check_eye_prot() < intensity && (override_blindness_check || !(disabilities & BLIND)))
- overlay_fullscreen("flash", type)
- addtimer(src, "clear_fullscreen", 25, FALSE, "flash", 25)
- return 1
-
-//this returns the mob's protection against eye damage (number between -1 and 2)
-/mob/living/proc/check_eye_prot()
- return 0
-
-//this returns the mob's protection against ear damage (0 or 1)
-/mob/living/proc/check_ear_prot()
- return 0
-
// The src mob is trying to strip an item from someone
// Override if a certain type of mob should be behave differently when stripping items (can't, for example)
/mob/living/stripPanelUnequip(obj/item/what, mob/who, where)
@@ -821,11 +650,6 @@
who.equip_to_slot_if_possible(what, where, 0, 1)
add_logs(src, who, "equipped", what)
-/mob/living/singularity_act()
- var/gain = 20
- investigate_log("([key_name(src)]) has been consumed by the singularity.","singulo") //Oh that's where the clown ended up!
- gib()
- return(gain)
/mob/living/singularity_pull(S, current_size)
if(current_size >= STAGE_SIX)
@@ -833,29 +657,6 @@
else
step_towards(src,S)
-/mob/living/narsie_act()
- if(is_servant_of_ratvar(src) && !stat)
- src << "You resist Nar-Sie's influence... but not all of it. Run!"
- adjustBruteLoss(35)
- if(src && reagents)
- reagents.add_reagent("heparin", 5)
- return 0
- if(client)
- makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, null, 0)
- else
- new /mob/living/simple_animal/hostile/construct/harvester/hostile(get_turf(src))
- spawn_dust()
- gib()
- return
-
-/mob/living/ratvar_act()
- if(!add_servant_of_ratvar(src) && !is_servant_of_ratvar(src))
- src << "A blinding light boils you alive! Run!"
- adjustFireLoss(35)
- if(src)
- adjust_fire_stacks(1)
- IgniteMob()
-
/atom/movable/proc/do_attack_animation(atom/A, end_pixel_y)
var/pixel_x_diff = 0
var/pixel_y_diff = 0
@@ -1016,7 +817,7 @@
new path(src.loc)
butcher_results.Remove(path) //In case you want to have things like simple_animals drop their butcher results on gib, so it won't double up below.
visible_message("[user] butchers [src].")
- gib()
+ gib(0, 0, 1)
/mob/living/canUseTopic(atom/movable/M, be_close = 0, no_dextery = 0)
if(incapacitated())
@@ -1104,3 +905,50 @@
/mob/living/proc/fakefire()
return
+
+
+
+//Mobs on Fire
+/mob/living/proc/IgniteMob()
+ if(fire_stacks > 0 && !on_fire)
+ on_fire = 1
+ src.visible_message("[src] catches fire!", \
+ "You're set on fire!")
+ src.AddLuminosity(3)
+ throw_alert("fire", /obj/screen/alert/fire)
+ update_fire()
+ return TRUE
+ return FALSE
+
+/mob/living/proc/ExtinguishMob()
+ if(on_fire)
+ on_fire = 0
+ fire_stacks = 0
+ src.AddLuminosity(-3)
+ clear_alert("fire")
+ update_fire()
+
+/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
+ fire_stacks = Clamp(fire_stacks + add_fire_stacks, -20, 20)
+ if(on_fire && fire_stacks <= 0)
+ ExtinguishMob()
+
+//Share fire evenly between the two mobs
+//Called in MobBump() and Crossed()
+/mob/living/proc/spreadFire(mob/living/L)
+ if(!istype(L))
+ return
+ var/L_old_on_fire = L.on_fire
+
+ if(on_fire) //Only spread fire stacks if we're on fire
+ fire_stacks /= 2
+ L.fire_stacks += fire_stacks
+ if(L.IgniteMob())
+ log_game("[key_name(src)] bumped into [key_name(L)] and set them on fire")
+
+ if(L_old_on_fire) //Only ignite us and gain their stacks if they were onfire before we bumped them
+ L.fire_stacks /= 2
+ fire_stacks += L.fire_stacks
+ IgniteMob()
+
+//Mobs on Fire end
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index c7543c03ede..ee4bd6ce206 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -1,3 +1,4 @@
+
/mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = null, soften_text = null, armour_penetration, penetrated_text)
var/armor = getarmor(def_zone, attack_flag)
@@ -24,6 +25,14 @@
/mob/living/proc/getarmor(def_zone, type)
return 0
+//this returns the mob's protection against eye damage (number between -1 and 2)
+/mob/living/proc/get_eye_protection()
+ return 0
+
+//this returns the mob's protection against ear damage (0:no protection; 1: some ear protection; 2: has no ears)
+/mob/living/proc/get_ear_protection()
+ return 0
+
/mob/living/proc/on_hit(obj/item/projectile/proj_type)
return
@@ -33,18 +42,16 @@
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)
+ return P.on_hit(src, armor)
/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
return 0
-/proc/vol_by_throwforce_and_or_w_class(obj/item/I)
- if(!I)
- return 0
- if(I.throwforce && I.w_class)
- return Clamp((I.throwforce + I.w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
- else if(I.w_class)
- return Clamp(I.w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
+/obj/item/proc/get_volume_by_throwforce_and_or_w_class()
+ if(throwforce && w_class)
+ return Clamp((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
+ else if(w_class)
+ return Clamp(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
else
return 0
@@ -53,7 +60,7 @@
var/obj/item/I = AM
var/zone = ran_zone("chest", 65)//Hits a random part of the body, geared towards the chest
var/dtype = BRUTE
- var/volume = vol_by_throwforce_and_or_w_class(I)
+ var/volume = I.get_volume_by_throwforce_and_or_w_class()
if(istype(I,/obj/item/weapon)) //If the item is a weapon...
var/obj/item/weapon/W = I
dtype = W.damtype
@@ -83,6 +90,7 @@
playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1)
..()
+
/mob/living/mech_melee_attack(obj/mecha/M)
if(M.occupant.a_intent == "harm")
M.do_attack_animation(src)
@@ -109,80 +117,10 @@
add_logs(M.occupant, src, "pushed", M)
visible_message("[M] pushes [src] out of the way.")
-
-//Mobs on Fire
-/mob/living/proc/IgniteMob()
- if(fire_stacks > 0 && !on_fire)
- on_fire = 1
- src.visible_message("[src] catches fire!", \
- "You're set on fire!")
- src.AddLuminosity(3)
- throw_alert("fire", /obj/screen/alert/fire)
- update_fire()
- return TRUE
- return FALSE
-
-/mob/living/proc/ExtinguishMob()
- if(on_fire)
- on_fire = 0
- fire_stacks = 0
- src.AddLuminosity(-3)
- clear_alert("fire")
- update_fire()
-
-/mob/living/proc/update_fire()
- return
-
-/mob/living/proc/adjust_fire_stacks(add_fire_stacks) //Adjusting the amount of fire_stacks we have on person
- fire_stacks = Clamp(fire_stacks + add_fire_stacks, -20, 20)
- if(on_fire && fire_stacks <= 0)
- ExtinguishMob()
-
-/mob/living/proc/handle_fire()
- if(fire_stacks < 0) //If we've doused ourselves in water to avoid fire, dry off slowly
- fire_stacks = min(0, fire_stacks + 1)//So we dry ourselves back to default, nonflammable.
- if(!on_fire)
- return 1
- if(fire_stacks > 0)
- adjust_fire_stacks(-0.1) //the fire is slowly consumed
- else
- ExtinguishMob()
- return
- var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
- if(!G.gases["o2"] || G.gases["o2"][MOLES] < 1)
- ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
- return
- var/turf/location = get_turf(src)
- location.hotspot_expose(700, 50, 1)
-
/mob/living/fire_act()
adjust_fire_stacks(3)
IgniteMob()
-
-//Share fire evenly between the two mobs
-//Called in MobBump() and Crossed()
-/mob/living/proc/spreadFire(mob/living/L)
- if(!istype(L))
- return
- var/L_old_on_fire = L.on_fire
-
- if(on_fire) //Only spread fire stacks if we're on fire
- fire_stacks /= 2
- L.fire_stacks += fire_stacks
- if(L.IgniteMob())
- log_game("[key_name(src)] bumped into [key_name(L)] and set them on fire")
-
- if(L_old_on_fire) //Only ignite us and gain their stacks if they were onfire before we bumped them
- L.fire_stacks /= 2
- fire_stacks += L.fire_stacks
- IgniteMob()
-
-//Mobs on Fire end
-
-/mob/living/acid_act(acidpwr, toxpwr, acid_volume)
- take_organ_damage(min(10*toxpwr, acid_volume * toxpwr))
-
/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = 0)
if(user == src || anchored)
return 0
@@ -291,7 +229,6 @@
return 0
/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
-
switch(L.a_intent)
if("help")
visible_message("[L.name] rubs its head against [src].")
@@ -331,60 +268,71 @@
M.do_attack_animation(src)
return 1
-/mob/living/incapacitated(ignore_restraints, ignore_grab)
- if(stat || paralysis || stunned || weakened || (!ignore_restraints && restrained(ignore_grab)))
- return 1
+/mob/living/ex_act(severity, origin)
+ if(istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
+ return
+ ..()
+ flash_act()
//Looking for irradiate()? It's been moved to radiation.dm under the rad_act() for mobs.
-/mob/living/proc/add_stun_absorption(key, duration, priority, message, self_message, examine_message)
-//adds a stun absorption with a key, a duration in deciseconds, its priority, and the messages it makes when you're stunned/examined, if any
- if(!islist(stun_absorption))
- stun_absorption = list()
- if(stun_absorption[key])
- stun_absorption[key]["end_time"] = world.time + duration
- stun_absorption[key]["priority"] = priority
- stun_absorption[key]["stuns_absorbed"] = 0
+/mob/living/acid_act(acidpwr, toxpwr, acid_volume)
+ take_bodypart_damage(min(10*toxpwr, acid_volume * toxpwr))
+
+
+/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0)
+ if(shock_damage > 0)
+ adjustFireLoss(shock_damage)
+ visible_message(
+ "[src] was shocked by \the [source]!", \
+ "You feel a powerful shock coursing through your body!", \
+ "You hear a heavy electrical crack." \
+ )
+ return shock_damage
+
+/mob/living/emp_act(severity)
+ var/list/L = src.get_contents()
+ for(var/obj/O in L)
+ O.emp_act(severity)
+ ..()
+
+/mob/living/singularity_act()
+ var/gain = 20
+ investigate_log("([key_name(src)]) has been consumed by the singularity.","singulo") //Oh that's where the clown ended up!
+ gib()
+ return(gain)
+
+/mob/living/narsie_act()
+ if(is_servant_of_ratvar(src) && !stat)
+ src << "You resist Nar-Sie's influence... but not all of it. Run!"
+ adjustBruteLoss(35)
+ if(src && reagents)
+ reagents.add_reagent("heparin", 5)
+ return 0
+ if(client)
+ makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, null, 0)
else
- stun_absorption[key] = list("end_time" = world.time + duration, "priority" = priority, "stuns_absorbed" = 0, \
- "visible_message" = message, "self_message" = self_message, "examine_message" = examine_message)
+ new /mob/living/simple_animal/hostile/construct/harvester/hostile(get_turf(src))
+ spawn_dust()
+ gib()
-/mob/living/Stun(amount, updating = 1, ignore_canstun = 0)
- if(!stat && islist(stun_absorption))
- var/priority_absorb_key
- var/highest_priority
- for(var/i in stun_absorption)
- if(stun_absorption[i]["end_time"] > world.time && (!priority_absorb_key || stun_absorption[i]["priority"] > highest_priority))
- priority_absorb_key = stun_absorption[i]
- highest_priority = stun_absorption[i]["priority"]
- if(priority_absorb_key)
- if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"])
- if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"])
- visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]")
- else if(priority_absorb_key["visible_message"])
- visible_message("[src][priority_absorb_key["visible_message"]]")
- else if(priority_absorb_key["self_message"])
- src << "[priority_absorb_key["self_message"]]"
- priority_absorb_key["stuns_absorbed"] += amount
- return 0
- ..()
-/mob/living/Weaken(amount, updating = 1, ignore_canweaken = 0)
- if(!stat && islist(stun_absorption))
- var/priority_absorb_key
- var/highest_priority
- for(var/i in stun_absorption)
- if(stun_absorption[i]["end_time"] > world.time && (!priority_absorb_key || stun_absorption[i]["priority"] > highest_priority))
- priority_absorb_key = stun_absorption[i]
- highest_priority = priority_absorb_key["priority"]
- if(priority_absorb_key)
- if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"])
- if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"])
- visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]")
- else if(priority_absorb_key["visible_message"])
- visible_message("[src][priority_absorb_key["visible_message"]]")
- else if(priority_absorb_key["self_message"])
- src << "[priority_absorb_key["self_message"]]"
- priority_absorb_key["stuns_absorbed"] += amount
- return 0
- ..()
+/mob/living/ratvar_act()
+ if(!add_servant_of_ratvar(src) && !is_servant_of_ratvar(src))
+ src << "A blinding light boils you alive! Run!"
+ adjustFireLoss(35)
+ if(src)
+ adjust_fire_stacks(1)
+ IgniteMob()
+
+
+//called when the mob receives a bright flash
+/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash)
+ if(get_eye_protection() < intensity && (override_blindness_check || !(disabilities & BLIND)))
+ overlay_fullscreen("flash", type)
+ addtimer(src, "clear_fullscreen", 25, FALSE, "flash", 25)
+ return 1
+
+//called when the mob receives a loud bang
+/mob/living/proc/soundbang_act()
+ return 0
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index 06e5ad4ff7f..59ab34a98eb 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -92,11 +92,12 @@ var/list/crit_allowed_modes = list(MODE_WHISPER,MODE_CHANGELING,MODE_ALIEN)
if(message_mode != MODE_WHISPER) //whisper() calls treat_message(); double process results in "hisspering"
message = treat_message(message)
- spans += get_spans()
if(!message)
return
+ spans += get_spans()
+
//Log of what we've said, plain message, no spans or junk
say_log += message
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index b19c799ee37..7cd4e02e618 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -351,39 +351,9 @@ var/list/ai_list = list()
SSshuttle.cancelEvac(src)
return
-/mob/living/silicon/ai/blob_act(obj/effect/blob/B)
- if (stat != DEAD)
- adjustBruteLoss(60)
- updatehealth()
- return 1
- return 0
-
/mob/living/silicon/ai/restrained(ignore_grab)
. = 0
-/mob/living/silicon/ai/emp_act(severity)
- if (prob(30))
- switch(pick(1,2))
- if(1)
- view_core()
- if(2)
- SSshuttle.requestEvac(src,"ALERT: Energy surge detected in AI core! Station integrity may be compromised! Initiati--%m091#ar-BZZT")
- ..()
-
-/mob/living/silicon/ai/ex_act(severity, target)
- ..()
-
- switch(severity)
- if(1)
- gib()
- if(2)
- if (stat != DEAD)
- adjustBruteLoss(60)
- adjustFireLoss(60)
- if(3)
- if (stat != DEAD)
- adjustBruteLoss(30)
-
/mob/living/silicon/ai/Topic(href, href_list)
if(usr != src)
return
@@ -455,18 +425,6 @@ var/list/ai_list = list()
if(M)
M.transfer_ai(AI_MECH_HACK,src, usr) //Called om the mech itself.
-/mob/living/silicon/ai/bullet_act(obj/item/projectile/Proj)
- ..(Proj)
- updatehealth()
- return 2
-
-
-/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(!ticker || !ticker.mode)
- M << "You cannot attack people before the game has started."
- return
-
- ..()
/mob/living/silicon/ai/proc/switchCamera(obj/machinery/camera/C)
@@ -790,9 +748,6 @@ var/list/ai_list = list()
return //won't work if dead
set_autosay()
-/mob/living/silicon/ai/attack_slime(mob/living/simple_animal/slime/user)
- return
-
/mob/living/silicon/ai/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
if(!..())
return
@@ -809,14 +764,6 @@ var/list/ai_list = list()
src << "You have been downloaded to a mobile storage device. Remote device connection severed."
user << "Transfer successful: [name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory."
-/mob/living/silicon/ai/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
- return // no eyes, no flashing
-
-/mob/living/silicon/ai/attackby(obj/item/weapon/W, mob/user, params)
- if(W.force && W.damtype != STAMINA && src.stat != DEAD) //only sparks if real damage is dealt.
- spark_system.start()
- return ..()
-
/mob/living/silicon/ai/can_buckle()
return 0
diff --git a/code/modules/mob/living/silicon/ai/ai_defense.dm b/code/modules/mob/living/silicon/ai/ai_defense.dm
new file mode 100644
index 00000000000..771a6d7c2f5
--- /dev/null
+++ b/code/modules/mob/living/silicon/ai/ai_defense.dm
@@ -0,0 +1,55 @@
+
+/mob/living/silicon/ai/attacked_by(obj/item/I, mob/living/user, def_zone)
+ if(I.force && I.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt.
+ spark_system.start()
+ return ..()
+
+
+/mob/living/silicon/ai/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if(!ticker || !ticker.mode)
+ M << "You cannot attack people before the game has started."
+ return
+ ..()
+
+/mob/living/silicon/ai/attack_slime(mob/living/simple_animal/slime/user)
+ return //immune to slimes
+
+/mob/living/silicon/ai/blob_act(obj/effect/blob/B)
+ if (stat != DEAD)
+ adjustBruteLoss(60)
+ updatehealth()
+ return 1
+ return 0
+
+/mob/living/silicon/ai/emp_act(severity)
+ if (prob(30))
+ switch(pick(1,2))
+ if(1)
+ view_core()
+ if(2)
+ SSshuttle.requestEvac(src,"ALERT: Energy surge detected in AI core! Station integrity may be compromised! Initiati--%m091#ar-BZZT")
+ ..()
+
+/mob/living/silicon/ai/ex_act(severity, target)
+ ..()
+
+ switch(severity)
+ if(1)
+ gib()
+ if(2)
+ if (stat != DEAD)
+ adjustBruteLoss(60)
+ adjustFireLoss(60)
+ if(3)
+ if (stat != DEAD)
+ adjustBruteLoss(30)
+
+
+
+/mob/living/silicon/ai/bullet_act(obj/item/projectile/Proj)
+ ..(Proj)
+ updatehealth()
+ return 2
+
+/mob/living/silicon/ai/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
+ return // no eyes, no flashing
diff --git a/code/modules/mob/living/silicon/ai/life.dm b/code/modules/mob/living/silicon/ai/life.dm
index 0c3b45c2d5c..c4a68499d21 100644
--- a/code/modules/mob/living/silicon/ai/life.dm
+++ b/code/modules/mob/living/silicon/ai/life.dm
@@ -4,12 +4,12 @@
#define POWER_RESTORATION_APC_FOUND 3
/mob/living/silicon/ai/Life()
- if (src.stat == DEAD)
+ if (stat == DEAD)
return
else //I'm not removing that shitton of tabs, unneeded as they are. -- Urist
//Being dead doesn't mean your temperature never changes
- update_gravity(has_gravity())
+ update_gravity(mob_has_gravity())
if(malfhack && malfhack.aidisabled)
deltimer(malfhacking)
diff --git a/code/modules/mob/living/silicon/damage_procs.dm b/code/modules/mob/living/silicon/damage_procs.dm
new file mode 100644
index 00000000000..181a166bb54
--- /dev/null
+++ b/code/modules/mob/living/silicon/damage_procs.dm
@@ -0,0 +1,36 @@
+
+/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0)
+ var/hit_percent = (100-blocked)/100
+ if(!damage || (hit_percent <= 0))
+ return 0
+ switch(damagetype)
+ if(BRUTE)
+ adjustBruteLoss(damage * hit_percent)
+ if(BURN)
+ adjustFireLoss(damage * hit_percent)
+ return 1
+
+
+/mob/living/silicon/apply_effect(effect = 0,effecttype = STUN, blocked = 0)
+ return 0//The only effect that can hit them atm is flashes and they still directly edit so this works for now
+
+
+
+/mob/living/silicon/adjustToxLoss(amount, updating_health=1) //immune to tox damage
+ return 0
+
+/mob/living/silicon/setToxLoss(amount, updating_health=1)
+ return 0
+
+/mob/living/silicon/adjustCloneLoss(amount) //immune to clone damage
+ return 0
+
+/mob/living/silicon/setCloneLoss(amount, updating_health=1)
+ return 0
+
+/mob/living/silicon/adjustStaminaLoss(amount, updating_stamina = 1)//immune to stamina damage.
+ return
+
+/mob/living/silicon/setStaminaLoss(amount, updating_stamina = 1)
+ return
+
diff --git a/code/modules/mob/living/silicon/death.dm b/code/modules/mob/living/silicon/death.dm
index 02fb54012b1..ebd3067bb0a 100644
--- a/code/modules/mob/living/silicon/death.dm
+++ b/code/modules/mob/living/silicon/death.dm
@@ -1,5 +1,5 @@
/mob/living/silicon/spawn_gibs()
- robogibs(loc, viruses)
+ new /obj/effect/gibspawner/robot(loc,viruses)
/mob/living/silicon/spawn_dust()
new /obj/effect/decal/remains/robot(loc)
diff --git a/code/modules/mob/living/silicon/login.dm b/code/modules/mob/living/silicon/login.dm
index 87e348dd92c..e0c6708d564 100644
--- a/code/modules/mob/living/silicon/login.dm
+++ b/code/modules/mob/living/silicon/login.dm
@@ -3,5 +3,4 @@
ticker.mode.remove_cultist(mind, 0, 0)
ticker.mode.remove_revolutionary(mind, 0)
ticker.mode.remove_gangster(mind, remove_bosses=1)
- ticker.mode.remove_hog_follower(mind,0)
..()
diff --git a/code/modules/mob/living/silicon/pai/life.dm b/code/modules/mob/living/silicon/pai/life.dm
index 191f28d7c37..f934a959316 100644
--- a/code/modules/mob/living/silicon/pai/life.dm
+++ b/code/modules/mob/living/silicon/pai/life.dm
@@ -1,7 +1,7 @@
/mob/living/silicon/pai/Life()
- if (src.stat == DEAD)
+ if(stat == DEAD)
return
- if(src.cable)
+ if(cable)
if(get_dist(src, src.cable) > 1)
var/turf/T = get_turf(src.loc)
T.visible_message("[src.cable] rapidly retracts back into its spool.", "You hear a click and the sound of wire spooling rapidly.")
diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm
index ea83dce7e1d..018c05e9800 100644
--- a/code/modules/mob/living/silicon/pai/pai.dm
+++ b/code/modules/mob/living/silicon/pai/pai.dm
@@ -94,66 +94,11 @@
else
stat(null, text("Systems nonfunctional"))
-/mob/living/silicon/pai/blob_act(obj/effect/blob/B)
- return 0
-
/mob/living/silicon/pai/restrained(ignore_grab)
. = 0
-/mob/living/silicon/pai/emp_act(severity)
- // 20% chance to kill
- // Silence for 2 minutes
- // 33% chance to unbind
- // 33% chance to change prime directive (based on severity)
- // 33% chance of no additional effect
-
- if(prob(20))
- visible_message("A shower of sparks spray from [src]'s inner workings.", 3, "You hear and smell the ozone hiss of electrical sparks being expelled violently.", 2)
- return src.death(0)
-
- silence_time = world.timeofday + 120 * 10 // Silence for 2 minutes
- src << "Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete."
-
- switch(pick(1,2,3))
- if(1)
- src.master = null
- src.master_dna = null
- src << "You feel unbound."
- if(2)
- var/command
- if(severity == 1)
- command = pick("Serve", "Love", "Fool", "Entice", "Observe", "Judge", "Respect", "Educate", "Amuse", "Entertain", "Glorify", "Memorialize", "Analyze")
- else
- command = pick("Serve", "Kill", "Love", "Hate", "Disobey", "Devour", "Fool", "Enrage", "Entice", "Observe", "Judge", "Respect", "Disrespect", "Consume", "Educate", "Destroy", "Disgrace", "Amuse", "Entertain", "Ignite", "Glorify", "Memorialize", "Analyze")
- src.laws.zeroth = "[command] your master."
- src << "Pr1m3 d1r3c71v3 uPd473D."
- if(3)
- src << "You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all."
-
-/mob/living/silicon/pai/ex_act(severity, target)
- ..()
-
- switch(severity)
- if(1)
- if (src.stat != 2)
- adjustBruteLoss(100)
- adjustFireLoss(100)
- if(2)
- if (src.stat != 2)
- adjustBruteLoss(60)
- adjustFireLoss(60)
- if(3)
- if (src.stat != 2)
- adjustBruteLoss(30)
-
- return
-
-
// See software.dm for Topic()
-/mob/living/silicon/pai/UnarmedAttack(atom/A)//Stops runtimes due to attack_animal being the default
- return
-
/mob/living/silicon/pai/canUseTopic(atom/movable/M)
return 1
/*
diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm
new file mode 100644
index 00000000000..5cdbebfd995
--- /dev/null
+++ b/code/modules/mob/living/silicon/pai/pai_defense.dm
@@ -0,0 +1,49 @@
+
+/mob/living/silicon/pai/blob_act(obj/effect/blob/B)
+ return 0
+
+/mob/living/silicon/pai/emp_act(severity)
+ // 20% chance to kill
+ // Silence for 2 minutes
+ // 33% chance to unbind
+ // 33% chance to change prime directive (based on severity)
+ // 33% chance of no additional effect
+
+ if(prob(20))
+ visible_message("A shower of sparks spray from [src]'s inner workings.", 3, "You hear and smell the ozone hiss of electrical sparks being expelled violently.", 2)
+ return src.death(0)
+
+ silence_time = world.timeofday + 120 * 10 // Silence for 2 minutes
+ src << "Communication circuit overload. Shutting down and reloading communication circuits - speech and messaging functionality will be unavailable until the reboot is complete."
+
+ switch(pick(1,2,3))
+ if(1)
+ src.master = null
+ src.master_dna = null
+ src << "You feel unbound."
+ if(2)
+ var/command
+ if(severity == 1)
+ command = pick("Serve", "Love", "Fool", "Entice", "Observe", "Judge", "Respect", "Educate", "Amuse", "Entertain", "Glorify", "Memorialize", "Analyze")
+ else
+ command = pick("Serve", "Kill", "Love", "Hate", "Disobey", "Devour", "Fool", "Enrage", "Entice", "Observe", "Judge", "Respect", "Disrespect", "Consume", "Educate", "Destroy", "Disgrace", "Amuse", "Entertain", "Ignite", "Glorify", "Memorialize", "Analyze")
+ src.laws.zeroth = "[command] your master."
+ src << "Pr1m3 d1r3c71v3 uPd473D."
+ if(3)
+ src << "You feel an electric surge run through your circuitry and become acutely aware at how lucky you are that you can still feel at all."
+
+/mob/living/silicon/pai/ex_act(severity, target)
+ ..()
+
+ switch(severity)
+ if(1)
+ if (src.stat != 2)
+ adjustBruteLoss(100)
+ adjustFireLoss(100)
+ if(2)
+ if (src.stat != 2)
+ adjustBruteLoss(60)
+ adjustFireLoss(60)
+ if(3)
+ if (src.stat != 2)
+ adjustBruteLoss(30)
diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm
index ca980e86bf5..fa94450b748 100644
--- a/code/modules/mob/living/silicon/robot/death.dm
+++ b/code/modules/mob/living/silicon/robot/death.dm
@@ -1,7 +1,4 @@
-/mob/living/silicon/robot/spawn_gibs()
- robogibs(loc, viruses)
-
/mob/living/silicon/robot/gib_animation()
PoolOrNew(/obj/effect/overlay/temp/gib_animation, list(loc, "gibbed-r"))
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index 33f24c1dc0b..d0350a7a267 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -106,10 +106,6 @@
if(on_fire)
add_overlay(image("icon"='icons/mob/OnFire.dmi', "icon_state"="Generic_mob_burning"))
-/mob/living/silicon/robot/fire_act()
- if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
- IgniteMob()
-
/mob/living/silicon/robot/update_canmove()
if(stat || buckled || lockcharge)
canmove = 0
diff --git a/code/modules/mob/living/silicon/robot/login.dm b/code/modules/mob/living/silicon/robot/login.dm
index 30712e68b42..59bcff4fa60 100644
--- a/code/modules/mob/living/silicon/robot/login.dm
+++ b/code/modules/mob/living/silicon/robot/login.dm
@@ -6,4 +6,3 @@
if(mind)
ticker.mode.remove_revolutionary(mind)
ticker.mode.remove_gangster(mind,1,remove_bosses=1)
- ticker.mode.remove_hog_follower(mind, 0)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 63fd0413051..6f56ca375b9 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -14,7 +14,7 @@
var/custom_name = ""
var/braintype = "Cyborg"
var/modtype = "robot"
- var/obj/item/robot_parts/robot_suit/robot_suit = null //Used for deconstruction to remember what the borg was constructed out of..
+ var/obj/item/robot_suit/robot_suit = null //Used for deconstruction to remember what the borg was constructed out of..
var/obj/item/device/mmi/mmi = null
//Hud stuff
@@ -366,16 +366,6 @@
if(thruster_button)
thruster_button.icon_state = "ionpulse[ionpulse_on]"
-/mob/living/silicon/robot/blob_act(obj/effect/blob/B)
- if (stat != 2)
- adjustBruteLoss(60)
- updatehealth()
- return 1
- else
- gib()
- return 1
- return 0
-
/mob/living/silicon/robot/Stat()
..()
if(statpanel("Status"))
@@ -394,27 +384,6 @@
/mob/living/silicon/robot/restrained(ignore_grab)
. = 0
-/mob/living/silicon/robot/ex_act(severity, target)
- switch(severity)
- if(1)
- gib()
- return
- if(2)
- if (stat != 2)
- adjustBruteLoss(60)
- adjustFireLoss(60)
- if(3)
- if (stat != 2)
- adjustBruteLoss(30)
- return
-
-
-/mob/living/silicon/robot/bullet_act(var/obj/item/projectile/Proj)
- ..(Proj)
- updatehealth()
- if(prob(75) && Proj.damage > 0) spark_system.start()
- return 2
-
/mob/living/silicon/robot/triggerAlarm(class, area/A, O, obj/alarmsource)
if(alarmsource.z != z)
return
@@ -622,83 +591,6 @@
else
return ..()
-/mob/living/silicon/robot/attacked_by(obj/item/I, mob/living/user, def_zone)
- if(I.force && I.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt.
- spark_system.start()
- return ..()
-
-
-/mob/living/silicon/robot/emag_act(mob/user)
- if(user != src)//To prevent syndieborgs from emagging themselves
- if(!opened)//Cover is closed
- if(locked)
- user << "You emag the cover lock."
- locked = 0
- else
- user << "The cover is already unlocked!"
- return
- if(opened)//Cover is open
- if((world.time - 100) < emag_cooldown)
- return
-
- if(syndicate)
- user << "You emag [src]'s interface."
- src << "ALERT: Foreign software execution prevented."
- log_game("[key_name(user)] attempted to emag cyborg [key_name(src)] but they were a syndicate cyborg.")
- emag_cooldown = world.time
- return
-
- var/ai_is_antag = 0
- if(connected_ai && connected_ai.mind)
- if(connected_ai.mind.special_role)
- ai_is_antag = (connected_ai.mind.special_role == "traitor")
- if(ai_is_antag)
- user << "You emag [src]'s interface."
- src << "ALERT: Foreign software execution prevented."
- connected_ai << "ALERT: Cyborg unit \[[src]] successfuly defended against subversion."
- log_game("[key_name(user)] attempted to emag cyborg [key_name(src)] slaved to traitor AI [connected_ai].")
- emag_cooldown = world.time
- return
-
- if(wiresexposed)
- user << "You must unexpose the wires first!"
- return
- else
- emag_cooldown = world.time
- sleep(6)
- SetEmagged(1)
- SetLockdown(1) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown
- lawupdate = 0
- connected_ai = null
- user << "You emag [src]'s interface."
- message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.")
- log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
- clear_supplied_laws()
- clear_inherent_laws()
- clear_zeroth_law(0)
- laws = new /datum/ai_laws/syndicate_override
- var/time = time2text(world.realtime,"hh:mm:ss")
- lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])")
- set_zeroth_law("Only [user.real_name] and people they designate as being such are Syndicate Agents.")
- src << "ALERT: Foreign software detected."
- sleep(5)
- src << "Initiating diagnostics..."
- sleep(20)
- src << "SynBorg v1.7 loaded."
- sleep(5)
- src << "LAW SYNCHRONISATION ERROR"
- sleep(5)
- src << "Would you like to send a report to NanoTraSoft? Y/N"
- sleep(10)
- src << "> N"
- sleep(20)
- src << "ERRORERRORERROR"
- src << "Obey these laws:"
- laws.show_laws(src)
- src << "ALERT: [user.real_name] is your new master. Obey your new laws and their commands."
- SetLockdown(0)
- update_icons()
-
/mob/living/silicon/robot/verb/unlock_own_cover()
set category = "Robot Commands"
set name = "Unlock Cover"
@@ -712,65 +604,6 @@
update_icons()
usr << "You unlock your cover."
-/mob/living/silicon/robot/attack_alien(mob/living/carbon/alien/humanoid/M)
- if (M.a_intent =="disarm")
- if(!(lying))
- M.do_attack_animation(src)
- if(get_active_held_item())
- uneq_active()
- visible_message("[M] disarmed [src]!", \
- "[M] has disabled [src]'s active module!")
- add_logs(M, src, "disarmed")
- else
- Stun(2)
- step(src,get_dir(M,src))
- add_logs(M, src, "pushed")
- visible_message("[M] has forced back [src]!", \
- "[M] has forced back [src]!")
- playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1)
- else
- ..()
- return
-
-/mob/living/silicon/robot/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime shock
- flash_eyes()
- var/stunprob = M.powerlevel * 7 + 10
- if(prob(stunprob) && M.powerlevel >= 8)
- adjustBruteLoss(M.powerlevel * rand(6,10))
-
- var/damage = rand(1, 3)
-
- if(M.is_adult)
- damage = rand(20, 40)
- else
- damage = rand(5, 35)
- damage = round(damage / 2) // borgs recieve half damage
- adjustBruteLoss(damage)
- updatehealth()
-
- return
-
-/mob/living/silicon/robot/attack_hand(mob/living/carbon/human/user)
- add_fingerprint(user)
- if(opened && !wiresexposed && (!istype(user, /mob/living/silicon)))
- if(cell)
- cell.updateicon()
- cell.add_fingerprint(user)
- user.put_in_active_hand(cell)
- user << "You remove \the [cell]."
- cell = null
- update_icons()
- diag_hud_set_borgcell()
-
- if(!opened)
- if(..()) // hulk attack
- spark_system.start()
- spawn(0)
- step_away(src,user,15)
- sleep(3)
- step_away(src,user,15)
-
/mob/living/silicon/robot/proc/allowed(mob/M)
//check if it doesn't require any access at all
if(check_access(null))
@@ -952,9 +785,8 @@
if(isturf(tile))
tile.clean_blood()
for(var/A in tile)
- if(istype(A, /obj/effect))
- if(is_cleanable(A))
- qdel(A)
+ if(is_cleanable(A))
+ qdel(A)
else if(istype(A, /obj/item))
var/obj/item/cleaned_item = A
cleaned_item.clean_blood()
@@ -1136,14 +968,14 @@
robot_suit.head = null
robot_suit.updateicon()
else
- new /obj/item/robot_parts/robot_suit(T)
- new /obj/item/robot_parts/l_leg(T)
- new /obj/item/robot_parts/r_leg(T)
+ new /obj/item/robot_suit(T)
+ new /obj/item/bodypart/l_leg/robot(T)
+ new /obj/item/bodypart/r_leg/robot(T)
new /obj/item/stack/cable_coil(T, 1)
- new /obj/item/robot_parts/chest(T)
- new /obj/item/robot_parts/l_arm(T)
- new /obj/item/robot_parts/r_arm(T)
- new /obj/item/robot_parts/head(T)
+ new /obj/item/bodypart/chest/robot(T)
+ new /obj/item/bodypart/l_arm/robot(T)
+ new /obj/item/bodypart/r_arm/robot(T)
+ new /obj/item/bodypart/head/robot(T)
var/b
for(b=0, b!=2, b++)
var/obj/item/device/assembly/flash/handheld/F = new /obj/item/device/assembly/flash/handheld(T)
@@ -1287,22 +1119,6 @@
diag_hud_set_health()
update_health_hud()
-/mob/living/silicon/robot/fully_replace_character_name(oldname, newname)
- ..()
- if(oldname != real_name)
- notify_ai(3, oldname, newname)
- if(camera)
- camera.c_tag = real_name
- custom_name = newname
-
-/mob/living/silicon/robot/emp_act(severity)
- switch(severity)
- if(1)
- Stun(8)
- if(2)
- Stun(3)
- ..()
-
/mob/living/silicon/robot/revive(full_heal = 0, admin_revive = 0)
if(..()) //successfully ressuscitated from death
if(camera && !wires.is_cut(WIRE_CAMERA))
@@ -1313,6 +1129,13 @@
notify_ai(1)
. = 1
+/mob/living/silicon/robot/fully_replace_character_name(oldname, newname)
+ ..()
+ if(oldname != real_name)
+ notify_ai(3, oldname, newname)
+ if(camera)
+ camera.c_tag = real_name
+ custom_name = newname
/mob/living/silicon/robot/proc/ResetModule()
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
new file mode 100644
index 00000000000..7fa7a720d42
--- /dev/null
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -0,0 +1,182 @@
+
+
+/mob/living/silicon/robot/attacked_by(obj/item/I, mob/living/user, def_zone)
+ if(I.force && I.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt.
+ spark_system.start()
+ return ..()
+
+/mob/living/silicon/robot/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if (M.a_intent =="disarm")
+ if(!(lying))
+ M.do_attack_animation(src)
+ if(get_active_held_item())
+ uneq_active()
+ visible_message("[M] disarmed [src]!", \
+ "[M] has disabled [src]'s active module!")
+ add_logs(M, src, "disarmed")
+ else
+ Stun(2)
+ step(src,get_dir(M,src))
+ add_logs(M, src, "pushed")
+ visible_message("[M] has forced back [src]!", \
+ "[M] has forced back [src]!")
+ playsound(loc, 'sound/weapons/pierce.ogg', 50, 1, -1)
+ else
+ ..()
+ return
+
+/mob/living/silicon/robot/attack_slime(mob/living/simple_animal/slime/M)
+ if(..()) //successful slime shock
+ flash_act()
+ var/stunprob = M.powerlevel * 7 + 10
+ if(prob(stunprob) && M.powerlevel >= 8)
+ adjustBruteLoss(M.powerlevel * rand(6,10))
+
+ var/damage = rand(1, 3)
+
+ if(M.is_adult)
+ damage = rand(20, 40)
+ else
+ damage = rand(5, 35)
+ damage = round(damage / 2) // borgs recieve half damage
+ adjustBruteLoss(damage)
+ updatehealth()
+
+ return
+
+/mob/living/silicon/robot/attack_hand(mob/living/carbon/human/user)
+ add_fingerprint(user)
+ if(opened && !wiresexposed && (!istype(user, /mob/living/silicon)))
+ if(cell)
+ cell.updateicon()
+ cell.add_fingerprint(user)
+ user.put_in_active_hand(cell)
+ user << "You remove \the [cell]."
+ cell = null
+ update_icons()
+ diag_hud_set_borgcell()
+
+ if(!opened)
+ if(..()) // hulk attack
+ spark_system.start()
+ spawn(0)
+ step_away(src,user,15)
+ sleep(3)
+ step_away(src,user,15)
+
+/mob/living/silicon/robot/fire_act()
+ if(!on_fire) //Silicons don't gain stacks from hotspots, but hotspots can ignite them
+ IgniteMob()
+
+
+/mob/living/silicon/robot/emp_act(severity)
+ switch(severity)
+ if(1)
+ Stun(8)
+ if(2)
+ Stun(3)
+ ..()
+
+
+/mob/living/silicon/robot/emag_act(mob/user)
+ if(user != src)//To prevent syndieborgs from emagging themselves
+ if(!opened)//Cover is closed
+ if(locked)
+ user << "You emag the cover lock."
+ locked = 0
+ else
+ user << "The cover is already unlocked!"
+ return
+ if(opened)//Cover is open
+ if((world.time - 100) < emag_cooldown)
+ return
+
+ if(syndicate)
+ user << "You emag [src]'s interface."
+ src << "ALERT: Foreign software execution prevented."
+ log_game("[key_name(user)] attempted to emag cyborg [key_name(src)] but they were a syndicate cyborg.")
+ emag_cooldown = world.time
+ return
+
+ var/ai_is_antag = 0
+ if(connected_ai && connected_ai.mind)
+ if(connected_ai.mind.special_role)
+ ai_is_antag = (connected_ai.mind.special_role == "traitor")
+ if(ai_is_antag)
+ user << "You emag [src]'s interface."
+ src << "ALERT: Foreign software execution prevented."
+ connected_ai << "ALERT: Cyborg unit \[[src]] successfuly defended against subversion."
+ log_game("[key_name(user)] attempted to emag cyborg [key_name(src)] slaved to traitor AI [connected_ai].")
+ emag_cooldown = world.time
+ return
+
+ if(wiresexposed)
+ user << "You must unexpose the wires first!"
+ return
+ else
+ emag_cooldown = world.time
+ sleep(6)
+ SetEmagged(1)
+ SetLockdown(1) //Borgs were getting into trouble because they would attack the emagger before the new laws were shown
+ lawupdate = 0
+ connected_ai = null
+ user << "You emag [src]'s interface."
+ message_admins("[key_name_admin(user)] emagged cyborg [key_name_admin(src)]. Laws overridden.")
+ log_game("[key_name(user)] emagged cyborg [key_name(src)]. Laws overridden.")
+ clear_supplied_laws()
+ clear_inherent_laws()
+ clear_zeroth_law(0)
+ laws = new /datum/ai_laws/syndicate_override
+ var/time = time2text(world.realtime,"hh:mm:ss")
+ lawchanges.Add("[time] : [user.name]([user.key]) emagged [name]([key])")
+ set_zeroth_law("Only [user.real_name] and people they designate as being such are Syndicate Agents.")
+ src << "ALERT: Foreign software detected."
+ sleep(5)
+ src << "Initiating diagnostics..."
+ sleep(20)
+ src << "SynBorg v1.7 loaded."
+ sleep(5)
+ src << "LAW SYNCHRONISATION ERROR"
+ sleep(5)
+ src << "Would you like to send a report to NanoTraSoft? Y/N"
+ sleep(10)
+ src << "> N"
+ sleep(20)
+ src << "ERRORERRORERROR"
+ src << "Obey these laws:"
+ laws.show_laws(src)
+ src << "ALERT: [user.real_name] is your new master. Obey your new laws and their commands."
+ SetLockdown(0)
+ update_icons()
+
+
+/mob/living/silicon/robot/blob_act(obj/effect/blob/B)
+ if (stat != 2)
+ adjustBruteLoss(60)
+ updatehealth()
+ return 1
+ else
+ gib()
+ return 1
+ return 0
+
+/mob/living/silicon/robot/ex_act(severity, target)
+ switch(severity)
+ if(1)
+ gib()
+ return
+ if(2)
+ if (stat != 2)
+ adjustBruteLoss(60)
+ adjustFireLoss(60)
+ if(3)
+ if (stat != 2)
+ adjustBruteLoss(30)
+ return
+
+
+/mob/living/silicon/robot/bullet_act(var/obj/item/projectile/Proj)
+ ..(Proj)
+ updatehealth()
+ if(prob(75) && Proj.damage > 0) spark_system.start()
+ return 2
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index 34017a7c64e..7658a71c484 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -402,4 +402,4 @@
/datum/robot_energy_storage/medical
max_energy = 2500
recharge_rate = 250
- name = "Medical Synthesizer"
+ name = "Medical Synthesizer"
diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm
index 695ea3e4978..63d76801c78 100644
--- a/code/modules/mob/living/silicon/robot/robot_movement.dm
+++ b/code/modules/mob/living/silicon/robot/robot_movement.dm
@@ -11,7 +11,7 @@
/mob/living/silicon/robot/mob_negates_gravity()
return magpulse
-/mob/living/silicon/robot/has_gravity()
+/mob/living/silicon/robot/mob_has_gravity()
return ..() || mob_negates_gravity()
/mob/living/silicon/robot/experience_pressure_difference(pressure_difference, direction)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 981f17a4b5e..fe2f2c5a5d1 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -142,34 +142,6 @@
/mob/living/silicon/drop_item()
return
-/mob/living/silicon/emp_act(severity)
- switch(severity)
- if(1)
- src.take_organ_damage(20)
- if(2)
- src.take_organ_damage(10)
- src << "*BZZZT*"
- src << "Warning: Electromagnetic pulse detected."
- flash_eyes(affect_silicon = 1)
- ..()
-
-/mob/living/silicon/apply_damage(damage = 0,damagetype = BRUTE, def_zone = null, blocked = 0)
- blocked = (100-blocked)/100
- if(!damage || (blocked <= 0))
- return 0
- switch(damagetype)
- if(BRUTE)
- adjustBruteLoss(damage * blocked)
- if(BURN)
- adjustFireLoss(damage * blocked)
- else
- return 1
- updatehealth()
- return 1
-
-/mob/living/silicon/proc/damage_mob(brute = 0, fire = 0, tox = 0)
- return
-
/mob/living/silicon/can_inject(mob/user, error_msg)
if(error_msg)
user << "Their outer shell is too tough."
@@ -178,35 +150,6 @@
/mob/living/silicon/IsAdvancedToolUser()
return 1
-/mob/living/silicon/bullet_act(obj/item/projectile/Proj)
- if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
- adjustBruteLoss(Proj.damage)
- Proj.on_hit(src)
- return 2
-
-/mob/living/silicon/apply_effect(effect = 0,effecttype = STUN, blocked = 0)
- return 0//The only effect that can hit them atm is flashes and they still directly edit so this works for now
-/*
- if(!effect || (blocked >= 2))
- return 0
- switch(effecttype)
- if(STUN)
- stunned = max(stunned,(effect/(blocked+1)))
- if(WEAKEN)
- weakened = max(weakened,(effect/(blocked+1)))
- if(PARALYZE)
- paralysis = max(paralysis,(effect/(blocked+1)))
- if(IRRADIATE)
- radiation += min((effect - (effect*getarmor(null, "rad"))), 0)//Rads auto check armor
- if(STUTTER)
- stuttering = max(stuttering,(effect/(blocked+1)))
- if(EYE_BLUR)
- blur_eyes(effect/(blocked+1))
- if(DROWSY)
- drowsyness = max(drowsyness,(effect/(blocked+1)))
- updatehealth()
- return 1*/
-
/proc/islinked(mob/living/silicon/robot/bot, mob/living/silicon/ai/ai)
if(!istype(bot) || !istype(ai))
return 0
@@ -421,87 +364,10 @@
src << "Sensor augmentations disabled."
-/mob/living/silicon/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(..()) //if harm or disarm intent
- var/damage = 20
- if (prob(90))
- add_logs(M, src, "attacked")
- playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
- visible_message("[M] has slashed at [src]!", \
- "[M] has slashed at [src]!")
- if(prob(8))
- flash_eyes(affect_silicon = 1)
- add_logs(M, src, "attacked")
- adjustBruteLoss(damage)
- updatehealth()
- else
- playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
- visible_message("[M] took a swipe at [src]!", \
- "[M] took a swipe at [src]!")
-
-/mob/living/silicon/attack_animal(mob/living/simple_animal/M)
- if(..())
- var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- switch(M.melee_damage_type)
- if(BRUTE)
- adjustBruteLoss(damage)
- if(BURN)
- adjustFireLoss(damage)
- if(TOX)
- adjustToxLoss(damage)
- if(OXY)
- adjustOxyLoss(damage)
- if(CLONE)
- adjustCloneLoss(damage)
- if(STAMINA)
- adjustStaminaLoss(damage)
- updatehealth()
-
-/mob/living/silicon/attack_paw(mob/living/user)
- return attack_hand(user)
-
-/mob/living/silicon/attack_larva(mob/living/carbon/alien/larva/L)
- if(L.a_intent == "help")
- visible_message("[L.name] rubs its head against [src].")
-
-/mob/living/silicon/attack_hulk(mob/living/carbon/human/user)
- if(user.a_intent == "harm")
- ..(user, 1)
- adjustBruteLoss(rand(10, 15))
- playsound(loc, "punch", 25, 1, -1)
- visible_message("[user] has punched [src]!", \
- "[user] has punched [src]!")
- return 1
- return 0
-
-/mob/living/silicon/attack_hand(mob/living/carbon/human/M)
- switch(M.a_intent)
- if ("help")
- M.visible_message("[M] pets [src].", \
- "You pet [src].")
- if("grab")
- grabbedby(M)
- else
- M.do_attack_animation(src)
- playsound(src.loc, 'sound/effects/bang.ogg', 10, 1)
- visible_message("[M] punches [src], but doesn't leave a dent.", \
- "[M] punches [src], but doesn't leave a dent.")
- return 0
-
/mob/living/silicon/proc/GetPhoto()
if (aicamera)
return aicamera.selectpicture(aicamera)
-/mob/living/silicon/grippedby(mob/living/user)
- return
-
-/mob/living/silicon/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/noise)
- if(affect_silicon)
- return ..()
-
-/mob/living/silicon/check_ear_prot()
- return 1
-
/mob/living/silicon/update_transform()
var/matrix/ntransform = matrix(transform) //aka transform.Copy()
var/changed = 0
@@ -516,6 +382,3 @@
/mob/living/silicon/is_literate()
return 1
-
-/mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0)
- return 0
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
new file mode 100644
index 00000000000..b216c04e1ab
--- /dev/null
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -0,0 +1,97 @@
+
+/mob/living/silicon/grippedby(mob/living/user)
+ return //can't upgrade a simple pull into a more aggressive grab.
+
+/mob/living/silicon/get_ear_protection()//no ears
+ return 2
+
+/mob/living/silicon/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if(..()) //if harm or disarm intent
+ var/damage = 20
+ if (prob(90))
+ add_logs(M, src, "attacked")
+ playsound(loc, 'sound/weapons/slash.ogg', 25, 1, -1)
+ visible_message("[M] has slashed at [src]!", \
+ "[M] has slashed at [src]!")
+ if(prob(8))
+ flash_act(affect_silicon = 1)
+ add_logs(M, src, "attacked")
+ adjustBruteLoss(damage)
+ updatehealth()
+ else
+ playsound(loc, 'sound/weapons/slashmiss.ogg', 25, 1, -1)
+ visible_message("[M] took a swipe at [src]!", \
+ "[M] took a swipe at [src]!")
+
+/mob/living/silicon/attack_animal(mob/living/simple_animal/M)
+ if(..())
+ var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
+ switch(M.melee_damage_type)
+ if(BRUTE)
+ adjustBruteLoss(damage)
+ if(BURN)
+ adjustFireLoss(damage)
+ if(TOX)
+ adjustToxLoss(damage)
+ if(OXY)
+ adjustOxyLoss(damage)
+ if(CLONE)
+ adjustCloneLoss(damage)
+ if(STAMINA)
+ adjustStaminaLoss(damage)
+ updatehealth()
+
+/mob/living/silicon/attack_paw(mob/living/user)
+ return attack_hand(user)
+
+/mob/living/silicon/attack_larva(mob/living/carbon/alien/larva/L)
+ if(L.a_intent == "help")
+ visible_message("[L.name] rubs its head against [src].")
+
+/mob/living/silicon/attack_hulk(mob/living/carbon/human/user)
+ if(user.a_intent == "harm")
+ ..(user, 1)
+ adjustBruteLoss(rand(10, 15))
+ playsound(loc, "punch", 25, 1, -1)
+ visible_message("[user] has punched [src]!", \
+ "[user] has punched [src]!")
+ return 1
+ return 0
+
+/mob/living/silicon/attack_hand(mob/living/carbon/human/M)
+ switch(M.a_intent)
+ if ("help")
+ M.visible_message("[M] pets [src].", \
+ "You pet [src].")
+ if("grab")
+ grabbedby(M)
+ else
+ M.do_attack_animation(src)
+ playsound(src.loc, 'sound/effects/bang.ogg', 10, 1)
+ visible_message("[M] punches [src], but doesn't leave a dent.", \
+ "[M] punches [src], but doesn't leave a dent.")
+ return 0
+
+/mob/living/silicon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0)
+ return 0 //So borgs they don't die trying to fix wiring
+
+/mob/living/silicon/emp_act(severity)
+ switch(severity)
+ if(1)
+ src.take_bodypart_damage(20)
+ if(2)
+ src.take_bodypart_damage(10)
+ src << "*BZZZT*"
+ src << "Warning: Electromagnetic pulse detected."
+ flash_act(affect_silicon = 1)
+ ..()
+
+/mob/living/silicon/bullet_act(obj/item/projectile/Proj)
+ if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
+ adjustBruteLoss(Proj.damage)
+ Proj.on_hit(src)
+ return 2
+
+/mob/living/silicon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash/noise)
+ if(affect_silicon)
+ return ..()
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
new file mode 100644
index 00000000000..53dd3b50454
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -0,0 +1,117 @@
+
+
+/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M)
+ ..()
+ switch(M.a_intent)
+
+ if("help")
+ if (health > 0)
+ visible_message("[M] [response_help] [src].")
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+
+ if("grab")
+ grabbedby(M)
+
+ if("harm", "disarm")
+ M.do_attack_animation(src)
+ visible_message("[M] [response_harm] [src]!")
+ playsound(loc, attacked_sound, 25, 1, -1)
+ attack_threshold_check(harm_intent_damage)
+ add_logs(M, src, "attacked")
+ updatehealth()
+ return 1
+
+/mob/living/simple_animal/attack_paw(mob/living/carbon/monkey/M)
+ if(..()) //successful monkey bite.
+ if(stat != DEAD)
+ var/damage = rand(1, 3)
+ attack_threshold_check(damage)
+ return 1
+ if (M.a_intent == "help")
+ if (health > 0)
+ visible_message("[M.name] [response_help] [src].")
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+
+
+/mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if(..()) //if harm or disarm intent.
+ if(M.a_intent == "disarm")
+ playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
+ visible_message("[M] [response_disarm] [name]!", \
+ "[M] [response_disarm] [name]!")
+ add_logs(M, src, "disarmed")
+ else
+ var/damage = rand(15, 30)
+ visible_message("[M] has slashed at [src]!", \
+ "[M] has slashed at [src]!")
+ playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
+ attack_threshold_check(damage)
+ add_logs(M, src, "attacked")
+ return 1
+
+/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L)
+ if(..()) //successful larva bite
+ var/damage = rand(5, 10)
+ if(stat != DEAD)
+ L.amount_grown = min(L.amount_grown + damage, L.max_grown)
+ attack_threshold_check(damage)
+ return 1
+
+/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M)
+ if(..())
+ var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
+ attack_threshold_check(damage,M.melee_damage_type)
+ return 1
+
+/mob/living/simple_animal/attack_slime(mob/living/simple_animal/slime/M)
+ if(..()) //successful slime attack
+ var/damage = rand(15, 25)
+ if(M.is_adult)
+ damage = rand(20, 35)
+ attack_threshold_check(damage)
+ return 1
+
+/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE)
+ if(!damage_coeff[damagetype])
+ damage = 0
+ else
+ damage *= damage_coeff[damagetype]
+
+ if(damage >= 0 && damage <= force_threshold)
+ visible_message("[src] looks unharmed.")
+ else
+ adjustHealth(damage * config.damage_multiplier)
+
+
+/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj)
+ if(!Proj)
+ return
+ apply_damage(Proj.damage, Proj.damage_type)
+ Proj.on_hit(src)
+ return 0
+
+/mob/living/simple_animal/ex_act(severity, target)
+ ..()
+ var/bomb_armor = getarmor(null, "bomb")
+ switch (severity)
+ if (1)
+ if(prob(bomb_armor))
+ adjustBruteLoss(500)
+ else
+ gib()
+ return
+ if (2)
+ var/bloss = 60
+ if(prob(bomb_armor))
+ bloss = bloss / 1.5
+ adjustBruteLoss(bloss)
+
+ if(3)
+ var/bloss = 30
+ if(prob(bomb_armor))
+ bloss = bloss / 1.5
+ adjustBruteLoss(bloss)
+
+/mob/living/simple_animal/blob_act(obj/effect/blob/B)
+ adjustBruteLoss(20)
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index 4cf22a7acda..d3cc4116ffb 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -257,7 +257,7 @@
new /obj/item/device/assembly/prox_sensor(Tsec)
if(prob(50))
- new /obj/item/robot_parts/l_arm(Tsec)
+ new /obj/item/bodypart/l_arm/robot(Tsec)
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, 1, src)
diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm
index cc05c511030..63a58a5f705 100644
--- a/code/modules/mob/living/simple_animal/bot/construction.dm
+++ b/code/modules/mob/living/simple_animal/bot/construction.dm
@@ -15,7 +15,7 @@
/obj/item/weapon/bucket_sensor/attackby(obj/item/W, mob/user as mob, params)
..()
- if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
+ if(istype(W, /obj/item/bodypart/l_arm/robot) || istype(W, /obj/item/bodypart/r_arm/robot))
if(!user.unEquip(W))
return
qdel(W)
@@ -60,7 +60,7 @@
switch(build_step)
if(0,1)
- if(istype(W, /obj/item/robot_parts/l_leg) || istype(W, /obj/item/robot_parts/r_leg))
+ if(istype(W, /obj/item/bodypart/l_leg/robot) || istype(W, /obj/item/bodypart/r_leg/robot))
if(!user.unEquip(W))
return
qdel(W)
@@ -261,7 +261,7 @@
/obj/item/weapon/toolbox_tiles_sensor/attackby(obj/item/W, mob/user, params)
..()
- if(istype(W, /obj/item/robot_parts/l_arm) || istype(W, /obj/item/robot_parts/r_arm))
+ if(istype(W, /obj/item/bodypart/l_arm/robot) || istype(W, /obj/item/bodypart/r_arm/robot))
qdel(W)
var/turf/T = get_turf(user.loc)
var/mob/living/simple_animal/bot/floorbot/A = new /mob/living/simple_animal/bot/floorbot(T)
@@ -295,11 +295,10 @@
if(skin)
add_overlay(image('icons/obj/aibots.dmi', "kit_skin_[skin]"))
-/obj/item/weapon/storage/firstaid/attackby(obj/item/robot_parts/S, mob/user, params)
+/obj/item/weapon/storage/firstaid/attackby(obj/item/bodypart/S, mob/user, params)
- if((!istype(S, /obj/item/robot_parts/l_arm)) && (!istype(S, /obj/item/robot_parts/r_arm)))
- ..()
- return
+ if((!istype(S, /obj/item/bodypart/l_arm/robot)) && (!istype(S, /obj/item/bodypart/r_arm/robot)))
+ return ..()
//Making a medibot!
if(contents.len >= 1)
@@ -416,7 +415,7 @@
name = "helmet/signaler/prox sensor assembly"
qdel(I)
- else if(((istype(I, /obj/item/robot_parts/l_arm)) || (istype(I, /obj/item/robot_parts/r_arm))) && (build_step == 2))
+ else if(((istype(I, /obj/item/bodypart/l_arm/robot)) || (istype(I, /obj/item/bodypart/r_arm/robot))) && (build_step == 2))
if(!user.unEquip(I))
return
build_step++
@@ -459,6 +458,6 @@
else if(build_step == 3)
overlays -= "hs_arm"
- new /obj/item/robot_parts/l_arm(get_turf(src))
+ new /obj/item/bodypart/l_arm/robot(get_turf(src))
user << "You remove the robot arm from [src]."
build_step--
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/bot/ed209bot.dm b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
index d19ce2687a2..fa4e69cf5ee 100644
--- a/code/modules/mob/living/simple_animal/bot/ed209bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/ed209bot.dm
@@ -376,9 +376,9 @@ Auto Patrol[]"},
G.update_icon()
if(prob(50))
- new /obj/item/robot_parts/l_leg(Tsec)
+ new /obj/item/bodypart/l_leg/robot(Tsec)
if(prob(25))
- new /obj/item/robot_parts/r_leg(Tsec)
+ new /obj/item/bodypart/r_leg/robot(Tsec)
if(prob(25))//50% chance for a helmet OR vest
if(prob(50))
new /obj/item/clothing/head/helmet(Tsec)
diff --git a/code/modules/mob/living/simple_animal/bot/floorbot.dm b/code/modules/mob/living/simple_animal/bot/floorbot.dm
index 8956f7872a6..1d276b2bf3b 100644
--- a/code/modules/mob/living/simple_animal/bot/floorbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/floorbot.dm
@@ -376,7 +376,7 @@
empty_tiles()
if(prob(50))
- new /obj/item/robot_parts/l_arm(Tsec)
+ new /obj/item/bodypart/l_arm/robot(Tsec)
var/obj/item/stack/tile/plasteel/T = new (Tsec)
T.amount = 1
diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm
index fdf5215ebc3..4d92739db83 100644
--- a/code/modules/mob/living/simple_animal/bot/medbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/medbot.dm
@@ -514,7 +514,7 @@
reagent_glass = null
if(prob(50))
- new /obj/item/robot_parts/l_arm(Tsec)
+ new /obj/item/bodypart/l_arm/robot(Tsec)
if(emagged && prob(25))
playsound(loc, 'sound/voice/minsult.ogg', 50, 0)
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index b9d4a7e313d..69be54689f6 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -383,7 +383,7 @@ Auto Patrol: []"},
new /obj/item/weapon/melee/baton(Tsec)
if(prob(50))
- new /obj/item/robot_parts/l_arm(Tsec)
+ new /obj/item/bodypart/l_arm/robot(Tsec)
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, 1, src)
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index a26f78cecf2..af34d8a989f 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -55,7 +55,7 @@
if(health < maxHealth)
adjustHealth(-5)
if(src != M)
- Beam(M,icon_state="sendbeam",icon='icons/effects/effects.dmi',time=4)
+ Beam(M,icon_state="sendbeam",time=4)
M.visible_message("[M] repairs some of \the [src]'s dents.", \
"You repair some of [src]'s dents, leaving [src] at [health]/[maxHealth] health.")
else
diff --git a/code/modules/mob/living/simple_animal/damage_procs.dm b/code/modules/mob/living/simple_animal/damage_procs.dm
new file mode 100644
index 00000000000..b39bc1bbe19
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/damage_procs.dm
@@ -0,0 +1,30 @@
+
+/mob/living/simple_animal/proc/adjustHealth(amount)
+ if(status_flags & GODMODE)
+ return 0
+ bruteloss = Clamp(bruteloss + amount, 0, maxHealth)
+ updatehealth()
+ return amount
+
+/mob/living/simple_animal/adjustBruteLoss(amount)
+ if(damage_coeff[BRUTE])
+ . = adjustHealth(amount * damage_coeff[BRUTE] * config.damage_multiplier)
+
+/mob/living/simple_animal/adjustFireLoss(amount)
+ if(damage_coeff[BURN])
+ . = adjustHealth(amount * damage_coeff[BURN] * config.damage_multiplier)
+
+/mob/living/simple_animal/adjustOxyLoss(amount)
+ if(damage_coeff[OXY])
+ . = adjustHealth(amount * damage_coeff[OXY] * config.damage_multiplier)
+
+/mob/living/simple_animal/adjustToxLoss(amount)
+ if(damage_coeff[TOX])
+ . = adjustHealth(amount * damage_coeff[TOX] * config.damage_multiplier)
+
+/mob/living/simple_animal/adjustCloneLoss(amount)
+ if(damage_coeff[CLONE])
+ . = adjustHealth(amount * damage_coeff[CLONE] * config.damage_multiplier)
+
+/mob/living/simple_animal/adjustStaminaLoss(amount)
+ return
diff --git a/code/modules/mob/living/simple_animal/friendly/cockroach.dm b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
index 9d6a9ab7f64..fc4045ae569 100644
--- a/code/modules/mob/living/simple_animal/friendly/cockroach.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cockroach.dm
@@ -53,4 +53,3 @@
icon = 'icons/effects/blood.dmi'
icon_state = "xfloor1"
random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
- layer = ABOVE_OPEN_TURF_LAYER
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
index 35b363ae285..fb94224fbbf 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/_drone.dm
@@ -46,7 +46,7 @@
staticOverlays = list()
hud_possible = list(DIAG_STAT_HUD, DIAG_HUD, ANTAG_HUD)
unique_name = TRUE
- faction = list("silicon")
+ faction = list("neutral","silicon")
dextrous = TRUE
dextrous_hud_type = /datum/hud/dextrous/drone
var/staticChoice = "static"
@@ -238,14 +238,14 @@
/mob/living/simple_animal/drone/handle_temperature_damage()
return
-/mob/living/simple_animal/drone/flash_eyes(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
+/mob/living/simple_animal/drone/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0)
if(affect_silicon)
return ..()
/mob/living/simple_animal/drone/mob_negates_gravity()
return 1
-/mob/living/simple_animal/drone/has_gravity()
+/mob/living/simple_animal/drone/mob_has_gravity()
return ..() || mob_negates_gravity()
/mob/living/simple_animal/drone/experience_pressure_difference(pressure_difference, direction)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
index b95e845d563..d3d99174436 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
@@ -6,60 +6,52 @@
//How the world interacts with drones
-/mob/living/simple_animal/drone/UnarmedAttack(atom/A, proximity)
- A.attack_hand(src)
+/mob/living/simple_animal/drone/attack_drone(mob/living/simple_animal/drone/D)
+ if(D != src && stat == DEAD)
+ var/d_input = alert(D,"Perform which action?","Drone Interaction","Reactivate","Cannibalize","Nothing")
+ if(d_input)
+ switch(d_input)
+ if("Reactivate")
+ var/mob/dead/observer/G = get_ghost()
+ if(!client && (!G || !G.client))
+ var/list/faux_gadgets = list("hypertext inflator","failsafe directory","DRM switch","stack initializer",\
+ "anti-freeze capacitor","data stream diode","TCP bottleneck","supercharged I/O bolt",\
+ "tradewind stablizer","radiated XML cable","registry fluid tank","open-source debunker")
+
+ var/list/faux_problems = list("won't be able to tune their bootstrap projector","will constantly remix their binary pool"+\
+ " even though the BMX calibrator is working","will start leaking their XSS coolant",\
+ "can't tell if their ethernet detour is moving or not", "won't be able to reseed enough"+\
+ " kernels to function properly","can't start their neurotube console")
+
+ D << "You can't seem to find the [pick(faux_gadgets)]! Without it, [src] [pick(faux_problems)]."
+ return
+ D.visible_message("[D] begins to reactivate [src].", "You begin to reactivate [src]...")
+ if(do_after(D,30, 1, target = src))
+ revive(full_heal = 1)
+ D.visible_message("[D] reactivates [src]!", "You reactivate [src].")
+ alert_drones(DRONE_NET_CONNECT)
+ if(G)
+ G << "DRONE NETWORK: You were reactivated by [D]!"
+ else
+ D << "You need to remain still to reactivate [src]!"
+
+ if("Cannibalize")
+ if(D.health < D.maxHealth)
+ D.visible_message("[D] begins to cannibalize parts from [src].", "You begin to cannibalize parts from [src]...")
+ if(do_after(D, 60, 0, target = src))
+ D.visible_message("[D] repairs itself using [src]'s remains!", "You repair yourself using [src]'s remains.")
+ D.adjustBruteLoss(-src.maxHealth)
+ new /obj/effect/decal/cleanable/oil/streak(get_turf(src))
+ qdel(src)
+ else
+ D << "You need to remain still to cannibalize [src]!"
+ else
+ D << "You're already in perfect condition!"
+ if("Nothing")
+ return
/mob/living/simple_animal/drone/attack_hand(mob/user)
- if(isdrone(user))
- var/mob/living/simple_animal/drone/D = user
- if(D != src)
- if(stat == DEAD)
- var/d_input = alert(D,"Perform which action?","Drone Interaction","Reactivate","Cannibalize","Nothing")
- if(d_input)
- switch(d_input)
- if("Reactivate")
- var/mob/dead/observer/G = get_ghost()
- if(!client && (!G || !G.client))
- var/list/faux_gadgets = list("hypertext inflator","failsafe directory","DRM switch","stack initializer",\
- "anti-freeze capacitor","data stream diode","TCP bottleneck","supercharged I/O bolt",\
- "tradewind stablizer","radiated XML cable","registry fluid tank","open-source debunker")
-
- var/list/faux_problems = list("won't be able to tune their bootstrap projector","will constantly remix their binary pool"+\
- " even though the BMX calibrator is working","will start leaking their XSS coolant",\
- "can't tell if their ethernet detour is moving or not", "won't be able to reseed enough"+\
- " kernels to function properly","can't start their neurotube console")
-
- D << "You can't seem to find the [pick(faux_gadgets)]! Without it, [src] [pick(faux_problems)]."
- return
- D.visible_message("[D] begins to reactivate [src].", "You begin to reactivate [src]...")
- if(do_after(user,30, 1, target = src))
- revive(full_heal = 1)
- D.visible_message("[D] reactivates [src]!", "You reactivate [src].")
- alert_drones(DRONE_NET_CONNECT)
- if(G)
- G << "DRONE NETWORK: You were reactivated by [D]!"
- else
- D << "You need to remain still to reactivate [src]!"
-
- if("Cannibalize")
- if(D.health < D.maxHealth)
- D.visible_message("[D] begins to cannibalize parts from [src].", "You begin to cannibalize parts from [src]...")
- if(do_after(D, 60, 0, target = src))
- D.visible_message("[D] repairs itself using [src]'s remains!", "You repair yourself using [src]'s remains.")
- D.adjustBruteLoss(-src.maxHealth)
- new /obj/effect/decal/cleanable/oil/streak(get_turf(src))
- qdel(src)
- else
- D << "You need to remain still to cannibalize [src]!"
- else
- D << "You're already in perfect condition!"
- if("Nothing")
- return
-
- return
-
-
if(ishuman(user))
if(stat == DEAD || status_flags & GODMODE)
..()
@@ -83,9 +75,7 @@
DH.drone = src
user.put_in_hands(DH)
forceMove(DH)
- return
- ..()
/mob/living/simple_animal/drone/attackby(obj/item/I, mob/user)
diff --git a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm
index 38a03707ef2..a37b4788297 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/lightning.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/lightning.dm
@@ -30,7 +30,7 @@
var/datum/beam/C = pick(enemychains)
qdel(C)
enemychains -= C
- enemychains += Beam(target,"lightning[rand(1,12)]",'icons/effects/effects.dmi',70, 7,/obj/effect/ebeam/chain)
+ enemychains += Beam(target, "lightning[rand(1,12)]", time=70, maxdistance=7, beam_type=/obj/effect/ebeam/chain)
/mob/living/simple_animal/hostile/guardian/beam/Destroy()
removechains()
@@ -39,7 +39,7 @@
/mob/living/simple_animal/hostile/guardian/beam/Manifest()
if(..())
if(summoner)
- summonerchain = Beam(summoner,"lightning[rand(1,12)]",'icons/effects/effects.dmi',INFINITY, INFINITY,/obj/effect/ebeam/chain)
+ summonerchain = Beam(summoner, "lightning[rand(1,12)]", time=INFINITY, maxdistance=INFINITY, beam_type=/obj/effect/ebeam/chain)
while(loc != summoner)
if(successfulshocks > 5)
successfulshocks = 0
@@ -57,7 +57,7 @@
if(summonerchain && !qdeleted(summonerchain))
. += chainshock(summonerchain)
else
- summonerchain = Beam(summoner,"lightning[rand(1,12)]",'icons/effects/effects.dmi',INFINITY, INFINITY,/obj/effect/ebeam/chain)
+ summonerchain = Beam(summoner, "lightning[rand(1,12)]", time=INFINITY, maxdistance=INFINITY, beam_type=/obj/effect/ebeam/chain)
if(enemychains.len)
for(var/chain in enemychains)
if(!qdeleted(chain))
diff --git a/code/modules/mob/living/simple_animal/guardian/types/support.dm b/code/modules/mob/living/simple_animal/guardian/types/support.dm
index 889ab1803ca..a7a204af676 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/support.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/support.dm
@@ -148,7 +148,7 @@
PoolOrNew(/obj/effect/overlay/temp/guardian/phase/out, T)
if(isliving(A))
var/mob/living/L = A
- L.flash_eyes()
+ L.flash_act()
A.visible_message("[A] disappears in a flash of \
light!", "Your vision is obscured \
by a flash of light!")
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index 013a77e81d1..f5c9269c0d9 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -27,6 +27,7 @@
var/ranged_message = "fires" //Fluff text for ranged mobs
var/ranged_cooldown = 0 //What the current cooldown on ranged attacks is, generally world.time + ranged_cooldown_time
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
@@ -53,6 +54,10 @@
environment_target_typecache = typecacheof(environment_target_typecache)
+/mob/living/simple_animal/hostile/Destroy()
+ targets_from = null
+ return ..()
+
/mob/living/simple_animal/hostile/Life()
. = ..()
if(!.) //dead
@@ -225,12 +230,14 @@
else
Goto(target,move_to_delay,minimum_distance)
if(target)
- if(isturf(targets_from.loc) && target.Adjacent(targets_from)) //If they're next to us, attack
+ 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(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()
@@ -256,12 +263,6 @@
else if(target != null && prob(40))//No more pulling a mob forever and having a second player attack it, it can switch targets now if it finds a more suitable one
FindTarget()
-/mob/living/simple_animal/hostile/UnarmedAttack(atom/A)
- target = A
- if(dextrous && !is_type_in_typecache(A, environment_target_typecache) && !ismob(A))
- ..()
- else
- AttackingTarget()
/mob/living/simple_animal/hostile/proc/AttackingTarget()
target.attack_animal(src)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index c3a657616f8..b64463f3b7c 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -9,15 +9,15 @@ 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 often charges, dealing massive damage to anything unfortunate enough to be standing where it's aiming.
-Whenever it isn't chasing something down, it will sink into nearby blood pools (if possible) and springs out of the closest one to its target.
-To make this possible, it sprays streams of blood at random.
-From these blood pools Bubblegum may summon slaughterlings - weak, low-damage minions designed to impede the target's progress.
+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 slaughter demon spawner
- 2. A bottle that, when activated, drives everyone nearby into a frenzy
- 3. A contract that marks for death the chosen target
+ 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
@@ -45,6 +45,7 @@ Difficulty: Hard
pixel_x = -32
del_on_death = 1
loot = list(/obj/structure/closet/crate/necropolis/bubblegum)
+ blood_volume = BLOOD_VOLUME_MAXIMUM //BLEED FOR ME
var/charging = 0
medal_type = MEDAL_PREFIX
score_type = BUBBLEGUM_SCORE
@@ -57,6 +58,12 @@ Difficulty: Hard
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(33))
+ var/obj/effect/decal/cleanable/blood/B = new /obj/effect/decal/cleanable/blood(loc)
+ B.bloodiness = 20
+ . = ..()
+
/mob/living/simple_animal/hostile/megafauna/bubblegum/Life()
..()
move_to_delay = Clamp(round((health/maxHealth) * 10), 5, 10)
@@ -67,18 +74,21 @@ Difficulty: Hard
return
ranged_cooldown = world.time + ranged_cooldown_time
- blood_warp()
-
- if(prob(25))
+ var/warped = FALSE
+ if(!try_bloodattack())
addtimer(src, "blood_spray", 0)
+ warped = blood_warp()
+ if(warped && prob(100 - anger_modifier))
+ return
- else if(prob(5+anger_modifier/2))
- slaughterlings()
- else
- if(health > maxHealth/2 && !client)
+ if(prob(90 - anger_modifier) || slaughterlings())
+ if(health > maxHealth * 0.5 || client)
addtimer(src, "charge", 0)
else
- addtimer(src, "triple_charge", 0)
+ if(prob(70) || warped)
+ addtimer(src, "triple_charge", 0)
+ else
+ addtimer(src, "warp_charge", 0)
/mob/living/simple_animal/hostile/megafauna/bubblegum/New()
@@ -109,20 +119,22 @@ Difficulty: Hard
..()
/mob/living/simple_animal/hostile/megafauna/bubblegum/Move()
- if(!stat)
- playsound(src.loc, 'sound/effects/meteorimpact.ogg', 200, 1, 2, 1)
if(charging)
PoolOrNew(/obj/effect/overlay/temp/decoy/fading, list(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()
- sleep(10)
charge()
- sleep(10)
charge()
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/charge()
@@ -135,11 +147,11 @@ Difficulty: Hard
walk(src, 0)
setDir(get_dir(src, T))
var/obj/effect/overlay/temp/decoy/D = PoolOrNew(/obj/effect/overlay/temp/decoy, list(loc,src))
- D.color = "#FF0000"
- animate(D, alpha = 0, color = initial(D.color), transform = matrix()*2, time = 5)
+ 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()
Goto(target, move_to_delay, minimum_distance)
@@ -167,17 +179,132 @@ Difficulty: Hard
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
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack()
+ var/list/targets = get_mobs_on_blood()
+ if(targets.len)
+ addtimer(src, "bloodattack", 0, FALSE, targets)
+
+ return TRUE
+ return FALSE
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodattack(list/targets)
+ 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))
+ PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightpaw, target_two_turf)
+ PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightthumb, target_two_turf)
+ bloodgrab(target_two_turf)
+ else
+ PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightsmack, target_two_turf)
+ bloodsmack(target_two_turf)
+
+ var/list/pools = get_pools(get_turf(target_one), 0)
+ if(pools.len)
+ target_one_turf = get_turf(target_one)
+ if(target_one.stat != CONSCIOUS || prob(10))
+ PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/leftpaw, target_one_turf)
+ PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/leftthumb, target_one_turf)
+ bloodgrab(target_one_turf)
+ else
+ PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/leftsmack, target_one_turf)
+ bloodsmack(target_one_turf)
+
+ if(!target_two && target_one)
+ pools = get_pools(get_turf(target_one), 0)
+ if(pools.len)
+ target_one_turf = get_turf(target_one)
+ if(target_one.stat != CONSCIOUS || prob(10))
+ PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightpaw, target_one_turf)
+ PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightthumb, target_one_turf)
+ bloodgrab(target_one_turf)
+ else
+ PoolOrNew(/obj/effect/overlay/temp/bubblegum_hands/rightsmack, target_one_turf)
+ bloodsmack(target_one_turf)
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodsmack(turf/T)
+ sleep(2.5)
+ for(var/mob/living/L in T)
+ if(!faction_check(L))
+ L << "[src] rends you!"
+ playsound(T, attack_sound, 100, 1, -1)
+ var/limb_to_hit = L.get_bodypart(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)
+ sleep(6)
+ for(var/mob/living/L in T)
+ if(!faction_check(L))
+ L << "[src] drags you through the blood!"
+ playsound(T, 'sound/magic/enter_blood.ogg', 100, 1, -1)
+ var/turf/targetturf = get_step(src, dir)
+ L.forceMove(targetturf)
+ playsound(targetturf, 'sound/magic/exit_blood.ogg', 100, 1, -1)
+ if(L.stat != CONSCIOUS)
+ addtimer(src, "devour", 2, FALSE, 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 = BELOW_MOB_LAYER
+
+/obj/effect/overlay/temp/bubblegum_hands/leftpaw
+ icon_state = "leftpawgrab"
+ layer = BELOW_MOB_LAYER
+
+/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 = PoolOrNew(/obj/effect/overlay/temp/decoy, list(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
- var/list/pools = list()
- var/can_jaunt = FALSE
- for(var/obj/effect/decal/cleanable/blood/nearby in view(src,2))
- can_jaunt = TRUE
- break
- if(!can_jaunt)
- return
- for(var/obj/effect/decal/cleanable/blood/nearby in view(get_turf(target),2))
- pools += nearby
+ 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)
@@ -187,35 +314,56 @@ Difficulty: Hard
forceMove(get_turf(found_bloodpool))
playsound(get_turf(src), 'sound/magic/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/blood/nearby in view(T, range))
+ . += nearby
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/blood_spray()
visible_message("[src] sprays a stream of gore!")
- var/turf/E = get_edge_target_turf(src, src.dir)
- var/range = 10
+ var/range = 6 + round(anger_modifier * 0.4)
var/turf/previousturf = get_turf(src)
- for(var/turf/J in getline(src,E))
- if(!range)
+ 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(J)
+ for(var/i in 1 to range)
+ J = get_step(previousturf, targetdir)
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/bloodsplatter, list(previousturf, get_dir(previousturf, J)))
+ playsound(previousturf,'sound/effects/splat.ogg', 100, 1, -1)
+ if(!J || !previousturf.CanAtmosPass(J))
break
- PoolOrNew(/obj/effect/overlay/temp/bloodsplatter, list(previousturf, get_dir(previousturf, J)))
- if(!previousturf.CanAtmosPass(J))
- break
- playsound(J,'sound/effects/splat.ogg', 100, 1, -1)
- new /obj/effect/decal/cleanable/blood(J)
- range--
+ var/obj/effect/decal/cleanable/blood/B = new /obj/effect/decal/cleanable/blood(J)
+ B.bloodiness = 0
previousturf = J
sleep(1)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/slaughterlings()
visible_message("[src] summons a shoal of slaughterlings!")
- for(var/obj/effect/decal/cleanable/blood/H in range(src, 10))
- if(prob(25))
- new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/blood/slaughter(H.loc)
+ 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."
- faction = list("mining")
+ 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
index a8f7b491bc9..7ebbdad514e 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -220,7 +220,8 @@ Difficulty: Very Hard
/mob/living/simple_animal/hostile/megafauna/colossus/proc/blast()
playsound(get_turf(src), 'sound/magic/clockwork/invoke_general.ogg', 200, 1, 2)
- for(var/turf/turf in range(1, target))
+ var/turf/T = get_turf(target)
+ for(var/turf/turf in range(1, T))
shoot_projectile(turf)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/dir_shots(list/dirs)
@@ -381,7 +382,7 @@ Difficulty: Very Hard
var/activation_sound = 'sound/effects/break_stone.ogg'
/obj/machinery/anomalous_crystal/New()
- activation_method = pick("touch","laser","bullet","energy","magic","mob_bump","heat","weapon","speech")
+ activation_method = pick("touch","laser","bullet","energy","bomb","mob_bump","heat","weapon","speech")
..()
/obj/machinery/anomalous_crystal/Hear(message, atom/movable/speaker, message_langs, raw_message, radio_freq, spans)
@@ -423,8 +424,11 @@ Difficulty: Very Hard
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)
+ var/random_crystal = pick(typesof(/obj/machinery/anomalous_crystal) - /obj/machinery/anomalous_crystal/random - /obj/machinery/anomalous_crystal)
new random_crystal(loc)
qdel(src)
@@ -472,13 +476,14 @@ Difficulty: Very Hard
NewTerrainChairs = /obj/structure/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.
+ if("jungle") //Beneficial due to actually having breathable air. Plus, monkeys and bows and arrows.
NewTerrainFloors = /turf/open/floor/grass
NewTerrainWalls = /turf/closed/wall/mineral/sandstone
NewTerrainChairs = /obj/structure/chair/wood
NewTerrainTables = /obj/structure/table/wood
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/monkey)
+ /obj/structure/flora/ausbushes/grassybush, /obj/structure/flora/ausbushes/sunnybush, /obj/structure/flora/tree/palm, /mob/living/carbon/monkey,
+ /obj/item/weapon/gun/projectile/bow, /obj/item/weapon/storage/backpack/quiver/full)
florachance = 20
if("ayy lmao") //Beneficial, turns stuff into alien alloy which is useful to cargo and research. Also repairs atmos.
NewTerrainFloors = /turf/open/floor/plating/abductor
@@ -523,8 +528,8 @@ Difficulty: Very Hard
/obj/machinery/anomalous_crystal/emitter/New()
..()
- generated_projectile = pick(/obj/item/projectile/beam/emitter,/obj/item/projectile/magic/fireball/infernal,/obj/item/projectile/magic/spellblade,
- /obj/item/projectile/energy/net, /obj/item/projectile/bullet/meteorshot, /obj/item/projectile/beam/xray)
+ 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(..())
@@ -545,17 +550,23 @@ Difficulty: Very Hard
P.xo = 0
P.fire()
-/obj/machinery/anomalous_crystal/dark_reprise //Revives anyone nearby, but turns them into shadowpeople. Cannot revive shadowpeople, so this is a one time thing.
+/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))
+ PoolOrNew(/obj/effect/overlay/temp/cult/sparks, i)
+ continue
if(ishuman(i))
var/mob/living/carbon/human/H = i
- if(H.stat == DEAD && !isshadowperson(H))
+ if(H.stat == DEAD)
H.set_species(/datum/species/shadow, 1)
H.revive(1,0)
+ 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"
@@ -564,17 +575,23 @@ Difficulty: Very Hard
/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)]!", enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK)
+ 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")
+ 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."
@@ -603,51 +620,62 @@ Difficulty: Very Hard
damage_coeff = list(BRUTE = 1, BURN = 1, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
luminosity = 4
faction = list("neutral")
- languages_spoken = 0
+ languages_spoken = SLIME
languages_understood = ALL
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, 1)
+ L.heal_overall_damage(heal_power, heal_power)
PoolOrNew(/obj/effect/overlay/temp/heal, list(get_turf(target), "#80F5FF"))
-/mob/living/simple_animal/hostile/lightgeist/Life()
- if(!ckey)
+/mob/living/simple_animal/hostile/lightgeist/ghostize()
+ if(..())
death()
- ..()
-/obj/machinery/anomalous_crystal/refresher //Deletes and recreates a copy of the item, "refreshing" it. Only works once per item.
+/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
+ var/list/L = list()
var/turf/T = get_step(src, dir)
+ PoolOrNew(/obj/effect/overlay/temp/emp/pulse,T)
for(var/i in T)
- if(istype(i, /obj/item) && !istype(i, /obj/item/weapon/storage) && !(i in affected_targets) && !istype(i, /obj/item/weapon/implant) && !istype(i, /obj/item/weapon/implanter) && !istype(i, /obj/item/weapon/disk/nuclear))
+ if(istype(i, /obj/item) && !is_type_in_typecache(i, banned_items_typecache))
var/obj/item/W = i
if(!W.admin_spawned)
L += W
- var/obj/item/CHOSEN = pick(L)
- if(CHOSEN)
- var/A = new CHOSEN.type(T)
- affected_targets += A
+ 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.
@@ -665,7 +693,7 @@ Difficulty: Very Hard
mobcheck = 1
break
if(!mobcheck)
- new /mob/living/simple_animal/cockroach(loc) //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
+ 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"
@@ -673,17 +701,15 @@ Difficulty: Very Hard
icon_state = null //This shouldn't even be visible, so if it DOES show up, at least nobody will notice
density = 1
anchored = 1
- health = 0
+ health = 999
var/mob/living/simple_animal/holder_animal
/obj/structure/closet/stasis/process()
- if(!isanimal(loc))
- dump_contents(1)
- return
if(holder_animal)
- if(holder_animal.stat == DEAD)
- dump_contents(1)
+ if(holder_animal.stat == DEAD && !qdeleted(holder_animal))
+ dump_contents()
holder_animal.gib()
+ return
/obj/structure/closet/stasis/New()
..()
@@ -702,14 +728,15 @@ Difficulty: Very Hard
holder_animal.mind.AddSpell(P)
holder_animal.verbs -= /mob/living/verb/pulled
-/obj/structure/closet/stasis/dump_contents(var/kill = 0)
+/obj/structure/closet/stasis/dump_contents(var/kill = 1)
STOP_PROCESSING(SSobj, src)
for(var/mob/living/L in src)
L.disabilities &= ~MUTE
L.status_flags &= ~GODMODE
L.notransform = 0
- holder_animal.mind.transfer_to(L)
- L.mind.RemoveSpell(/obj/effect/proc_holder/spell/targeted/exit_possession)
+ 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)
..()
@@ -717,6 +744,9 @@ Difficulty: Very Hard
/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"
@@ -737,7 +767,7 @@ Difficulty: Very Hard
for(var/i in user)
if(istype(i, /obj/structure/closet/stasis))
var/obj/structure/closet/stasis/S = i
- S.dump_contents()
+ S.dump_contents(0)
qdel(S)
break
user.gib()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
index 67b784fff9a..ff9e3ab67ca 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/dragon.dm
@@ -166,6 +166,7 @@ Difficulty: Medium
addtimer(src, "fire_wall", 0, FALSE, 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)
@@ -175,10 +176,10 @@ Difficulty: Medium
range--
PoolOrNew(/obj/effect/hotspot,J)
J.hotspot_expose(700,50,1)
- for(var/mob/living/L in J)
- if(L != src)
- L.adjustFireLoss(20)
- L << "You're hit by the drake's fire breath!"
+ for(var/mob/living/L in J.contents - hit_things)
+ L.adjustFireLoss(20)
+ L << "You're hit by the drake's fire breath!"
+ hit_things += L
previousturf = J
sleep(1)
@@ -257,6 +258,7 @@ Difficulty: Medium
name = "lesser ash drake"
maxHealth = 300
health = 300
+ 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)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index ee7e70bdcf2..37aa5575a9b 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -87,7 +87,7 @@ Difficulty: Hard
did_reset = TRUE
//visible_message("\"Vixyvrmrk xs fewi...\"")
blink(spawned_rune)
- adjustHealth(max((health - maxHealth) * 0.5, 25)) //heal for 50% of our missing health
+ 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.\"")
@@ -279,6 +279,8 @@ Difficulty: Hard
/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
PoolOrNew(/obj/effect/overlay/temp/hierophant/telegraph/diagonal, list(T, src))
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
@@ -289,6 +291,8 @@ Difficulty: Hard
/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
PoolOrNew(/obj/effect/overlay/temp/hierophant/telegraph/cardinal, list(T, src))
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
@@ -299,6 +303,8 @@ Difficulty: Hard
/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
PoolOrNew(/obj/effect/overlay/temp/hierophant/telegraph, list(T, src))
playsound(T,'sound/magic/blink.ogg', 200, 1)
//playsound(T,'sound/effects/bin_close.ogg', 200, 1)
@@ -396,6 +402,7 @@ Difficulty: Hard
/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
@@ -415,7 +422,7 @@ Difficulty: Hard
addtimer(src, "seek_target", 1)
/obj/effect/overlay/temp/hierophant/chaser/proc/get_target_dir()
- . = get_cardinal_dir(src, target)
+ . = 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
@@ -424,12 +431,13 @@ Difficulty: Hard
/obj/effect/overlay/temp/hierophant/chaser/proc/seek_target()
if(!currently_seeking)
currently_seeking = TRUE
- while(target && src && !qdeleted(src) && currently_seeking && x && y && target.x && target.y) //can this target actually be sook out
+ 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, target)
+ 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
@@ -446,6 +454,7 @@ Difficulty: Hard
make_blast() //make a blast, too
moving--
sleep(speed)
+ targetturf = get_turf(target)
/obj/effect/overlay/temp/hierophant/chaser/proc/make_blast()
PoolOrNew(/obj/effect/overlay/temp/hierophant/blast, list(loc, caster, friendly_fire_check))
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
index 948f01e56eb..b63b421ae83 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
@@ -15,6 +15,7 @@
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)
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 df5897d9f65..de6056ca76e 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs.dm
@@ -833,7 +833,7 @@
desc = "[src] has become inert, it crackles no more and is useless for \
healing injuries."
-/obj/item/organ/hivelord_core/legion/preserved()
+/obj/item/organ/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."
diff --git a/code/modules/mob/living/simple_animal/hostile/skeleton.dm b/code/modules/mob/living/simple_animal/hostile/skeleton.dm
index ad20e68458e..4664a41082c 100644
--- a/code/modules/mob/living/simple_animal/hostile/skeleton.dm
+++ b/code/modules/mob/living/simple_animal/hostile/skeleton.dm
@@ -70,7 +70,7 @@
loot = list(/obj/effect/decal/remains/human,
/obj/item/clothing/suit/armor/riot/knight/templar,
/obj/item/clothing/head/helmet/knight/templar,
- /obj/item/weapon/claymore/hog{name = "holy sword"})
+ /obj/item/weapon/claymore/weak{name = "holy sword"})
/mob/living/simple_animal/hostile/skeleton/ice
name = "ice skeleton"
diff --git a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm
index 7dc5c54bd33..14aeb265158 100644
--- a/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm
+++ b/code/modules/mob/living/simple_animal/hostile/venus_human_trap.dm
@@ -21,7 +21,7 @@
anchors += locate(x+2,y-2,z)
for(var/turf/T in anchors)
- var/datum/beam/B = Beam(T,"vine",'icons/effects/spacevines.dmi',INFINITY, 5,/obj/effect/ebeam/vine)
+ var/datum/beam/B = Beam(T, "vine", time=INFINITY, maxdistance=5, beam_type=/obj/effect/ebeam/vine)
B.sleep_time = 10 //these shouldn't move, so let's slow down updates to 1 second (any slower and the deletion of the vines would be too slow)
addtimer(src, "bear_fruit", growth_time)
@@ -98,15 +98,15 @@
if(A.density && A != L)
continue grasping
if(prob(grasp_chance))
- L << "\the [src] has you entangled!"
- grasping[L] = Beam(L,"vine",'icons/effects/spacevines.dmi',INFINITY, 5,/obj/effect/ebeam/vine)
+ L << "\The [src] has you entangled!"
+ grasping[L] = Beam(L, "vine", time=INFINITY, maxdistance=5, beam_type=/obj/effect/ebeam/vine)
break //only take 1 new victim per cycle
/mob/living/simple_animal/hostile/venus_human_trap/OpenFire(atom/the_target)
var/dist = get_dist(src,the_target)
- Beam(the_target,"vine",'icons/effects/spacevines.dmi',dist*2, dist+2,/obj/effect/ebeam/vine)
+ Beam(the_target, "vine", time=dist*2, maxdistance=dist+2, beam_type=/obj/effect/ebeam/vine)
the_target.attack_animal(src)
diff --git a/code/modules/mob/living/simple_animal/shade.dm b/code/modules/mob/living/simple_animal/shade.dm
index 939c1d57ffc..a6387667c7a 100644
--- a/code/modules/mob/living/simple_animal/shade.dm
+++ b/code/modules/mob/living/simple_animal/shade.dm
@@ -43,7 +43,7 @@
if(istype(M, /mob/living/simple_animal/hostile/construct/builder))
if(health < maxHealth)
adjustHealth(-25)
- Beam(M,icon_state="sendbeam",icon='icons/effects/effects.dmi',time=4)
+ Beam(M,icon_state="sendbeam",time=4)
M.visible_message("[M] heals \the [src].", \
"You heal [src], leaving [src] at [health]/[maxHealth] health.")
else
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 7f05844b296..8de22d32685 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -101,17 +101,21 @@
client.screen += client.void
..()
-/mob/living/simple_animal/updatehealth()
- ..()
- health = Clamp(health, 0, maxHealth)
-
/mob/living/simple_animal/Life()
if(..()) //alive
if(!ckey)
- handle_automated_movement()
- handle_automated_action()
- handle_automated_speech()
- return 1
+ if(stat != DEAD)
+ handle_automated_movement()
+ if(stat != DEAD)
+ handle_automated_action()
+ if(stat != DEAD)
+ handle_automated_speech()
+ if(stat != DEAD)
+ return 1
+
+/mob/living/simple_animal/updatehealth()
+ ..()
+ health = Clamp(health, 0, maxHealth)
/mob/living/simple_animal/update_stat()
if(status_flags & GODMODE)
@@ -251,10 +255,6 @@
if(icon_gib)
new /obj/effect/overlay/temp/gib_animation/animal(loc, icon_gib)
-/mob/living/simple_animal/blob_act(obj/effect/blob/B)
- adjustBruteLoss(20)
- return
-
/mob/living/simple_animal/say_quote(input)
var/ending = copytext(input, length(input))
if(speak_emote && speak_emote.len && ending != "?" && ending != "!")
@@ -271,125 +271,7 @@
act = "me"
..(act, m_type, message)
-/mob/living/simple_animal/attack_animal(mob/living/simple_animal/M)
- if(..())
- var/damage = rand(M.melee_damage_lower, M.melee_damage_upper)
- attack_threshold_check(damage,M.melee_damage_type)
- return 1
-/mob/living/simple_animal/bullet_act(obj/item/projectile/Proj)
- if(!Proj)
- return
- apply_damage(Proj.damage, Proj.damage_type)
- Proj.on_hit(src)
- return 0
-
-/mob/living/simple_animal/proc/adjustHealth(amount)
- if(status_flags & GODMODE)
- return 0
- bruteloss = Clamp(bruteloss + amount, 0, maxHealth)
- updatehealth()
- return amount
-
-/mob/living/simple_animal/adjustBruteLoss(amount)
- if(damage_coeff[BRUTE])
- . = adjustHealth(amount * damage_coeff[BRUTE] * config.damage_multiplier)
-
-/mob/living/simple_animal/adjustFireLoss(amount)
- if(damage_coeff[BURN])
- . = adjustHealth(amount * damage_coeff[BURN] * config.damage_multiplier)
-
-/mob/living/simple_animal/adjustOxyLoss(amount)
- if(damage_coeff[OXY])
- . = adjustHealth(amount * damage_coeff[OXY] * config.damage_multiplier)
-
-/mob/living/simple_animal/adjustToxLoss(amount)
- if(damage_coeff[TOX])
- . = adjustHealth(amount * damage_coeff[TOX] * config.damage_multiplier)
-
-/mob/living/simple_animal/adjustCloneLoss(amount)
- if(damage_coeff[CLONE])
- . = adjustHealth(amount * damage_coeff[CLONE] * config.damage_multiplier)
-
-/mob/living/simple_animal/adjustStaminaLoss(amount)
- return
-
-/mob/living/simple_animal/attack_hand(mob/living/carbon/human/M)
- ..()
- switch(M.a_intent)
-
- if("help")
- if (health > 0)
- visible_message("[M] [response_help] [src].")
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
-
- if("grab")
- grabbedby(M)
-
- if("harm", "disarm")
- M.do_attack_animation(src)
- visible_message("[M] [response_harm] [src]!")
- playsound(loc, attacked_sound, 25, 1, -1)
- attack_threshold_check(harm_intent_damage)
- add_logs(M, src, "attacked")
- updatehealth()
- return 1
-
-/mob/living/simple_animal/attack_paw(mob/living/carbon/monkey/M)
- if(..()) //successful monkey bite.
- if(stat != DEAD)
- var/damage = rand(1, 3)
- attack_threshold_check(damage)
- return 1
- if (M.a_intent == "help")
- if (health > 0)
- visible_message("[M.name] [response_help] [src].")
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
-
- return
-
-/mob/living/simple_animal/attack_alien(mob/living/carbon/alien/humanoid/M)
- if(..()) //if harm or disarm intent.
- if(M.a_intent == "disarm")
- playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1)
- visible_message("[M] [response_disarm] [name]!", \
- "[M] [response_disarm] [name]!")
- add_logs(M, src, "disarmed")
- else
- var/damage = rand(15, 30)
- visible_message("[M] has slashed at [src]!", \
- "[M] has slashed at [src]!")
- playsound(loc, 'sound/weapons/slice.ogg', 25, 1, -1)
- attack_threshold_check(damage)
- add_logs(M, src, "attacked")
- return 1
-
-/mob/living/simple_animal/attack_larva(mob/living/carbon/alien/larva/L)
- if(..()) //successful larva bite
- var/damage = rand(5, 10)
- if(stat != DEAD)
- L.amount_grown = min(L.amount_grown + damage, L.max_grown)
- attack_threshold_check(damage)
- return 1
-
-/mob/living/simple_animal/attack_slime(mob/living/simple_animal/slime/M)
- if(..()) //successful slime attack
- var/damage = rand(15, 25)
- if(M.is_adult)
- damage = rand(20, 35)
- attack_threshold_check(damage)
- return 1
-
-/mob/living/simple_animal/proc/attack_threshold_check(damage, damagetype = BRUTE)
- if(!damage_coeff[damagetype])
- damage = 0
- else
- damage *= damage_coeff[damagetype]
-
- if(damage >= 0 && damage <= force_threshold)
- visible_message("[src] looks unharmed.")
- else
- adjustHealth(damage * config.damage_multiplier)
/mob/living/simple_animal/movement_delay()
. = ..()
@@ -422,7 +304,12 @@
visible_message("\The [src] stops moving...")
if(del_on_death)
ghostize()
+ stat = DEAD
+ //Prevent infinite loops if the mob Destroy() is overriden in such
+ //a manner as to cause a call to death() again
+ del_on_death = FALSE
qdel(src)
+ return
else
health = 0
icon_state = icon_dead
@@ -431,28 +318,6 @@
lying = 1
..()
-/mob/living/simple_animal/ex_act(severity, target)
- ..()
- var/bomb_armor = getarmor(null, "bomb")
- switch (severity)
- if (1)
- if(prob(bomb_armor))
- adjustBruteLoss(500)
- else
- gib()
- return
- if (2)
- var/bloss = 60
- if(prob(bomb_armor))
- bloss = bloss / 1.5
- adjustBruteLoss(bloss)
-
- if(3)
- var/bloss = 30
- if(prob(bomb_armor))
- bloss = bloss / 1.5
- adjustBruteLoss(bloss)
-
/mob/living/simple_animal/proc/CanAttack(atom/the_target)
if(see_invisible < the_target.invisibility)
return 0
@@ -469,9 +334,6 @@
/mob/living/simple_animal/handle_fire()
return
-/mob/living/simple_animal/update_fire()
- return
-
/mob/living/simple_animal/IgniteMob()
return FALSE
@@ -599,14 +461,6 @@
/mob/living/simple_animal/get_idcard()
return access_card
-//Dextrous simple mobs can use hands!
-/mob/living/simple_animal/create_mob_hud()
- if(client && !hud_used)
- if(dextrous)
- hud_used = new dextrous_hud_type(src, ui_style2icon(client.prefs.UI_style))
- else
- ..()
-
/mob/living/simple_animal/OpenCraftingMenu()
if(dextrous)
handcrafting.ui_interact(src)
@@ -656,13 +510,6 @@
if(H)
H.update_icon()
-/mob/living/simple_animal/UnarmedAttack(atom/A, proximity)
- if(!dextrous)
- return ..()
- if(!ismob(A))
- A.attack_hand(src)
- update_inv_hands()
-
/mob/living/simple_animal/put_in_hands(obj/item/I)
..()
update_inv_hands()
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index 44c96f7f216..0545bd03b00 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -14,4 +14,61 @@
if(damage >= 0)
ear_damage = damage
if(deaf >= 0)
- ear_deaf = deaf
\ No newline at end of file
+ ear_deaf = deaf
+
+
+//////////////////////////////STUN ////////////////////////////////////
+
+/mob/living/proc/add_stun_absorption(key, duration, priority, message, self_message, examine_message)
+//adds a stun absorption with a key, a duration in deciseconds, its priority, and the messages it makes when you're stunned/examined, if any
+ if(!islist(stun_absorption))
+ stun_absorption = list()
+ if(stun_absorption[key])
+ stun_absorption[key]["end_time"] = world.time + duration
+ stun_absorption[key]["priority"] = priority
+ stun_absorption[key]["stuns_absorbed"] = 0
+ else
+ stun_absorption[key] = list("end_time" = world.time + duration, "priority" = priority, "stuns_absorbed" = 0, \
+ "visible_message" = message, "self_message" = self_message, "examine_message" = examine_message)
+
+/mob/living/Stun(amount, updating = 1, ignore_canstun = 0)
+ if(!stat && islist(stun_absorption))
+ var/priority_absorb_key
+ var/highest_priority
+ for(var/i in stun_absorption)
+ if(stun_absorption[i]["end_time"] > world.time && (!priority_absorb_key || stun_absorption[i]["priority"] > highest_priority))
+ priority_absorb_key = stun_absorption[i]
+ highest_priority = stun_absorption[i]["priority"]
+ if(priority_absorb_key)
+ if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"])
+ if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"])
+ visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]")
+ else if(priority_absorb_key["visible_message"])
+ visible_message("[src][priority_absorb_key["visible_message"]]")
+ else if(priority_absorb_key["self_message"])
+ src << "[priority_absorb_key["self_message"]]"
+ priority_absorb_key["stuns_absorbed"] += amount
+ return 0
+ ..()
+
+///////////////////////////////// WEAKEN /////////////////////////////////////
+
+/mob/living/Weaken(amount, updating = 1, ignore_canweaken = 0)
+ if(!stat && islist(stun_absorption))
+ var/priority_absorb_key
+ var/highest_priority
+ for(var/i in stun_absorption)
+ if(stun_absorption[i]["end_time"] > world.time && (!priority_absorb_key || stun_absorption[i]["priority"] > highest_priority))
+ priority_absorb_key = stun_absorption[i]
+ highest_priority = priority_absorb_key["priority"]
+ if(priority_absorb_key)
+ if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"])
+ if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"])
+ visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]")
+ else if(priority_absorb_key["visible_message"])
+ visible_message("[src][priority_absorb_key["visible_message"]]")
+ else if(priority_absorb_key["self_message"])
+ src << "[priority_absorb_key["self_message"]]"
+ priority_absorb_key["stuns_absorbed"] += amount
+ return 0
+ ..()
\ No newline at end of file
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 4744180d207..1b1808518f8 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -499,8 +499,8 @@ var/next_mob_id = 0
return
var/mob/mob_eye = creatures[eye_name]
-
- if(client && mob_eye)
+ //Istype so we filter out points of interest that are not mobs
+ if(client && mob_eye && istype(mob_eye))
client.eye = mob_eye
if(isobserver(src))
src.client.screen = list()
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 37e60e3b93c..e59f4708e90 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -413,14 +413,15 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
/proc/item_heal_robotic(mob/living/carbon/human/H, mob/user, brute_heal, burn_heal)
var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected))
- if(affecting && affecting.status == ORGAN_ROBOTIC)
+ if(affecting && affecting.status == BODYPART_ROBOTIC)
var/dam //changes repair text based on how much brute/burn was supplied
if(brute_heal > burn_heal)
dam = 1
else
dam = 0
if((brute_heal > 0 && affecting.brute_dam > 0) || (burn_heal > 0 && affecting.burn_dam > 0))
- affecting.heal_damage(brute_heal,burn_heal,1)
+ if(affecting.heal_damage(brute_heal, burn_heal, 1, 0))
+ H.update_damage_overlays()
user.visible_message("[user] has fixed some of the [dam ? "dents on" : "burnt wires in"] [H]'s [affecting].", "You fix some of the [dam ? "dents on" : "burnt wires in"] [H]'s [affecting].")
return 1 //successful heal
else
@@ -464,3 +465,15 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
M << "There were no ghosts willing to take control."
message_admins("No ghosts were willing to take control of [key_name_admin(M)])")
return FALSE
+
+//toggles the talk wheel
+/mob/verb/toggle_talk_wheel()
+ set name = "talk-wheel"
+ set hidden = 1
+
+ if(isliving(src))
+ var/mob/living/L = src
+ if(L.hud_used)
+ for(var/obj/screen/wheel/talk/TW in L.hud_used.wheels)
+ TW.Click()
+
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 919e995bca8..25df31320da 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -236,14 +236,12 @@
L.loc = locate(locx,locy,mobloc.z)
var/limit = 2//For only two trailing shadows.
for(var/turf/T in getline(mobloc, L.loc))
- spawn(0)
- anim(T,L,'icons/mob/mob.dmi',,"shadow",,L.dir)
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/ninja/shadow, list(T, L.dir))
limit--
if(limit<=0)
break
else
- spawn(0)
- anim(mobloc,mob,'icons/mob/mob.dmi',,"shadow",,L.dir)
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/ninja/shadow, list(mobloc, L.dir))
L.loc = get_step(L, direct)
L.setDir(direct)
if(3) //Incorporeal move, but blocked by holy-watered tiles and salt piles.
@@ -303,6 +301,9 @@
break
. = dense_object_backup
+/mob/proc/mob_has_gravity()
+ return has_gravity()
+
/mob/proc/mob_negates_gravity()
return 0
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 3c2c95fbbf8..e947d24c1a7 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -332,6 +332,9 @@
data_core.manifest_inject(humanc)
AnnounceArrival(humanc, rank)
AddEmploymentContract(humanc)
+ if(highlander)
+ humanc << "THERE CAN BE ONLY ONE!!!"
+ humanc.make_scottish()
joined_player_list += character.ckey
diff --git a/code/modules/mob/status_procs.dm b/code/modules/mob/status_procs.dm
index 649fe0462bb..dfbe6250533 100644
--- a/code/modules/mob/status_procs.dm
+++ b/code/modules/mob/status_procs.dm
@@ -245,7 +245,13 @@
return
-
+//////////////////////////////// HUSK DISABILITY ///////////////////////////:
+
+/mob/proc/cure_husk()
+ return
+
+/mob/proc/become_husk()
+ return
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index e1b2f760b4c..6f662412c65 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -7,19 +7,32 @@
var/list/implants = list()
var/list/int_organs = list()
+
+
if (tr_flags & TR_KEEPIMPLANTS)
for(var/obj/item/weapon/implant/W in src)
implants += W
if (tr_flags & TR_KEEPORGANS)
- for(var/obj/item/organ/I in internal_organs)
+ for(var/X in internal_organs)
+ var/obj/item/organ/I = X
int_organs += I
I.Remove(src, 1)
+ var/list/missing_bodyparts_zones = get_missing_limbs()
+
+ var/obj/item/cavity_object
+
+ var/obj/item/bodypart/chest/CH = get_bodypart("chest")
+ if(CH.cavity_item)
+ cavity_object = CH.cavity_item
+ CH.cavity_item = null
+
if(tr_flags & TR_KEEPITEMS)
- for(var/obj/item/W in (src.contents-implants-int_organs))
+ for(var/obj/item/W in (contents-implants-cavity_object))
unEquip(W)
+
//Make mob invisible and spawn animation
notransform = 1
canmove = 0
@@ -28,14 +41,9 @@
cut_overlays()
invisibility = INVISIBILITY_MAXIMUM
- var/atom/movable/overlay/animation = new( loc )
- animation.icon_state = "blank"
- animation.icon = 'icons/mob/mob.dmi'
- animation.master = src
- flick("h2monkey", animation)
+ PoolOrNew(/obj/effect/overlay/temp/monkeyify, get_turf(src))
sleep(22)
var/mob/living/carbon/monkey/O = new /mob/living/carbon/monkey( loc )
- qdel(animation)
// hash the original name?
if(tr_flags & TR_HASHNAME)
@@ -82,17 +90,37 @@
//re-add organs to new mob
if(tr_flags & TR_KEEPORGANS)
- for(var/obj/item/organ/I in O.internal_organs)
- qdel(I)
+ for(var/X in O.internal_organs)
+ qdel(X)
- for(var/obj/item/organ/I in int_organs)
+ for(var/X in int_organs)
+ var/obj/item/organ/I = X
I.Insert(O, 1)
+ var/obj/item/bodypart/chest/torso = O.get_bodypart("chest")
+ if(cavity_object)
+ torso.cavity_item = cavity_object //cavity item is given to the new chest
+ cavity_object.loc = O
+
+ for(var/missing_zone in missing_bodyparts_zones)
+ var/obj/item/bodypart/BP = O.get_bodypart(missing_zone)
+ BP.drop_limb(1)
+ if(!(tr_flags & TR_KEEPORGANS)) //we didn't already get rid of the organs of the newly spawned mob
+ for(var/X in O.internal_organs)
+ var/obj/item/organ/G = X
+ if(BP.body_zone == check_zone(G.zone))
+ if(mind && mind.changeling && istype(G, /obj/item/organ/brain))
+ continue //so headless changelings don't lose their brain when transforming
+ qdel(G) //we lose the organs in the missing limbs
+ qdel(BP)
+
//transfer mind and delete old mob
if(mind)
mind.transfer_to(O)
if(O.mind.changeling)
O.mind.changeling.purchasedpowers += new /obj/effect/proc_holder/changeling/humanform(null)
+
+
if (tr_flags & TR_DEFAULTMSG)
O << "You are now a monkey."
@@ -121,13 +149,23 @@
implants += W
if (tr_flags & TR_KEEPORGANS)
- for(var/obj/item/organ/I in internal_organs)
+ for(var/X in internal_organs)
+ var/obj/item/organ/I = X
int_organs += I
I.Remove(src, 1)
+ var/list/missing_bodyparts_zones = get_missing_limbs()
+
+ var/obj/item/cavity_object
+
+ var/obj/item/bodypart/chest/CH = get_bodypart("chest")
+ if(CH.cavity_item)
+ cavity_object = CH.cavity_item
+ CH.cavity_item = null
+
//now the rest
if (tr_flags & TR_KEEPITEMS)
- for(var/obj/item/W in (src.contents-implants-int_organs))
+ for(var/obj/item/W in (contents-implants-cavity_object))
unEquip(W)
if (client)
client.screen -= W
@@ -136,6 +174,8 @@
W.dropped(src)
W.layer = initial(W.layer)
+
+
//Make mob invisible and spawn animation
notransform = 1
canmove = 0
@@ -143,16 +183,11 @@
icon = null
cut_overlays()
invisibility = INVISIBILITY_MAXIMUM
- var/atom/movable/overlay/animation = new( loc )
- animation.icon_state = "blank"
- animation.icon = 'icons/mob/mob.dmi'
- animation.master = src
- flick("monkey2h", animation)
+ PoolOrNew(/obj/effect/overlay/temp/monkeyify/humanify, get_turf(src))
sleep(22)
var/mob/living/carbon/human/O = new( loc )
for(var/obj/item/C in O.loc)
O.equip_to_appropriate_slot(C)
- qdel(animation)
dna.transfer_identity(O)
O.updateappearance(mutcolor_update=1)
@@ -202,12 +237,31 @@
O.sec_hud_set_implants()
if(tr_flags & TR_KEEPORGANS)
- for(var/obj/item/organ/I in O.internal_organs)
- qdel(I)
+ for(var/X in O.internal_organs)
+ qdel(X)
- for(var/obj/item/organ/I in int_organs)
+ for(var/X in int_organs)
+ var/obj/item/organ/I = X
I.Insert(O, 1)
+
+ var/obj/item/bodypart/chest/torso = get_bodypart("chest")
+ if(cavity_object)
+ torso.cavity_item = cavity_object //cavity item is given to the new chest
+ cavity_object.loc = O
+
+ for(var/missing_zone in missing_bodyparts_zones)
+ var/obj/item/bodypart/BP = O.get_bodypart(missing_zone)
+ BP.drop_limb(1)
+ if(!(tr_flags & TR_KEEPORGANS)) //we didn't already get rid of the organs of the newly spawned mob
+ for(var/X in O.internal_organs)
+ var/obj/item/organ/G = X
+ if(BP.body_zone == check_zone(G.zone))
+ if(mind && mind.changeling && istype(G, /obj/item/organ/brain))
+ continue //so headless changelings don't lose their brain when transforming
+ qdel(G) //we lose the organs in the missing limbs
+ qdel(BP)
+
if(mind)
mind.transfer_to(O)
if(O.mind.changeling)
@@ -432,23 +486,6 @@
qdel(src)
-/mob/proc/become_god(var/side_colour)
- var/mob/camera/god/G = new /mob/camera/god(loc)
- G.side = side_colour
- if(mind)
- mind.transfer_to(G)
- else
- G.key = key
-
- G.job = "Deity"
- G.rename_self("deity")
- G.update_icons()
-
- . = G
- qdel(src)
-
-
-
/mob/living/carbon/human/proc/corgize()
if (notransform)
return
diff --git a/code/modules/mob/update_icons.dm b/code/modules/mob/update_icons.dm
index e2cb8d95974..6ed04dbbdd3 100644
--- a/code/modules/mob/update_icons.dm
+++ b/code/modules/mob/update_icons.dm
@@ -37,9 +37,15 @@
/mob/proc/update_inv_head()
return
+/mob/proc/update_body()
+ return
+
/mob/proc/update_hair()
return
+/mob/proc/update_fire()
+ return
+
/mob/proc/update_inv_gloves()
return
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index 516293bfc27..942a114dc56 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -36,22 +36,12 @@
var/max_damage = 100 // Damage level at which the computer breaks apart.
// Important hardware (must be installed for computer to work)
- var/obj/item/weapon/computer_hardware/processor_unit/processor_unit // CPU. Without it the computer won't run. Better CPUs can run more programs at once.
- var/obj/item/weapon/computer_hardware/hard_drive/hard_drive // Hard Drive component of this computer. Stores programs and files.
-
- var/obj/item/weapon/computer_hardware/battery/battery_module // Power cell connector. Power cell can be recharged.
- // OR
- var/obj/item/weapon/computer_hardware/recharger/recharger // Recharger. Can be used to recharge power cell or power the PC without it.
// Optional hardware (improves functionality, but is not critical for computer to work)
- var/obj/item/weapon/computer_hardware/network_card/network_card // Network Card component of this computer. Allows connection to NTNet.
- var/obj/item/weapon/computer_hardware/card_slot/card_slot // ID Card slot component of this computer.
- var/obj/item/weapon/computer_hardware/printer/printer // Printer component of this computer, for your everyday paperwork needs.
- var/obj/item/weapon/computer_hardware/hard_drive/portable/portable_drive // Portable data storage
- var/list/all_components = list()
+ var/list/all_components // List of "connection ports" in this computer and the components with which they are plugged
- var/list/idle_threads = list() // Idle programs on background. They still receive process calls but can't be interacted with.
+ var/list/idle_threads // Idle programs on background. They still receive process calls but can't be interacted with.
var/obj/physical = null // Object that represents our computer. It's used for Adjacent() and UI visibility checks.
@@ -63,30 +53,48 @@
physical = src
..()
+ all_components = list()
+ idle_threads = list()
+
/obj/item/device/modular_computer/Destroy()
kill_program(forced = TRUE)
STOP_PROCESSING(SSobj, src)
for(var/H in all_components)
- var/obj/item/weapon/computer_hardware/CH = H
+ var/obj/item/weapon/computer_hardware/CH = all_components[H]
if(CH.holder == src)
CH.holder = null
qdel(CH)
return ..()
+
+/obj/item/device/modular_computer/proc/add_verb(var/path)
+ switch(path)
+ if(MC_CARD)
+ verbs += /obj/item/device/modular_computer/proc/eject_id
+ if(MC_SDD)
+ verbs += /obj/item/device/modular_computer/proc/eject_disk
+
+/obj/item/device/modular_computer/proc/remove_verb(path)
+ switch(path)
+ if(MC_CARD)
+ verbs -= /obj/item/device/modular_computer/proc/eject_id
+ if(MC_SDD)
+ verbs -= /obj/item/device/modular_computer/proc/eject_disk
+
// Eject ID card from computer, if it has ID slot with card inside.
-/obj/item/device/modular_computer/verb/eject_id()
+/obj/item/device/modular_computer/proc/eject_id()
set name = "Eject ID"
set category = "Object"
set src in view(1)
if(issilicon(usr))
return
-
- if (usr.canUseTopic(src))
- proc_eject_id(usr)
+ var/obj/item/weapon/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
+ if(usr.canUseTopic(src))
+ card_slot.try_eject(, usr)
// Eject ID card from computer, if it has ID slot with card inside.
-/obj/item/device/modular_computer/verb/eject_disk()
+/obj/item/device/modular_computer/proc/eject_disk()
set name = "Eject Data Disk"
set category = "Object"
set src in view(1)
@@ -94,30 +102,10 @@
if(issilicon(usr))
return
- if (usr.canUseTopic(src))
- proc_eject_disk(usr)
-
-/obj/item/device/modular_computer/proc/proc_eject_id(mob/user, slot)
- if(!user)
- user = usr
-
- if(!card_slot)
- user << "\The [src] does not have an ID card slot!"
- return
-
- card_slot.try_eject(slot, user)
-
-/obj/item/device/modular_computer/proc/proc_eject_disk(mob/user)
- if(!user)
- user = usr
-
- if(!portable_drive)
- user << "There is no data disk in \the [src]!"
- return
-
- var/obj/item/I = portable_drive
- if(uninstall_component(portable_drive, user))
- I.verb_pickup()
+ if(usr.canUseTopic(src))
+ var/obj/item/weapon/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD]
+ if(uninstall_component(portable_drive, usr))
+ portable_drive.verb_pickup()
/obj/item/device/modular_computer/AltClick(mob/user)
..()
@@ -125,19 +113,24 @@
return
if(user.canUseTopic(src))
+ var/obj/item/weapon/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
+ var/obj/item/weapon/computer_hardware/hard_drive/portable/portable_drive = all_components[MC_SDD]
if(portable_drive)
- proc_eject_disk(user)
+ if(uninstall_component(portable_drive, user))
+ portable_drive.verb_pickup()
else if(card_slot)
- proc_eject_id(user)
+ card_slot.try_eject(, user)
// Gets IDs/access levels from card slot. Would be useful when/if PDAs would become modular PCs.
/obj/item/device/modular_computer/GetAccess()
+ var/obj/item/weapon/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
if(card_slot)
return card_slot.GetAccess()
return ..()
/obj/item/device/modular_computer/GetID()
+ var/obj/item/weapon/computer_hardware/card_slot/card_slot = all_components[MC_CARD]
if(card_slot)
return card_slot.GetID()
return ..()
@@ -208,10 +201,11 @@
return
// If we have a recharger, enable it automatically. Lets computer without a battery work.
+ var/obj/item/weapon/computer_hardware/recharger/recharger = all_components[MC_CHARGE]
if(recharger)
recharger.enabled = 1
- if(processor_unit && use_power()) // use_power() checks if the PC is powered
+ if(all_components[MC_CPU] && use_power()) // use_power() checks if the PC is powered
if(issynth)
user << "You send an activation signal to \the [src], turning it on."
else
@@ -265,6 +259,9 @@
/obj/item/device/modular_computer/proc/get_header_data()
var/list/data = list()
+ var/obj/item/weapon/computer_hardware/battery/battery_module = all_components[MC_CELL]
+ var/obj/item/weapon/computer_hardware/recharger/recharger = all_components[MC_CHARGE]
+
if(battery_module && battery_module.battery)
switch(battery_module.battery.percent())
if(80 to 200) // 100 should be maximal but just in case..
@@ -328,6 +325,7 @@
// Returns 0 for No Signal, 1 for Low Signal and 2 for Good Signal. 3 is for wired connection (always-on)
/obj/item/device/modular_computer/proc/get_ntnet_status(specific_action = 0)
+ var/obj/item/weapon/computer_hardware/network_card/network_card = all_components[MC_NET]
if(network_card)
return network_card.get_signal(specific_action)
else
@@ -336,6 +334,7 @@
/obj/item/device/modular_computer/proc/add_log(text)
if(!get_ntnet_status())
return FALSE
+ var/obj/item/weapon/computer_hardware/network_card/network_card = all_components[MC_NET]
return ntnet_global.add_log(text, network_card)
/obj/item/device/modular_computer/proc/shutdown_computer(loud = 1)
@@ -352,7 +351,7 @@
/obj/item/device/modular_computer/attackby(obj/item/weapon/W as obj, mob/user as mob)
// Insert items into the components
for(var/h in all_components)
- var/obj/item/weapon/computer_hardware/H = h
+ var/obj/item/weapon/computer_hardware/H = all_components[h]
if(H.try_insert(W, user))
return
diff --git a/code/modules/modular_computers/computers/item/computer_components.dm b/code/modules/modular_computers/computers/item/computer_components.dm
index 3a5b68579e1..0f27580a27f 100644
--- a/code/modules/modular_computers/computers/item/computer_components.dm
+++ b/code/modules/modular_computers/computers/item/computer_components.dm
@@ -6,32 +6,8 @@
user << "This component is too large for \the [src]!"
return FALSE
- if(istype(H, /obj/item/weapon/computer_hardware/hard_drive/portable) && portable_drive)
- user << "This computer's FDD is already occupied by \the [portable_drive]."
- return FALSE
-
- else if(istype(H, /obj/item/weapon/computer_hardware/processor_unit) && processor_unit)
- user << "This computer's CPU slot is already occupied by \the [processor_unit]."
- return FALSE
- else if(istype(H, /obj/item/weapon/computer_hardware/hard_drive) && hard_drive)
- user << "This computer's data port is already occupied by \the [hard_drive]."
- return FALSE
-
- else if(istype(H, /obj/item/weapon/computer_hardware/battery) && battery_module)
- user << "This computer's power converter slot is already occupied by \the [battery_module]."
- return FALSE
- else if(istype(H, /obj/item/weapon/computer_hardware/recharger) && recharger)
- user << "This computer's recharger slot is already occupied by \the [recharger]."
- return FALSE
-
- else if(istype(H, /obj/item/weapon/computer_hardware/card_slot) && card_slot)
- user << "This computer's card reader slot is already occupied by \the [card_slot]."
- return FALSE
- else if(istype(H, /obj/item/weapon/computer_hardware/network_card) && network_card)
- user << "This computer's network card is already occupied by \the [network_card]."
- return FALSE
- else if(istype(H, /obj/item/weapon/computer_hardware/printer) && printer)
- user << "This computer's printer slot is already occupied by \the [printer]."
+ if(all_components[H.device_type])
+ user << "This computer's hardware slot is already occupied by \the [all_components[H.device_type]]."
return FALSE
return TRUE
@@ -44,32 +20,12 @@
if(user && !user.unEquip(H))
return FALSE
- if(istype(H, /obj/item/weapon/computer_hardware/hard_drive/portable))
- portable_drive = H
-
- else if(istype(H, /obj/item/weapon/computer_hardware/processor_unit))
- processor_unit = H
- else if(istype(H, /obj/item/weapon/computer_hardware/hard_drive))
- hard_drive = H
-
- else if(istype(H, /obj/item/weapon/computer_hardware/battery))
- battery_module = H
- else if(istype(H, /obj/item/weapon/computer_hardware/recharger))
- recharger = H
-
- else if(istype(H, /obj/item/weapon/computer_hardware/card_slot))
- card_slot = H
- else if(istype(H, /obj/item/weapon/computer_hardware/network_card))
- network_card = H
- else if(istype(H, /obj/item/weapon/computer_hardware/printer))
- printer = H
+ all_components[H.device_type] = H
user << "You install \the [H] into \the [src]."
H.forceMove(src)
H.holder = src
- all_components |= H
H.on_install(src, user)
- return TRUE
// Uninstalls component.
@@ -77,41 +33,22 @@
if(H.holder != src) // Not our component at all.
return FALSE
- if(processor_unit == H)
- processor_unit = null
- if(hard_drive == H)
- hard_drive = null
-
- if(battery_module == H)
- battery_module = null
- if(recharger == H)
- recharger = null
-
- if(card_slot == H)
- card_slot = null
- if(network_card == H)
- network_card = null
- if(printer == H)
- printer = null
- if(portable_drive == H)
- portable_drive = null
+ all_components.Remove(H.device_type)
user << "You remove \the [H] from \the [src]."
H.forceMove(get_turf(src))
H.holder = null
- all_components -= H
H.on_remove(src, user)
- if(enabled && (!processor_unit || !hard_drive || !use_power()))
+ if(enabled && !use_power())
shutdown_computer()
update_icon()
- return TRUE
// Checks all hardware pieces to determine if name matches, if yes, returns the hardware piece, otherwise returns null
/obj/item/device/modular_computer/proc/find_hardware_by_name(name)
for(var/i in all_components)
- var/obj/O = i
+ var/obj/O = all_components[i]
if(O.name == name)
return O
return null
diff --git a/code/modules/modular_computers/computers/item/computer_damage.dm b/code/modules/modular_computers/computers/item/computer_damage.dm
index 8214840bc2b..d27ec0a750f 100644
--- a/code/modules/modular_computers/computers/item/computer_damage.dm
+++ b/code/modules/modular_computers/computers/item/computer_damage.dm
@@ -9,7 +9,7 @@
if(component_probability)
for(var/I in all_components)
- var/obj/item/weapon/computer_hardware/H = I
+ var/obj/item/weapon/computer_hardware/H = all_components[I]
if(prob(component_probability))
H.take_damage(round(amount / 2))
@@ -40,7 +40,7 @@
var/turf/newloc = get_turf(src)
new /obj/item/stack/sheet/metal(newloc, round(steel_sheet_cost/2))
for(var/C in all_components)
- var/obj/item/weapon/computer_hardware/H = C
+ var/obj/item/weapon/computer_hardware/H = all_components[C]
uninstall_component(H)
H.forceMove(newloc)
if(prob(25))
diff --git a/code/modules/modular_computers/computers/item/computer_power.dm b/code/modules/modular_computers/computers/item/computer_power.dm
index f6196477000..c5aab99ce57 100644
--- a/code/modules/modular_computers/computers/item/computer_power.dm
+++ b/code/modules/modular_computers/computers/item/computer_power.dm
@@ -3,10 +3,14 @@
if(check_power_override())
return TRUE
+ var/obj/item/weapon/computer_hardware/recharger/recharger = all_components[MC_CHARGE]
+
if(recharger && recharger.check_functionality())
if(recharger.use_power(amount))
return TRUE
+ var/obj/item/weapon/computer_hardware/battery/battery_module = all_components[MC_CELL]
+
if(battery_module && battery_module.battery && battery_module.battery.charge)
var/obj/item/weapon/stock_parts/cell/cell = battery_module.battery
if(cell.use(amount * CELLRATE))
@@ -17,6 +21,7 @@
return FALSE
/obj/item/device/modular_computer/proc/give_power(amount)
+ var/obj/item/weapon/computer_hardware/battery/battery_module = all_components[MC_CELL]
if(battery_module && battery_module.battery)
return battery_module.battery.give(amount)
return 0
@@ -34,6 +39,7 @@
// Handles power-related things, such as battery interaction, recharging, shutdown when it's discharged
/obj/item/device/modular_computer/proc/handle_power()
+ var/obj/item/weapon/computer_hardware/recharger/recharger = all_components[MC_CHARGE]
if(recharger)
recharger.process()
diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm
index a89e84b31f4..b551b98ede7 100644
--- a/code/modules/modular_computers/computers/item/computer_ui.dm
+++ b/code/modules/modular_computers/computers/item/computer_ui.dm
@@ -24,6 +24,7 @@
// We are still here, that means there is no program loaded. Load the BIOS/ROM/OS/whatever you want to call it.
// This screen simply lists available programs and user may select them.
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD]
if(!hard_drive || !hard_drive.stored_files || !hard_drive.stored_files.len)
physical.visible_message("\The [src] beeps three times, it's screen displaying \"DISK ERROR\" warning.")
return // No HDD, No HDD files list or no stored files. Something is very broken.
@@ -41,6 +42,7 @@
/obj/item/device/modular_computer/ui_data(mob/user)
var/list/data = get_header_data()
data["programs"] = list()
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD]
for(var/datum/computer_file/program/P in hard_drive.stored_files)
var/running = 0
if(P in idle_threads)
@@ -55,6 +57,7 @@
/obj/item/device/modular_computer/ui_act(action, params)
if(..())
return
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = all_components[MC_HDD]
switch(action)
if("PC_exit")
kill_program()
@@ -64,7 +67,7 @@
return 1
if("PC_minimize")
var/mob/user = usr
- if(!active_program || !processor_unit)
+ if(!active_program || !all_components[MC_CPU])
return
idle_threads.Add(active_program)
@@ -112,7 +115,9 @@
update_icon()
return
- if(idle_threads.len >= processor_unit.max_idle_programs+1)
+ var/obj/item/weapon/computer_hardware/processor_unit/PU = all_components[MC_CPU]
+
+ if(idle_threads.len > PU.max_idle_programs)
user << "\The [src] displays a \"Maximal CPU load reached. Unable to run another program.\" error."
return
diff --git a/code/modules/modular_computers/computers/item/processor.dm b/code/modules/modular_computers/computers/item/processor.dm
index 65712546ef6..d50b9f9fd30 100644
--- a/code/modules/modular_computers/computers/item/processor.dm
+++ b/code/modules/modular_computers/computers/item/processor.dm
@@ -23,6 +23,8 @@
CRASH("Inapropriate type passed to obj/item/device/modular_computer/processor/New()! Aborting.")
return
// Obtain reference to machinery computer
+ all_components = list()
+ idle_threads = list()
machinery_computer = comp
machinery_computer.cpu = src
hardware_flag = machinery_computer.hardware_flag
@@ -53,3 +55,17 @@
..()
machinery_computer.update_icon()
return
+
+/obj/item/device/modular_computer/processor/add_verb(path)
+ switch(path)
+ if(MC_CARD)
+ machinery_computer.verbs += /obj/machinery/modular_computer/proc/eject_id
+ if(MC_SDD)
+ machinery_computer.verbs += /obj/machinery/modular_computer/proc/eject_disk
+
+/obj/item/device/modular_computer/processor/remove_verb(path)
+ switch(path)
+ if(MC_CARD)
+ machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_id
+ if(MC_SDD)
+ machinery_computer.verbs -= /obj/machinery/modular_computer/proc/eject_disk
\ No newline at end of file
diff --git a/code/modules/modular_computers/computers/item/tablet.dm b/code/modules/modular_computers/computers/item/tablet.dm
index 0c8cad838de..54e27ea1d15 100644
--- a/code/modules/modular_computers/computers/item/tablet.dm
+++ b/code/modules/modular_computers/computers/item/tablet.dm
@@ -1,4 +1,4 @@
-/obj/item/device/modular_computer/tablet
+/obj/item/device/modular_computer/tablet //Its called tablet for theme of 90ies but actually its a "big smartphone" sized
name = "tablet computer"
icon = 'icons/obj/modular_tablet.dmi'
icon_state = "tablet"
@@ -9,3 +9,4 @@
max_hardware_size = 1
w_class = 2
steel_sheet_cost = 1
+ slot_flags = SLOT_ID | SLOT_BELT
\ No newline at end of file
diff --git a/code/modules/modular_computers/computers/machinery/console_presets.dm b/code/modules/modular_computers/computers/machinery/console_presets.dm
index a4741b16745..7f16199f53f 100644
--- a/code/modules/modular_computers/computers/machinery/console_presets.dm
+++ b/code/modules/modular_computers/computers/machinery/console_presets.dm
@@ -30,8 +30,9 @@
desc = "A stationary computer. This one comes preloaded with engineering programs."
/obj/machinery/modular_computer/console/preset/engineering/install_programs()
- cpu.hard_drive.store_file(new/datum/computer_file/program/power_monitor())
- cpu.hard_drive.store_file(new/datum/computer_file/program/alarm_monitor())
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
+ hard_drive.store_file(new/datum/computer_file/program/power_monitor())
+ hard_drive.store_file(new/datum/computer_file/program/alarm_monitor())
// ===== RESEARCH CONSOLE =====
/obj/machinery/modular_computer/console/preset/research
@@ -39,9 +40,10 @@
desc = "A stationary computer. This one comes preloaded with research programs."
/obj/machinery/modular_computer/console/preset/research/install_programs()
- cpu.hard_drive.store_file(new/datum/computer_file/program/ntnetmonitor())
- cpu.hard_drive.store_file(new/datum/computer_file/program/nttransfer())
- cpu.hard_drive.store_file(new/datum/computer_file/program/chatclient())
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
+ hard_drive.store_file(new/datum/computer_file/program/ntnetmonitor())
+ hard_drive.store_file(new/datum/computer_file/program/nttransfer())
+ hard_drive.store_file(new/datum/computer_file/program/chatclient())
// ===== COMMAND CONSOLE =====
@@ -52,8 +54,9 @@
_has_printer = 1
/obj/machinery/modular_computer/console/preset/command/install_programs()
- cpu.hard_drive.store_file(new/datum/computer_file/program/chatclient())
- cpu.hard_drive.store_file(new/datum/computer_file/program/card_mod())
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
+ hard_drive.store_file(new/datum/computer_file/program/chatclient())
+ hard_drive.store_file(new/datum/computer_file/program/card_mod())
// ===== CIVILIAN CONSOLE =====
/obj/machinery/modular_computer/console/preset/civilian
@@ -61,6 +64,6 @@
desc = "A stationary computer. This one comes preloaded with generic programs."
/obj/machinery/modular_computer/console/preset/civilian/install_programs()
- cpu.hard_drive.store_file(new/datum/computer_file/program/chatclient())
- cpu.hard_drive.store_file(new/datum/computer_file/program/nttransfer())
-
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
+ hard_drive.store_file(new/datum/computer_file/program/chatclient())
+ hard_drive.store_file(new/datum/computer_file/program/nttransfer())
\ No newline at end of file
diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm
index 2aada0b5860..e04bc0cee73 100644
--- a/code/modules/modular_computers/computers/machinery/modular_computer.dm
+++ b/code/modules/modular_computers/computers/machinery/modular_computer.dm
@@ -74,7 +74,7 @@ var/list/global_modular_computers = list()
add_overlay("broken")
// Eject ID card from computer, if it has ID slot with card inside.
-/obj/machinery/modular_computer/verb/eject_id()
+/obj/machinery/modular_computer/proc/eject_id()
set name = "Eject ID"
set category = "Object"
set src in view(1)
@@ -83,7 +83,7 @@ var/list/global_modular_computers = list()
cpu.eject_id()
// Eject ID card from computer, if it has ID slot with card inside.
-/obj/machinery/modular_computer/verb/eject_disk()
+/obj/machinery/modular_computer/proc/eject_disk()
set name = "Eject Data Disk"
set category = "Object"
set src in view(1)
@@ -109,8 +109,9 @@ var/list/global_modular_computers = list()
// Used in following function to reduce copypaste
/obj/machinery/modular_computer/proc/power_failure(malfunction = 0)
+ var/obj/item/weapon/computer_hardware/battery/battery_module = cpu.all_components[MC_CELL]
if(cpu && cpu.enabled) // Shut down the computer
- visible_message("\The [src]'s screen flickers [cpu.battery_module ? "\"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\"" : "\"EXTERNAL POWER LOSS\""] warning as it shuts down unexpectedly.")
+ visible_message("\The [src]'s screen flickers [battery_module ? "\"BATTERY [malfunction ? "MALFUNCTION" : "CRITICAL"]\"" : "\"EXTERNAL POWER LOSS\""] warning as it shuts down unexpectedly.")
if(cpu)
cpu.shutdown_computer(0)
stat |= NOPOWER
@@ -119,7 +120,7 @@ var/list/global_modular_computers = list()
// Modular computers can have battery in them, we handle power in previous proc, so prevent this from messing it up for us.
/obj/machinery/modular_computer/power_change()
- if(cpu && cpu.use_power()) // If "CPU" still has a power source, PC wouldn't go offline.
+ if(cpu && cpu.use_power()) // If MC_CPU still has a power source, PC wouldn't go offline.
stat &= ~NOPOWER
update_icon()
return
diff --git a/code/modules/modular_computers/computers/machinery/modular_console.dm b/code/modules/modular_computers/computers/machinery/modular_console.dm
index b5b6fe7b143..cebb1f4d715 100644
--- a/code/modules/modular_computers/computers/machinery/modular_console.dm
+++ b/code/modules/modular_computers/computers/machinery/modular_console.dm
@@ -22,29 +22,35 @@
/obj/machinery/modular_computer/console/buildable/New()
..()
// User-built consoles start as empty frames.
- qdel(cpu.recharger)
- qdel(cpu.network_card)
- qdel(cpu.hard_drive)
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = cpu.all_components[MC_HDD]
+ var/obj/item/weapon/computer_hardware/hard_drive/network_card = cpu.all_components[MC_NET]
+ var/obj/item/weapon/computer_hardware/hard_drive/recharger = cpu.all_components[MC_CHARGE]
+ qdel(recharger)
+ qdel(network_card)
+ qdel(hard_drive)
/obj/machinery/modular_computer/console/New()
..()
- if(cpu.battery_module)
- qdel(cpu.battery_module)
+ var/obj/item/weapon/computer_hardware/battery/battery_module = cpu.all_components[MC_CELL]
+ if(battery_module)
+ qdel(battery_module)
- cpu.install_component(new /obj/item/weapon/computer_hardware/network_card/wired)
+ var/obj/item/weapon/computer_hardware/network_card/wired/network_card = new()
+
+ cpu.install_component(network_card)
cpu.install_component(new /obj/item/weapon/computer_hardware/recharger/APC)
cpu.install_component(new /obj/item/weapon/computer_hardware/hard_drive/super) // Consoles generally have better HDDs due to lower space limitations
var/area/A = get_area(src)
// Attempts to set this console's tag according to our area. Since some areas have stuff like "XX - YY" in their names we try to remove that too.
if(A && console_department)
- cpu.network_card.identification_string = replacetext(replacetext(replacetext("[A.name] [console_department] Console", " ", "_"), "-", ""), "__", "_") // Replace spaces with "_"
+ network_card.identification_string = replacetext(replacetext(replacetext("[A.name] [console_department] Console", " ", "_"), "-", ""), "__", "_") // Replace spaces with "_"
else if(A)
- cpu.network_card.identification_string = replacetext(replacetext(replacetext("[A.name] Console", " ", "_"), "-", ""), "__", "_")
+ network_card.identification_string = replacetext(replacetext(replacetext("[A.name] Console", " ", "_"), "-", ""), "__", "_")
else if(console_department)
- cpu.network_card.identification_string = replacetext(replacetext(replacetext("[console_department] Console", " ", "_"), "-", ""), "__", "_")
+ network_card.identification_string = replacetext(replacetext(replacetext("[console_department] Console", " ", "_"), "-", ""), "__", "_")
else
- cpu.network_card.identification_string = "Unknown Console"
+ network_card.identification_string = "Unknown Console"
if(cpu)
cpu.screen_on = 1
update_icon()
\ No newline at end of file
diff --git a/code/modules/modular_computers/documentation.dm b/code/modules/modular_computers/documentation.dm
deleted file mode 100644
index 94e02f8125c..00000000000
--- a/code/modules/modular_computers/documentation.dm
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-
-Ok. so a quick rundown on how to make a program. This is kind of a shitty documentation, but oh well I was asked to.
-
-
-This is how the base program is setup. the rest is mostly tgui stuff. I'll use the ntnetmonitor as a base
-
-/datum/computer_file/program/ntnetmonitor
- filename = "ntmonitor" <- This is obviously the name of the file itself. not much to be said
- filedesc = "NTNet Diagnostics and Monitoring" <- This sort of the official name. it's what shows up on the main menu
- program_icon_state = "comm_monitor" <- This is what the screen will look like when the program is active
- extended_desc = "This program is a dummy. <- This is a sort of description, visible when looking on the ntnet
- size = 12 <- size of the program. Big programs need more hard drive space. Don't make it too big though.
- requires_ntnet = 1 <- if this is set, the program will not run and will close if ntnet connection is lost. mainly for primarily online programs.
- required_access = access_network <- This is access required to run the program itself. ONLY SET THIS FOR SUPER SECURE SHIT. This also acts as transfer_access as well.
- transfer_access = access_change_ids <- this is the access needed to download from ntnet or host on the ptp program. This is what you want to use most of the time.
- available_on_ntnet = 1 <- If it's available to download on ntnet. pretty self explanatory.
- available_on_syndinet = 0 <- ditto but on emagged syndie net. Use this for antag programs
- usage_flags = PROGRAM_ALL // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL
- ^^- The comment above sorta explains it. Use this to limit what kind of machines can run the program. For example, comms program should be limited to consoles and laptops.
- var/ui_header = "downloader_finished.gif" <- this one is kinda cool. If you have the program minimized, this will show up in the header of the computer screen.
- you can even have the program change what the header is based on the situation! see alarm.dm for an example.
-
-
-Now. for pre-installing stuff.
-
-Primarily done for consoles, there's an install_programs() proc in the console presets file in the machines folder.
-
-for example, the command console one.
-
-/obj/machinery/modular_computer/console/preset/command/install_programs()
- cpu.hard_drive.store_file(new/datum/computer_file/program/chatclient())
- cpu.hard_drive.store_file(new/datum/computer_file/program/card_mod())
-
-Basically, you want to do cpu.hard_drive.store_file(new/*program path here*()) and put it in the subtype's install_programs().
-Probably pretty self explanatory, but just in case.
-
-Will probably be expanded when new features come around or I get asked to mention something.
-
-*/
\ No newline at end of file
diff --git a/code/modules/modular_computers/documentation.md b/code/modules/modular_computers/documentation.md
new file mode 100644
index 00000000000..88d8602729d
--- /dev/null
+++ b/code/modules/modular_computers/documentation.md
@@ -0,0 +1,45 @@
+
+
+#Modular computer programs
+Ok. so a quick rundown on how to make a program. This is kind of a shitty documentation, but oh well I was asked to.
+
+
+## Base setup
+This is how the base program is setup. the rest is mostly tgui stuff. I'll use the ntnetmonitor as a base
+
+
+```DM
+/datum/computer_file/program/ntnetmonitor
+ filename = "ntmonitor" //This is obviously the name of the file itself. not much to be said
+ filedesc = "NTNet Diagnostics and Monitoring" // This is sort of the official name. it's what shows up on the main menu
+ program_icon_state = "comm_monitor" // This is what the screen will look like when the program is active
+ extended_desc = "This program is a dummy. // This is a sort of a description, visible when looking on the ntnet
+ size = 12 // size of the program. Big programs need more hard drive space. Don't make it too big though.
+ requires_ntnet = 1 // If this is set, the program will not run without an ntnet connection, and will close if the connection is lost. Mainly for primarily online programs.
+ required_access = access_network //This is access required to run the program itself. ONLY SET THIS FOR SUPER SECURE SHIT. This also acts as transfer_access as well.
+ transfer_access = access_change_ids // This is the access needed to download from ntnet or host on the ptp program. This is what you want to use most of the time.
+ available_on_ntnet = 1 //If it's available to download on ntnet. pretty self explanatory.
+ available_on_syndinet = 0 // ditto but on emagged syndie net. Use this for antag programs
+ usage_flags = PROGRAM_ALL // Bitflags (PROGRAM_CONSOLE, PROGRAM_LAPTOP, PROGRAM_TABLET combination) or PROGRAM_ALL
+ //^^- The comment above sorta explains it. Use this to limit what kind of machines can run the program. For example, comms program should be limited to consoles and laptops.
+ var/ui_header = "downloader_finished.gif" //This one is kinda cool. If you have the program minimized, this will show up in the header of the computer screen.
+ //you can even have the program change what the header is based on the situation! see alarm.dm for an example.
+```
+
+##Preinstalls
+Now. for pre-installing stuff.
+
+Primarily done for consoles, there's an install_programs() proc in the console presets file in the machines folder.
+
+for example, the command console one.
+
+```DM
+/obj/machinery/modular_computer/console/preset/command/install_programs()
+ cpu.hard_drive.store_file(new/datum/computer_file/program/chatclient())
+ cpu.hard_drive.store_file(new/datum/computer_file/program/card_mod())
+```
+Basically, you want to do cpu.hard_drive.store_file(new/*program path here*()) and put it in the subtype's install_programs().
+Probably pretty self explanatory, but just in case.
+
+Will probably be expanded when new features come around or I get asked to mention something.
+
diff --git a/code/modules/modular_computers/file_system/program.dm b/code/modules/modular_computers/file_system/program.dm
index 8ddff02fb64..46a9ea8ebc8 100644
--- a/code/modules/modular_computers/file_system/program.dm
+++ b/code/modules/modular_computers/file_system/program.dm
@@ -87,6 +87,11 @@
return 1
if(ishuman(user))
+ var/obj/item/weapon/card/id/D
+ var/obj/item/weapon/computer_hardware/card_slot/card_slot
+ if(computer && card_slot)
+ card_slot = computer.all_components[MC_CARD]
+ D = card_slot.GetID()
var/mob/living/carbon/human/h = user
var/obj/item/weapon/card/id/I = h.get_idcard()
var/obj/item/weapon/card/id/C = h.get_active_held_item()
@@ -95,7 +100,7 @@
if(!(C && istype(C)))
C = null
- if(!I && !C)
+ if(!I && !C && !D)
if(loud)
user << "\The [computer] flashes an \"RFID Error - Unable to scan ID\" warning."
return 0
@@ -106,6 +111,9 @@
else if(C)
if(access_to_check in C.GetAccess())
return 1
+ else if(D)
+ if(access_to_check in D.GetAccess())
+ return 1
if(loud)
user << "\The [computer] flashes an \"Access Denied\" warning."
return 0
@@ -162,7 +170,7 @@
return 1
if("PC_minimize")
var/mob/user = usr
- if(!computer.active_program || !computer.processor_unit)
+ if(!computer.active_program || !computer.all_components[MC_CPU])
return
computer.idle_threads.Add(computer.active_program)
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
index d14bb885bfe..3d54938ba11 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/dos.dm
@@ -69,7 +69,8 @@
executed = 1
target.dos_sources.Add(src)
if(ntnet_global.intrusion_detection_enabled)
- ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [computer.network_card.get_network_tag()]")
+ var/obj/item/weapon/computer_hardware/network_card/network_card = computer.all_components[MC_NET]
+ ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]")
ntnet_global.intrusion_detection_alarm = 1
return 1
diff --git a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
index f5ae0766f74..89040ca7ae7 100644
--- a/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
+++ b/code/modules/modular_computers/file_system/programs/antagonist/revelation.dm
@@ -19,16 +19,19 @@
computer.visible_message("\The [computer]'s screen brightly flashes and loud electrical buzzing is heard.")
computer.enabled = 0
computer.update_icon()
- qdel(computer.hard_drive)
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
+ var/obj/item/weapon/computer_hardware/battery/battery_module = computer.all_components[MC_CELL]
+ var/obj/item/weapon/computer_hardware/recharger/recharger = computer.all_components[MC_CHARGE]
+ qdel(hard_drive)
computer.take_damage(25, 10, 1, 1)
- if(computer.battery_module && prob(25))
- qdel(computer.battery_module)
+ if(battery_module && prob(25))
+ qdel(battery_module)
computer.visible_message("\The [computer]'s battery explodes in rain of sparks.")
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
spark_system.start()
- if(computer.recharger && prob(50))
- qdel(computer.recharger)
+ if(recharger && prob(50))
+ qdel(recharger)
computer.visible_message("\The [computer]'s recharger explodes in rain of sparks.")
var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
spark_system.start()
diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm
index 780045d8b73..0f1b03f4b38 100644
--- a/code/modules/modular_computers/file_system/programs/card.dm
+++ b/code/modules/modular_computers/file_system/programs/card.dm
@@ -88,7 +88,8 @@
/datum/computer_file/program/card_mod/proc/format_jobs(list/jobs)
- var/obj/item/weapon/card/id/id_card = computer.card_slot.stored_card
+ var/obj/item/weapon/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
+ var/obj/item/weapon/card/id/id_card = card_slot.stored_card
var/list/formatted = list()
for(var/job in jobs)
formatted.Add(list(list(
@@ -102,11 +103,19 @@
if(..())
return 1
+ var/obj/item/weapon/computer_hardware/card_slot/card_slot
+ var/obj/item/weapon/computer_hardware/printer/printer
+ if(computer)
+ card_slot = computer.all_components[MC_CARD]
+ printer = computer.all_components[MC_PRINT]
+ if(!card_slot)
+ return
+
var/obj/item/weapon/card/id/user_id_card = null
var/mob/user = usr
- var/obj/item/weapon/card/id/id_card = computer.card_slot.stored_card
- var/obj/item/weapon/card/id/auth_card = computer.card_slot.stored_card2
+ var/obj/item/weapon/card/id/id_card = card_slot.stored_card
+ var/obj/item/weapon/card/id/auth_card = card_slot.stored_card2
if(auth_card)
user_id_card = auth_card
@@ -129,7 +138,7 @@
else
show_assignments = 1
if("PRG_print")
- if(computer && computer.printer) //This option should never be called if there is no printer
+ if(computer && printer) //This option should never be called if there is no printer
if(mod_mode)
if(authorized())
var/contents = {"
Access Report
@@ -145,7 +154,7 @@
if(A in known_access_rights)
contents += " [get_access_desc(A)]"
- if(!computer.printer.print_text(contents,"access report"))
+ if(!printer.print_text(contents,"access report"))
usr << "Hardware error: Printer was unable to print the file. It may be out of paper."
return
else
@@ -155,26 +164,26 @@
[data_core ? data_core.get_manifest(0) : ""]
"}
- if(!computer.printer.print_text(contents,text("crew manifest ([])", worldtime2text())))
+ if(!printer.print_text(contents,text("crew manifest ([])", worldtime2text())))
usr << "Hardware error: Printer was unable to print the file. It may be out of paper."
return
else
computer.visible_message("\The [computer] prints out paper.")
if("PRG_eject")
- if(computer && computer.card_slot)
+ if(computer && card_slot)
var/select = params["target"]
switch(select)
if("id")
if(id_card)
data_core.manifest_modify(id_card.registered_name, id_card.assignment)
- computer.proc_eject_id(user, 1)
+ card_slot.try_eject(, user)
else
var/obj/item/I = usr.get_active_held_item()
if (istype(I, /obj/item/weapon/card/id))
if(!usr.drop_item())
return
I.forceMove(computer)
- computer.card_slot.stored_card = I
+ card_slot.stored_card = I
if("auth")
if(auth_card)
if(id_card)
@@ -183,14 +192,14 @@
region_access = null
authenticated = 0
minor = 0
- computer.proc_eject_id(user, 2)
+ card_slot.try_eject(, user)
else
var/obj/item/I = usr.get_active_held_item()
if (istype(I, /obj/item/weapon/card/id))
if(!usr.drop_item())
return
I.forceMove(computer)
- computer.card_slot.stored_card2 = I
+ card_slot.stored_card2 = I
if("PRG_terminate")
if(computer && ((id_card.assignment in head_subordinates) || id_card.assignment == "Assistant"))
id_card.assignment = "Unassigned"
@@ -292,13 +301,21 @@
var/list/data = get_header_data()
+ var/obj/item/weapon/computer_hardware/card_slot/card_slot
+ var/obj/item/weapon/computer_hardware/printer/printer
+
+ if(computer)
+ card_slot = computer.all_components[MC_CARD]
+ printer = computer.all_components[MC_PRINT]
+
data["mmode"] = mod_mode
var/authed = 0
- if(computer && computer.card_slot)
- var/obj/item/weapon/card/id/auth_card = computer.card_slot.stored_card2
- data["auth_name"] = auth_card ? strip_html_simple(auth_card.name) : "-----"
- authed = authorized()
+ if(computer)
+ if(card_slot)
+ var/obj/item/weapon/card/id/auth_card = card_slot.stored_card2
+ data["auth_name"] = auth_card ? strip_html_simple(auth_card.name) : "-----"
+ authed = authorized()
if(mod_mode == 2)
@@ -336,9 +353,9 @@
data["manifest"] = crew
data["assignments"] = show_assignments
if(computer)
- data["have_id_slot"] = !!computer.card_slot
- data["have_printer"] = !!computer.printer
- if(!computer.card_slot && mod_mode == 1)
+ data["have_id_slot"] = !!card_slot
+ data["have_printer"] = !!printer
+ if(!card_slot && mod_mode == 1)
mod_mode = 0 //We can't modify IDs when there is no card reader
else
data["have_id_slot"] = 0
@@ -350,10 +367,9 @@
data["authenticated"] = authed
- if(mod_mode == 1)
-
- if(computer && computer.card_slot)
- var/obj/item/weapon/card/id/id_card = computer.card_slot.stored_card
+ if(mod_mode == 1 && computer)
+ if(card_slot)
+ var/obj/item/weapon/card/id/id_card = card_slot.stored_card
data["has_id"] = !!id_card
data["id_rank"] = id_card && id_card.assignment ? html_encode(id_card.assignment) : "Unassigned"
@@ -370,8 +386,8 @@
data["centcom_jobs"] = format_jobs(get_all_centcom_jobs())
- if(computer.card_slot.stored_card)
- var/obj/item/weapon/card/id/id_card = computer.card_slot.stored_card
+ if(card_slot.stored_card)
+ var/obj/item/weapon/card/id/id_card = card_slot.stored_card
if(is_centcom)
var/list/all_centcom_access = list()
for(var/access in get_all_centcom_access())
@@ -431,9 +447,10 @@
/datum/computer_file/program/card_mod/proc/authorized()
- if(!authenticated)
- if(computer && computer.card_slot)
- var/obj/item/weapon/card/id/auth_card = computer.card_slot.stored_card2
+ if(!authenticated && computer)
+ var/obj/item/weapon/computer_hardware/card_slot/card_slot = computer.all_components[MC_CARD]
+ if(card_slot)
+ var/obj/item/weapon/card/id/auth_card = card_slot.stored_card2
if(auth_card)
region_access = list()
if(transfer_access in auth_card.GetAccess())
diff --git a/code/modules/modular_computers/file_system/programs/configurator.dm b/code/modules/modular_computers/file_system/programs/configurator.dm
index 6b77cbbd4e6..57348d27441 100644
--- a/code/modules/modular_computers/file_system/programs/configurator.dm
+++ b/code/modules/modular_computers/file_system/programs/configurator.dm
@@ -29,6 +29,8 @@
/datum/computer_file/program/computerconfig/ui_data(mob/user)
movable = computer
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = movable.all_components[MC_HDD]
+ var/obj/item/weapon/computer_hardware/battery/battery_module = movable.all_components[MC_CELL]
if(!istype(movable))
movable = null
@@ -38,20 +40,20 @@
var/list/data = get_header_data()
- data["disk_size"] = movable.hard_drive.max_capacity
- data["disk_used"] = movable.hard_drive.used_capacity
+ data["disk_size"] = hard_drive.max_capacity
+ data["disk_used"] = hard_drive.used_capacity
data["power_usage"] = movable.last_power_usage
- data["battery_exists"] = movable.battery_module ? 1 : 0
- if(movable.battery_module && movable.battery_module.battery)
- data["battery_rating"] = movable.battery_module.battery.maxcharge
- data["battery_percent"] = round(movable.battery_module.battery.percent())
+ data["battery_exists"] = battery_module ? 1 : 0
+ if(battery_module && battery_module.battery)
+ data["battery_rating"] = battery_module.battery.maxcharge
+ data["battery_percent"] = round(battery_module.battery.percent())
- if(movable.battery_module && movable.battery_module.battery)
- data["battery"] = list("max" = movable.battery_module.battery.maxcharge, "charge" = round(movable.battery_module.battery.charge))
+ if(battery_module && battery_module.battery)
+ data["battery"] = list("max" = battery_module.battery.maxcharge, "charge" = round(battery_module.battery.charge))
var/list/all_entries[0]
for(var/I in movable.all_components)
- var/obj/item/weapon/computer_hardware/H = I
+ var/obj/item/weapon/computer_hardware/H = movable.all_components[I]
all_entries.Add(list(list(
"name" = H.name,
"desc" = H.desc,
diff --git a/code/modules/modular_computers/file_system/programs/file_browser.dm b/code/modules/modular_computers/file_system/programs/file_browser.dm
index 254f09b694a..50a07014e5c 100644
--- a/code/modules/modular_computers/file_system/programs/file_browser.dm
+++ b/code/modules/modular_computers/file_system/programs/file_browser.dm
@@ -14,8 +14,9 @@
if(..())
return 1
- var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.hard_drive
- var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.portable_drive
+ var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD]
+ var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.all_components[MC_HDD]
+ var/obj/item/weapon/computer_hardware/printer/printer = computer.all_components[MC_PRINT]
switch(action)
if("PRG_openfile")
@@ -106,10 +107,10 @@
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
if(!F || !istype(F))
return 1
- if(!computer.printer)
+ if(!printer)
error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
return 1
- if(!computer.printer.print_text(parse_tags(F.stored_data)))
+ if(!printer.print_text(parse_tags(F.stored_data)))
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
return 1
if("PRG_copytousb")
@@ -185,17 +186,16 @@
/datum/computer_file/program/filemanager/ui_data(mob/user)
var/list/data = get_header_data()
- var/obj/item/weapon/computer_hardware/hard_drive/HDD
- var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD
+ var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD]
+ var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.all_components[MC_SDD]
if(error)
data["error"] = error
if(open_file)
var/datum/computer_file/data/file
- if(!computer || !computer.hard_drive)
+ if(!computer || !HDD)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
- HDD = computer.hard_drive
file = HDD.find_file_by_name(open_file)
if(!istype(file))
data["error"] = "I/O ERROR: Unable to open file."
@@ -203,11 +203,9 @@
data["filedata"] = parse_tags(file.stored_data)
data["filename"] = "[file.filename].[file.filetype]"
else
- if(!computer || !computer.hard_drive)
+ if(!computer || !HDD)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
- HDD = computer.hard_drive
- RHDD = computer.portable_drive
var/list/files[0]
for(var/datum/computer_file/F in HDD.stored_files)
files.Add(list(list(
diff --git a/code/modules/modular_computers/file_system/programs/ntdownloader.dm b/code/modules/modular_computers/file_system/programs/ntdownloader.dm
index 32d8d2eba13..c15bcd1fce2 100644
--- a/code/modules/modular_computers/file_system/programs/ntdownloader.dm
+++ b/code/modules/modular_computers/file_system/programs/ntdownloader.dm
@@ -30,7 +30,9 @@
if(PRG.available_on_syndinet && !computer.emagged)
return 0
- if(!computer || !computer.hard_drive || !computer.hard_drive.can_store_file(PRG))
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
+
+ if(!computer || !hard_drive || !hard_drive.can_store_file(PRG))
return 0
ui_header = "downloader_running.gif"
@@ -59,7 +61,8 @@
if(!downloaded_file)
return
generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : "[downloaded_file.filename].[downloaded_file.filetype]"].")
- if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(downloaded_file))
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
+ if(!computer || !hard_drive || !hard_drive.store_file(downloaded_file))
// The download failed
downloaderror = "I/O ERROR - Unable to save file. Check whether you have enough free space on your hard drive and whether your hard drive is properly connected. If the issue persists contact your system administrator for assistance."
downloaded_file = null
@@ -129,8 +132,9 @@
data["downloadspeed"] = download_netspeed
data["downloadcompletion"] = round(download_completion, 0.1)
else // No download running, pick file.
- data["disk_size"] = my_computer.hard_drive.max_capacity
- data["disk_used"] = my_computer.hard_drive.used_capacity
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = my_computer.all_components[MC_HDD]
+ data["disk_size"] = hard_drive.max_capacity
+ data["disk_used"] = hard_drive.used_capacity
var/list/all_entries[0]
for(var/A in ntnet_global.available_station_software)
var/datum/computer_file/program/P = A
@@ -160,3 +164,7 @@
data["downloadable_programs"] = all_entries
return data
+
+/datum/computer_file/program/ntnetdownload/kill_program(forced)
+ abort_file_download()
+ return ..(forced)
\ No newline at end of file
diff --git a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
index b559e9d161f..1b8ff887673 100644
--- a/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
+++ b/code/modules/modular_computers/file_system/programs/ntnrc_client.dm
@@ -28,7 +28,7 @@
if(!channel)
return 1
var/mob/living/user = usr
- var/message = sanitize(input(user, "Enter message or leave blank to cancel: "))
+ var/message = reject_bad_text(input(user, "Enter message or leave blank to cancel: "))
if(!message || !channel)
return
channel.add_message(message, username)
@@ -51,7 +51,7 @@
if(C.password)
var/mob/living/user = usr
- var/password = sanitize(input(user,"Access Denied. Enter password:"))
+ var/password = reject_bad_text(input(user,"Access Denied. Enter password:"))
if(C && (password == C.password))
C.add_client(src)
channel = C
@@ -66,7 +66,7 @@
if("PRG_newchannel")
. = 1
var/mob/living/user = usr
- var/channel_title = sanitize(input(user,"Enter channel name or leave blank to cancel:"))
+ var/channel_title = reject_bad_text(input(user,"Enter channel name or leave blank to cancel:"))
if(!channel_title)
return
var/datum/ntnet_conversation/C = new/datum/ntnet_conversation()
@@ -119,12 +119,13 @@
logfile.stored_data += "[logstring]\[BR\]"
logfile.stored_data += "\[b\]Logfile dump completed.\[/b\]"
logfile.calculate_size()
- if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(logfile))
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
+ if(!computer || !hard_drive || !hard_drive.store_file(logfile))
if(!computer)
// This program shouldn't even be runnable without computer.
CRASH("Var computer is null!")
return 1
- if(!computer.hard_drive)
+ if(!hard_drive)
computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.")
else // In 99.9% cases this will mean our HDD is full
computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.")
@@ -133,7 +134,7 @@
if(!operator_mode || !channel)
return 1
var/mob/living/user = usr
- var/newname = sanitize(input(user, "Enter new channel name or leave blank to cancel:"))
+ var/newname = reject_bad_text(input(user, "Enter new channel name or leave blank to cancel:"))
if(!newname || !channel)
return
channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.")
diff --git a/code/modules/modular_computers/file_system/programs/nttransfer.dm b/code/modules/modular_computers/file_system/programs/nttransfer.dm
index ffc4653221e..4e20bbf9ea5 100644
--- a/code/modules/modular_computers/file_system/programs/nttransfer.dm
+++ b/code/modules/modular_computers/file_system/programs/nttransfer.dm
@@ -66,7 +66,8 @@ var/global/nttransfer_uid = 0
// Finishes download and attempts to store the file on HDD
/datum/computer_file/program/nttransfer/proc/finish_download()
- if(!computer || !computer.hard_drive || !computer.hard_drive.store_file(downloaded_file))
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
+ if(!computer || !hard_drive || !hard_drive.store_file(downloaded_file))
error = "I/O Error: Unable to save file. Check your hard drive and try again."
finalize_download()
@@ -109,7 +110,7 @@ var/global/nttransfer_uid = 0
if(!remote || !remote.provided_file)
return
if(remote.server_password)
- var/pass = sanitize(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required"))
+ var/pass = reject_bad_text(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required"))
if(pass != remote.server_password)
error = "Incorrect Password"
return
@@ -127,7 +128,7 @@ var/global/nttransfer_uid = 0
provided_file = null
return 1
if("PRG_setpassword")
- var/pass = sanitize(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none"))
+ var/pass = reject_bad_text(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none"))
if(!pass)
return
if(pass == "none")
@@ -136,7 +137,8 @@ var/global/nttransfer_uid = 0
server_password = pass
return 1
if("PRG_uploadfile")
- for(var/datum/computer_file/F in computer.hard_drive.stored_files)
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
+ for(var/datum/computer_file/F in hard_drive.stored_files)
if("[F.uid]" == params["id"])
if(F.unsendable)
error = "I/O Error: File locked."
@@ -174,7 +176,8 @@ var/global/nttransfer_uid = 0
data["upload_filename"] = "[provided_file.filename].[provided_file.filetype]"
else if (upload_menu)
var/list/all_files[0]
- for(var/datum/computer_file/F in computer.hard_drive.stored_files)
+ var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
+ for(var/datum/computer_file/F in hard_drive.stored_files)
all_files.Add(list(list(
"uid" = F.uid,
"filename" = "[F.filename].[F.filetype]",
diff --git a/code/modules/modular_computers/hardware/CPU.dm b/code/modules/modular_computers/hardware/CPU.dm
index e78f02d85cc..d212df22028 100644
--- a/code/modules/modular_computers/hardware/CPU.dm
+++ b/code/modules/modular_computers/hardware/CPU.dm
@@ -11,6 +11,10 @@
malfunction_probability = 1
origin_tech = "programming=3;engineering=2"
var/max_idle_programs = 2 // 2 idle, + 1 active = 3 as said in description.
+ device_type = MC_CPU
+
+/obj/item/weapon/computer_hardware/processor_unit/on_remove(obj/item/device/modular_computer/MC, mob/user)
+ MC.shutdown_computer()
/obj/item/weapon/computer_hardware/processor_unit/small
name = "microprocessor"
diff --git a/code/modules/modular_computers/hardware/_hardware.dm b/code/modules/modular_computers/hardware/_hardware.dm
index ebbef88c2d0..81f61671555 100644
--- a/code/modules/modular_computers/hardware/_hardware.dm
+++ b/code/modules/modular_computers/hardware/_hardware.dm
@@ -18,6 +18,7 @@
var/damage_malfunction = 20 // "Malfunction" threshold. When damage exceeds this value the hardware piece will semi-randomly fail and do !!FUN!! things
var/damage_failure = 50 // "Failure" threshold. When damage exceeds this value the hardware piece will not work at all.
var/malfunction_probability = 10// Chance of malfunction when the component is damaged
+ var/device_type
/obj/item/weapon/computer_hardware/New(var/obj/L)
..()
diff --git a/code/modules/modular_computers/hardware/battery_module.dm b/code/modules/modular_computers/hardware/battery_module.dm
index 824cd03bf21..7c4e9d169a1 100644
--- a/code/modules/modular_computers/hardware/battery_module.dm
+++ b/code/modules/modular_computers/hardware/battery_module.dm
@@ -6,6 +6,7 @@
malfunction_probability = 1
origin_tech = "powerstorage=1;engineering=1"
var/obj/item/weapon/stock_parts/cell/battery = null
+ device_type = MC_CELL
/obj/item/weapon/computer_hardware/battery/New(loc, battery_type = null)
if(battery_type)
diff --git a/code/modules/modular_computers/hardware/card_slot.dm b/code/modules/modular_computers/hardware/card_slot.dm
index f0fb2cd20c2..7648d74f54b 100644
--- a/code/modules/modular_computers/hardware/card_slot.dm
+++ b/code/modules/modular_computers/hardware/card_slot.dm
@@ -5,6 +5,7 @@
icon_state = "card_mini"
w_class = 1
origin_tech = "programming=2"
+ device_type = MC_CARD
var/obj/item/weapon/card/id/stored_card = null
var/obj/item/weapon/card/id/stored_card2 = null
@@ -29,6 +30,12 @@
return stored_card2
return ..()
+/obj/item/weapon/computer_hardware/card_slot/on_install(obj/item/device/modular_computer/M, mob/living/user = null)
+ M.add_verb(device_type)
+
+/obj/item/weapon/computer_hardware/card_slot/on_remove(obj/item/device/modular_computer/M, mob/living/user = null)
+ M.remove_verb(device_type)
+
/obj/item/weapon/computer_hardware/card_slot/try_insert(obj/item/I, mob/living/user = null)
if(!holder)
return FALSE
diff --git a/code/modules/modular_computers/hardware/hard_drive.dm b/code/modules/modular_computers/hardware/hard_drive.dm
index e5e43f57283..62c02e0a07a 100644
--- a/code/modules/modular_computers/hardware/hard_drive.dm
+++ b/code/modules/modular_computers/hardware/hard_drive.dm
@@ -6,10 +6,14 @@
critical = 1
w_class = 1
origin_tech = "programming=1;engineering=1"
+ device_type = MC_HDD
var/max_capacity = 128
var/used_capacity = 0
var/list/stored_files = list() // List of stored files on this drive. DO NOT MODIFY DIRECTLY!
+/obj/item/weapon/computer_hardware/hard_drive/on_remove(obj/item/device/modular_computer/MC, mob/user)
+ MC.shutdown_computer()
+
/obj/item/weapon/computer_hardware/hard_drive/proc/install_default_programs()
store_file(new/datum/computer_file/program/computerconfig(src)) // Computer configuration utility, allows hardware control and displays more info than status bar
store_file(new/datum/computer_file/program/ntnetdownload(src)) // NTNet Downloader Utility, allows users to download more software from NTNet repository
diff --git a/code/modules/modular_computers/hardware/network_card.dm b/code/modules/modular_computers/hardware/network_card.dm
index 681dbd503da..8370ad4e384 100644
--- a/code/modules/modular_computers/hardware/network_card.dm
+++ b/code/modules/modular_computers/hardware/network_card.dm
@@ -11,6 +11,7 @@ var/global/ntnet_card_uid = 1
var/long_range = 0
var/ethernet = 0 // Hard-wired, therefore always on, ignores NTNet wireless checks.
malfunction_probability = 1
+ device_type = MC_NET
/obj/item/weapon/computer_hardware/network_card/diagnostics(var/mob/user)
..()
diff --git a/code/modules/modular_computers/hardware/portable_disk.dm b/code/modules/modular_computers/hardware/portable_disk.dm
index 4878e530150..b7392d531f9 100644
--- a/code/modules/modular_computers/hardware/portable_disk.dm
+++ b/code/modules/modular_computers/hardware/portable_disk.dm
@@ -7,6 +7,14 @@
critical = 0
max_capacity = 16
origin_tech = "programming=1"
+ device_type = MC_SDD
+
+/obj/item/weapon/computer_hardware/hard_drive/portable/on_install(obj/item/device/modular_computer/M, mob/living/user = null)
+ M.add_verb(device_type)
+
+/obj/item/weapon/computer_hardware/hard_drive/portable/on_remove(obj/item/device/modular_computer/M, mob/living/user = null)
+ ..()
+ M.remove_verb(device_type)
/obj/item/weapon/computer_hardware/hard_drive/portable/install_default_programs()
return // Empty by default
diff --git a/code/modules/modular_computers/hardware/printer.dm b/code/modules/modular_computers/hardware/printer.dm
index c23905bf119..a93fdd20309 100644
--- a/code/modules/modular_computers/hardware/printer.dm
+++ b/code/modules/modular_computers/hardware/printer.dm
@@ -5,6 +5,7 @@
origin_tech = "programming=2;engineering=2"
icon_state = "printer"
w_class = 3
+ device_type = MC_PRINT
var/stored_paper = 20
var/max_paper = 30
diff --git a/code/modules/modular_computers/hardware/recharger.dm b/code/modules/modular_computers/hardware/recharger.dm
index fc3469fd3aa..0b83714ec42 100644
--- a/code/modules/modular_computers/hardware/recharger.dm
+++ b/code/modules/modular_computers/hardware/recharger.dm
@@ -2,6 +2,7 @@
critical = 1
enabled = 1
var/charge_rate = 100
+ device_type = MC_CHARGE
/obj/item/weapon/computer_hardware/recharger/proc/use_power(amount, charging=0)
if(charging)
@@ -10,10 +11,11 @@
/obj/item/weapon/computer_hardware/recharger/process()
..()
- if(!holder || !holder.battery_module || !holder.battery_module.battery)
+ var/obj/item/weapon/computer_hardware/battery/battery_module = holder.all_components[MC_CELL]
+ if(!holder || !battery_module || !battery_module.battery)
return
- var/obj/item/weapon/stock_parts/cell/cell = holder.battery_module.battery
+ var/obj/item/weapon/stock_parts/cell/cell = battery_module.battery
if(cell.charge >= cell.maxcharge)
return
diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm
index 8cb1805f7f6..82ca666360a 100644
--- a/code/modules/modular_computers/laptop_vendor.dm
+++ b/code/modules/modular_computers/laptop_vendor.dm
@@ -54,6 +54,7 @@
fabricated_laptop = new /obj/item/device/modular_computer/laptop/buildable(src)
fabricated_laptop.install_component(new /obj/item/weapon/computer_hardware/battery)
total_price = 99
+ var/obj/item/weapon/computer_hardware/battery/battery_module = fabricated_laptop.all_components[MC_CELL]
switch(dev_cpu)
if(1)
if(fabricate)
@@ -65,14 +66,14 @@
switch(dev_battery)
if(1) // Basic(750C)
if(fabricate)
- fabricated_laptop.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer)
+ battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer)
if(2) // Upgraded(1100C)
if(fabricate)
- fabricated_laptop.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/advanced)
+ battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/advanced)
total_price += 199
if(3) // Advanced(1500C)
if(fabricate)
- fabricated_laptop.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/super)
+ battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/super)
total_price += 499
switch(dev_disk)
if(1) // Basic(128GQ)
@@ -115,17 +116,18 @@
fabricated_tablet.install_component(new /obj/item/weapon/computer_hardware/battery)
fabricated_tablet.install_component(new /obj/item/weapon/computer_hardware/processor_unit/small)
total_price = 199
+ var/obj/item/weapon/computer_hardware/battery/battery_module = fabricated_tablet.all_components[MC_CELL]
switch(dev_battery)
if(1) // Basic(300C)
if(fabricate)
- fabricated_tablet.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/nano)
+ battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/nano)
if(2) // Upgraded(500C)
if(fabricate)
- fabricated_tablet.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/micro)
+ battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer/micro)
total_price += 199
if(3) // Advanced(750C)
if(fabricate)
- fabricated_tablet.battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer)
+ battery_module.try_insert(new /obj/item/weapon/stock_parts/cell/computer)
total_price += 499
switch(dev_disk)
if(1) // Basic(32GQ)
diff --git a/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm b/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm
index 04c0c796f23..56457b02ba5 100644
--- a/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/energy_net_nets.dm
@@ -76,28 +76,23 @@ It is possible to destroy the net by the occupant or someone else.
continue
M.unEquip(W)
- spawn(0)
- playsound(M.loc, 'sound/effects/sparks4.ogg', 50, 1)
- anim(M.loc,M,'icons/mob/mob.dmi',,"phaseout",,M.dir)
+ playsound(M.loc, 'sound/effects/sparks4.ogg', 50, 1)
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/ninja/phase/out, list(get_turf(M), M.dir))
- M.loc = pick(holdingfacility)//Throw mob in to the holding facility.
+ visible_message("[M] suddenly vanishes!")
+ M.forceMove(pick(holdingfacility)) //Throw mob in to the holding facility.
M << "You appear in a strange place!"
- spawn(0)
- var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread()
- spark_system.set_up(5, 0, M.loc)
- spark_system.start()
- playsound(M.loc, 'sound/effects/phasein.ogg', 25, 1)
- playsound(M.loc, 'sound/effects/sparks2.ogg', 50, 1)
- anim(M.loc,M,'icons/mob/mob.dmi',,"phasein",,M.dir)
- qdel(src)//Wait for everything to finish, delete the net. Else it will stop everything once net is deleted, including the spawn(0).
-
- for(var/mob/O in viewers(src, 3))
- O.show_message("[M] vanishes!", 1, "You hear sparks flying!", 2)
-
if(!isnull(master))//As long as they still exist.
master << "SUCCESS: transport procedure of \the [affecting] complete."
M.notransform = 0
+ var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread()
+ spark_system.set_up(5, 0, M.loc)
+ spark_system.start()
+ playsound(M.loc, 'sound/effects/phasein.ogg', 25, 1)
+ playsound(M.loc, 'sound/effects/sparks2.ogg', 50, 1)
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/ninja/phase, list(get_turf(M), M.dir))
+ qdel(src)
else//And they are free.
M << "You are free of the net!"
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm
index 34d47d7e469..a8d6931a951 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_net.dm
@@ -15,7 +15,7 @@
H << "You may not use an energy net through solid obstacles!"
return
spawn(0)
- H.Beam(C,"n_beam",,15)
+ H.Beam(C,"n_beam",time=15)
H.say("Get over here!")
var/obj/effect/energy_net/E = new /obj/effect/energy_net(C.loc)
H.visible_message("[H] caught [C] with an energy net!","You caught [C] with an energy net!")
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm
index fb38a3fbdd7..8062c023bc1 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_sword_recall.dm
@@ -32,9 +32,6 @@
if(energyKatana in C.stomach_contents)
C.stomach_contents -= energyKatana
- if(energyKatana in C.internal_organs)
- C.internal_organs -= energyKatana
-
energyKatana.loc = get_turf(energyKatana)
if(inview) //If we can see the katana, throw it towards ourselves, damaging people as we go.
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_teleporting.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_teleporting.dm
index d8a8b642777..50fdd52b241 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_teleporting.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_teleporting.dm
@@ -31,22 +31,19 @@ Contents:
var/turf/destination = get_teleport_loc(H.loc,H,9,1,3,1,0,1)
var/turf/mobloc = get_turf(H.loc)//Safety
- if(destination&&istype(mobloc, /turf))//So we don't teleport out of containers
- spawn(0)
- playsound(H.loc, "sparks", 50, 1)
- anim(mobloc,src,'icons/mob/mob.dmi',,"phaseout",,H.dir)
+ if(destination && isturf(mobloc))//So we don't teleport out of containers
+ playsound(H.loc, "sparks", 50, 1)
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/ninja/phase/out, list(get_turf(H), H.dir))
handle_teleport_grab(destination, H)
H.loc = destination
- spawn(0)
- spark_system.start()
- playsound(H.loc, 'sound/effects/phasein.ogg', 25, 1)
- playsound(H.loc, "sparks", 50, 1)
- anim(H.loc,H,'icons/mob/mob.dmi',,"phasein",,H.dir)
+ spark_system.start()
+ playsound(H.loc, 'sound/effects/phasein.ogg', 25, 1)
+ playsound(H.loc, "sparks", 50, 1)
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/ninja/phase, list(get_turf(H), H.dir))
- spawn(0)
- destination.phase_damage_creatures(20,H)//Paralyse and damage mobs and mechas on the turf
+ destination.phase_damage_creatures(20,H)//Paralyse and damage mobs and mechas on the turf
s_coold = 1
else
H << "The VOID-shift device is malfunctioning, teleportation failed."
@@ -63,22 +60,19 @@ Contents:
if(!ninjacost(200,N_STEALTH_CANCEL))
var/mob/living/carbon/human/H = affecting
var/turf/mobloc = get_turf(H.loc)//To make sure that certain things work properly below.
- if((!T.density)&&istype(mobloc, /turf))
- spawn(0)
- playsound(H.loc, 'sound/effects/sparks4.ogg', 50, 1)
- anim(mobloc,src,'icons/mob/mob.dmi',,"phaseout",,H.dir)
+ if(T.density && isturf(mobloc))
+ playsound(H.loc, "sparks", 50, 1)
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/ninja/phase/out, list(get_turf(H), H.dir))
handle_teleport_grab(T, H)
H.loc = T
- spawn(0)
- spark_system.start()
- playsound(H.loc, 'sound/effects/phasein.ogg', 25, 1)
- playsound(H.loc, 'sound/effects/sparks2.ogg', 50, 1)
- anim(H.loc,H,'icons/mob/mob.dmi',,"phasein",,H.dir)
+ spark_system.start()
+ playsound(H.loc, 'sound/effects/phasein.ogg', 25, 1)
+ playsound(H.loc, "sparks", 50, 1)
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/ninja/phase, list(get_turf(H), H.dir))
- spawn(0)//Any living mobs in teleport area are gibbed.
- T.phase_damage_creatures(20,H)//Paralyse and damage mobs and mechas on the turf
+ T.phase_damage_creatures(20,H)//Paralyse and damage mobs and mechas on the turf
s_coold = 1
else
H << "You cannot teleport into solid walls or from solid matter"
diff --git a/code/modules/paperwork/paperplane.dm b/code/modules/paperwork/paperplane.dm
index 78c045f555c..dab3ef6cdb1 100644
--- a/code/modules/paperwork/paperplane.dm
+++ b/code/modules/paperwork/paperplane.dm
@@ -87,7 +87,7 @@
add_fingerprint(user)
-/obj/item/weapon/paperplane/throw_at(atom/target, range, speed, mob/thrower, spin=0) //prevent the paper plane from spinning
+/obj/item/weapon/paperplane/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0) //prevent the paper plane from spinning
if(!..())
return
diff --git a/code/modules/power/antimatter/control.dm b/code/modules/power/antimatter/control.dm
index 3f10566dde8..89d63ba3f06 100644
--- a/code/modules/power/antimatter/control.dm
+++ b/code/modules/power/antimatter/control.dm
@@ -170,12 +170,11 @@
if(fueljar)
user << "There is already a [fueljar] inside!"
return
+
+ if(!user.unEquip(W))
+ return
fueljar = W
- W.loc = src
- if(user.client)
- user.client.screen -= W
- user.unEquip(W)
- user.update_icons()
+ W.forceMove(src)
user.visible_message("[user.name] loads an [W.name] into the [src.name].", \
"You load an [W.name].", \
"You hear a thunk.")
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index a5e754cd015..434a31157a4 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -517,7 +517,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list ( \
return ..()
var/obj/item/bodypart/affecting = H.get_bodypart(check_zone(user.zone_selected))
- if(affecting && affecting.status == ORGAN_ROBOTIC)
+ if(affecting && affecting.status == BODYPART_ROBOTIC)
user.visible_message("[user] starts to fix some of the wires in [H]'s [affecting.name].", "You start fixing some of the wires in [H]'s [affecting.name].")
if(!do_mob(user, H, 50))
return
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index 5ec232ea1ed..80b96c18152 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -372,7 +372,7 @@ var/const/GRAV_NEEDS_WRENCH = 3
for(var/mob/M in mob_list)
if(M.z != z)
continue
- M.update_gravity(M.has_gravity())
+ M.update_gravity(M.mob_has_gravity())
if(M.client)
shake_camera(M, 15, 1)
M.playsound_local(T, 'sound/effects/alert.ogg', 100, 1, 0.5)
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 9b6f7a79297..6dd8f092ea1 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -441,8 +441,7 @@
var/obj/item/bodypart/affecting = H.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm")
if(affecting && affecting.take_damage( 0, 5 )) // 5 burn damage
- H.update_damage_overlays(0)
- H.updatehealth()
+ H.update_damage_overlays()
return // if burned, don't remove the light
else
user << "You remove the light [fitting]."
@@ -535,8 +534,9 @@
else
flicker()
-/obj/machinery/light/tesla_act(var/power)
- explosion(src.loc,0,0,0,flame_range = 5, adminlog = 0)
+/obj/machinery/light/tesla_act(power, explosive = FALSE)
+ if(explosive)
+ explosion(src.loc,0,0,0,flame_range = 5, adminlog = 0)
qdel(src)
// called when area power state changes
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index 107b9c68197..a3469c6b699 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -392,7 +392,7 @@
/obj/singularity/proc/mezzer()
for(var/mob/living/carbon/M in oviewers(8, src))
- if(istype(M, /mob/living/carbon/brain)) //Ignore brains
+ if(istype(M, /mob/living/brain)) //Ignore brains
continue
if(M.stat == CONSCIOUS)
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index c0c108ffe41..a6f99c390a8 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -236,8 +236,9 @@
message_admins("Singularity has consumed a supermatter shard and can now become stage six.")
visible_message("[src] is consumed by the singularity!")
for(var/mob/M in mob_list)
- M << 'sound/effects/supermatter.ogg' //everyone goan know bout this
- M << "A horrible screeching fills your ears, and a wave of dread washes over you..."
+ if(M.z == z)
+ M << 'sound/effects/supermatter.ogg' //everyone goan know bout this
+ M << "A horrible screeching fills your ears, and a wave of dread washes over you..."
qdel(src)
return(gain)
diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm
index 3ee76344e49..dc7717c3701 100644
--- a/code/modules/power/tesla/coil.dm
+++ b/code/modules/power/tesla/coil.dm
@@ -49,7 +49,9 @@
/obj/machinery/power/tesla_coil/tesla_act(var/power)
being_shocked = 1
- var/power_produced = power / power_loss
+ //don't lose arc power when it's not connected to anything
+ //please place tesla coils all around the station to maximize effectiveness
+ var/power_produced = powernet ? power / power_loss : power
add_avail(power_produced*input_power_multiplier)
flick("coilhit", src)
playsound(src.loc, 'sound/magic/LightningShock.ogg', 100, 1, extrarange = 5)
diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm
index 6af4d863856..4b7399cad3e 100644
--- a/code/modules/power/tesla/energy_ball.dm
+++ b/code/modules/power/tesla/energy_ball.dm
@@ -65,13 +65,13 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
pixel_x = 0
pixel_y = 0
- setDir(tesla_zap(src, 7, TESLA_DEFAULT_POWER))
+ setDir(tesla_zap(src, 7, TESLA_DEFAULT_POWER, TRUE))
pixel_x = -32
pixel_y = -32
for (var/ball in orbiting_balls)
var/range = rand(1, Clamp(orbiting_balls.len, 3, 7))
- tesla_zap(ball, range, TESLA_MINI_POWER/7*range)
+ tesla_zap(ball, range, TESLA_MINI_POWER/7*range, TRUE)
else
energy = 0 // ensure we dont have miniballs of miniballs
@@ -152,7 +152,7 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
var/mob/living/carbon/C = A
C.dust()
-/proc/tesla_zap(var/atom/source, zap_range = 3, power)
+/proc/tesla_zap(atom/source, zap_range = 3, power, explosive = FALSE)
. = source.dir
if(power < 1000)
return
@@ -236,17 +236,17 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
//Alright, we've done our loop, now lets see if was anything interesting in range
if(closest_atom)
//common stuff
- source.Beam(closest_atom, icon_state="lightning[rand(1,12)]", icon='icons/effects/effects.dmi', time=5)
+ source.Beam(closest_atom, icon_state="lightning[rand(1,12)]", time=5)
var/zapdir = get_dir(source, closest_atom)
if(zapdir)
. = zapdir
//per type stuff:
if(closest_tesla_coil)
- closest_tesla_coil.tesla_act(power)
+ closest_tesla_coil.tesla_act(power, explosive)
else if(closest_grounding_rod)
- closest_grounding_rod.tesla_act(power)
+ closest_grounding_rod.tesla_act(power, explosive)
else if(closest_mob)
var/shock_damage = Clamp(round(power/400), 10, 90) + rand(-5, 5)
@@ -259,10 +259,10 @@ var/list/blacklisted_tesla_types = typecacheof(list(/obj/machinery/atmospherics,
tesla_zap(closest_mob, 5, power / 1.5)
else if(closest_machine)
- closest_machine.tesla_act(power)
+ closest_machine.tesla_act(power, explosive)
else if(closest_blob)
- closest_blob.tesla_act(power)
+ closest_blob.tesla_act(power, explosive)
else if(closest_structure)
- closest_structure.tesla_act(power)
+ closest_structure.tesla_act(power, explosive)
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index 40fe0f36a46..e401a5dae8b 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -16,6 +16,8 @@
var/randomspread = 0 //Randomspread for automatics
var/delay = 0 //Delay for energy weapons
var/click_cooldown_override = 0 //Override this to make your gun have a faster fire rate, in tenths of a second. 4 is the default gun cooldown.
+ var/firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect //the visual effect appearing when the ammo is fired.
+
/obj/item/ammo_casing/New()
..()
diff --git a/code/modules/projectiles/ammunition/ammo_casings.dm b/code/modules/projectiles/ammunition/ammo_casings.dm
index 20f59b6404f..a3653f0717c 100644
--- a/code/modules/projectiles/ammunition/ammo_casings.dm
+++ b/code/modules/projectiles/ammunition/ammo_casings.dm
@@ -309,6 +309,7 @@
/obj/item/ammo_casing/caseless
desc = "A caseless bullet casing."
+ firing_effect_type = null
/obj/item/ammo_casing/caseless/fire(atom/target as mob|obj|turf, mob/living/user as mob|obj, params, distro, quiet)
@@ -345,6 +346,7 @@
icon_state = "s-casing-live"
projectile_type = /obj/item/projectile/beam
fire_sound = 'sound/weapons/Laser.ogg'
+ firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect/energy
/obj/item/ammo_casing/caseless/laser/gatling
projectile_type = /obj/item/projectile/beam/weak
diff --git a/code/modules/projectiles/ammunition/energy.dm b/code/modules/projectiles/ammunition/energy.dm
index abe46e6732d..d2c414b131c 100644
--- a/code/modules/projectiles/ammunition/energy.dm
+++ b/code/modules/projectiles/ammunition/energy.dm
@@ -6,6 +6,7 @@
var/e_cost = 100 //The amount of energy a cell needs to expend to create this shot.
var/select_name = "energy"
fire_sound = 'sound/weapons/Laser.ogg'
+ firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect/energy
/obj/item/ammo_casing/energy/laser
projectile_type = /obj/item/projectile/beam/laser
@@ -209,4 +210,12 @@ obj/item/ammo_casing/energy/net
var/obj/item/weapon/gun/energy/gravity_gun/gun = null
/obj/item/ammo_casing/energy/gravitychaos/New(var/obj/item/weapon/gun/energy/gravity_gun/G)
- gun = G
\ No newline at end of file
+ gun = G
+
+/obj/item/ammo_casing/energy/plasma
+ projectile_type = /obj/item/projectile/plasma
+ select_name = "plasma burst"
+ fire_sound = 'sound/weapons/pulse.ogg'
+
+/obj/item/ammo_casing/energy/plasma/adv
+ projectile_type = /obj/item/projectile/plasma/adv
diff --git a/code/modules/projectiles/ammunition/special.dm b/code/modules/projectiles/ammunition/special.dm
index 9a720b84138..181333af1a1 100644
--- a/code/modules/projectiles/ammunition/special.dm
+++ b/code/modules/projectiles/ammunition/special.dm
@@ -2,6 +2,7 @@
name = "magic casing"
desc = "I didn't even know magic needed ammo..."
projectile_type = /obj/item/projectile/magic
+ firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect/magic
/obj/item/ammo_casing/magic/change
projectile_type = /obj/item/projectile/magic/change
@@ -41,9 +42,11 @@
name = "syringe gun spring"
desc = "A high-power spring that throws syringes."
projectile_type = null
+ firing_effect_type = null
/obj/item/ammo_casing/energy/c3dbullet
projectile_type = /obj/item/projectile/bullet/midbullet3
select_name = "spraydown"
fire_sound = 'sound/weapons/gunshot_smg.ogg'
e_cost = 20
+ firing_effect_type = /obj/effect/overlay/temp/dir_setting/firing_effect
diff --git a/code/modules/projectiles/firing.dm b/code/modules/projectiles/firing.dm
index d25e65891cf..d293520cb89 100644
--- a/code/modules/projectiles/firing.dm
+++ b/code/modules/projectiles/firing.dm
@@ -40,6 +40,13 @@
if (!istype(targloc) || !istype(curloc) || !BB)
return 0
BB.ammo_casing = src
+
+ var/firing_dir
+ if(BB.firer)
+ firing_dir = BB.firer.dir
+ if(!BB.suppressed && firing_effect_type)
+ PoolOrNew(firing_effect_type, list(get_turf(src), firing_dir))
+
if(targloc == curloc)
if(target) //if the target is right on our location we go straight to bullet_act()
target.bullet_act(BB, BB.def_zone)
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 9311a0e0e42..b1ec4893a43 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -14,6 +14,7 @@
force = 5
origin_tech = "combat=1"
needs_permit = 1
+ unique_rename = 0
attack_verb = list("struck", "hit", "bashed")
var/fire_sound = "gunshot"
@@ -31,11 +32,8 @@
var/firing_burst = 0 //Prevent the weapon from firing again while already firing
var/semicd = 0 //cooldown handler
var/weapon_weight = WEAPON_LIGHT
-
var/spread = 0 //Spread induced by the gun itself.
var/randomspread = 1 //Set to 0 for shotguns. This is used for weapons that don't fire all their bullets at once.
-
- var/unique_rename = 0 //allows renaming with a pen
var/unique_reskin = 0 //allows one-time reskinning
var/current_skin = null //the skin choice if we had a reskin
var/list/options = list()
@@ -90,8 +88,6 @@
user << "It doesn't have a firing pin installed, and won't fire."
if(unique_reskin && !current_skin)
user << "Alt-click it to reskin it."
- if(unique_rename)
- user << "Use a pen on it to rename it."
/obj/item/weapon/gun/proc/process_chamber()
@@ -302,10 +298,7 @@ obj/item/weapon/gun/proc/newshot()
for(var/datum/action/item_action/toggle_gunlight/TGL in actions)
qdel(TGL)
- if(unique_rename)
- if(istype(I, /obj/item/weapon/pen))
- rename_gun(user)
- ..()
+
/obj/item/weapon/gun/proc/toggle_gunlight()
set name = "Toggle Gunlight"
@@ -386,13 +379,6 @@ obj/item/weapon/gun/proc/newshot()
update_icon()
-/obj/item/weapon/gun/proc/rename_gun(mob/M)
- var/input = stripped_input(M,"What do you want to name the gun?", ,"", MAX_NAME_LEN)
-
- if(src && input && !M.stat && in_range(M,src) && !M.restrained() && M.canmove)
- name = input
- M << "You name the gun [input]. Say hello to your new friend."
- return
/obj/item/weapon/gun/proc/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params)
diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
index 34ac3eb6407..bb586419f9b 100644
--- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
+++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm
@@ -243,18 +243,19 @@
if(number_of_denied >= maximum_of_type)
. = FALSE
break
- if(.)
- if(KA.get_remaining_mod_capacity() >= cost)
+ if(KA.get_remaining_mod_capacity() >= cost)
+ if(.)
user << "You install the modkit."
playsound(loc, 'sound/items/Screwdriver.ogg', 100, 1)
user.unEquip(src)
forceMove(KA)
KA.modkits += src
else
- user << "You don't have room([KA.get_remaining_mod_capacity()]% remaining, [cost]% needed) to install this modkit. Use a crowbar to remove existing modkits."
- . = FALSE
+ user << "The modkit you're trying to install would conflict with an already installed modkit. Use a crowbar to remove existing modkits."
else
- user << "The modkit you're trying to install would conflict with an already installed modkit. Use a crowbar to remove existing modkits."
+ user << "You don't have room([KA.get_remaining_mod_capacity()]% remaining, [cost]% needed) to install this modkit. Use a crowbar to remove existing modkits."
+ . = FALSE
+
/obj/item/borg/upgrade/modkit/proc/uninstall(obj/item/weapon/gun/energy/kinetic_accelerator/KA)
@@ -301,27 +302,34 @@
//AoE blasts
+/obj/item/borg/upgrade/modkit/aoe
+ modifier = 0
+
/obj/item/borg/upgrade/modkit/aoe/modify_projectile(obj/item/projectile/kinetic/K)
K.name = "kinetic explosion"
if(!K.turf_aoe && !K.mob_aoe)
K.hit_overlays += /obj/effect/overlay/temp/explosion/fast
+ K.mob_aoe += modifier
/obj/item/borg/upgrade/modkit/aoe/turfs
name = "mining explosion"
desc = "Causes the kinetic accelerator to destroy rock in an AoE."
+ denied_type = /obj/item/borg/upgrade/modkit/aoe/turfs
/obj/item/borg/upgrade/modkit/aoe/turfs/modify_projectile(obj/item/projectile/kinetic/K)
..()
K.turf_aoe = TRUE
+/obj/item/borg/upgrade/modkit/aoe/turfs/andmobs
+ name = "offensive mining explosion"
+ desc = "Causes the kinetic accelerator to destroy rock and damage mobs in an AoE."
+ maximum_of_type = 3
+ modifier = 0.25
+
/obj/item/borg/upgrade/modkit/aoe/mobs
name = "offensive explosion"
desc = "Causes the kinetic accelerator to damage mobs in an AoE."
- modifier = 0.25
-
-/obj/item/borg/upgrade/modkit/aoe/mobs/modify_projectile(obj/item/projectile/kinetic/K)
- ..()
- K.mob_aoe += modifier
+ modifier = 0.2
//Indoors
diff --git a/code/modules/projectiles/guns/projectile.dm b/code/modules/projectiles/guns/projectile.dm
index 594df3bd3b6..9b50a1e4a98 100644
--- a/code/modules/projectiles/guns/projectile.dm
+++ b/code/modules/projectiles/guns/projectile.dm
@@ -178,7 +178,7 @@
name = "sawn-off [src.name]"
desc = sawn_desc
w_class = 3
- item_state = "gun"//phil235 is it different with different skin?
+ item_state = "gun"
slot_flags &= ~SLOT_BACK //you can't sling it on your back
slot_flags |= SLOT_BELT //but you can wear it on your belt (poorly concealed under a trenchcoat, ideally)
sawn_state = SAWN_OFF
diff --git a/code/modules/projectiles/guns/projectile/bow.dm b/code/modules/projectiles/guns/projectile/bow.dm
index 4ed0fac5829..ff16125d8a7 100644
--- a/code/modules/projectiles/guns/projectile/bow.dm
+++ b/code/modules/projectiles/guns/projectile/bow.dm
@@ -74,6 +74,7 @@
/obj/item/ammo_casing/caseless/arrow
name = "arrow"
+ desc = "Stab, stab, stab."
icon_state = "arrow"
force = 10
sharpness = IS_SHARP
@@ -94,4 +95,4 @@
/obj/item/weapon/storage/backpack/quiver/full/New()
..()
for(var/i in 1 to storage_slots)
- new /obj/item/ammo_casing/caseless/arrow(src)
\ No newline at end of file
+ new /obj/item/ammo_casing/caseless/arrow(src)
diff --git a/code/modules/projectiles/guns/projectile/revolver.dm b/code/modules/projectiles/guns/projectile/revolver.dm
index a238c60623a..fdd8b765f67 100644
--- a/code/modules/projectiles/guns/projectile/revolver.dm
+++ b/code/modules/projectiles/guns/projectile/revolver.dm
@@ -37,7 +37,7 @@
if(unique_rename)
if(istype(A, /obj/item/weapon/pen))
- rename_gun(user)
+ rename_weapon(user)
/obj/item/weapon/gun/projectile/revolver/attack_self(mob/living/user)
var/num_unloaded = 0
@@ -111,7 +111,7 @@
if(prob(70 - (magazine.ammo_count() * 10))) //minimum probability of 10, maximum of 60
playsound(user, fire_sound, 50, 1)
user << "[src] blows up in your face!"
- user.take_organ_damage(0,20)
+ user.take_bodypart_damage(0,20)
user.unEquip(src)
return 0
..()
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 1c4616c90ed..74320f6c062 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -50,6 +50,7 @@
var/jitter = 0
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/impact_effect_type //what type of impact effect to show when hitting something
/obj/item/projectile/New()
permutated = list()
@@ -63,14 +64,39 @@
/obj/item/projectile/proc/on_range() //if we want there to be effects when they reach the end of their range
qdel(src)
-/obj/item/projectile/proc/on_hit(atom/target, blocked = 0, hit_zone)
+//to get the correct limb (if any) for the projectile hit message
+/mob/living/proc/check_limb_hit(hit_zone)
+ if(has_limbs)
+ return hit_zone
+
+/mob/living/carbon/check_limb_hit(hit_zone)
+ if(get_bodypart(hit_zone))
+ return hit_zone
+ else //when a limb is missing the damage is actually passed to the chest
+ return "chest"
+
+/obj/item/projectile/proc/on_hit(atom/target, blocked = 0)
+ var/turf/target_loca = get_turf(target)
if(!isliving(target))
+ if(impact_effect_type)
+ PoolOrNew(impact_effect_type, list(target_loca, target, src))
return 0
var/mob/living/L = target
if(blocked != 100) // not completely blocked
+ if(damage && L.blood_volume && damage_type == BRUTE)
+ if(isalien(L))
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/bloodsplatter/xenosplatter, list(target_loca, dir))
+ else
+ PoolOrNew(/obj/effect/overlay/temp/dir_setting/bloodsplatter, list(target_loca, dir))
+ if(prob(33))
+ L.add_splatter_floor(target_loca)
+ else if(impact_effect_type)
+ PoolOrNew(impact_effect_type, list(target_loca, target, src))
+
var/organ_hit_text = ""
- if(L.has_limbs)
- organ_hit_text = " in \the [parse_zone(def_zone)]"
+ var/limb_hit = L.check_limb_hit(def_zone)//to get the correct message info.
+ if(limb_hit)
+ organ_hit_text = " in \the [parse_zone(limb_hit)]"
if(suppressed)
playsound(loc, hitsound, 5, 1, -1)
L << "You're shot by \a [src][organ_hit_text]!"
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index 59cd030b85f..28902c019dc 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -9,6 +9,7 @@
hitsound_wall = 'sound/weapons/effects/searwall.ogg'
flag = "laser"
eyeblur = 2
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/red_laser
/obj/item/projectile/beam/laser
@@ -44,6 +45,7 @@
irradiate = 30
range = 15
forcedodge = 1
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/green_laser
/obj/item/projectile/beam/disabler
name = "disabler beam"
@@ -53,12 +55,14 @@
flag = "energy"
hitsound = 'sound/weapons/tap.ogg'
eyeblur = 0
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/blue_laser
/obj/item/projectile/beam/pulse
name = "pulse"
icon_state = "u_laser"
damage = 50
luminosity = 2
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/blue_laser
/obj/item/projectile/beam/pulse/on_hit(atom/target, blocked = 0)
. = ..()
@@ -73,7 +77,7 @@
icon_state = "pulse1_bl"
var/life = 20
-/obj/item/projectile/beam/pulse/heavy/on_hit(atom/target, blocked = 0, hit_zone)
+/obj/item/projectile/beam/pulse/heavy/on_hit(atom/target, blocked = 0)
life -= 10
if(life > 0)
. = -1
@@ -86,6 +90,7 @@
legacy = 1
luminosity = 2
animate_movement = SLIDE_STEPS
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/green_laser
/obj/item/projectile/beam/emitter/singularity_pull()
return //don't want the emitters to miss
@@ -102,6 +107,7 @@
damage_type = STAMINA
flag = "laser"
var/suit_types = list(/obj/item/clothing/suit/redtag, /obj/item/clothing/suit/bluetag)
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/blue_laser
/obj/item/projectile/beam/lasertag/on_hit(atom/target, blocked = 0)
. = ..()
@@ -114,6 +120,7 @@
/obj/item/projectile/beam/lasertag/redtag
icon_state = "laser"
suit_types = list(/obj/item/clothing/suit/bluetag)
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/red_laser
/obj/item/projectile/beam/lasertag/bluetag
icon_state = "bluelaser"
@@ -124,12 +131,15 @@
icon_state = "purple_laser"
damage = 200
damage_type = BURN
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/purple_laser
/obj/item/projectile/beam/instakill/blue
icon_state = "blue_laser"
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/blue_laser
/obj/item/projectile/beam/instakill/red
icon_state = "red_laser"
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/red_laser
/obj/item/projectile/beam/instakill/on_hit(atom/target)
. = ..()
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index c1061c57293..ab287338cc9 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -6,6 +6,7 @@
nodamage = 0
flag = "bullet"
hitsound_wall = "ricochet"
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect
/obj/item/projectile/bullet/weakbullet //beanbag, heavy stamina damage
damage = 5
@@ -174,11 +175,11 @@
create_reagents(50)
reagents.set_reacting(FALSE)
-/obj/item/projectile/bullet/dart/on_hit(atom/target, blocked = 0, hit_zone)
+/obj/item/projectile/bullet/dart/on_hit(atom/target, blocked = 0)
if(iscarbon(target))
var/mob/living/carbon/M = target
if(blocked != 100) // not completely blocked
- if(M.can_inject(null,0,hit_zone,piercing)) // Pass the hit zone to see if it can inject by whether it hit the head or the body.
+ if(M.can_inject(null, 0, def_zone, piercing)) // Pass the hit zone to see if it can inject by whether it hit the head or the body.
..()
reagents.reaction(M, INJECT)
reagents.trans_to(M, reagents.total_volume)
@@ -188,7 +189,7 @@
target.visible_message("The [name] was deflected!", \
"You were protected against the [name]!")
- ..(target, blocked, hit_zone)
+ ..(target, blocked)
reagents.set_reacting(TRUE)
reagents.handle_reactions()
return 1
@@ -234,7 +235,7 @@
armour_penetration = 50
var/breakthings = TRUE
-/obj/item/projectile/bullet/sniper/on_hit(atom/target, blocked = 0, hit_zone)
+/obj/item/projectile/bullet/sniper/on_hit(atom/target, blocked = 0)
if((blocked != 100) && (!ismob(target) && breakthings))
target.ex_act(rand(1,2))
return ..()
@@ -248,7 +249,7 @@
weaken = 0
breakthings = FALSE
-/obj/item/projectile/bullet/sniper/soporific/on_hit(atom/target, blocked = 0, hit_zone)
+/obj/item/projectile/bullet/sniper/soporific/on_hit(atom/target, blocked = 0)
if((blocked != 100) && istype(target, /mob/living))
var/mob/living/L = target
L.Sleeping(20)
@@ -263,7 +264,7 @@
weaken = 0
breakthings = FALSE
-/obj/item/projectile/bullet/sniper/haemorrhage/on_hit(atom/target, blocked = 0, hit_zone)
+/obj/item/projectile/bullet/sniper/haemorrhage/on_hit(atom/target, blocked = 0)
if((blocked != 100) && iscarbon(target))
var/mob/living/carbon/C = target
C.bleed(100)
@@ -293,7 +294,7 @@
damage = 20
armour_penetration = 0
-/obj/item/projectile/bullet/saw/bleeding/on_hit(atom/target, blocked = 0, hit_zone)
+/obj/item/projectile/bullet/saw/bleeding/on_hit(atom/target, blocked = 0)
. = ..()
if((blocked != 100) && iscarbon(target))
var/mob/living/carbon/C = target
diff --git a/code/modules/projectiles/projectile/energy.dm b/code/modules/projectiles/projectile/energy.dm
index 6c41ca751d7..a4830b7c28d 100644
--- a/code/modules/projectiles/projectile/energy.dm
+++ b/code/modules/projectiles/projectile/energy.dm
@@ -143,6 +143,7 @@
damage = 20
damage_type = CLONE
irradiate = 10
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/green_laser
/obj/item/projectile/energy/dart //ninja throwing dart
name = "dart"
@@ -164,22 +165,15 @@
/obj/item/projectile/energy/bolt/large
damage = 20
-/obj/item/ammo_casing/energy/plasma
- projectile_type = /obj/item/projectile/plasma
- select_name = "plasma burst"
- fire_sound = 'sound/weapons/pulse.ogg'
-
-/obj/item/ammo_casing/energy/plasma/adv
- projectile_type = /obj/item/projectile/plasma/adv
-
/obj/item/projectile/energy/shock_revolver
name = "shock bolt"
icon_state = "purple_laser"
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/purple_laser
var/chain
/obj/item/projectile/energy/shock_revolver/fire(setAngle)
if(firer)
- chain = Beam(firer, icon_state = "lightning[rand(1, 12)]", icon = 'icons/effects/effects.dmi', time = INFINITY, maxdistance = INFINITY)
+ chain = firer.Beam(src, icon_state = "lightning[rand(1, 12)]", time = INFINITY, maxdistance = INFINITY)
..()
/obj/item/projectile/energy/shock_revolver/on_hit(atom/target)
@@ -189,3 +183,4 @@
/obj/item/projectile/energy/shock_revolver/Destroy()
qdel(chain)
+ return ..()
diff --git a/code/modules/projectiles/projectile/reusable.dm b/code/modules/projectiles/projectile/reusable.dm
index f253655e3f6..6d6b086f63b 100644
--- a/code/modules/projectiles/projectile/reusable.dm
+++ b/code/modules/projectiles/projectile/reusable.dm
@@ -3,6 +3,7 @@
desc = "How do you even reuse a bullet?"
var/ammo_type = /obj/item/ammo_casing/caseless/
var/dropped = 0
+ impact_effect_type = null
/obj/item/projectile/bullet/reusable/on_hit(atom/target, blocked = 0)
. = ..()
diff --git a/code/modules/projectiles/projectile/special.dm b/code/modules/projectiles/projectile/special.dm
index 0dadac9de80..6a991950ff0 100644
--- a/code/modules/projectiles/projectile/special.dm
+++ b/code/modules/projectiles/projectile/special.dm
@@ -5,6 +5,7 @@
damage_type = BURN
nodamage = 1
flag = "energy"
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/ion
/obj/item/projectile/ion/on_hit(atom/target, blocked = 0)
@@ -98,8 +99,8 @@
if(iscarbon(target))
var/mob/living/carbon/C = target
if(C.dna.species.id == "pod")
- randmuti(C)
- randmut(C)
+ C.randmuti()
+ C.randmut()
C.updateappearance()
C.domutcheck()
@@ -166,6 +167,7 @@
damage = 5
range = 3.5 //works as 4, but doubles to 7
dismemberment = 20
+ impact_effect_type = /obj/effect/overlay/temp/impact_effect/purple_laser
/obj/item/projectile/plasma/New()
var/turf/proj_turf = get_turf(src)
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index c70c022d467..1c78b5c6f8e 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -150,7 +150,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/bilk/on_mob_life(mob/living/M)
if(M.getBruteLoss() && prob(10))
- M.heal_organ_damage(1,0, 0)
+ M.heal_bodypart_damage(1,0, 0)
. = 1
return ..() || .
@@ -681,7 +681,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/bananahonk/on_mob_life(mob/living/M)
if( ( istype(M, /mob/living/carbon/human) && M.job in list("Clown") ) || istype(M, /mob/living/carbon/monkey) )
- M.heal_organ_damage(1,1, 0)
+ M.heal_bodypart_damage(1,1, 0)
. = 1
return ..() || .
@@ -695,7 +695,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/silencer/on_mob_life(mob/living/M)
if(istype(M, /mob/living/carbon/human) && M.job in list("Mime"))
- M.heal_organ_damage(1,1)
+ M.heal_bodypart_damage(1,1)
. = 1
return ..() || .
diff --git a/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index 6e2d5c607e0..3055d8733e0 100644
--- a/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -24,7 +24,7 @@
/datum/reagent/consumable/tomatojuice/on_mob_life(mob/living/M)
if(M.getFireLoss() && prob(20))
- M.heal_organ_damage(0,1, 0)
+ M.heal_bodypart_damage(0,1, 0)
. = 1
..()
@@ -95,7 +95,7 @@
/datum/reagent/consumable/banana/on_mob_life(mob/living/M)
if( ( istype(M, /mob/living/carbon/human) && M.job in list("Clown") ) || istype(M, /mob/living/carbon/monkey) )
- M.heal_organ_damage(1,1, 0)
+ M.heal_bodypart_damage(1,1, 0)
. = 1
..()
@@ -106,7 +106,7 @@
/datum/reagent/consumable/nothing/on_mob_life(mob/living/M)
if(istype(M, /mob/living/carbon/human) && M.job in list("Mime"))
- M.heal_organ_damage(1,1, 0)
+ M.heal_bodypart_damage(1,1, 0)
. = 1
..()
@@ -155,13 +155,13 @@
/datum/reagent/consumable/milk/on_mob_life(mob/living/M)
if(M.getBruteLoss() && prob(20))
- M.heal_organ_damage(1,0, 0)
+ M.heal_bodypart_damage(1,0, 0)
. = 1
if(holder.has_reagent("capsaicin"))
holder.remove_reagent("capsaicin", 2)
var/datum/dna/Mdna = M.has_dna()
if(Mdna && Mdna.species && (Mdna.species.id == "plasmaman" || Mdna.species.id == "skeleton"))
- M.heal_organ_damage(1,0, 0)
+ M.heal_bodypart_damage(1,0, 0)
. = 1
..()
@@ -173,7 +173,7 @@
/datum/reagent/consumable/soymilk/on_mob_life(mob/living/M)
if(M.getBruteLoss() && prob(20))
- M.heal_organ_damage(1,0, 0)
+ M.heal_bodypart_damage(1,0, 0)
. = 1
..()
@@ -185,7 +185,7 @@
/datum/reagent/consumable/cream/on_mob_life(mob/living/M)
if(M.getBruteLoss() && prob(20))
- M.heal_organ_damage(1,0, 0)
+ M.heal_bodypart_damage(1,0, 0)
. = 1
..()
@@ -411,7 +411,7 @@
M.bodytemperature = min(310, M.bodytemperature + (5 * TEMPERATURE_DAMAGE_COEFFICIENT))
M.Jitter(5)
if(M.getBruteLoss() && prob(20))
- M.heal_organ_damage(1,0, 0)
+ M.heal_bodypart_damage(1,0, 0)
..()
. = 1
@@ -429,7 +429,7 @@
M.bodytemperature = min(310, M.bodytemperature + (5 * TEMPERATURE_DAMAGE_COEFFICIENT))
M.Jitter(5)
if(M.getBruteLoss() && prob(20))
- M.heal_organ_damage(1,0, 0)
+ M.heal_bodypart_damage(1,0, 0)
..()
. = 1
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index c10c97cdaca..e65c395f7c7 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -27,7 +27,7 @@
/datum/reagent/consumable/nutriment/on_mob_life(mob/living/M)
if(prob(50))
- M.heal_organ_damage(1,0, 0)
+ M.heal_bodypart_damage(1,0, 0)
. = 1
if(iscarbon(M))
var/mob/living/carbon/C = M
@@ -44,7 +44,7 @@
/datum/reagent/consumable/vitamin/on_mob_life(mob/living/M)
if(prob(50))
- M.heal_organ_damage(1,1, 0)
+ M.heal_bodypart_damage(1,1, 0)
. = 1
if(M.satiety < 600)
M.satiety += 30
@@ -325,7 +325,7 @@
/datum/reagent/consumable/sprinkles/on_mob_life(mob/living/M)
if(istype(M, /mob/living/carbon/human) && M.job in list("Security Officer", "Head of Security", "Detective", "Warden"))
- M.heal_organ_damage(1,1, 0)
+ M.heal_bodypart_damage(1,1, 0)
. = 1
..()
@@ -457,5 +457,5 @@
/datum/reagent/consumable/honey/on_mob_life(mob/living/M)
M.reagents.add_reagent("sugar",3)
if(prob(20))
- M.heal_organ_damage(3,1)
+ M.heal_bodypart_damage(3,1)
..()
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index 2461aaba745..ce375b1d228 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -38,7 +38,7 @@
M.setCloneLoss(0, 0)
M.setOxyLoss(0, 0)
M.radiation = 0
- M.heal_organ_damage(5,5, 0)
+ M.heal_bodypart_damage(5,5, 0)
M.adjustToxLoss(-5, 0)
M.hallucination = 0
M.setBrainLoss(0)
@@ -163,7 +163,7 @@
/datum/reagent/medicine/rezadone/on_mob_life(mob/living/M)
M.setCloneLoss(0) //Rezadone is almost never used in favor of cryoxadone. Hopefully this will change that.
- M.heal_organ_damage(1,1, 0)
+ M.heal_bodypart_damage(1,1, 0)
M.status_flags &= ~DISFIGURED
..()
. = 1
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index ff9eb7197d6..c38d9023457 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -188,11 +188,9 @@
if("emote")
M.visible_message("[M] [pick("whimpers quietly", "shivers as though cold", "glances around in paranoia")].")
if(data >= 75) // 30 units, 135 seconds
- if(iscultist(M) || is_handofgod_cultist(M) || is_handofgod_prophet(M) || is_servant_of_ratvar(M))
+ if(iscultist(M) || is_servant_of_ratvar(M))
if(iscultist(M))
ticker.mode.remove_cultist(M.mind, 1, 1)
- else if(is_handofgod_cultist(M) || is_handofgod_prophet(M))
- ticker.mode.remove_hog_follower(M.mind)
else if(is_servant_of_ratvar(M))
remove_servant_of_ratvar(M)
holder.remove_reagent(id, volume) // maybe this is a little too perfect and a max() cap on the statuses would be better??
@@ -537,7 +535,7 @@
color = "#808080" // rgb: 128, 128, 128
/datum/reagent/chlorine/on_mob_life(mob/living/M)
- M.take_organ_damage(1*REM, 0, 0)
+ M.take_bodypart_damage(1*REM, 0, 0)
. = 1
..()
diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
index 22d718e0b76..d2958b475da 100644
--- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
@@ -164,7 +164,7 @@
/datum/reagent/cryostylane
name = "Cryostylane"
id = "cryostylane"
- description = "Comes into existence at 20K. As long as there is sufficient oxygen for it to react with, Cryostylane slowly cools all other reagents in the mob down to 0K."
+ description = "Comes into existence at 20K. As long as there is sufficient oxygen for it to react with, Cryostylane slowly cools all other reagents in the container 0K."
color = "#0000DC"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
@@ -190,7 +190,7 @@
/datum/reagent/pyrosium
name = "Pyrosium"
id = "pyrosium"
- description = "Comes into existence at 20K. As long as there is sufficient oxygen for it to react with, Pyrosium slowly cools all other reagents in the mob down to 0K."
+ description = "Comes into existence at 20K. As long as there is sufficient oxygen for it to react with, Pyrosium slowly heats all other reagents in the container."
color = "#64FAC8"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
@@ -206,3 +206,21 @@
holder.chem_temp += 10
holder.handle_reactions()
..()
+
+/datum/reagent/teslium //Teslium. Causes periodic shocks, and makes shocks against the target much more effective.
+ name = "Teslium"
+ id = "teslium"
+ description = "An unstable, electrically-charged metallic slurry. Periodically electrocutes its victim, and makes electrocutions against them more deadly. Excessively heating teslium results in dangerous destabilization. Do not allow to come into contact with water."
+ reagent_state = LIQUID
+ color = "#20324D" //RGB: 32, 50, 77
+ metabolization_rate = 0.5 * REAGENTS_METABOLISM
+ var/shock_timer = 0
+
+/datum/reagent/teslium/on_mob_life(mob/living/M)
+ shock_timer++
+ if(shock_timer >= rand(5,30)) //Random shocks are wildly unpredictable
+ shock_timer = 0
+ M.electrocute_act(rand(5,20), "Teslium in their body", 1, 1) //Override because it's caused from INSIDE of you
+ playsound(M, "sparks", 50, 1)
+ ..()
+
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index b3fb7d29526..2d344c1276e 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -34,11 +34,11 @@
if(!M.has_dna())
return //No robots, AIs, aliens, Ians or other mobs should be affected by this.
if((method==VAPOR && prob(min(33, reac_volume))) || method==INGEST || method==PATCH || method==INJECT)
- randmuti(M)
+ M.randmuti()
if(prob(98))
- randmutb(M)
+ M.randmutb()
else
- randmutg(M)
+ M.randmutg()
M.updateappearance()
M.domutcheck()
..()
@@ -118,7 +118,7 @@
M.adjustToxLoss(rand(20,60)*REM, 0)
. = 1
else if(prob(40))
- M.heal_organ_damage(5*REM,0, 0)
+ M.heal_bodypart_damage(5*REM,0, 0)
. = 1
..()
@@ -657,24 +657,6 @@
. = 1
return ..() || .
-/datum/reagent/toxin/teslium //Teslium. Causes periodic shocks, and makes shocks against the target much more effective.
- name = "Teslium"
- id = "teslium"
- description = "An unstable, electrically-charged metallic slurry. Periodically electrocutes its victim, and makes electrocutions against them more deadly."
- reagent_state = LIQUID
- color = "#20324D" //RGB: 32, 50, 77
- metabolization_rate = 0.5 * REAGENTS_METABOLISM
- toxpwr = 0
- var/shock_timer = 0
-
-/datum/reagent/toxin/teslium/on_mob_life(mob/living/M)
- shock_timer++
- if(shock_timer >= rand(5,30)) //Random shocks are wildly unpredictable
- shock_timer = 0
- M.electrocute_act(rand(5,20), "Teslium in their body", 1, 1) //Override because it's caused from INSIDE of you
- playsound(M, "sparks", 50, 1)
- ..()
-
//ACID
diff --git a/code/modules/reagents/chemistry/recipes.dm b/code/modules/reagents/chemistry/recipes.dm
index 5943577d59c..a7bfedb2145 100644
--- a/code/modules/reagents/chemistry/recipes.dm
+++ b/code/modules/reagents/chemistry/recipes.dm
@@ -50,16 +50,16 @@ var/list/chemical_mob_spawn_nicecritters = list() // and possible friendly mobs
playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1)
for(var/mob/living/carbon/C in viewers(get_turf(holder.my_atom), null))
- C.flash_eyes()
+ C.flash_act()
for(var/i = 1, i <= amount_to_spawn, i++)
var/chosen
if (reaction_name == "Friendly Gold Slime")
chosen = pick(chemical_mob_spawn_nicecritters)
else
chosen = pick(chemical_mob_spawn_meancritters)
- var/mob/living/simple_animal/C = new chosen
+ var/spawnloc = get_turf(holder.my_atom)
+ var/mob/living/simple_animal/C = new chosen(spawnloc)
C.faction |= mob_faction
- C.loc = get_turf(holder.my_atom)
if(prob(50))
for(var/j = 1, j <= rand(1, 3), j++)
step(C, pick(NORTH,SOUTH,EAST,WEST))
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index 38e316be26b..ec261d12045 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -69,7 +69,7 @@
R.adjustHealth(50)
sleep(20)
for(var/mob/living/carbon/C in get_hearers_in_view(round(created_volume/48,1),get_turf(holder.my_atom)))
- if(iscultist(C) || is_handofgod_cultist(C))
+ if(iscultist(C))
C << "The divine explosion sears you!"
C.Weaken(2)
C.adjust_fire_stacks(5)
@@ -218,7 +218,7 @@
s.set_up(2, 1, location)
s.start()
for(var/mob/living/carbon/C in get_hearers_in_view(created_volume/3, location))
- if(C.flash_eyes())
+ if(C.flash_act())
if(get_dist(C, location) < 4)
C.Weaken(5)
else
@@ -237,7 +237,7 @@
s.set_up(2, 1, location)
s.start()
for(var/mob/living/carbon/C in get_hearers_in_view(created_volume/10, location))
- if(C.flash_eyes())
+ if(C.flash_act())
if(get_dist(C, location) < 4)
C.Weaken(5)
else
@@ -297,16 +297,7 @@
var/location = get_turf(holder.my_atom)
playsound(location, 'sound/effects/bang.ogg', 25, 1)
for(var/mob/living/carbon/C in get_hearers_in_view(created_volume/3, location))
- if(C.check_ear_prot())
- continue
- C.show_message("BANG", 2)
- C.Stun(5)
- C.Weaken(5)
- C.setEarDamage(C.ear_damage + rand(0, 5), max(C.ear_deaf,15))
- if(C.ear_damage >= 15)
- C << "Your ears start to ring badly!"
- else if(C.ear_damage >= 5)
- C << "Your ears start to ring!"
+ C.soundbang_act(1, 5, rand(0, 5))
/datum/chemical_reaction/sonic_powder_deafen
name = "sonic_powder_deafen"
@@ -318,17 +309,7 @@
var/location = get_turf(holder.my_atom)
playsound(location, 'sound/effects/bang.ogg', 25, 1)
for(var/mob/living/carbon/C in get_hearers_in_view(created_volume/10, location))
- if(C.check_ear_prot())
- continue
- C.show_message("BANG", 2)
- C.Stun(5)
- C.Weaken(5)
- C.setEarDamage(C.ear_damage + rand(0, 5), max(C.ear_deaf,15))
- if(C.ear_damage >= 15)
- C << "Your ears start to ring badly!"
- else if(C.ear_damage >= 5)
- C << "Your ears start to ring!"
-
+ C.soundbang_act(1, 5, rand(0, 5))
/datum/chemical_reaction/phlogiston
name = "phlogiston"
@@ -371,3 +352,44 @@
/datum/chemical_reaction/pyrosium/on_reaction(datum/reagents/holder, created_volume)
holder.chem_temp = 20 // also cools the fuck down
return
+
+/datum/chemical_reaction/teslium
+ name = "Teslium"
+ id = "teslium"
+ results = list("teslium" = 3)
+ required_reagents = list("stable_plasma" = 1, "silver" = 1, "blackpowder" = 1)
+ mix_message = "A jet of sparks flies from the mixture as it merges into a flickering slurry."
+ required_temp = 400
+
+/datum/chemical_reaction/reagent_explosion/teslium_lightning
+ name = "Teslium Destabilization"
+ id = "teslium_lightning"
+ required_reagents = list("teslium" = 1, "water" = 1)
+ results = list("destabilized_teslium" = 1)
+ strengthdiv = 100
+ modifier = -100
+ mix_message = "The teslium starts to spark as electricity arcs away from it!"
+ mix_sound = 'sound/machines/defib_zap.ogg'
+
+/datum/chemical_reaction/reagent_explosion/teslium_lightning/on_reaction(datum/reagents/holder, created_volume)
+ var/T1 = created_volume * 20 //100 units : Zap 3 times, with powers 2000/5000/12000. Tesla revolvers have a power of 10000 for comparison.
+ var/T2 = created_volume * 50
+ var/T3 = created_volume * 120
+ sleep(10)
+ if(created_volume >= 75) //10 units minimum for lightning, 40 units for secondary blast, 75 units for tertiary blast.
+ tesla_zap(holder.my_atom, 7, T1)
+ playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
+ sleep(10)
+ if(created_volume >= 40)
+ tesla_zap(holder.my_atom, 7, T2)
+ playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
+ sleep(10)
+ if(created_volume >= 10)
+ tesla_zap(holder.my_atom, 7, T3)
+ playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
+ ..()
+
+/datum/chemical_reaction/reagent_explosion/teslium_lightning/heat
+ id = "teslium_lightning2"
+ required_temp = 474
+ required_reagents = list("teslium" = 1)
diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
index ca2b41ffbe7..fd73906d8bc 100644
--- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm
+++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
@@ -167,7 +167,7 @@
playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1)
for(var/mob/living/carbon/C in viewers(get_turf(holder.my_atom), null))
- C.flash_eyes()
+ C.flash_act()
for(var/i = 1, i <= 4 + rand(1,2), i++)
var/chosen = pick(borks)
@@ -195,7 +195,7 @@
playsound(get_turf(holder.my_atom), 'sound/effects/phasein.ogg', 100, 1)
for(var/mob/living/carbon/M in viewers(get_turf(holder.my_atom), null))
- M.flash_eyes()
+ M.flash_act()
for(var/i = 1, i <= 4 + rand(1,2), i++)
var/chosen = pick(borks)
diff --git a/code/modules/reagents/chemistry/recipes/toxins.dm b/code/modules/reagents/chemistry/recipes/toxins.dm
index 5d4fd3ba501..53fcb2bc473 100644
--- a/code/modules/reagents/chemistry/recipes/toxins.dm
+++ b/code/modules/reagents/chemistry/recipes/toxins.dm
@@ -81,14 +81,6 @@
results = list("mindbreaker" = 5)
required_reagents = list("silicon" = 1, "hydrogen" = 1, "charcoal" = 1)
-/datum/chemical_reaction/teslium
- name = "Teslium"
- id = "teslium"
- results = list("teslium" = 3)
- required_reagents = list("plasma" = 1, "silver" = 1, "blackpowder" = 1)
- mix_message = "A jet of sparks flies from the mixture as it merges into a flickering slurry."
- required_temp = 400
-
/datum/chemical_reaction/heparin
name = "Heparin"
id = "Heparin"
diff --git a/code/modules/reagents/reagent_containers/glass.dm b/code/modules/reagents/reagent_containers/glass.dm
index 1676c8339e0..469be2bbbb2 100644
--- a/code/modules/reagents/reagent_containers/glass.dm
+++ b/code/modules/reagents/reagent_containers/glass.dm
@@ -212,6 +212,9 @@
/obj/item/weapon/reagent_containers/glass/beaker/large/epinephrine
name = "epinephrine reserve tank"
list_reagents = list("epinephrine" = 50)
+
+/obj/item/weapon/reagent_containers/glass/beaker/synthflesh
+ list_reagents = list("synthflesh" = 50)
/obj/item/weapon/reagent_containers/glass/bucket
name = "bucket"
diff --git a/code/modules/research/designs/limbgrower_designs.dm b/code/modules/research/designs/limbgrower_designs.dm
new file mode 100644
index 00000000000..591888bfd9d
--- /dev/null
+++ b/code/modules/research/designs/limbgrower_designs.dm
@@ -0,0 +1,43 @@
+/////////////////////////////////////
+//////////Limb Grower Designs ///////
+/////////////////////////////////////
+
+/datum/design/leftarm
+ name = "Left Arm"
+ id = "leftarm"
+ build_type = LIMBGROWER
+ reagents = list("synthflesh" = 25)
+ build_path = /obj/item/bodypart/l_arm
+ category = list("initial","human","lizard","plasmaman")
+
+/datum/design/rightarm
+ name = "Right Arm"
+ id = "rightarm"
+ build_type = LIMBGROWER
+ reagents = list("synthflesh" = 25)
+ build_path = /obj/item/bodypart/r_arm
+ category = list("initial","human","lizard","plasmaman")
+
+/datum/design/leftleg
+ name = "Left Leg"
+ id = "leftleg"
+ build_type = LIMBGROWER
+ reagents = list("synthflesh" = 25)
+ build_path = /obj/item/bodypart/l_leg
+ category = list("initial","human","lizard","plasmaman")
+
+/datum/design/rightleg
+ name = "Right Leg"
+ id = "rightleg"
+ build_type = LIMBGROWER
+ reagents = list("synthflesh" = 25)
+ build_path = /obj/item/bodypart/r_leg
+ category = list("initial","human","lizard","plasmaman")
+
+/datum/design/armblade
+ name = "Arm Blade"
+ id = "armblade"
+ build_type = LIMBGROWER
+ reagents = list("synthflesh" = 75)
+ build_path = /obj/item/weapon/melee/synthetic_arm_blade
+ category = list("special")
\ No newline at end of file
diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm
index 6a1604a4c26..387e56aaf9c 100644
--- a/code/modules/research/designs/mechfabricator_designs.dm
+++ b/code/modules/research/designs/mechfabricator_designs.dm
@@ -3,7 +3,7 @@
name = "Cyborg Endoskeleton"
id = "borg_suit"
build_type = MECHFAB
- build_path = /obj/item/robot_parts/robot_suit
+ build_path = /obj/item/robot_suit
materials = list(MAT_METAL=15000)
construction_time = 500
category = list("Cyborg")
@@ -12,7 +12,7 @@
name = "Cyborg Torso"
id = "borg_chest"
build_type = MECHFAB
- build_path = /obj/item/robot_parts/chest
+ build_path = /obj/item/bodypart/chest/robot
materials = list(MAT_METAL=40000)
construction_time = 350
category = list("Cyborg")
@@ -21,7 +21,7 @@
name = "Cyborg Head"
id = "borg_head"
build_type = MECHFAB
- build_path = /obj/item/robot_parts/head
+ build_path = /obj/item/bodypart/head/robot
materials = list(MAT_METAL=5000)
construction_time = 350
category = list("Cyborg")
@@ -30,7 +30,7 @@
name = "Cyborg Left Arm"
id = "borg_l_arm"
build_type = MECHFAB
- build_path = /obj/item/robot_parts/l_arm
+ build_path = /obj/item/bodypart/l_arm/robot
materials = list(MAT_METAL=10000)
construction_time = 200
category = list("Cyborg")
@@ -39,7 +39,7 @@
name = "Cyborg Right Arm"
id = "borg_r_arm"
build_type = MECHFAB
- build_path = /obj/item/robot_parts/r_arm
+ build_path = /obj/item/bodypart/r_arm/robot
materials = list(MAT_METAL=10000)
construction_time = 200
category = list("Cyborg")
@@ -48,7 +48,7 @@
name = "Cyborg Left Leg"
id = "borg_l_leg"
build_type = MECHFAB
- build_path = /obj/item/robot_parts/l_leg
+ build_path = /obj/item/bodypart/l_leg/robot
materials = list(MAT_METAL=10000)
construction_time = 200
category = list("Cyborg")
@@ -57,7 +57,7 @@
name = "Cyborg Right Leg"
id = "borg_r_leg"
build_type = MECHFAB
- build_path = /obj/item/robot_parts/r_leg
+ build_path = /obj/item/bodypart/r_leg/robot
materials = list(MAT_METAL=10000)
construction_time = 200
category = list("Cyborg")
diff --git a/code/modules/research/research.dm b/code/modules/research/research.dm
index 94bc846e530..6d1cabc38b8 100644
--- a/code/modules/research/research.dm
+++ b/code/modules/research/research.dm
@@ -143,6 +143,16 @@ research holder datum.
if((D.build_type & AUTOLATHE) && ("initial" in D.category)) //autolathe starts without hacked designs
AddDesign2Known(D)
+//Limb Grower files
+/datum/research/limbgrower/New()
+ for(var/T in (subtypesof(/datum/tech)))
+ possible_tech += new T(src)
+ for(var/path in subtypesof(/datum/design))
+ var/datum/design/D = new path(src)
+ possible_designs += D
+ if((D.build_type & LIMBGROWER) && ("initial" in D.category))
+ AddDesign2Known(D)
+
/datum/research/autolathe/AddDesign2Known(datum/design/D)
if(!(D.build_type & AUTOLATHE))
return
diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm
index d21722150e1..d010bfbbc57 100644
--- a/code/modules/research/stock_parts.dm
+++ b/code/modules/research/stock_parts.dm
@@ -25,7 +25,7 @@
if(istype(T))
if(T.component_parts)
T.exchange_parts(user, src)
- user.Beam(T,icon_state="rped_upgrade",icon='icons/effects/effects.dmi',time=5)
+ user.Beam(T,icon_state="rped_upgrade",time=5)
return
/obj/item/weapon/storage/part_replacer/bluespace
@@ -45,7 +45,7 @@
if(get_dist(user, dest_object) < 8)
if(dest_object.storage_contents_dump_act(src, user))
play_rped_sound()
- user.Beam(dest_object,icon_state="rped_upgrade",icon='icons/effects/effects.dmi',time=5)
+ user.Beam(dest_object,icon_state="rped_upgrade",time=5)
return 1
user << "The [src.name] buzzes."
playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)
diff --git a/code/modules/spells/spell_types/barnyard.dm b/code/modules/spells/spell_types/barnyard.dm
index e11115c64d3..a63d91c6437 100644
--- a/code/modules/spells/spell_types/barnyard.dm
+++ b/code/modules/spells/spell_types/barnyard.dm
@@ -47,4 +47,4 @@
target.equip_to_slot_if_possible(magichead, slot_wear_mask, 1, 1)
playsound(get_turf(target), mSounds[randM], 50, 1)
- target.flash_eyes()
+ target.flash_act()
diff --git a/code/modules/spells/spell_types/construct_spells.dm b/code/modules/spells/spell_types/construct_spells.dm
index 0142489bc88..47aaa643c88 100644
--- a/code/modules/spells/spell_types/construct_spells.dm
+++ b/code/modules/spells/spell_types/construct_spells.dm
@@ -108,16 +108,9 @@
centcom_cancast = 0 //Stop people from getting to centcom
action_icon_state = "phaseshift"
action_background_icon_state = "bg_demon"
-
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/jaunt_disappear(atom/movable/overlay/animation, mob/living/target)
- animation.icon_state = "phase_shift"
- animation.setDir(target.dir)
- flick("phase_shift",animation)
-
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/jaunt_reappear(atom/movable/overlay/animation, mob/living/target)
- animation.icon_state = "phase_shift2"
- animation.setDir(target.dir)
- flick("phase_shift2",animation)
+ jaunt_in_time = 12
+ jaunt_in_type = /obj/effect/overlay/temp/dir_setting/wraith
+ jaunt_out_type = /obj/effect/overlay/temp/dir_setting/wraith/out
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/jaunt_steam(mobloc)
return
diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm
index 71b58883ddb..84cfcc108aa 100644
--- a/code/modules/spells/spell_types/ethereal_jaunt.dm
+++ b/code/modules/spells/spell_types/ethereal_jaunt.dm
@@ -13,70 +13,56 @@
centcom_cancast = 0 //Prevent people from getting to centcom
nonabstract_req = 1
var/jaunt_duration = 50 //in deciseconds
+ var/jaunt_in_time = 5
+ var/jaunt_in_type = /obj/effect/overlay/temp/wizard
+ var/jaunt_out_type = /obj/effect/overlay/temp/wizard/out
action_icon_state = "jaunt"
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast(list/targets,mob/user = usr) //magnets, so mostly hardcoded
playsound(get_turf(user), 'sound/magic/Ethereal_Enter.ogg', 50, 1, -1)
for(var/mob/living/target in targets)
- target.notransform = 1 //protects the mob from being transformed (replaced) midjaunt and getting stuck in bluespace
- spawn(0)
- var/turf/mobloc = get_turf(target.loc)
- var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt( mobloc )
- var/atom/movable/overlay/animation = new /atom/movable/overlay( mobloc )
- animation.name = "water"
- animation.density = 0
- animation.anchored = 1
- animation.icon = 'icons/mob/mob.dmi'
- animation.layer = FLY_LAYER
- animation.master = holder
- target.ExtinguishMob()
- if(target.buckled)
- target.buckled.unbuckle_mob(target,force=1)
- if(target.pulledby)
- target.pulledby.stop_pulling()
- target.stop_pulling()
- if(target.has_buckled_mobs())
- target.unbuckle_all_mobs(force=1)
- jaunt_disappear(animation, target)
- target.loc = holder
- target.reset_perspective(holder)
- target.notransform=0 //mob is safely inside holder now, no need for protection.
- jaunt_steam(mobloc)
+ addtimer(src, "do_jaunt", 0, FALSE, target)
- sleep(jaunt_duration)
+/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/do_jaunt(mob/living/target)
+ target.notransform = 1
+ var/turf/mobloc = get_turf(target)
+ var/obj/effect/dummy/spell_jaunt/holder = new /obj/effect/dummy/spell_jaunt(mobloc)
+ PoolOrNew(jaunt_out_type, list(mobloc, holder.dir))
+ target.ExtinguishMob()
+ if(target.buckled)
+ target.buckled.unbuckle_mob(target,force=1)
+ if(target.pulledby)
+ target.pulledby.stop_pulling()
+ target.stop_pulling()
+ if(target.has_buckled_mobs())
+ target.unbuckle_all_mobs(force=1)
+ target.loc = holder
+ target.reset_perspective(holder)
+ target.notransform=0 //mob is safely inside holder now, no need for protection.
+ jaunt_steam(mobloc)
- if(target.loc != holder) //mob warped out of the warp
- qdel(holder)
- return
- mobloc = get_turf(target.loc)
- animation.loc = mobloc
- jaunt_steam(mobloc)
- target.canmove = 0
- holder.reappearing = 1
- playsound(get_turf(user), 'sound/magic/Ethereal_Exit.ogg', 50, 1, -1)
- sleep(20)
- if(!qdeleted(target))
- jaunt_reappear(animation, target)
- sleep(5)
- qdel(animation)
- qdel(holder)
- if(!qdeleted(target))
- if(mobloc.density)
- for(var/direction in list(1,2,4,8,5,6,9,10))
- var/turf/T = get_step(mobloc, direction)
- if(T)
- if(target.Move(T))
- break
- target.canmove = 1
-
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/jaunt_disappear(atom/movable/overlay/animation, mob/living/target)
- animation.icon_state = "liquify"
- flick("liquify",animation)
-
-
-/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/jaunt_reappear(atom/movable/overlay/animation, mob/living/target)
- flick("reappear",animation)
+ sleep(jaunt_duration)
+ if(target.loc != holder) //mob warped out of the warp
+ qdel(holder)
+ return
+ mobloc = get_turf(target.loc)
+ jaunt_steam(mobloc)
+ target.canmove = 0
+ holder.reappearing = 1
+ playsound(get_turf(target), 'sound/magic/Ethereal_Exit.ogg', 50, 1, -1)
+ sleep(25 - jaunt_in_time)
+ PoolOrNew(jaunt_in_type, list(mobloc, holder.dir))
+ sleep(jaunt_in_time)
+ qdel(holder)
+ if(!qdeleted(target))
+ if(mobloc.density)
+ for(var/direction in alldirs)
+ var/turf/T = get_step(mobloc, direction)
+ if(T)
+ if(target.Move(T))
+ break
+ target.canmove = 1
/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/jaunt_steam(mobloc)
var/datum/effect_system/steam_spread/steam = new /datum/effect_system/steam_spread()
@@ -103,6 +89,7 @@
/obj/effect/dummy/spell_jaunt/relaymove(var/mob/user, direction)
if (!src.canmove || reappearing || !direction) return
var/turf/newLoc = get_step(src,direction)
+ setDir(direction)
if(!(newLoc.flags & NOJAUNT))
loc = newLoc
else
diff --git a/code/modules/spells/spell_types/lichdom.dm b/code/modules/spells/spell_types/lichdom.dm
index 9a1d27ebbc7..1cf58b7fd9b 100644
--- a/code/modules/spells/spell_types/lichdom.dm
+++ b/code/modules/spells/spell_types/lichdom.dm
@@ -92,13 +92,14 @@
var/mob/living/carbon/C = old_body
for(var/obj/item/W in C)
C.unEquip(W)
- for(var/obj/item/organ/I in C.internal_organs)
+ for(var/X in C.internal_organs)
+ var/obj/item/organ/I = X
I.Remove(C)
I.forceMove(body_turf)
var/wheres_wizdo = dir2text(get_dir(body_turf, item_turf))
if(wheres_wizdo)
old_body.visible_message("Suddenly [old_body.name]'s corpse falls to pieces! You see a strange energy rise from the remains, and speed off towards the [wheres_wizdo]!")
- body_turf.Beam(item_turf,icon_state="lichbeam",icon='icons/effects/effects.dmi',time=10+10*resurrections,maxdistance=INFINITY)
+ body_turf.Beam(item_turf,icon_state="lichbeam",time=10+10*resurrections,maxdistance=INFINITY)
old_body.dust()
if(!marked_item) //linking item to the spell
diff --git a/code/modules/spells/spell_types/lightning.dm b/code/modules/spells/spell_types/lightning.dm
index 4fac684f72c..73e958926ca 100644
--- a/code/modules/spells/spell_types/lightning.dm
+++ b/code/modules/spells/spell_types/lightning.dm
@@ -58,13 +58,13 @@
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)
+ user.Beam(target,icon_state="lightning[rand(1,12)]",time=5)
Bolt(user,target,30,5,user)
Reset(user)
/obj/effect/proc_holder/spell/targeted/lightning/proc/Bolt(mob/origin,mob/target,bolt_energy,bounces,mob/user = usr)
- origin.Beam(target,icon_state="lightning[rand(1,12)]",icon='icons/effects/effects.dmi',time=5)
+ origin.Beam(target,icon_state="lightning[rand(1,12)]",time=5)
var/mob/living/carbon/current = target
if(bounces < 1)
current.electrocute_act(bolt_energy,"Lightning Bolt",safety=1)
diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm
index 77e69582ef0..fdc5247f4aa 100644
--- a/code/modules/station_goals/bsa.dm
+++ b/code/modules/station_goals/bsa.dm
@@ -7,7 +7,7 @@
/datum/station_goal/bluespace_cannon/get_report()
return {"Our military presence is inadequate in your sector.
- We need you to construct BSA-[rand(0-99)] Artillery position aboard your station.
+ We need you to construct BSA-[rand(1,99)] Artillery position aboard your station.
Base parts should be availible for shipping by your cargo shuttle.
-Nanotrasen Naval Command"}
@@ -60,7 +60,7 @@
name = "Bluespace Artillery Fusor"
desc = "Contents classifed by Nanotrasen Naval Command. Needs to be linked with the other BSA parts using multitool."
icon_state = "fuel_chamber"
- var/obj/machinery/bsa/back/back
+ var/obj/machinery/bsa/back/back
var/obj/machinery/bsa/front/front
/obj/machinery/bsa/middle/attackby(obj/item/weapon/W, mob/user, params)
@@ -169,7 +169,7 @@
var/turf/point = get_front_turf()
for(var/turf/T in getline(get_step(point,dir),get_target_turf()))
T.ex_act(1)
- point.Beam(get_target_turf(),icon_state="bsa_beam",icon='icons/effects/beam.dmi',time=50,maxdistance = world.maxx) //ZZZAP
+ point.Beam(get_target_turf(),icon_state="bsa_beam",time=50,maxdistance = world.maxx) //ZZZAP
/obj/structure/filler
@@ -218,7 +218,7 @@
var/notice
var/target
use_power = 0
- circuit = /obj/machinery/computer/bsa_control
+ circuit = /obj/item/weapon/circuitboard/machine/computer/bsa_control
icon = 'icons/obj/machines/particle_accelerator.dmi'
icon_state = "control_boxp"
var/area_aim = FALSE //should also show areas for targeting
diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm
index 6de3312238f..7f831986f2a 100644
--- a/code/modules/station_goals/dna_vault.dm
+++ b/code/modules/station_goals/dna_vault.dm
@@ -7,7 +7,7 @@
#define VAULT_NOBREATH "Lung Enhancement"
#define VAULT_FIREPROOF "Thermal Regulation"
#define VAULT_STUNTIME "Neural Repathing"
-#define VAULT_ARMOUR "Bone Reinforcment"
+#define VAULT_ARMOUR "Bone Reinforcement"
/datum/station_goal/dna_vault
name = "DNA Vault"
@@ -20,7 +20,7 @@
animal_count = rand(15,20) //might be too few given ~15 roundstart stationside ones
human_count = rand(round(0.75 * ticker.totalPlayersReady) , ticker.totalPlayersReady) // 75%+ roundstart population.
var/non_standard_plants = non_standard_plants_count()
- plant_count = rand(round(0.7 * non_standard_plants),round(0.9 * non_standard_plants))
+ plant_count = rand(round(0.5 * non_standard_plants),round(0.7 * non_standard_plants))
/datum/station_goal/dna_vault/proc/non_standard_plants_count()
. = 0
@@ -52,7 +52,7 @@
if(..())
return TRUE
for(var/obj/machinery/dna_vault/V in machines)
- if(V.animals.len >= animal_count && V.plants.len >= plant_count && V.dna >= human_count)
+ if(V.animals.len >= animal_count && V.plants.len >= plant_count && V.dna.len >= human_count)
return TRUE
return FALSE
diff --git a/code/modules/station_goals/shield.dm b/code/modules/station_goals/shield.dm
index 357cc426e15..20f5a76f6d4 100644
--- a/code/modules/station_goals/shield.dm
+++ b/code/modules/station_goals/shield.dm
@@ -14,7 +14,7 @@
/datum/station_goal/station_shield/on_report()
- //Unlock
+ //Unlock
var/datum/supply_pack/P = SSshuttle.supply_packs[/datum/supply_pack/misc/shield_sat]
P.special_enabled = TRUE
@@ -69,7 +69,7 @@
/obj/machinery/computer/sat_control/ui_data()
var/list/data = list()
-
+
data["satellites"] = list()
for(var/obj/machinery/satellite/S in machines)
data["satellites"] += list(list(
@@ -78,8 +78,8 @@
"mode" = S.mode
))
data["notice"] = notice
-
-
+
+
var/datum/station_goal/station_shield/G = locate() in ticker.mode.station_goals
if(G)
data["meteor_shield"] = 1
@@ -116,7 +116,7 @@
active = !active
if(active)
animate(src, pixel_y = 2, time = 10, loop = -1)
- anchored = 1
+ anchored = 1
else
animate(src, pixel_y = 0, time = 10)
anchored = 0
@@ -136,7 +136,7 @@
desc = "Meteor Point Defense Satellite"
mode = "M-SHIELD"
var/kill_range = 10
-
+
/obj/machinery/satellite/meteor_shield/proc/space_los(meteor)
for(var/turf/T in getline(src,meteor))
if(!istype(T, /turf/open/space))
@@ -152,7 +152,7 @@
if(get_dist(M,src) > kill_range)
continue
if(!emagged && space_los(M))
- Beam(get_turf(M),time=5,maxdistance=kill_range)
+ Beam(get_turf(M),icon_state="sat_beam",time=5,maxdistance=kill_range)
qdel(M)
/obj/machinery/satellite/meteor_shield/toggle(user)
diff --git a/code/modules/stock_market/computer.dm b/code/modules/stock_market/computer.dm
index ced8a43f179..97a2bc983b1 100644
--- a/code/modules/stock_market/computer.dm
+++ b/code/modules/stock_market/computer.dm
@@ -83,25 +83,6 @@ a.updated {
dat += "Prominent products: "
for (var/prod in S.products)
dat += "[prod] "
- dat += " Borrow options: "
- if (S.borrow_brokers.len)
- for (var/datum/borrow/B in S.borrow_brokers)
- dat += "[B.broker] offers [B.share_amount] shares for borrowing, for a deposit of [B.deposit * 100]% of the shares' value. "
- dat += "The broker expects the return of the shares after [B.lease_time / 600] minutes, with a grace period of [B.grace_time / 600] minute(s). "
- dat += "This offer expires in [(B.offer_expires - world.time) / 600] minutes. "
- dat += "Note: If you do not return all shares by the end of the grace period, you will lose your deposit and the value of all unreturned shares at current value from your account! "
- dat += "Note: You cannot withdraw or transfer money off your account while a borrow is active. "
- dat += "Take offer (Estimated deposit: [B.deposit * S.current_value * B.share_amount] credits)
"
- else
- dat += "No borrow options available
"
- for (var/datum/borrow/B in S.borrows)
- if (B.borrower == logged_in)
- dat += "You are borrowing [B.share_amount] shares from [B.broker]. "
- dat += "Your deposit riding on the deal is [B.deposit] credits. "
- if (world.time < B.lease_expires)
- dat += "You are expected to return the borrowed shares in [(B.lease_expires - world.time) / 600] minutes.
"
- else
- dat += "The brokering agency is collecting. You still owe them [B.share_debt] shares, which you have [(B.grace_expires - world.time) / 600] minutes to present.
"
var/news = 0
if (logged_in)
var/list/LR = stockExchange.last_read[S]
diff --git a/code/modules/surgery/amputation.dm b/code/modules/surgery/amputation.dm
index 1e13586eea8..2ebe45f2d31 100644
--- a/code/modules/surgery/amputation.dm
+++ b/code/modules/surgery/amputation.dm
@@ -2,8 +2,10 @@
/datum/surgery/amputation
name = "amputation"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/sever_limb)
- species = list(/mob/living/carbon/human)
+ species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list("r_arm", "l_arm", "l_leg", "r_leg", "head")
+ requires_organic_bodypart = 0
+
/datum/surgery_step/sever_limb
name = "sever limb"
@@ -16,7 +18,6 @@
/datum/surgery_step/sever_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
var/mob/living/carbon/human/L = target
user.visible_message("[user] severs [L]'s [parse_zone(target_zone)]!", "You sever [L]'s [parse_zone(target_zone)].")
- var/obj/item/bodypart/BP = L.get_bodypart(target_zone)
- if(BP)
- BP.drop_limb()
+ if(surgery.operated_bodypart)
+ surgery.operated_bodypart.drop_limb()
return 1
\ No newline at end of file
diff --git a/code/modules/surgery/bodyparts/bodyparts.dm b/code/modules/surgery/bodyparts/bodyparts.dm
index 74c8679cd78..6e4ee1d069d 100644
--- a/code/modules/surgery/bodyparts/bodyparts.dm
+++ b/code/modules/surgery/bodyparts/bodyparts.dm
@@ -4,10 +4,11 @@
desc = "why is it detached..."
force = 3
throwforce = 3
+ icon = 'icons/mob/human_parts.dmi'
icon_state = ""
layer = BELOW_MOB_LAYER //so it isn't hidden behind objects when on the floor
- var/mob/living/carbon/human/owner = null
- var/status = ORGAN_ORGANIC
+ var/mob/living/carbon/owner = null
+ var/status = BODYPART_ORGANIC
var/body_zone //"chest", "l_arm", etc , used for def_zone
var/body_part = null //bitflag used to check which clothes cover this bodypart
var/brutestate = 0
@@ -28,10 +29,14 @@
var/mutation_color = ""
var/no_update = 0
+ var/animal_origin = null //for nonhuman bodypart (e.g. monkey)
+ var/dismemberable = 1 //whether it can be dismembered with a weapon.
+
var/px_x = 0
var/px_y = 0
- var/state_flags
+ var/species_flags_list = list()
+ var/dmg_overlay_type //the type of damage overlay (if any) to use when this bodypart is bruised/burned.
/obj/item/bodypart/examine(mob/user)
..()
@@ -53,7 +58,7 @@
if(ishuman(C))
var/mob/living/carbon/human/H = C
if(EASYLIMBATTACHMENT in H.dna.species.specflags)
- if(!H.get_bodypart(body_zone))
+ if(!H.get_bodypart(body_zone) && !animal_origin)
if(H == user)
H.visible_message("[H] jams [src] into \his empty socket!",\
"You force [src] into your empty socket, and it locks into place!")
@@ -72,8 +77,8 @@
user << "There is nothing left inside [src]!"
return
playsound(loc, 'sound/weapons/slice.ogg', 50, 1, -1)
- user.visible_message("[user] begins to cut through the bone in [src].",\
- "You begin to cut through the bone in [src]...")
+ user.visible_message("[user] begins to cut open [src].",\
+ "You begin to cut open [src]...")
if(do_after(user, 54, target = src))
drop_organs(user)
else
@@ -81,27 +86,30 @@
/obj/item/bodypart/throw_impact(atom/hit_atom)
..()
- playsound(get_turf(src), 'sound/misc/splort.ogg', 50, 1, -1)
+ if(status != BODYPART_ROBOTIC)
+ playsound(get_turf(src), 'sound/misc/splort.ogg', 50, 1, -1)
pixel_x = rand(-3, 3)
pixel_y = rand(-3, 3)
+//empties the bodypart from its organs and other things inside it
/obj/item/bodypart/proc/drop_organs(mob/user)
var/turf/T = get_turf(src)
- playsound(T, 'sound/misc/splort.ogg', 50, 1, -1)
+ if(status != BODYPART_ROBOTIC)
+ playsound(T, 'sound/misc/splort.ogg', 50, 1, -1)
for(var/obj/item/I in src)
- I.loc = T
+ I.forceMove(T)
//Applies brute and burn damage to the organ. Returns 1 if the damage-icon states changed at all.
//Damage will not exceed max_damage using this proc
//Cannot apply negative damage
-/obj/item/bodypart/proc/take_damage(brute, burn)
+/obj/item/bodypart/proc/take_damage(brute, burn, updating_health = 1)
if(owner && (owner.status_flags & GODMODE))
return 0 //godmode
brute = max(brute * config.damage_multiplier,0)
burn = max(burn * config.damage_multiplier,0)
- if(status == ORGAN_ROBOTIC) //This makes robolimbs not damageable by chems and makes it stronger
+ if(status == BODYPART_ROBOTIC) //This makes robolimbs not damageable by chems and makes it stronger
brute = max(0, brute - 5)
burn = max(0, burn - 4)
@@ -126,7 +134,7 @@
burn_dam += can_inflict
else
return 0
- if(owner)
+ if(owner && updating_health)
owner.updatehealth()
return update_bodypart_damage_state()
@@ -134,17 +142,17 @@
//Heals brute and burn damage for the organ. Returns 1 if the damage-icon states changed at all.
//Damage cannot go below zero.
//Cannot remove negative damage (i.e. apply damage)
-/obj/item/bodypart/proc/heal_damage(brute, burn, robotic)
+/obj/item/bodypart/proc/heal_damage(brute, burn, only_robotic = 0, only_organic = 1, updating_health = 1)
- if(robotic && status != ORGAN_ROBOTIC) //This makes organic limbs not heal when the proc is in Robotic mode.
+ if(only_robotic && status != BODYPART_ROBOTIC) //This makes organic limbs not heal when the proc is in Robotic mode.
return
- if(!robotic && status == ORGAN_ROBOTIC) //This makes robolimbs not healable by chems.
+ if(only_organic && status != BODYPART_ORGANIC) //This makes robolimbs not healable by chems.
return
brute_dam = max(brute_dam - brute, 0)
burn_dam = max(burn_dam - burn, 0)
- if(owner)
+ if(owner && updating_health)
owner.updatehealth()
return update_bodypart_damage_state()
@@ -157,14 +165,13 @@
//Updates an organ's brute/burn states for use by update_damage_overlays()
//Returns 1 if we need to update overlays. 0 otherwise.
/obj/item/bodypart/proc/update_bodypart_damage_state()
- if(status == ORGAN_ORGANIC) //Robotic limbs show no damage - RR
- var/tbrute = round( (brute_dam/max_damage)*3, 1 )
- var/tburn = round( (burn_dam/max_damage)*3, 1 )
- if((tbrute != brutestate) || (tburn != burnstate))
- brutestate = tbrute
- burnstate = tburn
- return 1
- return 0
+ var/tbrute = round( (brute_dam/max_damage)*3, 1 )
+ var/tburn = round( (burn_dam/max_damage)*3, 1 )
+ if((tbrute != brutestate) || (tburn != burnstate))
+ brutestate = tbrute
+ burnstate = tburn
+ return 1
+ return 0
@@ -183,47 +190,57 @@
owner.update_damage_overlays()
//we inform the bodypart of the changes that happened to the owner, or give it the informations from a source mob.
-/obj/item/bodypart/proc/update_limb(dropping_limb, mob/living/carbon/human/source)
- var/mob/living/carbon/human/H
+/obj/item/bodypart/proc/update_limb(dropping_limb, mob/living/carbon/source)
+ var/mob/living/carbon/C
if(source)
- H = source
+ C = source
else
- H = owner
- if(!istype(H))
- return
+ C = owner
- should_draw_greyscale = FALSE
+ if(!animal_origin)
+ var/mob/living/carbon/human/H = C
+ should_draw_greyscale = FALSE
- var/datum/species/S = H.dna.species
- species_id = S.limbs_id
+ var/datum/species/S = H.dna.species
+ species_id = S.limbs_id
+ species_flags_list = H.dna.species.specflags
- if(S.use_skintones)
- skin_tone = H.skin_tone
- should_draw_greyscale = TRUE
- else
- skin_tone = ""
-
- body_gender = H.gender
- should_draw_gender = S.sexes
-
- if(MUTCOLORS in S.specflags)
- if(S.fixed_mut_color)
- species_color = S.fixed_mut_color
+ if(S.use_skintones)
+ skin_tone = H.skin_tone
+ should_draw_greyscale = TRUE
else
- species_color = H.dna.features["mcolor"]
- should_draw_greyscale = TRUE
- else
- species_color = ""
+ skin_tone = ""
- if(H.disabilities & HUSK)
- species_id = "husk"
+ body_gender = H.gender
+ should_draw_gender = S.sexes
+
+ if(MUTCOLORS in S.specflags)
+ if(S.fixed_mut_color)
+ species_color = S.fixed_mut_color
+ else
+ species_color = H.dna.features["mcolor"]
+ should_draw_greyscale = TRUE
+ else
+ species_color = ""
+
+ if(!dropping_limb && H.dna.check_mutation(HULK))
+ mutation_color = "00aa00"
+ else
+ mutation_color = ""
+
+ dmg_overlay_type = S.damage_overlay_type
+
+ else if(animal_origin == MONKEY_BODYPART) //currently monkeys are the only non human mob to have damage overlays.
+ dmg_overlay_type = animal_origin
+
+ if(C.disabilities & HUSK)
+ species_id = "husk" //overrides species_id
+ dmg_overlay_type = "" //no damage overlay shown when husked
should_draw_gender = FALSE
should_draw_greyscale = FALSE
- if(!dropping_limb && H.dna.check_mutation(HULK))
- mutation_color = "00aa00"
- else
- mutation_color = ""
+ if(status == BODYPART_ROBOTIC)
+ dmg_overlay_type = "robotic"
if(dropping_limb)
no_update = 1 //when attached, the limb won't be affected by the appearance changes of its mob owner.
@@ -231,25 +248,49 @@
//to update the bodypart's icon when not attached to a mob
/obj/item/bodypart/proc/update_icon_dropped()
cut_overlays()
- var/image/I = get_limb_icon(1)
- if(I)
+ var/list/standing = get_limb_icon(1)
+ if(!standing.len)
+ icon_state = initial(icon_state)//no overlays found, we default back to initial icon.
+ return
+ for(var/image/I in standing)
I.pixel_x = px_x
I.pixel_y = px_y
- add_overlay(I)
+ add_overlay(standing)
//Gives you a proper icon appearance for the dismembered limb
/obj/item/bodypart/proc/get_limb_icon(dropped)
- var/image/I
+ icon_state = "" //to erase the default sprite, we're building the visual aspects of the bodypart through overlays alone.
+
+ var/list/standing = list()
+
+ var/image_dir
+ if(dropped)
+ image_dir = SOUTH
+ if(dmg_overlay_type)
+ if(brutestate)
+ standing += image("icon"='icons/mob/dam_mob.dmi', "icon_state"="[dmg_overlay_type]_[body_zone]_[brutestate]0", "layer"=-DAMAGE_LAYER, "dir"=image_dir)
+ if(burnstate)
+ standing += image("icon"='icons/mob/dam_mob.dmi', "icon_state"="[dmg_overlay_type]_[body_zone]_0[burnstate]", "layer"=-DAMAGE_LAYER, "dir"=image_dir)
+
+
+ if(animal_origin)
+ if(status == BODYPART_ORGANIC)
+ if(species_id == "husk")
+ standing += image("icon"='icons/mob/animal_parts.dmi', "icon_state"="[animal_origin]_husk_[body_zone]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
+ else
+ standing += image("icon"='icons/mob/animal_parts.dmi', "icon_state"="[animal_origin]_[body_zone]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
+ else
+ standing += image("icon"='icons/mob/augments.dmi', "icon_state"="[animal_origin]_[body_zone]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
+ return standing
var/icon_gender = (body_gender == FEMALE) ? "f" : "m" //gender of the icon, if applicable
if((body_zone != "head" && body_zone != "chest"))
should_draw_gender = FALSE
- var/image_dir
- if(dropped)
- image_dir = SOUTH
- if(status == ORGAN_ORGANIC)
+ var/image/I
+
+ if(status == BODYPART_ORGANIC)
if(should_draw_greyscale)
if(should_draw_gender)
I = image("icon"='icons/mob/human_parts_greyscale.dmi', "icon_state"="[species_id]_[body_zone]_[icon_gender]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
@@ -265,11 +306,13 @@
I = image("icon"='icons/mob/augments.dmi', "icon_state"="[body_zone]_[icon_gender]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
else
I = image("icon"='icons/mob/augments.dmi', "icon_state"="[body_zone]_s", "layer"=-BODYPARTS_LAYER, "dir"=image_dir)
- return I
+ standing += I
+ return standing
if(!should_draw_greyscale)
- return I
+ standing += I
+ return standing
//Greyscale Colouring
var/draw_color
@@ -284,13 +327,15 @@
if(draw_color)
I.color = "#[draw_color]"
//End Greyscale Colouring
+ standing += I
- return I
+ return standing
/obj/item/bodypart/chest
name = "chest"
desc = "It's impolite to stare at a person's chest."
+ icon_state = "default_human_chest"
max_damage = 200
body_zone = "chest"
body_part = CHEST
@@ -303,12 +348,43 @@
qdel(cavity_item)
return ..()
+/obj/item/bodypart/chest/drop_organs(mob/user)
+ if(cavity_item)
+ cavity_item.forceMove(user.loc)
+ cavity_item = null
+ ..()
+
+/obj/item/bodypart/chest/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_chest"
+ animal_origin = MONKEY_BODYPART
+
+/obj/item/bodypart/chest/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_chest_s"
+ dismemberable = 0
+ max_damage = 500
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/chest/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
+
+/obj/item/bodypart/chest/larva
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "larva_chest_s"
+ dismemberable = 0
+ max_damage = 50
+ animal_origin = LARVA_BODYPART
+
/obj/item/bodypart/l_arm
name = "left arm"
desc = "Did you know that the word 'sinister' stems originally from the \
Latin 'sinestra' (left hand), because the left hand was supposed to \
be possessed by the devil? This arm appears to be possessed by no \
one though."
+ icon_state = "default_human_l_arm"
attack_verb = list("slapped", "punched")
max_damage = 50
body_zone ="l_arm"
@@ -316,10 +392,32 @@
px_x = -6
px_y = 0
+/obj/item/bodypart/l_arm/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_l_arm"
+ animal_origin = MONKEY_BODYPART
+ px_x = -5
+ px_y = -3
+
+/obj/item/bodypart/l_arm/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_l_arm_s"
+ px_x = 0
+ px_y = 0
+ dismemberable = 0
+ max_damage = 100
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/l_arm/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
+
/obj/item/bodypart/r_arm
name = "right arm"
desc = "Over 87% of humans are right handed. That figure is much lower \
among humans missing their right arm."
+ icon_state = "default_human_r_arm"
attack_verb = list("slapped", "punched")
max_damage = 50
body_zone = "r_arm"
@@ -327,10 +425,32 @@
px_x = 6
px_y = 0
+/obj/item/bodypart/r_arm/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_r_arm"
+ animal_origin = MONKEY_BODYPART
+ px_x = 5
+ px_y = -3
+
+/obj/item/bodypart/r_arm/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_r_arm_s"
+ px_x = 0
+ px_y = 0
+ dismemberable = 0
+ max_damage = 100
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/r_arm/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
+
/obj/item/bodypart/l_leg
name = "left leg"
desc = "Some athletes prefer to tie their left shoelaces first for good \
luck. In this instance, it probably would not have helped."
+ icon_state = "default_human_l_leg"
attack_verb = list("kicked", "stomped")
max_damage = 50
body_zone = "l_leg"
@@ -338,12 +458,33 @@
px_x = -2
px_y = 12
+/obj/item/bodypart/l_leg/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_l_leg"
+ animal_origin = MONKEY_BODYPART
+ px_y = 4
+
+/obj/item/bodypart/l_leg/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_l_leg_s"
+ px_x = 0
+ px_y = 0
+ dismemberable = 0
+ max_damage = 100
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/l_leg/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
+
/obj/item/bodypart/r_leg
name = "right leg"
desc = "You put your right leg in, your right leg out. In, out, in, out, \
shake it all about. And apparently then it detaches.\n\
The hokey pokey has certainly changed a lot since space colonisation."
// alternative spellings of 'pokey' are availible
+ icon_state = "default_human_r_leg"
attack_verb = list("kicked", "stomped")
max_damage = 50
body_zone = "r_leg"
@@ -351,6 +492,26 @@
px_x = 2
px_y = 12
+/obj/item/bodypart/r_leg/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_r_leg"
+ animal_origin = MONKEY_BODYPART
+ px_y = 4
+
+/obj/item/bodypart/r_leg/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_r_leg_s"
+ px_x = 0
+ px_y = 0
+ dismemberable = 0
+ max_damage = 100
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/r_leg/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
+
/////////////////////////////////////////////////////////////////////////
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 92bc44d3582..cec2417e876 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -1,26 +1,33 @@
/obj/item/bodypart/proc/can_dismember(obj/item/I)
- . = (get_damage() >= (max_damage - I.armour_penetration/2))
+ if(dismemberable)
+ . = (get_damage() >= (max_damage - I.armour_penetration/2))
//Dismember a limb
/obj/item/bodypart/proc/dismember(dam_type = BRUTE)
- var/mob/living/carbon/human/H = owner
- if(!istype(H) || (NODISMEMBER in H.dna.species.specflags)) // species don't allow dismemberment
+ if(!owner)
return 0
+ var/mob/living/carbon/C = owner
+ if(!dismemberable)
+ return 0
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ if(NODISMEMBER in H.dna.species.specflags) // species don't allow dismemberment
+ return 0
- var/obj/item/bodypart/affecting = H.get_bodypart("chest")
+ var/obj/item/bodypart/affecting = C.get_bodypart("chest")
affecting.take_damage(Clamp(brute_dam/2, 15, 50), Clamp(burn_dam/2, 0, 50)) //Damage the chest based on limb's existing damage
- H.visible_message("[H]'s [src.name] has been violently dismembered!")
- H.emote("scream")
+ C.visible_message("[C]'s [src.name] has been violently dismembered!")
+ C.emote("scream")
drop_limb()
if(dam_type == BURN)
burn()
return 1
- add_mob_blood(H)
- var/turf/location = H.loc
+ add_mob_blood(C)
+ var/turf/location = C.loc
if(istype(location))
- H.add_splatter_floor(location)
+ C.add_splatter_floor(location)
var/direction = pick(cardinal)
var/t_range = rand(2,max(throw_range/2, 2))
var/turf/target_turf = get_turf(src)
@@ -34,92 +41,100 @@
/obj/item/bodypart/chest/dismember()
- var/mob/living/carbon/human/H = owner
- if(!istype(H) || (NODISMEMBER in H.dna.species.specflags)) //human's species don't allow dismemberment
+ if(!owner)
return 0
+ var/mob/living/carbon/C = owner
+ if(!dismemberable)
+ return 0
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ if(NODISMEMBER in H.dna.species.specflags) // species don't allow dismemberment
+ return 0
var/organ_spilled = 0
- var/turf/T = get_turf(H)
- H.add_splatter_floor(T)
- playsound(get_turf(owner), 'sound/misc/splort.ogg', 80, 1)
- for(var/X in owner.internal_organs)
+ var/turf/T = get_turf(C)
+ C.add_splatter_floor(T)
+ playsound(get_turf(C), 'sound/misc/splort.ogg', 80, 1)
+ for(var/X in C.internal_organs)
var/obj/item/organ/O = X
- if(O.zone != "chest")
+ var/org_zone = check_zone(O.zone)
+ if(org_zone != "chest")
continue
- O.Remove(owner)
- O.loc = T
+ O.Remove(C)
+ O.forceMove(T)
organ_spilled = 1
if(cavity_item)
- cavity_item.loc = T
+ cavity_item.forceMove(T)
cavity_item = null
organ_spilled = 1
if(organ_spilled)
- owner.visible_message("[owner]'s internal organs spill out onto the floor!")
+ C.visible_message("[C]'s internal organs spill out onto the floor!")
return 1
//limb removal. The "special" argument is used for swapping a limb with a new one without the effects of losing a limb kicking in.
/obj/item/bodypart/proc/drop_limb(special)
- if(!ishuman(owner))
+ if(!owner)
return
var/turf/T = get_turf(owner)
- var/mob/living/carbon/human/H = owner
+ var/mob/living/carbon/C = owner
if(!no_update)
update_limb(1)
- H.bodyparts -= src
+ C.bodyparts -= src
if(held_index)
- H.unEquip(owner.get_item_for_held_index(held_index), 1)
- H.hand_bodyparts[held_index] = null
+ C.unEquip(owner.get_item_for_held_index(held_index), 1)
+ C.hand_bodyparts[held_index] = null
owner = null
- for(var/X in H.surgeries) //if we had an ongoing surgery on that limb, we stop it.
+ for(var/X in C.surgeries) //if we had an ongoing surgery on that limb, we stop it.
var/datum/surgery/S = X
- if(S.organ == src)
- H.surgeries -= S
+ if(S.operated_bodypart == src)
+ C.surgeries -= S
qdel(S)
break
for(var/obj/item/I in embedded_objects)
embedded_objects -= I
I.loc = src
- if(!H.has_embedded_objects())
- H.clear_alert("embeddedobject")
+ if(!C.has_embedded_objects())
+ C.clear_alert("embeddedobject")
if(!special)
- for(var/X in H.dna.mutations) //some mutations require having specific limbs to be kept.
- var/datum/mutation/human/MT = X
- if(MT.limb_req && MT.limb_req == body_zone)
- MT.force_lose(H)
+ if(C.dna)
+ for(var/X in C.dna.mutations) //some mutations require having specific limbs to be kept.
+ var/datum/mutation/human/MT = X
+ if(MT.limb_req && MT.limb_req == body_zone)
+ MT.force_lose(C)
- for(var/X in H.internal_organs) //internal organs inside the dismembered limb are dropped.
+ for(var/X in C.internal_organs) //internal organs inside the dismembered limb are dropped.
var/obj/item/organ/O = X
var/org_zone = check_zone(O.zone)
if(org_zone != body_zone)
continue
- O.transfer_to_limb(src, H)
+ O.transfer_to_limb(src, C)
update_icon_dropped()
- src.loc = T
- H.update_health_hud() //update the healthdoll
- H.update_body()
- H.update_hair()
- H.update_canmove()
+ forceMove(T)
+ C.update_health_hud() //update the healthdoll
+ C.update_body()
+ C.update_hair()
+ C.update_canmove()
//when a limb is dropped, the internal organs are removed from the mob and put into the limb
-/obj/item/organ/proc/transfer_to_limb(obj/item/bodypart/LB, mob/living/carbon/human/H)
- Remove(H)
+/obj/item/organ/proc/transfer_to_limb(obj/item/bodypart/LB, mob/living/carbon/C)
+ Remove(C)
loc = LB
-/obj/item/organ/brain/transfer_to_limb(obj/item/bodypart/head/LB, mob/living/carbon/human/H)
- if(H.mind && H.mind.changeling)
+/obj/item/organ/brain/transfer_to_limb(obj/item/bodypart/head/LB, mob/living/carbon/human/C)
+ if(C.mind && C.mind.changeling)
LB.brain = new //changeling doesn't lose its real brain organ, we drop a decoy.
LB.brain.loc = LB
else //if not a changeling, we put the brain organ inside the dropped head
- Remove(H) //and put the player in control of the brainmob
+ Remove(C) //and put the player in control of the brainmob
loc = LB
LB.brain = src
LB.brainmob = brainmob
@@ -133,39 +148,39 @@
return
/obj/item/bodypart/r_arm/drop_limb(special)
- var/mob/living/carbon/human/H = owner
+ var/mob/living/carbon/C = owner
..()
- if(istype(H) && !special)
- if(H.handcuffed)
- H.handcuffed.loc = H.loc
- H.handcuffed.dropped(H)
- H.handcuffed = null
- H.update_handcuffed()
- if(H.hud_used)
- var/obj/screen/inventory/hand/R = H.hud_used.hand_slots["[held_index]"]
+ if(C && !special)
+ if(C.handcuffed)
+ C.handcuffed.loc = C.loc
+ C.handcuffed.dropped(C)
+ C.handcuffed = null
+ C.update_handcuffed()
+ if(C.hud_used)
+ var/obj/screen/inventory/hand/R = C.hud_used.hand_slots["[held_index]"]
if(R)
R.update_icon()
- if(H.gloves)
- H.unEquip(H.gloves, 1)
- H.update_inv_gloves() //to remove the bloody hands overlay
+ if(C.gloves)
+ C.unEquip(C.gloves, 1)
+ C.update_inv_gloves() //to remove the bloody hands overlay
/obj/item/bodypart/l_arm/drop_limb(special)
- var/mob/living/carbon/human/H = owner
+ var/mob/living/carbon/C = owner
..()
- if(istype(H) && !special)
- if(H.handcuffed)
- H.handcuffed.loc = H.loc
- H.handcuffed.dropped(H)
- H.handcuffed = null
- H.update_handcuffed()
- if(H.hud_used)
- var/obj/screen/inventory/hand/L = H.hud_used.hand_slots["[held_index]"]
+ if(C && !special)
+ if(C.handcuffed)
+ C.handcuffed.loc = C.loc
+ C.handcuffed.dropped(C)
+ C.handcuffed = null
+ C.update_handcuffed()
+ if(C.hud_used)
+ var/obj/screen/inventory/hand/L = C.hud_used.hand_slots["[held_index]"]
if(L)
L.update_icon()
- if(H.gloves)
- H.unEquip(H.gloves, 1)
- H.update_inv_gloves() //to remove the bloody hands overlay
+ if(C.gloves)
+ C.unEquip(C.gloves, 1)
+ C.update_inv_gloves() //to remove the bloody hands overlay
/obj/item/bodypart/r_leg/drop_limb(special)
@@ -176,10 +191,8 @@
owner.legcuffed.dropped(owner)
owner.legcuffed = null
owner.update_inv_legcuffed()
- if(ishuman(owner))
- var/mob/living/carbon/human/H = owner
- if(H.shoes)
- H.unEquip(H.shoes, 1)
+ if(owner.shoes)
+ owner.unEquip(owner.shoes, 1)
..()
/obj/item/bodypart/l_leg/drop_limb(special) //copypasta
@@ -190,21 +203,17 @@
owner.legcuffed.dropped(owner)
owner.legcuffed = null
owner.update_inv_legcuffed()
- if(ishuman(owner))
- var/mob/living/carbon/human/H = owner
- if(H.shoes)
- H.unEquip(H.shoes, 1)
+ if(owner.shoes)
+ owner.unEquip(owner.shoes, 1)
..()
/obj/item/bodypart/head/drop_limb(special)
- var/mob/living/carbon/human/H = owner
- if(istype(H))
- if(!special)
- //Drop all worn head items
- for(var/X in list(H.glasses, H.ears, H.wear_mask, H.head))
- var/obj/item/I = X
- H.unEquip(I, 1)
- name = "[H]'s head"
+ if(!special)
+ //Drop all worn head items
+ for(var/X in list(owner.glasses, owner.ears, owner.wear_mask, owner.head))
+ var/obj/item/I = X
+ owner.unEquip(I, 1)
+ name = "[owner]'s head"
..()
@@ -213,72 +222,76 @@
//Attach a limb to a human and drop any existing limb of that type.
-/obj/item/bodypart/proc/replace_limb(mob/living/carbon/human/H, special)
- if(!istype(H))
+/obj/item/bodypart/proc/replace_limb(mob/living/carbon/C, special)
+ if(!istype(C))
return
- var/obj/item/bodypart/O = locate(src.type) in H.bodyparts
-
+ var/obj/item/bodypart/O = locate(src.type) in C.bodyparts
if(O)
O.drop_limb(1)
- attach_limb(H, special)
+ attach_limb(C, special)
-/obj/item/bodypart/head/replace_limb(mob/living/carbon/human/H, special)
- if(!istype(H))
+/obj/item/bodypart/head/replace_limb(mob/living/carbon/C, special)
+ if(!istype(C))
return
- var/obj/item/bodypart/head/O = locate(src.type) in H.bodyparts
+ var/obj/item/bodypart/head/O = locate(src.type) in C.bodyparts
if(O)
if(!special)
return
else
O.drop_limb(1)
- attach_limb(H, special)
+ attach_limb(C, special)
-/obj/item/bodypart/proc/attach_limb(mob/living/carbon/human/H, special)
+/obj/item/bodypart/proc/attach_limb(mob/living/carbon/C, special)
loc = null
- owner = H
- H.bodyparts += src
+ owner = C
+ C.bodyparts += src
if(held_index)
- H.hand_bodyparts += src
- if(H.hud_used)
- var/obj/screen/inventory/hand/hand = H.hud_used.hand_slots["[held_index]"]
+ C.hand_bodyparts += src
+ if(C.hud_used)
+ var/obj/screen/inventory/hand/hand = C.hud_used.hand_slots["[held_index]"]
if(hand)
hand.update_icon()
+ C.update_inv_gloves()
if(special) //non conventional limb attachment
- for(var/X in H.surgeries) //if we had an ongoing surgery to attach a new limb, we stop it.
+ for(var/X in C.surgeries) //if we had an ongoing surgery to attach a new limb, we stop it.
var/datum/surgery/S = X
var/surgery_zone = check_zone(S.location)
if(surgery_zone == body_zone)
- H.surgeries -= S
+ C.surgeries -= S
qdel(S)
break
update_bodypart_damage_state()
- H.updatehealth()
- H.update_body()
- H.update_hair()
- H.update_damage_overlays()
- H.update_canmove()
-/obj/item/bodypart/head/attach_limb(mob/living/carbon/human/H, special)
+ C.updatehealth()
+ C.update_body()
+ C.update_hair()
+ C.update_damage_overlays()
+ C.update_canmove()
+
+
+/obj/item/bodypart/head/attach_limb(mob/living/carbon/C, special)
//Transfer some head appearance vars over
if(brain)
brainmob.container = null //Reset brainmob head var.
brainmob.loc = brain //Throw mob into brain.
brain.brainmob = brainmob //Set the brain to use the brainmob
brainmob = null //Set head brainmob var to null
- brain.Insert(H) //Now insert the brain proper
+ brain.Insert(C) //Now insert the brain proper
brain = null //No more brain in the head
- H.hair_color = hair_color
- H.hair_style = hair_style
- H.facial_hair_color = facial_hair_color
- H.facial_hair_style = facial_hair_style
- H.eye_color = eye_color
- H.lip_style = lip_style
- H.lip_color = lip_color
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ H.hair_color = hair_color
+ H.hair_style = hair_style
+ H.facial_hair_color = facial_hair_color
+ H.facial_hair_style = facial_hair_style
+ H.eye_color = eye_color
+ H.lip_style = lip_style
+ H.lip_color = lip_color
if(real_name)
- H.real_name = real_name
+ C.real_name = real_name
real_name = ""
name = initial(name)
..()
@@ -288,21 +301,22 @@
/mob/living/proc/regenerate_limbs(noheal, excluded_limbs)
return 0
-/mob/living/carbon/human/regenerate_limbs(noheal, list/excluded_limbs)
+/mob/living/carbon/regenerate_limbs(noheal, list/excluded_limbs)
var/list/limb_list = list("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg")
if(excluded_limbs)
limb_list -= excluded_limbs
for(var/Z in limb_list)
. += regenerate_limb(Z, noheal)
+/
/mob/living/proc/regenerate_limb(limb_zone, noheal)
return
-/mob/living/carbon/human/regenerate_limb(limb_zone, noheal)
+/mob/living/carbon/regenerate_limb(limb_zone, noheal)
var/obj/item/bodypart/L
if(get_bodypart(limb_zone))
return 0
- L = newBodyPart(limb_zone, 0, 0, src)
+ L = newBodyPart(limb_zone, 0, 0)
if(L)
if(!noheal)
L.brute_dam = 0
diff --git a/code/modules/surgery/bodyparts/head.dm b/code/modules/surgery/bodyparts/head.dm
index 16c742fc6fd..c3d86b5d4a2 100644
--- a/code/modules/surgery/bodyparts/head.dm
+++ b/code/modules/surgery/bodyparts/head.dm
@@ -1,6 +1,8 @@
/obj/item/bodypart/head
name = "head"
desc = "Didn't make sense not to live for fun, your brain gets smart but your head gets dumb."
+ icon = 'icons/mob/human_parts.dmi'
+ icon_state = "default_human_head"
max_damage = 200
body_zone = "head"
body_part = HEAD
@@ -10,7 +12,7 @@
px_x = 0
px_y = -8
- var/mob/living/carbon/brain/brainmob = null //The current occupant.
+ var/mob/living/brain/brainmob = null //The current occupant.
var/obj/item/organ/brain/brain = null //The brain organ
//Limb appearance info:
@@ -30,7 +32,8 @@
/obj/item/bodypart/head/drop_organs(mob/user)
var/turf/T = get_turf(src)
- playsound(T, 'sound/misc/splort.ogg', 50, 1, -1)
+ if(status != BODYPART_ROBOTIC)
+ playsound(T, 'sound/misc/splort.ogg', 50, 1, -1)
for(var/obj/item/I in src)
if(I == brain)
if(user)
@@ -46,67 +49,77 @@
else
I.loc = T
-/obj/item/bodypart/head/update_limb(dropping_limb, mob/living/carbon/human/source)
- var/mob/living/carbon/human/H
+/obj/item/bodypart/head/update_limb(dropping_limb, mob/living/carbon/source)
+ var/mob/living/carbon/C
if(source)
- H = source
+ C = source
else
- H = owner
- if(!istype(H))
- return
- var/datum/species/S = H.dna.species
- //First of all, name.
- real_name = H.real_name
+ C = owner
- //Facial hair
- if(H.facial_hair_style && (FACEHAIR in S.specflags))
- facial_hair_style = H.facial_hair_style
- if(S.hair_color)
- if(S.hair_color == "mutcolor")
- facial_hair_color = H.dna.features["mcolor"]
- else
- facial_hair_color = S.hair_color
- else
- facial_hair_color = H.facial_hair_color
- hair_alpha = S.hair_alpha
- else
- facial_hair_style = "Shaved"
- facial_hair_color = "000"
- hair_alpha = 255
- //Hair
- if(H.hair_style && (HAIR in S.specflags))
- hair_style = H.hair_style
- if(S.hair_color)
- if(S.hair_color == "mutcolor")
- hair_color = H.dna.features["mcolor"]
- else
- hair_color = S.hair_color
- else
- hair_color = H.hair_color
- hair_alpha = S.hair_alpha
- else
+ real_name = C.real_name
+ if(C.disabilities & HUSK)
+ real_name = "Unknown"
hair_style = "Bald"
- hair_color = "000"
- hair_alpha = initial(hair_alpha)
- // lipstick
- if(H.lip_style && (LIPS in S.specflags))
- lip_style = H.lip_style
- lip_color = H.lip_color
- else
- lip_style = null
- lip_color = "white"
- // eyes
- if(EYECOLOR in S.specflags)
- eyes = S.eyes
- eye_color = H.eye_color
- else
+ facial_hair_style = "Shaved"
eyes = "eyes"
eye_color = ""
+ lip_style = null
+
+ else if(!animal_origin)
+ var/mob/living/carbon/human/H = C
+ var/datum/species/S = H.dna.species
+
+ //Facial hair
+ if(H.facial_hair_style && (FACEHAIR in S.specflags))
+ facial_hair_style = H.facial_hair_style
+ if(S.hair_color)
+ if(S.hair_color == "mutcolor")
+ facial_hair_color = H.dna.features["mcolor"]
+ else
+ facial_hair_color = S.hair_color
+ else
+ facial_hair_color = H.facial_hair_color
+ hair_alpha = S.hair_alpha
+ else
+ facial_hair_style = "Shaved"
+ facial_hair_color = "000"
+ hair_alpha = 255
+ //Hair
+ if(H.hair_style && (HAIR in S.specflags))
+ hair_style = H.hair_style
+ if(S.hair_color)
+ if(S.hair_color == "mutcolor")
+ hair_color = H.dna.features["mcolor"]
+ else
+ hair_color = S.hair_color
+ else
+ hair_color = H.hair_color
+ hair_alpha = S.hair_alpha
+ else
+ hair_style = "Bald"
+ hair_color = "000"
+ hair_alpha = initial(hair_alpha)
+ // lipstick
+ if(H.lip_style && (LIPS in S.specflags))
+ lip_style = H.lip_style
+ lip_color = H.lip_color
+ else
+ lip_style = null
+ lip_color = "white"
+ // eyes
+ if(EYECOLOR in S.specflags)
+ eyes = S.eyes
+ eye_color = H.eye_color
+ else
+ eyes = "eyes"
+ eye_color = ""
+
..()
/obj/item/bodypart/head/update_icon_dropped()
var/list/standing = get_limb_icon(1)
- if(!standing)
+ if(!standing.len)
+ icon_state = initial(icon_state)//no overlays found, we default back to initial icon.
return
for(var/image/I in standing)
I.pixel_x = px_x
@@ -115,13 +128,11 @@
/obj/item/bodypart/head/get_limb_icon(dropped)
cut_overlays()
- var/image/I = ..()
- var/list/standing = list()
- standing += I
+ var/list/standing = ..()
if(dropped) //certain overlays only appear when the limb is being detached from its owner.
var/datum/sprite_accessory/S
- if(status != ORGAN_ROBOTIC) //having a robotic head hides certain features.
+ if(status != BODYPART_ROBOTIC) //having a robotic head hides certain features.
//facial hair
if(facial_hair_style)
S = facial_hair_styles_list[facial_hair_style]
@@ -133,7 +144,12 @@
//Applies the debrained overlay if there is no brain
if(!brain)
- standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER, "dir"=SOUTH)
+ if(animal_origin == ALIEN_BODYPART)
+ standing += image("icon"='icons/mob/animal_parts.dmi', "icon_state" = "debrained_alien_s", "layer" = -HAIR_LAYER, "dir"=SOUTH)
+ else if(animal_origin == LARVA_BODYPART)
+ standing += image("icon"='icons/mob/animal_parts.dmi', "icon_state" = "debrained_larva_s", "layer" = -HAIR_LAYER, "dir"=SOUTH)
+ else if(!(NOBLOOD in species_flags_list))
+ standing += image("icon"='icons/mob/human_face.dmi', "icon_state" = "debrained_s", "layer" = -HAIR_LAYER, "dir"=SOUTH)
else
if(hair_style)
S = hair_styles_list[hair_style]
@@ -156,9 +172,36 @@
img_eyes_s.color = "#" + eye_color
standing += img_eyes_s
- if(standing.len)
- return standing
+ return standing
/obj/item/bodypart/head/burn()
drop_organs()
..()
+
+/obj/item/bodypart/head/monkey
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "default_monkey_head"
+ animal_origin = MONKEY_BODYPART
+
+/obj/item/bodypart/head/alien
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "alien_head_s"
+ px_x = 0
+ px_y = 0
+ dismemberable = 0
+ max_damage = 500
+ animal_origin = ALIEN_BODYPART
+
+/obj/item/bodypart/head/devil
+ dismemberable = 0
+ max_damage = 5000
+ animal_origin = DEVIL_BODYPART
+
+/obj/item/bodypart/head/larva
+ icon = 'icons/mob/animal_parts.dmi'
+ icon_state = "larva_head_s"
+ px_x = 0
+ px_y = 0
+ dismemberable = 0
+ max_damage = 50
+ animal_origin = LARVA_BODYPART
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index 4ceec195c09..9f2c6ac37c1 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -10,47 +10,48 @@
if(L.body_zone == zone)
return L
-/mob/living/carbon/human/has_hand_for_held_index(i)
+/mob/living/carbon/has_hand_for_held_index(i)
if(i)
var/obj/item/bodypart/L = hand_bodyparts[i]
if(L)
return L
return FALSE
+
+
+
/mob/proc/has_left_hand()
return TRUE
-/mob/living/carbon/human/has_left_hand()
+/mob/living/carbon/has_left_hand()
+ for(var/obj/item/bodypart/L in hand_bodyparts)
+ if(L.held_index % 2)
+ return TRUE
+ return FALSE
+
+/mob/living/carbon/alien/larva/has_left_hand()
+ return 1
+
+
+/mob/proc/has_right_hand()
+ return TRUE
+
+/mob/living/carbon/has_right_hand()
for(var/obj/item/bodypart/L in hand_bodyparts)
if(!(L.held_index % 2))
return TRUE
return FALSE
-/mob/proc/has_right_hand()
- return TRUE
+/mob/living/carbon/alien/larva/has_right_hand()
+ return 1
-/mob/living/carbon/human/has_right_hand()
- for(var/obj/item/bodypart/L in hand_bodyparts)
- if(L.held_index % 2)
- return TRUE
- return FALSE
//Limb numbers
/mob/proc/get_num_arms()
return 2
-/mob/proc/get_num_legs()
- return 2
-
-/mob/proc/get_leg_ignore()
- return 0
-
-/mob/living/carbon/human/get_leg_ignore()
- if(FLYING in dna.species.specflags)
- return 1
-
-/mob/living/carbon/human/get_num_arms()
+/mob/living/carbon/get_num_arms()
. = 0
for(var/X in bodyparts)
var/obj/item/bodypart/affecting = X
@@ -59,7 +60,19 @@
if(affecting.body_part == ARM_LEFT)
.++
-/mob/living/carbon/human/get_num_legs()
+
+//sometimes we want to ignore that we don't have the required amount of arms.
+/mob/proc/get_arm_ignore()
+ return 0
+
+/mob/living/carbon/alien/larva/get_arm_ignore()
+ return 1 //so we can still handcuff larvas.
+
+
+/mob/proc/get_num_legs()
+ return 2
+
+/mob/living/carbon/get_num_legs()
. = 0
for(var/X in bodyparts)
var/obj/item/bodypart/affecting = X
@@ -68,19 +81,36 @@
if(affecting.body_part == LEG_LEFT)
.++
+//sometimes we want to ignore that we don't have the required amount of legs.
+/mob/proc/get_leg_ignore()
+ return 0
+
+/mob/living/carbon/alien/larva/get_leg_ignore()
+ return 1
+
+/mob/living/carbon/human/get_leg_ignore()
+ if(FLYING in dna.species.specflags)
+ return 1
+
/mob/living/proc/get_missing_limbs()
return list()
-/mob/living/carbon/human/get_missing_limbs()
+/mob/living/carbon/get_missing_limbs()
var/list/full = list("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg")
for(var/zone in full)
if(get_bodypart(zone))
full -= zone
return full
+/mob/living/carbon/alien/larva/get_missing_limbs()
+ var/list/full = list("head", "chest")
+ for(var/zone in full)
+ if(get_bodypart(zone))
+ full -= zone
+ return full
-//Remove all embedded objects from all limbs on the human mob
-/mob/living/carbon/human/proc/remove_all_embedded_objects()
+//Remove all embedded objects from all limbs on the carbon mob
+/mob/living/carbon/proc/remove_all_embedded_objects()
var/turf/T = get_turf(src)
for(var/X in bodyparts)
@@ -91,7 +121,7 @@
clear_alert("embeddedobject")
-/mob/living/carbon/human/proc/has_embedded_objects()
+/mob/living/carbon/proc/has_embedded_objects()
. = 0
for(var/X in bodyparts)
var/obj/item/bodypart/L = X
@@ -100,7 +130,7 @@
//Helper for quickly creating a new limb - used by augment code in species.dm spec_attacked_by
-/proc/newBodyPart(zone, robotic, fixed_icon, mob/living/carbon/human/source)
+/mob/living/carbon/proc/newBodyPart(zone, robotic, fixed_icon)
var/obj/item/bodypart/L
switch(zone)
if("l_arm")
@@ -116,13 +146,64 @@
if("chest")
L = new /obj/item/bodypart/chest()
if(L)
- if(source)
- L.update_limb(fixed_icon, source)
- else if(fixed_icon)
- L.no_update = 1//when attached, the limb won't be affected by the appearance changes of its mob owner.
+ L.update_limb(fixed_icon, src)
if(robotic)
- L.change_bodypart_status(ORGAN_ROBOTIC)
+ L.change_bodypart_status(BODYPART_ROBOTIC)
+ . = L
+/mob/living/carbon/monkey/newBodyPart(zone, robotic, fixed_icon)
+ var/obj/item/bodypart/L
+ switch(zone)
+ if("l_arm")
+ L = new /obj/item/bodypart/l_arm/monkey()
+ if("r_arm")
+ L = new /obj/item/bodypart/r_arm/monkey()
+ if("head")
+ L = new /obj/item/bodypart/head/monkey()
+ if("l_leg")
+ L = new /obj/item/bodypart/l_leg/monkey()
+ if("r_leg")
+ L = new /obj/item/bodypart/r_leg/monkey()
+ if("chest")
+ L = new /obj/item/bodypart/chest/monkey()
+ if(L)
+ L.update_limb(fixed_icon, src)
+ if(robotic)
+ L.change_bodypart_status(BODYPART_ROBOTIC)
+ . = L
+
+/mob/living/carbon/alien/larva/newBodyPart(zone, robotic, fixed_icon)
+ var/obj/item/bodypart/L
+ switch(zone)
+ if("head")
+ L = new /obj/item/bodypart/head/larva()
+ if("chest")
+ L = new /obj/item/bodypart/chest/larva()
+ if(L)
+ L.update_limb(fixed_icon, src)
+ if(robotic)
+ L.change_bodypart_status(BODYPART_ROBOTIC)
+ . = L
+
+/mob/living/carbon/alien/humanoid/newBodyPart(zone, robotic, fixed_icon)
+ var/obj/item/bodypart/L
+ switch(zone)
+ if("l_arm")
+ L = new /obj/item/bodypart/l_arm/alien()
+ if("r_arm")
+ L = new /obj/item/bodypart/r_arm/alien()
+ if("head")
+ L = new /obj/item/bodypart/head/alien()
+ if("l_leg")
+ L = new /obj/item/bodypart/l_leg/alien()
+ if("r_leg")
+ L = new /obj/item/bodypart/r_leg/alien()
+ if("chest")
+ L = new /obj/item/bodypart/chest/alien()
+ if(L)
+ L.update_limb(fixed_icon, src)
+ if(robotic)
+ L.change_bodypart_status(BODYPART_ROBOTIC)
. = L
diff --git a/code/modules/surgery/bodyparts/robot_bodyparts.dm b/code/modules/surgery/bodyparts/robot_bodyparts.dm
new file mode 100644
index 00000000000..a5cefa1a0a7
--- /dev/null
+++ b/code/modules/surgery/bodyparts/robot_bodyparts.dm
@@ -0,0 +1,162 @@
+
+
+/obj/item/bodypart/l_arm/robot
+ name = "cyborg left arm"
+ desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case."
+ attack_verb = list("slapped", "punched")
+ item_state = "buildpipe"
+ icon = 'icons/obj/robot_parts.dmi'
+ flags = CONDUCT
+ icon_state = "l_arm"
+ status = BODYPART_ROBOTIC
+
+
+/obj/item/bodypart/r_arm/robot
+ name = "cyborg right arm"
+ desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case."
+ attack_verb = list("slapped", "punched")
+ item_state = "buildpipe"
+ icon = 'icons/obj/robot_parts.dmi'
+ flags = CONDUCT
+ icon_state = "r_arm"
+ status = BODYPART_ROBOTIC
+
+
+/obj/item/bodypart/l_leg/robot
+ name = "cyborg left leg"
+ desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case."
+ attack_verb = list("kicked", "stomped")
+ item_state = "buildpipe"
+ icon = 'icons/obj/robot_parts.dmi'
+ flags = CONDUCT
+ icon_state = "l_leg"
+ status = BODYPART_ROBOTIC
+
+
+/obj/item/bodypart/r_leg/robot
+ name = "cyborg right leg"
+ desc = "A skeletal limb wrapped in pseudomuscles, with a low-conductivity case."
+ attack_verb = list("kicked", "stomped")
+ item_state = "buildpipe"
+ icon = 'icons/obj/robot_parts.dmi'
+ flags = CONDUCT
+ icon_state = "r_leg"
+ status = BODYPART_ROBOTIC
+
+
+/obj/item/bodypart/chest/robot
+ name = "cyborg torso"
+ desc = "A heavily reinforced case containing cyborg logic boards, with space for a standard power cell."
+ item_state = "buildpipe"
+ icon = 'icons/obj/robot_parts.dmi'
+ flags = CONDUCT
+ icon_state = "chest"
+ status = BODYPART_ROBOTIC
+ var/wired = 0
+ var/obj/item/weapon/stock_parts/cell/cell = null
+
+/obj/item/bodypart/chest/robot/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/weapon/stock_parts/cell))
+ if(src.cell)
+ user << "You have already inserted a cell!"
+ return
+ else
+ if(!user.unEquip(W))
+ return
+ W.loc = src
+ src.cell = W
+ user << "You insert the cell."
+ else if(istype(W, /obj/item/stack/cable_coil))
+ if(src.wired)
+ user << "You have already inserted wire!"
+ return
+ var/obj/item/stack/cable_coil/coil = W
+ if (coil.use(1))
+ src.wired = 1
+ user << "You insert the wire."
+ else
+ user << "You need one length of coil to wire it!"
+ else
+ return ..()
+
+/obj/item/bodypart/chest/robot/Destroy()
+ if(cell)
+ qdel(cell)
+ cell = null
+ return ..()
+
+
+/obj/item/bodypart/chest/robot/drop_organs(mob/user)
+ if(wired)
+ new /obj/item/stack/cable_coil(user.loc, 1)
+ if(cell)
+ cell.forceMove(user.loc)
+ cell = null
+ ..()
+
+
+/obj/item/bodypart/head/robot
+ name = "cyborg head"
+ desc = "A standard reinforced braincase, with spine-plugged neural socket and sensor gimbals."
+ item_state = "buildpipe"
+ icon = 'icons/obj/robot_parts.dmi'
+ flags = CONDUCT
+ icon_state = "head"
+ status = BODYPART_ROBOTIC
+ var/obj/item/device/assembly/flash/handheld/flash1 = null
+ var/obj/item/device/assembly/flash/handheld/flash2 = null
+
+
+
+/obj/item/bodypart/head/robot/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/device/assembly/flash/handheld))
+ var/obj/item/device/assembly/flash/handheld/F = W
+ if(src.flash1 && src.flash2)
+ user << "You have already inserted the eyes!"
+ return
+ else if(F.crit_fail)
+ user << "You can't use a broken flash!"
+ return
+ else
+ if(!user.unEquip(W))
+ return
+ F.loc = src
+ if(src.flash1)
+ src.flash2 = F
+ else
+ src.flash1 = F
+ user << "You insert the flash into the eye socket."
+ else if(istype(W, /obj/item/weapon/crowbar))
+ if(flash1 || flash2)
+ playsound(src.loc, 'sound/items/Crowbar.ogg', 50, 1)
+ user << "You remove the flash from [src]."
+ if(flash1)
+ flash1.forceMove(user.loc)
+ flash1 = null
+ if(flash2)
+ flash2.forceMove(user.loc)
+ flash2 = null
+ else
+ user << "There are no flash to remove from [src]."
+
+ else
+ return ..()
+
+/obj/item/bodypart/head/robot/Destroy()
+ if(flash1)
+ qdel(flash1)
+ flash1 = null
+ if(flash2)
+ qdel(flash2)
+ flash2 = null
+ return ..()
+
+
+/obj/item/bodypart/head/robot/drop_organs(mob/user)
+ if(flash1)
+ flash1.forceMove(user.loc)
+ flash1 = null
+ if(flash2)
+ flash2.forceMove(user.loc)
+ flash2 = null
+ ..()
diff --git a/code/modules/surgery/generic_steps.dm b/code/modules/surgery/generic_steps.dm
index ee324e432b4..89b070f28cc 100644
--- a/code/modules/surgery/generic_steps.dm
+++ b/code/modules/surgery/generic_steps.dm
@@ -21,7 +21,7 @@
/datum/surgery_step/clamp_bleeders/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(locate(/datum/surgery_step/saw) in surgery.steps)
- target.heal_organ_damage(20,0)
+ target.heal_bodypart_damage(20,0)
return ..()
@@ -69,7 +69,7 @@
/datum/surgery_step/close/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(locate(/datum/surgery_step/saw) in surgery.steps)
- target.heal_organ_damage(45,0)
+ target.heal_bodypart_damage(45,0)
return ..()
@@ -84,9 +84,7 @@
user.visible_message("[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].", "You begin to saw through the bone in [target]'s [parse_zone(target_zone)]...")
/datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- if(ishuman(target))
- var/mob/living/carbon/human/H = target
- H.apply_damage(50,"brute","[target_zone]")
+ target.apply_damage(50,"brute","[target_zone]")
user.visible_message("[user] saws [target]'s [parse_zone(target_zone)] open!", "You saw [target]'s [parse_zone(target_zone)] open.")
return 1
diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm
index 982ef0d4d40..32b294a7999 100644
--- a/code/modules/surgery/helpers.dm
+++ b/code/modules/surgery/helpers.dm
@@ -2,13 +2,13 @@
if(!istype(M))
return
- var/mob/living/carbon/human/H
+ var/mob/living/carbon/C
var/obj/item/bodypart/affecting
var/selected_zone = user.zone_selected
- if(istype(M, /mob/living/carbon/human))
- H = M
- affecting = H.get_bodypart(check_zone(selected_zone))
+ if(istype(M, /mob/living/carbon))
+ C = M
+ affecting = C.get_bodypart(check_zone(selected_zone))
if(!M.lying && !isslime(M)) //if they're prone or a slime
return
@@ -29,9 +29,9 @@
if(affecting)
if(!S.requires_bodypart)
continue
- if(S.requires_organic_bodypart && affecting.status == ORGAN_ROBOTIC)
+ if(S.requires_organic_bodypart && affecting.status == BODYPART_ROBOTIC)
continue
- else if(H && S.requires_bodypart) //human with no limb in surgery zone when we need a limb
+ else if(C && S.requires_bodypart) //mob with no limb in surgery zone when we need a limb
continue
if(!S.can_start(user, M))
continue
@@ -49,14 +49,14 @@
return //during the input() another surgery was started at the same location.
//we check that the surgery is still doable after the input() wait.
- if(H)
- affecting = H.get_bodypart(check_zone(selected_zone))
+ if(C)
+ affecting = C.get_bodypart(check_zone(selected_zone))
if(affecting)
if(!S.requires_bodypart)
return
- if(S.requires_organic_bodypart && affecting.status == ORGAN_ROBOTIC)
+ if(S.requires_organic_bodypart && affecting.status == BODYPART_ROBOTIC)
return
- else if(H && S.requires_bodypart)
+ else if(C && S.requires_bodypart)
return
if(!S.can_start(user, M))
return
diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm
index 3a00620a172..5e16b420f21 100644
--- a/code/modules/surgery/limb_augmentation.dm
+++ b/code/modules/surgery/limb_augmentation.dm
@@ -16,17 +16,17 @@
/datum/surgery_step/add_limb
name = "replace limb"
- implements = list(/obj/item/robot_parts = 100)
+ implements = list(/obj/item/bodypart = 100)
time = 32
var/obj/item/bodypart/L = null // L because "limb"
/datum/surgery_step/add_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- var/obj/item/robot_parts/aug = tool
- if(istype(aug) && aug.body_zone != target_zone)
+ var/obj/item/bodypart/aug = tool
+ if(aug.status != BODYPART_ROBOTIC && aug.body_zone != target_zone)
user << "[tool] isn't the right type for [parse_zone(target_zone)]."
return -1
- L = surgery.organ
+ L = surgery.operated_bodypart
if(L)
user.visible_message("[user] begins to augment [target]'s [parse_zone(user.zone_selected)].", "You begin to augment [target]'s [parse_zone(user.zone_selected)]...")
else
@@ -45,15 +45,13 @@
/datum/surgery_step/add_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(L)
- if(ishuman(target))
- var/mob/living/carbon/human/H = target
- user.visible_message("[user] successfully augments [target]'s [parse_zone(target_zone)]!", "You successfully augment [target]'s [parse_zone(target_zone)].")
- L.change_bodypart_status(ORGAN_ROBOTIC, 1)
- user.drop_item()
- qdel(tool)
- H.update_damage_overlays(0)
- H.updatehealth()
- add_logs(user, target, "augmented", addition="by giving him new [parse_zone(target_zone)] INTENT: [uppertext(user.a_intent)]")
+ user.visible_message("[user] successfully augments [target]'s [parse_zone(target_zone)]!", "You successfully augment [target]'s [parse_zone(target_zone)].")
+ L.change_bodypart_status(BODYPART_ROBOTIC, 1)
+ user.drop_item()
+ qdel(tool)
+ target.update_damage_overlays()
+ target.updatehealth()
+ add_logs(user, target, "augmented", addition="by giving him new [parse_zone(target_zone)] INTENT: [uppertext(user.a_intent)]")
else
user << "[target] has no organic [parse_zone(target_zone)] there!"
return 1
diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm
index 76220ef9ddc..9cfed984f4c 100644
--- a/code/modules/surgery/organs/augments_arms.dm
+++ b/code/modules/surgery/organs/augments_arms.dm
@@ -68,6 +68,10 @@
"[holder] snaps back into your [zone == "r_arm" ? "right" : "left"] arm.",
"You hear a short mechanical noise.")
+ if(istype(holder, /obj/item/device/assembly/flash/armimplant))
+ var/obj/item/device/assembly/flash/F = holder
+ F.SetLuminosity(0)
+
owner.unEquip(holder, 1)
holder.loc = src
holder = null
@@ -85,6 +89,10 @@
holder.w_class = 5
holder.materials = null
+ if(istype(holder, /obj/item/device/assembly/flash/armimplant))
+ var/obj/item/device/assembly/flash/F = holder
+ F.SetLuminosity(7)
+
var/obj/item/arm_item = owner.get_active_held_item()
if(arm_item)
@@ -178,3 +186,45 @@
items_list += new /obj/item/weapon/kitchen/knife/combat/cyborg(src)
return 1
return 0
+
+/obj/item/organ/cyberimp/arm/esword
+ name = "arm-mounted energy blade"
+ desc = "An illegal, and highly dangerous cybernetic implant that can project a deadly blade of concentrated enregy."
+ contents = newlist(/obj/item/weapon/melee/energy/blade)
+
+/obj/item/organ/cyberimp/arm/medibeam
+ name = "integrated medical beamgun"
+ desc = "A cybernetic implant that allows the user to project a healing beam from their hand."
+ contents = newlist(/obj/item/weapon/gun/medbeam)
+
+/obj/item/organ/cyberimp/arm/flash
+ name = "integrated high-intensity photon projector" //Why not
+ desc = "An integrated projector mounted onto a user's arm, that is able to be used as a powerful flash."
+ contents = newlist(/obj/item/device/assembly/flash/armimplant)
+
+/obj/item/organ/cyberimp/arm/flash/New()
+ ..()
+ if(locate(/obj/item/device/assembly/flash/armimplant) in items_list)
+ var/obj/item/device/assembly/flash/armimplant/F = locate(/obj/item/device/assembly/flash/armimplant) in items_list
+ F.I = src
+
+/obj/item/organ/cyberimp/arm/baton
+ name = "arm electrification implant"
+ desc = "An illegal combat implant that allows the user to administer disabling shocks from their arm."
+ contents = newlist(/obj/item/borg/stun)
+
+/obj/item/organ/cyberimp/arm/combat
+ name = "combat cybernetics implant"
+ desc = "A powerful cybernetic implant that contains combat modules built into the user's arm"
+ contents = newlist(/obj/item/weapon/melee/energy/blade, /obj/item/weapon/gun/medbeam, /obj/item/borg/stun, /obj/item/device/assembly/flash/armimplant)
+
+/obj/item/organ/cyberimp/arm/combat/New()
+ ..()
+ if(locate(/obj/item/device/assembly/flash/armimplant) in items_list)
+ var/obj/item/device/assembly/flash/armimplant/F = locate(/obj/item/device/assembly/flash/armimplant) in items_list
+ F.I = src
+
+/obj/item/organ/cyberimp/arm/surgery
+ name = "surgical toolset implant"
+ desc = "A set of surgical tools hidden behind a concealed panel on the user's arm"
+ contents = newlist(/obj/item/weapon/retractor, /obj/item/weapon/hemostat, /obj/item/weapon/cautery, /obj/item/weapon/surgicaldrill, /obj/item/weapon/scalpel, /obj/item/weapon/circular_saw, /obj/item/weapon/surgical_drapes)
diff --git a/code/modules/surgery/organs/augments_chest.dm b/code/modules/surgery/organs/augments_chest.dm
index b977b039dff..5121e955a1b 100644
--- a/code/modules/surgery/organs/augments_chest.dm
+++ b/code/modules/surgery/organs/augments_chest.dm
@@ -197,3 +197,4 @@
toggle(silent=1)
return 0
+
diff --git a/code/modules/surgery/organs/augments_eyes.dm b/code/modules/surgery/organs/augments_eyes.dm
index 50c3875f258..eef8bf6dfd3 100644
--- a/code/modules/surgery/organs/augments_eyes.dm
+++ b/code/modules/surgery/organs/augments_eyes.dm
@@ -43,7 +43,7 @@
if(prob(10 * severity))
return
owner << "Static obfuscates your vision!"
- owner.flash_eyes(visual = 1)
+ owner.flash_act(visual = 1)
/obj/item/organ/cyberimp/eyes/xray
name = "X-ray implant"
diff --git a/code/modules/surgery/organs/helpers.dm b/code/modules/surgery/organs/helpers.dm
index f1ee5ec13f6..48915fd59bd 100644
--- a/code/modules/surgery/organs/helpers.dm
+++ b/code/modules/surgery/organs/helpers.dm
@@ -11,7 +11,7 @@ mob/proc/getorganslot(slot)
mob/living/carbon/getorgan(typepath)
return (locate(typepath) in internal_organs)
-mob/living/carbon/getorganszone(zone, var/subzones = 0)
+mob/living/carbon/getorganszone(zone, subzones = 0)
var/list/returnorg = list()
if(subzones)
// Include subzones - groin for chest, eyes and mouth for head
@@ -20,7 +20,8 @@ mob/living/carbon/getorganszone(zone, var/subzones = 0)
if(zone == "chest")
returnorg = getorganszone("groin")
- for(var/obj/item/organ/O in internal_organs)
+ for(var/X in internal_organs)
+ var/obj/item/organ/O = X
if(zone == O.zone)
returnorg += O
return returnorg
diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm
index 7a0c9fa6718..5341c2bf09d 100644
--- a/code/modules/surgery/prosthetic_replacement.dm
+++ b/code/modules/surgery/prosthetic_replacement.dm
@@ -1,52 +1,50 @@
/datum/surgery/prosthetic_replacement
name = "prosthetic replacement"
steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/add_prosthetic)
- species = list(/mob/living/carbon/human)
+ species = list(/mob/living/carbon/human, /mob/living/carbon/monkey)
possible_locs = list("r_arm", "l_arm", "l_leg", "r_leg", "head")
requires_bodypart = FALSE //need a missing limb
/datum/surgery/prosthetic_replacement/can_start(mob/user, mob/living/carbon/target)
- if(!ishuman(target))
+ if(!iscarbon(target))
return 0
- var/mob/living/carbon/human/H = target
- if(!H.get_bodypart(user.zone_selected)) //can only start if limb is missing
+ var/mob/living/carbon/C = target
+ if(!C.get_bodypart(user.zone_selected)) //can only start if limb is missing
return 1
/datum/surgery_step/add_prosthetic
name = "add prosthetic"
- implements = list(/obj/item/robot_parts = 100, /obj/item/bodypart = 100)
+ implements = list(/obj/item/bodypart = 100)
time = 32
var/organ_rejection_dam = 0
/datum/surgery_step/add_prosthetic/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- var/tool_body_zone
- if(istype(tool, /obj/item/robot_parts))
- var/obj/item/robot_parts/RP = tool
- tool_body_zone = RP.body_zone
- else if(istype(tool, /obj/item/bodypart))
- var/obj/item/bodypart/L = tool
- if(L.status != ORGAN_ROBOTIC)
- organ_rejection_dam = 10
- if(target.dna.species.id != L.species_id)
+ var/obj/item/bodypart/BP = tool
+ if(ismonkey(target))// monkey patient only accept organic monkey limbs
+ if(BP.status == BODYPART_ROBOTIC || BP.animal_origin != MONKEY_BODYPART)
+ user << "[BP] doesn't match the patient's morphology."
+ return -1
+ if(BP.status != BODYPART_ROBOTIC)
+ organ_rejection_dam = 10
+ if(ishuman(target))
+ if(BP.animal_origin)
+ user << "[BP] doesn't match the patient's morphology."
+ return -1
+ var/mob/living/carbon/human/H = target
+ if(H.dna.species.id != BP.species_id)
organ_rejection_dam = 30
- tool_body_zone = L.body_zone
- if(target_zone == tool_body_zone) //so we can't replace a leg with an arm.
+
+ if(target_zone == BP.body_zone) //so we can't replace a leg with an arm, or a human arm with a monkey arm.
user.visible_message("[user] begins to replace [target]'s [parse_zone(target_zone)].", "You begin to replace [target]'s [parse_zone(target_zone)]...")
else
user << "[tool] isn't the right type for [parse_zone(target_zone)]."
return -1
/datum/surgery_step/add_prosthetic/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- var/obj/item/bodypart/L
- if(istype(tool, /obj/item/robot_parts))
- L = newBodyPart(target_zone, 1, 1)
- user.drop_item()
- qdel(tool)
- else
- L = tool
- user.drop_item()
+ var/obj/item/bodypart/L = tool
+ user.drop_item()
L.attach_limb(target)
if(organ_rejection_dam)
target.adjustToxLoss(organ_rejection_dam)
diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm
index 7117d276a76..fa9db1ae8ed 100644
--- a/code/modules/surgery/remove_embedded_object.dm
+++ b/code/modules/surgery/remove_embedded_object.dm
@@ -12,7 +12,7 @@
/datum/surgery_step/remove_object/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- L = surgery.organ
+ L = surgery.operated_bodypart
if(L)
user.visible_message("[user] looks for objects embedded in [target]'s [parse_zone(user.zone_selected)].", "You look for objects embedded in [target]'s [parse_zone(user.zone_selected)]...")
else
diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm
index 35b15432304..26e57700ae5 100644
--- a/code/modules/surgery/surgery.dm
+++ b/code/modules/surgery/surgery.dm
@@ -10,26 +10,26 @@
var/list/possible_locs = list() //Multiple locations
var/ignore_clothes = 0 //This surgery ignores clothes
var/mob/living/carbon/target //Operation target mob
- var/obj/item/organ/organ //Operable body part
+ var/obj/item/bodypart/operated_bodypart //Operable body part
var/requires_bodypart = TRUE //Surgery available only when a bodypart is present, or only when it is missing.
var/success_multiplier = 0 //Step success propability multiplier
-/datum/surgery/New(surgery_target, surgery_location, surgery_organ)
+/datum/surgery/New(surgery_target, surgery_location, surgery_bodypart)
..()
if(surgery_target)
target = surgery_target
target.surgeries += src
if(surgery_location)
location = surgery_location
- if(surgery_organ)
- organ = surgery_organ
+ if(surgery_bodypart)
+ operated_bodypart = surgery_bodypart
/datum/surgery/Destroy()
if(target)
target.surgeries -= src
target = null
- organ = null
+ operated_bodypart = null
return ..()
diff --git a/code/modules/vehicles/pimpin_ride.dm b/code/modules/vehicles/pimpin_ride.dm
index c1bfbc020ab..4e001cb1680 100644
--- a/code/modules/vehicles/pimpin_ride.dm
+++ b/code/modules/vehicles/pimpin_ride.dm
@@ -49,6 +49,7 @@
for(var/A in tile)
if(is_cleanable(A))
qdel(A)
+ . = ..()
/obj/vehicle/janicart/examine(mob/user)
diff --git a/code/modules/vehicles/scooter.dm b/code/modules/vehicles/scooter.dm
index 64223336da1..7e3cbf954ac 100644
--- a/code/modules/vehicles/scooter.dm
+++ b/code/modules/vehicles/scooter.dm
@@ -38,15 +38,18 @@
else
buckled_mob.pixel_y = -4
+/obj/vehicle/scooter/buckle_mob(mob/living/M, force = 0)
+ if(!istype(M))
+ return 0
+ if(M.get_num_legs() < 2 && M.get_num_arms() <= 0)
+ M << "Your limbless body can't use [src]."
+ return 0
+ . = ..()
+
/obj/vehicle/scooter/post_buckle_mob(mob/living/M)
vehicle_move_delay = initial(vehicle_move_delay)
- ..()
if(M.get_num_legs() < 2)
vehicle_move_delay ++
- if(M.get_num_arms() <= 0)
- if(has_buckled_mobs())//to prevent the message displaying twice due to unbuckling
- M << "Your limbless body flops off \the [src]."
- unbuckle_mob(M)
/obj/vehicle/scooter/skateboard
name = "skateboard"
diff --git a/code/modules/vehicles/vehicle.dm b/code/modules/vehicles/vehicle.dm
index ac8fdaa8b6b..f21275b6fce 100644
--- a/code/modules/vehicles/vehicle.dm
+++ b/code/modules/vehicles/vehicle.dm
@@ -94,12 +94,14 @@
/obj/vehicle/relaymove(mob/user, direction)
if(user.incapacitated())
unbuckle_mob(user)
+ return
+ if(world.time < next_vehicle_move)
+ return
+ next_vehicle_move = world.time + vehicle_move_delay
if(keycheck(user))
- if(!Process_Spacemove(direction) || world.time < next_vehicle_move || !isturf(loc))
+ if(!Process_Spacemove(direction) || !isturf(loc))
return
- next_vehicle_move = world.time + vehicle_move_delay
-
step(src, direction)
handle_vehicle_layer()
diff --git a/config/game_options.txt b/config/game_options.txt
index 9f7e778833d..6a4c773117c 100644
--- a/config/game_options.txt
+++ b/config/game_options.txt
@@ -355,3 +355,6 @@ BOMBCAP 20
# spawn, while the converse is true. Alter this number to affect the amount
# of ruins.
LAVALAND_BUDGET 60
+
+## Space Ruin Budged
+Space_Budget 16
diff --git a/config/tips.txt b/config/tips.txt
index 917443afefa..5af9a6d1938 100644
--- a/config/tips.txt
+++ b/config/tips.txt
@@ -120,7 +120,7 @@ As a Nuclear Operative, you should look into purchasing a syndicate cyborg, as t
As a Nuclear Operative, stick together! While your equipment is robust, your fellow operatives are much better at saving your life: they can drag you away from danger while stunned and provide cover fire.
As a Nuclear Operative, you might end up in a situation where the AI has bolted you into a room. Having some spare C4 in your pocket can save your life.
As a Monkey, you can crawl through air or scrubber vents by alt+left clicking them. You must drop everything you are wearing and holding to do this, however.
-As a Monkey, you can still wear a few human items, like backpacks and gas masks, and still have two free hands. Remember that you cannot use guns!
+As a Monkey, you can still wear a few human items, such as backpacks, gas masks and hats, and still have two free hands.
As a Malfunctioning AI, you can shunt to an APC if the situation gets bad. This can allow the clock to tick down long enough for you to win, but keep in mind the crew's pinpointer will point to you when you do this.
As a Malfunctioning AI, you should either order your cyborgs to dismantle the robotics console or blow it up yourself in order to protect them.
As a Malfunctioning AI, look into flooding the station with plasma fires to kill off large portions of the crew, letting you pick off the remaining few with space suits who escaped.
diff --git a/html/changelog.html b/html/changelog.html
index e5ee7fea60f..9cc8dc1941b 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -55,6 +55,199 @@
-->
+
21 September 2016
+
Cyberboss updated:
+
+
The food processor's sprite's maintenance panel is no longer open while closed and vice/versa
+
Tesla arcs no longer lose power when passing through a coil that isn't connected to a grid
+
+
MrStonedOne updated:
+
+
Fixes minimap generation crashes by making parts of it less precise
+
+
+
20 September 2016
+
Ergovisavi updated:
+
+
fixed "friendly" xenobio mobs and mining drones attacking station drones
+
+
Joan updated:
+
+
Miners can now buy KA AoE damage mods from the mining vendor for 2000 points per mod.
+
Combined the Convert and Sacrifice runes into one rune. It'll convert targets that are alive and eligible, and attempt to sacrifice them otherwise. The only changes to mechanics are that: Converting someone will heal them of all brute and burn damage they had, and sacrificing anything will always produce a soulstone(but will still only sometimes fill it)
+
You can no longer teleport to Teleport runes that have dense objects on top of them.
+
Wall runes will now activate other nearby wall runes when activated, but will automatically disable after a minute and a half of continuous activity and become unusable for 5 seconds.
+
The Blood Boil rune no longer does all of its damage instantly or stuns, but if you remain in range for the full duration you will be sent deep into critical.
+
Bubblegum has been seen reaching through blood. Try not to get hit.
+
The Raise Dead rune no longer requires a noncultist corpse to revive a cultist; instead, it will draw from the pool of all people sacrificed to power the rune.
+
+
Mekhi updated:
+
+
Nanotrasen has been experimenting on cybernetics for a while, and rumors are they have a few combat prototypes available...
+
New arm implants: Energy-blade projector, implanted medical beamgun, stun-arm implant (Like the borg version), flash implant that is automatically-regenerating and doubles as a powerful flashlight. There is also one with all four items in one. Also, a surgery toolkit implant. Adminspawn only for the moment.
+
+
MrStonedOne updated:
+
+
Fixed space/nograv movement not triggering when atoms moved twice quickly in space/nograv
+
+
Nanotrasen Stress Relief Board updated:
+
+
Latecomers to highlander can now join in on the fun.
+
The crew are encouraged to less pacifistic during highlander. Failing to shed blood will result in your soul being devoured. Have a nice day.
+
+
Nicho1010 updated:
+
+
Fixed lattices appearing after exploding lava
+
+
Screemonster updated:
+
+
Abandoned crates no longer accept impossible guesses.
+
Lets players know that all the digits in the code must be unique.
+
Reads the last guess back on the multitool along with the correct/incorrect guess readout.
+
multitool output on crates no longer returns nonsense values.
+
+
XDTM updated:
+
+
Positive viruses are now recognized by medical HUDs with a special icon.
+
fully_heal no longer removes nonharmful viruses. This affects legion souls, staffs of healing, and changeling's revive.
+
Canisters of any type of gas are now orderable in cargo. Dangerous experimental gases will require Research Director approval.
+
+
Yackemflam updated:
+
+
The syndicate has learned on how to give their agents a true syndicate ninja experience.
+
+
chickenboy10 updated:
+
+
Added a Experimental Limb Grower to the medbay department, now medical stuff can grow synthetic limbs using Synthflesh to help crew that suffer any work related accidents. There may also be a limb that can be grown with a special card...
+
+
feemjmeem updated:
+
+
You can now disassemble meatspike frames with a welding tool.
+
+
phil235 updated:
+
+
adds a talk button next to the crafting button. Clicking it makes a "wheel" appear around you with short predetermined messages that you click to say them. This lets you say common responses without having to type in the chat bar. Current messages available are: "Hi", "Bye", "Thanks", "Come", "Help", "Stop", "Get out", "Yes", and "No". The talk button can be activated with the hotkey "H" or "CTRL+H"
+
Wearing colored glasses colors your vision. This option can be enabled/disabled by alt-clicking any glasses with such feature.
+
+
+
17 September 2016
+
BoxcarRacer41 updated:
+
+
Added a new food, bacon. Bacon is made by processing raw meat cutlets.
+
Added a new burger recipe, the Bacon Burger. It is made with one bun, one cheese wedge and three pieces of cooked bacon.
+
+
Ergovisavi updated:
+
+
Added a nightvision toggle to Shadowpeople
+
Made several anomalous crystal variants more easily identified/easier to see the effects thereof, and removed the "magic" activation possibility (replaced with the "bomb" flag)
+
+
Gun Hog updated:
+
+
Nanotrasen Robotics Division is proud to announce slightly less clunky leg servo designs relating to the "Ripley" APLU and "Firefighter" exosuits. Tests show increased mobility in both high and low pressure environments. The previous designer has been fired for incompetence.
+
+
Improves tablets design updated:
+
+
Brings the tablet icons into the holy light of having depth
+
+
Joan updated:
+
+
Megafauna will now use ranged attacks even if they don't have direct vision on their target.
+
Volt Void and Interdiction Lenses will now drain mech cells of energy.
+
Ocular Wardens do slightly more damage to mechs.
+
Replicant, Soul Vessel, Cogscarab, and Anima Fragment now take an additional second to recite.
+
Anima Fragments do slightly less damage in melee.
+
Mending Motors and Clockwork Obelisks have slightly less health.
+
Invoking Nezbere now requires 3 invokers.
+
Clockwork armor no longer has 5% energy resistance.
+
You can no longer construct clockwork structures on space turfs.
+
+
Papa Bones updated:
+
+
BZ gas is no longer available on Box and Metastation layouts.
+
+
phil235 updated:
+
+
You no longer have to click a megaphone to use it, you simply keep it in your active hand and talk normally.
Upgraded sleepers can now inject inacusiate to treat ear damage.
+
+
Joan updated:
+
+
Added brass, producible by proselytizing rods, metal, or plasteel, or by using Replicant Alloy in-hand, and usable to construct a variety of cult-y brass objects.
+
Objects constructable with brass include; wall gears, pinion airlocks, brass windoors, brass windows, brass table frames and tables, and brass floor tiles.
+
Cogscarabs can convert brass sheets into liquified alloy with their proselytizer.
+
You can use brass sheets on wall gears to produce clockwork walls, or, if the gear is unanchored, false clockwork walls.
+
Fixed a bug preventing you from converting grilles into ratvar grilles.
+
Please note that conservation of mass exists.
+
+
Sligneris updated:
+
+
Captain's space armor has been readapted with modern hardsuit technology.
+
+
oranges updated:
+
+
Examine code for dismembered humans now has better easter eggs
+
+
+
12 September 2016
+
Joan updated:
+
+
Cult structures can once again be constructed with runed metal.
+
Cult structures can now take damage and be destroyed. Artificers can repair them if they're damaged.
+
The Recollection function of the clockwork slab is much more useful and easier to parse.
+
Tweaked the Recital menus for scripture so the scripture are all in the proper order. This might fuck you up if you were used to the incorrect order, but you'll get used to it.
+
+
Nanotrasen Anti-Cheese Committee updated:
+
+
A glitch in the hydroponics tray firmware allowed it to retain plant growth even after the plant was removed, resulting in the next planted seed being grown instantaneously. This is no longer possible.
+
+
PKPenguin321 updated:
+
+
Tesla shocks from grilles will no longer do thousands and thousands of damage. They now properly deal burn damage that is equal to the current power in the powernet divided by 5000.
+
+
Papa Bones updated:
+
+
You can now rename the captain's sabre by using a pen on it.
+
+
RemieRichards updated:
+
+
Added the functionality for mobs to have multiple hands, this might have broken some things, so please report any weirdness
+
+
Shadowlight213 updated:
+
+
The surplus crate and random item will now only contain items allowed by the gamemode
+
removes sleeping carp scroll from surplus crates
+
Minimaps will now try to load from a cache or backup file if minimap generation is disabled.
+
+
TheCarlSaganExpress updated:
+
+
Crayons, lipstick, cigarettes, and penlights can now be inserted into PDAs.
+
+
phil235 updated:
+
+
Monkeys can be dismembered.
+
Humans, monkeys and aliens can drop limbs when they are gibbed.
+
Roboticists can remove flashes, wires and power cells that they inserted in robot head or torso by using a crowbar on it.
+
visual wounds appear on a monkey's bodyparts when injured, exactly like humans.
+
Using a health analyzer on a monkey or alien shows the injuries to each bodypart.
+
Monkeys can become husks.
+
Human-monkey transformations now respect missing limbs. No more limb regrowth by becoming a monkey.
+
Changeling's regenerate ability also work while in monkey form.
+
Alien larva has its own gib and dust animation.
+
A bodypart that looks wounded still looks bloody when dismembered.
+
Amputation surgery now works on robotic limbs, and monkeys.
+
+
09 September 2016
Ergovisavi updated:
@@ -938,231 +1131,6 @@
Clockwork cultists may now have the "Escape" and "Silicon" objectives, requiring a certain amount of servants to escape on the shuttle and all silicons to be converted respectively.
Ocular wardens are now forced to target bibles rather than the people holding them.
-
-
19 July 2016
-
Joan updated:
-
-
Cogscarabs can no longer pass mobs and have slightly less health.
-
The Gateway to the Celestial Derelict can now take damage from bombs.
-
-
RemieRichards updated:
-
-
Added VR Sleepers that allow users to enter a virtual body in a virtual world (Currently not mapped in ;_;)
-
-
Xhuis updated:
-
-
Added communication intercept texts for gamemodes that were missing them.
-
Changed all intercept texts and improved grammar for a lot of key game code.
-
The shuttle can now leave while a celestial gateway exists.
-
If the shuttle docks at Central Command while a celestial gateway exists, Ratvar's servants will win a minor victory. His arrival will still award a major victory.
-
The celestial gateway can now take damage from explosions.
-
-
-
18 July 2016
-
CoreOverload updated:
-
-
Sterilizine now reduces probability of step failure if you apply it after starting surgery. Useful while operating in less-than-perfect conditions.
-
Potent alcohol can be used as replacement for sterilizine.
-
-
Joan updated:
-
-
The Vanguard scripture no longer prevents you from using slabs while active, but you cannot reactivate it if it is currently active.
-
It now only lasts 20 seconds, instead of 30.
-
When Vanguard deactivates, it now stuns for half the time of all stuns absorbed, instead of all of them.
-
Invoking Sevtug is less potent at long ranges, and slightly more potent if extremely close.
-
Invoking Sevtug now requires 3 invokers instead of 1.
-
The Clockwork Slab now has action buttons for rapidly invoking Guvax and Vanguard.
-
Belligerent is now chanted more often.
-
Taunting Tirade now weakens nearby nonservants, but is now only invoked once every 6 seconds(1 second chant, 5 second flee time) and is only chanted five times.
-
-
lordpidey updated:
-
-
Flyswatters are now included in beekeeping crates, they are great at killing insects and flies of all sizes.
-
-
-
16 July 2016
-
Gun Hog and WJohnston updated:
-
-
Aliens (Xenos) now have the ability to sense the direction and rough distance of their queen!
-
-
Iamgoofball updated:
-
-
Fixed the lag when opening the foodcrafting menu by splitting everything up into categories.
-
-
Joan updated:
-
-
Cogscarabs(and other nonhuman mobs able to hold clockwork slabs) can now check the stats of the clockwork cult by using a clockwork slab. They remain unable to use slabs under normal conditions.
-
-
MrStonedOne updated:
-
-
Added a system to detect when stickybans go rogue and revert all recent matches.
-
-
-
15 July 2016
-
Cheridan updated:
-
-
Added an aesthetic new space ruin
-
-
-
14 July 2016
-
Basilman updated:
-
-
Added a new hairstyle "Boddicker"
-
-
Bawhoppen updated:
-
-
Added two new materials, Titanium and plastitanium. Titanium is naturally occuring, and plastitanium is an alloy made of plasma and titanium.
-
These materials can be used to build shuttle walls and floors, though this serves no current purpose.
-
-
CoreOverload updated:
-
-
Some clothing has pockets now.
-
-
Firecage updated:
-
-
Mechas can no longer pass through Plastic Flaps
-
-
Fox McCloud updated:
-
-
Fixes borg stun arm not having a hitsound, bypassing shields, and not doing an attack animation
-
Fixes simple mobs not properly having armor penetration
-
-
Joan updated:
-
-
Added dextrous guardians to the code, able to hold and use items and store a single item within themselves.
-
Dextrous guardians do low damage on punches, have medium damage resist, and recalling or leashing will force them to drop any items in their hands.
-
-
Kor updated:
-
-
Shuttle travel time has been shortened from 25 seconds to 6 seconds
-
-
Lzimann updated:
-
-
Alt clicking a jumpsuit now removes the accessories(if there's any)!
-
-
Papa Bones updated:
-
-
Security's lethal injections are actually lethal now.
-
-
Xhuis updated:
-
-
Nanotrasen electricians have introduced a software update to all licensed pinpointers. The new pinpointers are more responsive and automatically switch modes based on the current crisis.
-
It should be noted that some of these pinpointers have been reported as missing from their distribution warehouse and are presumed to have been stolen. This is likely nothing to worry about.
-
-
lordpidey updated:
-
-
Infernal jaunt now has a cooldown, to prevent trying to jaunt while already jaunting. This should have no practical changes.
-
Infernal jaunt no longer occasionally leaves you permanently on fire.
-
Pitchforks no longer burn devils and soul-sellers, as intended.
-
-
-
12 July 2016
-
MMMiracles updated:
-
-
Hotel staff can now actually use their own lockers.
-
-
RemieRichards updated:
-
-
fixed Kor's plant disguises
-
fixed some issues with Alternate Appearances not being added/removed
-
-
hornygranny updated:
-
-
Attacks will no longer miss missing limbs
-
-
-
11 July 2016
-
Iamgoofball updated:
-
-
Fixes Nicotine's stun reduction
-
-
Joan updated:
-
-
The Function Call action that summons a Ratvarian Spear is no longer one-use; instead, it can be reused once every five minutes.
-
Clockwork Walls and Floors will appear as normal walls and plating to mesons, respectively.
-
-
coiax updated:
-
-
Syndicate bombs now use a more accurate timer.
-
Fixed a separate bug that caused bomb timers to take twice as long (ie. 60 seconds took 120 seconds)
-
The AI doomsday device timer is more accurate.
-
Fixes a bug where the doomsday device would take twice as long as it should.
-
-
optional name here updated:
-
-
The search function on security records consoles now works.
-
-
-
09 July 2016
-
CoreOverload updated:
-
-
You can remove jetpack from a hardsuit by using screwdriver on it.
-
-
Crazylemon updated:
-
-
The map loader no longer resets when reading another map mid-load
-
-
Goofball Sanders updated:
-
-
Added a new plant to the game to encourage the Chef to be a more relevant job, alongside a recipe for a food related to it. Throw a cannabis leaf on a table and check the recipes list to find it.
-
-
Gun Hog updated:
-
-
Malf (Traitor) AI's Fireproof Core ability has been removed, as it was entirely obsolete.
-
Nanotrasen is proud to announce that conveyor belts can now be fabricated at your station's autolathes!
-
-
Iamgoofball updated:
-
-
Fixes the Atheist's Fedora's throw damage.
-
-
Joan updated:
-
-
Tips for Clock Cult may now show up.
-
The global component cache can only be accessed by clockwork slabs if there is at least one Tinkerer's Cache active.
-
Ratvarian Spears are now sharp and can be used to cut off limbs or butcher mobs.
-
Clock Cult silicons get an action button to communicate with other servants.
-
Clockwork Slabs now produce a component every 1 minute, 30 seconds, from every 1 minute.
-
The slab production time gain from each servant above 5 has been increased from 20 seconds to 30 seconds, and the maximum production time has been increased from 5 minutes to 6 minutes.
-
You can now transfer components between two clockwork slabs by attacking one slab, or a person holding a slab, with the other; this will transfer the attacking slab's components into the target slab.
-
Application scripture now requires 100 CV, from 75, Revenant scripture now requires 200 CV, from 150, and Judgment scripture now requires 300 CV, from 250.
-
However, converted windows, windoors, airlocks, and grilles will all provide some CV.
-
-
Lzimann & Keekenox updated:
-
-
You can now craft a baseball bat with 5 sheets of wood!
-
-
MrStonedOne updated:
-
-
Atmos on planets is now more realistic. There is an unseen upper atmosphere that gas changes get carried away into, causing planet turfs to revert back to their original gas mixture.
-
This should massively improve atmos run speed as all of lavaland won't be processing the moment somebody opens a door anymore
-
-
MrStonedOne, coiax updated:
-
-
View Variables can expand on associated lists with type keys. Only 90s admins will truely understand.
-
-
RemieRichards updated:
-
-
Added a Compact mode to the crafting tgui
-
Modified the back end of the crafting tgui so that it has well let's just say "a lot less" calls to certain functions, should lag a little less but don't expect miracles (you'd have to wait till we get a new version of ractive for those!)
-
-
coiax updated:
-
-
Podpeople (and venus human traps) are now no longer damaged, poisoned or obstructed by space vines. Explosive vines still damage them, because there's an actual explosion.
-
During a meteor shower, observers can automatically orbit threatening meteors via an action button and watch them hit the station.
-
Added Major Space Dust event, which is a meteor shower containing only space dust.
-
Fixes bug where meteors wouldn't move when spawned.
-
Meteor Shower split into three different events, Normal, Threatening and Catastrophic. They all have the same crew messages, but admins can tell the difference.
-
Damage to a shuttle while it is moving will now correctly make transit space turfs, rather than non-moving space.
-
AIs get a notification when hacking an APC, which can be clicked to jump your camera to the APC's location. AIs also get notification sounds when a hack has completed or failed.
-
Nuclear bombs now use a more accurate timer system, the same as gang dominators and shuttles.
-
Nuclear bombs now have a TGUI interface.
-
Fleshmend no longer regrows lost limbs.
-
Added free Regenerate power to changelings, which regrows all external limbs and internal organs (including the tongue if you lost your head). It costs 10 chemicals to use.
-
Fleshmend now costs 20 chemicals, down from 25.
-
Changeling revive power name changed from Regenerate to Revive.
-
When a player uses a communication console to ask for the codes to the self destruct, for better or for worse, the admins can set them with a single click. Whether the admins a) click the button b) actually give the random person the codes, is another thing entirely.
-
Servants of Ratvar get an alert if they have no tinkerer's caches constructed. Because it's important that they should.
-
GoonStation 13 Development Team
diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml
index b38c0a146bf..07339eff261 100644
--- a/html/changelogs/.all_changelog.yml
+++ b/html/changelogs/.all_changelog.yml
@@ -7005,3 +7005,186 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
Shadowlight213:
- tweak: Radiation storm direct tox loss removed
- tweak: Radiation storms now cause a radiation alert to appear for the duration
+2016-09-12:
+ Joan:
+ - rscadd: Cult structures can once again be constructed with runed metal.
+ - experiment: Cult structures can now take damage and be destroyed. Artificers can
+ repair them if they're damaged.
+ - tweak: The Recollection function of the clockwork slab is much more useful and
+ easier to parse.
+ - wip: Tweaked the Recital menus for scripture so the scripture are all in the proper
+ order. This might fuck you up if you were used to the incorrect order, but you'll
+ get used to it.
+ Nanotrasen Anti-Cheese Committee:
+ - bugfix: A glitch in the hydroponics tray firmware allowed it to retain plant growth
+ even after the plant was removed, resulting in the next planted seed being grown
+ instantaneously. This is no longer possible.
+ PKPenguin321:
+ - bugfix: Tesla shocks from grilles will no longer do thousands and thousands of
+ damage. They now properly deal burn damage that is equal to the current power
+ in the powernet divided by 5000.
+ Papa Bones:
+ - tweak: You can now rename the captain's sabre by using a pen on it.
+ RemieRichards:
+ - rscadd: Added the functionality for mobs to have multiple hands, this might have
+ broken some things, so please report any weirdness
+ Shadowlight213:
+ - rscdel: The surplus crate and random item will now only contain items allowed
+ by the gamemode
+ - rscdel: removes sleeping carp scroll from surplus crates
+ - experiment: Minimaps will now try to load from a cache or backup file if minimap
+ generation is disabled.
+ TheCarlSaganExpress:
+ - rscadd: Crayons, lipstick, cigarettes, and penlights can now be inserted into
+ PDAs.
+ phil235:
+ - rscadd: Monkeys can be dismembered.
+ - rscadd: Humans, monkeys and aliens can drop limbs when they are gibbed.
+ - rscadd: Roboticists can remove flashes, wires and power cells that they inserted
+ in robot head or torso by using a crowbar on it.
+ - rscadd: visual wounds appear on a monkey's bodyparts when injured, exactly like
+ humans.
+ - rscadd: Using a health analyzer on a monkey or alien shows the injuries to each
+ bodypart.
+ - rscadd: Monkeys can become husks.
+ - bugfix: Human-monkey transformations now respect missing limbs. No more limb regrowth
+ by becoming a monkey.
+ - bugfix: Changeling's regenerate ability also work while in monkey form.
+ - bugfix: Alien larva has its own gib and dust animation.
+ - bugfix: A bodypart that looks wounded still looks bloody when dismembered.
+ - bugfix: Amputation surgery now works on robotic limbs, and monkeys.
+2016-09-14:
+ Ergovisavi:
+ - bugfix: Fixes lockers, bodybags, etc, giving you ash storm / radiation storm protection
+ Erwgd:
+ - rscadd: Upgraded sleepers can now inject inacusiate to treat ear damage.
+ Joan:
+ - rscadd: Added brass, producible by proselytizing rods, metal, or plasteel, or
+ by using Replicant Alloy in-hand, and usable to construct a variety of cult-y
+ brass objects.
+ - tweak: Objects constructable with brass include; wall gears, pinion airlocks,
+ brass windoors, brass windows, brass table frames and tables, and brass floor
+ tiles.
+ - rscadd: Cogscarabs can convert brass sheets into liquified alloy with their proselytizer.
+ - tweak: You can use brass sheets on wall gears to produce clockwork walls, or,
+ if the gear is unanchored, false clockwork walls.
+ - bugfix: Fixed a bug preventing you from converting grilles into ratvar grilles.
+ - experiment: Please note that conservation of mass exists.
+ Sligneris:
+ - tweak: Captain's space armor has been readapted with modern hardsuit technology.
+ oranges:
+ - tweak: Examine code for dismembered humans now has better easter eggs
+2016-09-17:
+ BoxcarRacer41:
+ - rscadd: Added a new food, bacon. Bacon is made by processing raw meat cutlets.
+ - rscadd: Added a new burger recipe, the Bacon Burger. It is made with one bun,
+ one cheese wedge and three pieces of cooked bacon.
+ Ergovisavi:
+ - rscadd: Added a nightvision toggle to Shadowpeople
+ - tweak: Made several anomalous crystal variants more easily identified/easier to
+ see the effects thereof, and removed the "magic" activation possibility (replaced
+ with the "bomb" flag)
+ Gun Hog:
+ - tweak: Nanotrasen Robotics Division is proud to announce slightly less clunky
+ leg servo designs relating to the "Ripley" APLU and "Firefighter" exosuits.
+ Tests show increased mobility in both high and low pressure environments. The
+ previous designer has been fired for incompetence.
+ Improves tablets design:
+ - imageadd: Brings the tablet icons into the holy light of having depth
+ Joan:
+ - rscadd: Megafauna will now use ranged attacks even if they don't have direct vision
+ on their target.
+ - rscadd: Volt Void and Interdiction Lenses will now drain mech cells of energy.
+ - tweak: Ocular Wardens do slightly more damage to mechs.
+ - experiment: Replicant, Soul Vessel, Cogscarab, and Anima Fragment now take an
+ additional second to recite.
+ - tweak: Anima Fragments do slightly less damage in melee.
+ - tweak: Mending Motors and Clockwork Obelisks have slightly less health.
+ - tweak: Invoking Nezbere now requires 3 invokers.
+ - rscdel: Clockwork armor no longer has 5% energy resistance.
+ - bugfix: You can no longer construct clockwork structures on space turfs.
+ Papa Bones:
+ - tweak: BZ gas is no longer available on Box and Metastation layouts.
+ phil235:
+ - tweak: You no longer have to click a megaphone to use it, you simply keep it in
+ your active hand and talk normally.
+ - rscadd: Added new things
+ - imageadd: added some icons and images
+2016-09-20:
+ Ergovisavi:
+ - bugfix: fixed "friendly" xenobio mobs and mining drones attacking station drones
+ Joan:
+ - rscadd: Miners can now buy KA AoE damage mods from the mining vendor for 2000
+ points per mod.
+ - rscadd: 'Combined the Convert and Sacrifice runes into one rune. It''ll convert
+ targets that are alive and eligible, and attempt to sacrifice them otherwise.
+ The only changes to mechanics are that: Converting someone will heal them of
+ all brute and burn damage they had, and sacrificing anything will always produce
+ a soulstone(but will still only sometimes fill it)'
+ - tweak: You can no longer teleport to Teleport runes that have dense objects on
+ top of them.
+ - experiment: Wall runes will now activate other nearby wall runes when activated,
+ but will automatically disable after a minute and a half of continuous activity
+ and become unusable for 5 seconds.
+ - experiment: The Blood Boil rune no longer does all of its damage instantly or
+ stuns, but if you remain in range for the full duration you will be sent deep
+ into critical.
+ - experiment: Bubblegum has been seen reaching through blood. Try not to get hit.
+ - experiment: The Raise Dead rune no longer requires a noncultist corpse to revive
+ a cultist; instead, it will draw from the pool of all people sacrificed to power
+ the rune.
+ Mekhi:
+ - rscadd: Nanotrasen has been experimenting on cybernetics for a while, and rumors
+ are they have a few combat prototypes available...
+ - experiment: 'New arm implants: Energy-blade projector, implanted medical beamgun,
+ stun-arm implant (Like the borg version), flash implant that is automatically-regenerating
+ and doubles as a powerful flashlight. There is also one with all four items
+ in one. Also, a surgery toolkit implant. Adminspawn only for the moment.'
+ MrStonedOne:
+ - bugfix: Fixed space/nograv movement not triggering when atoms moved twice quickly
+ in space/nograv
+ Nanotrasen Stress Relief Board:
+ - rscadd: Latecomers to highlander can now join in on the fun.
+ - rscadd: The crew are encouraged to less pacifistic during highlander. Failing
+ to shed blood will result in your soul being devoured. Have a nice day.
+ Nicho1010:
+ - bugfix: Fixed lattices appearing after exploding lava
+ Screemonster:
+ - tweak: Abandoned crates no longer accept impossible guesses.
+ - tweak: Lets players know that all the digits in the code must be unique.
+ - tweak: Reads the last guess back on the multitool along with the correct/incorrect
+ guess readout.
+ - bugfix: multitool output on crates no longer returns nonsense values.
+ XDTM:
+ - rscadd: Positive viruses are now recognized by medical HUDs with a special icon.
+ - tweak: fully_heal no longer removes nonharmful viruses. This affects legion souls,
+ staffs of healing, and changeling's revive.
+ - rscadd: Canisters of any type of gas are now orderable in cargo. Dangerous experimental
+ gases will require Research Director approval.
+ Yackemflam:
+ - rscadd: The syndicate has learned on how to give their agents a true syndicate
+ ninja experience.
+ chickenboy10:
+ - rscadd: Added a Experimental Limb Grower to the medbay department, now medical
+ stuff can grow synthetic limbs using Synthflesh to help crew that suffer any
+ work related accidents. There may also be a limb that can be grown with a special
+ card...
+ feemjmeem:
+ - tweak: You can now disassemble meatspike frames with a welding tool.
+ phil235:
+ - experiment: 'adds a talk button next to the crafting button. Clicking it makes
+ a "wheel" appear around you with short predetermined messages that you click
+ to say them. This lets you say common responses without having to type in the
+ chat bar. Current messages available are: "Hi", "Bye", "Thanks", "Come", "Help",
+ "Stop", "Get out", "Yes", and "No". The talk button can be activated with the
+ hotkey "H" or "CTRL+H"'
+ - rscadd: Wearing colored glasses colors your vision. This option can be enabled/disabled
+ by alt-clicking any glasses with such feature.
+2016-09-21:
+ Cyberboss:
+ - bugfix: The food processor's sprite's maintenance panel is no longer open while
+ closed and vice/versa
+ - tweak: Tesla arcs no longer lose power when passing through a coil that isn't
+ connected to a grid
+ MrStonedOne:
+ - bugfix: Fixes minimap generation crashes by making parts of it less precise
diff --git a/html/changelogs/AutoChangeLog-pr-20283.yml b/html/changelogs/AutoChangeLog-pr-20283.yml
deleted file mode 100644
index e990daac41d..00000000000
--- a/html/changelogs/AutoChangeLog-pr-20283.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "RemieRichards"
-delete-after: True
-changes:
- - rscadd: "Added the functionality for mobs to have multiple hands, this might have broken some things, so please report any weirdness"
diff --git a/html/changelogs/AutoChangeLog-pr-20370.yml b/html/changelogs/AutoChangeLog-pr-20370.yml
deleted file mode 100644
index af148b7acfe..00000000000
--- a/html/changelogs/AutoChangeLog-pr-20370.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "TheCarlSaganExpress"
-delete-after: True
-changes:
- - rscadd: "Crayons, lipstick, cigarettes, and penlights can now be inserted into PDAs."
diff --git a/html/changelogs/AutoChangeLog-pr-20395.yml b/html/changelogs/AutoChangeLog-pr-20395.yml
deleted file mode 100644
index 079783c4ca8..00000000000
--- a/html/changelogs/AutoChangeLog-pr-20395.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Shadowlight213"
-delete-after: True
-changes:
- - rscdel: "The surplus crate and random item will now only contain items allowed by the gamemode"
- - rscdel: "removes sleeping carp scroll from surplus crates"
diff --git a/html/changelogs/AutoChangeLog-pr-20402.yml b/html/changelogs/AutoChangeLog-pr-20402.yml
deleted file mode 100644
index e1cc68b7f55..00000000000
--- a/html/changelogs/AutoChangeLog-pr-20402.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "Joan"
-delete-after: True
-changes:
- - rscadd: "Cult structures can once again be constructed with runed metal."
- - experiment: "Cult structures can now take damage and be destroyed. Artificers can repair them if they're damaged."
diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi
index d41b9403fa2..247d6a401f7 100644
Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ
diff --git a/icons/effects/blood.dmi b/icons/effects/blood.dmi
index f073ff5b338..5e71e45d4bf 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 01e00f7163f..adef4345cc9 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/minimaps/BirdboatStation_1.png b/icons/minimaps/BirdboatStation_1.png
new file mode 100644
index 00000000000..a6c1a4dd932
Binary files /dev/null and b/icons/minimaps/BirdboatStation_1.png differ
diff --git a/icons/minimaps/Box Station_1.png b/icons/minimaps/Box Station_1.png
new file mode 100644
index 00000000000..d14145b5604
Binary files /dev/null and b/icons/minimaps/Box Station_1.png differ
diff --git a/icons/minimaps/DreamStation_1.png b/icons/minimaps/DreamStation_1.png
new file mode 100644
index 00000000000..75ac12fec85
Binary files /dev/null and b/icons/minimaps/DreamStation_1.png differ
diff --git a/icons/minimaps/Efficiency Station_1.png b/icons/minimaps/Efficiency Station_1.png
new file mode 100644
index 00000000000..3c952a21493
Binary files /dev/null and b/icons/minimaps/Efficiency Station_1.png differ
diff --git a/icons/minimaps/MetaStation_1.png b/icons/minimaps/MetaStation_1.png
new file mode 100644
index 00000000000..bf8a6ed430a
Binary files /dev/null and b/icons/minimaps/MetaStation_1.png differ
diff --git a/icons/minimaps/MiniStation_1.png b/icons/minimaps/MiniStation_1.png
new file mode 100644
index 00000000000..52689a1a576
Binary files /dev/null and b/icons/minimaps/MiniStation_1.png differ
diff --git a/icons/mob/animal_parts.dmi b/icons/mob/animal_parts.dmi
new file mode 100644
index 00000000000..b120e81d411
Binary files /dev/null and b/icons/mob/animal_parts.dmi differ
diff --git a/icons/mob/augments.dmi b/icons/mob/augments.dmi
index 8cbb3f03d5e..7ab1b3893d2 100644
Binary files a/icons/mob/augments.dmi and b/icons/mob/augments.dmi differ
diff --git a/icons/mob/dam_human.dmi b/icons/mob/dam_human.dmi
deleted file mode 100644
index d6d30c87f40..00000000000
Binary files a/icons/mob/dam_human.dmi and /dev/null differ
diff --git a/icons/mob/dam_mob.dmi b/icons/mob/dam_mob.dmi
new file mode 100644
index 00000000000..fe92746b43e
Binary files /dev/null and b/icons/mob/dam_mob.dmi differ
diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi
index 2338f667955..0d61c44cbbd 100644
Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ
diff --git a/icons/mob/human_parts.dmi b/icons/mob/human_parts.dmi
index bddb6641c8a..58ba1d42168 100644
Binary files a/icons/mob/human_parts.dmi and b/icons/mob/human_parts.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 4fd8e88842f..613fdf7e18b 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 438f41daca2..fc596866750 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi
index 9ec94d38800..486e4e7fb74 100644
Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ
diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi
index b0a1dbcb168..256bd412b4f 100644
Binary files a/icons/mob/screen_gen.dmi and b/icons/mob/screen_gen.dmi differ
diff --git a/icons/mob/screen_midnight.dmi b/icons/mob/screen_midnight.dmi
index 4de01c73cc8..c25813197fe 100644
Binary files a/icons/mob/screen_midnight.dmi and b/icons/mob/screen_midnight.dmi differ
diff --git a/icons/mob/screen_operative.dmi b/icons/mob/screen_operative.dmi
index e1728959e6a..e6a65052c14 100644
Binary files a/icons/mob/screen_operative.dmi and b/icons/mob/screen_operative.dmi differ
diff --git a/icons/mob/screen_plasmafire.dmi b/icons/mob/screen_plasmafire.dmi
index c40a531d8a6..3d1846b3009 100644
Binary files a/icons/mob/screen_plasmafire.dmi and b/icons/mob/screen_plasmafire.dmi differ
diff --git a/icons/mob/screen_retro.dmi b/icons/mob/screen_retro.dmi
index 9c99dba486b..db87b592169 100644
Binary files a/icons/mob/screen_retro.dmi and b/icons/mob/screen_retro.dmi differ
diff --git a/icons/mob/screen_slimecore.dmi b/icons/mob/screen_slimecore.dmi
index 91e2d73abe2..8575fa037de 100644
Binary files a/icons/mob/screen_slimecore.dmi and b/icons/mob/screen_slimecore.dmi differ
diff --git a/icons/obj/clothing/glasses.dmi b/icons/obj/clothing/glasses.dmi
index 2084597bea4..06c3a0ce8a4 100644
Binary files a/icons/obj/clothing/glasses.dmi and b/icons/obj/clothing/glasses.dmi differ
diff --git a/icons/obj/food/burgerbread.dmi b/icons/obj/food/burgerbread.dmi
index 843a6cd508b..64fac1c3eb7 100644
Binary files a/icons/obj/food/burgerbread.dmi and b/icons/obj/food/burgerbread.dmi differ
diff --git a/icons/obj/food/food.dmi b/icons/obj/food/food.dmi
index 7c0df528dd6..fec63c0a165 100644
Binary files a/icons/obj/food/food.dmi and b/icons/obj/food/food.dmi differ
diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi
index ffac4fc2f7e..29ab421834e 100644
Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index 62f5dd37112..c629012bb16 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/obj/machines/limbgrower.dmi b/icons/obj/machines/limbgrower.dmi
new file mode 100644
index 00000000000..7e26a9f7f24
Binary files /dev/null and b/icons/obj/machines/limbgrower.dmi differ
diff --git a/icons/obj/modular_tablet.dmi b/icons/obj/modular_tablet.dmi
index 82f4e1438f6..2438f375f65 100644
Binary files a/icons/obj/modular_tablet.dmi and b/icons/obj/modular_tablet.dmi differ
diff --git a/icons/obj/tiles.dmi b/icons/obj/tiles.dmi
index f6054cca6a7..9347e67f233 100644
Binary files a/icons/obj/tiles.dmi and b/icons/obj/tiles.dmi differ
diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi
index dcc0ffb5ce8..d0afb945f00 100644
Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ
diff --git a/icons/turf/walls/clockwork_wall.dmi b/icons/turf/walls/clockwork_wall.dmi
index ae9f2de887a..8263e901d00 100644
Binary files a/icons/turf/walls/clockwork_wall.dmi and b/icons/turf/walls/clockwork_wall.dmi differ
diff --git a/interface/skin.dmf b/interface/skin.dmf
index 335caf26118..27dca90bcc8 100644
--- a/interface/skin.dmf
+++ b/interface/skin.dmf
@@ -77,6 +77,9 @@ macro "default"
elem
name = "CTRL+G"
command = "a-intent right"
+ elem
+ name = "CTRL+H"
+ command = "talk-wheel"
elem
name = "CTRL+Q"
command = ".northwest"
@@ -238,6 +241,12 @@ macro "hotkeys"
elem
name = "CTRL+G"
command = "a-intent right"
+ elem
+ name = "H"
+ command = "talk-wheel"
+ elem
+ name = "CTRL+H"
+ command = "talk-wheel"
elem
name = "M"
command = "me"
diff --git a/tgstation.dme b/tgstation.dme
index 57e25379006..a29bd5bc4da 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -156,6 +156,7 @@
#include "code\controllers\subsystem\radio.dm"
#include "code\controllers\subsystem\server_maintenance.dm"
#include "code\controllers\subsystem\shuttles.dm"
+#include "code\controllers\subsystem\spacedrift.dm"
#include "code\controllers\subsystem\stickyban.dm"
#include "code\controllers\subsystem\sun.dm"
#include "code\controllers\subsystem\tgui.dm"
@@ -336,6 +337,7 @@
#include "code\game\gamemodes\clock_cult\clock_items.dm"
#include "code\game\gamemodes\clock_cult\clock_machines.dm"
#include "code\game\gamemodes\clock_cult\clock_mobs.dm"
+#include "code\game\gamemodes\clock_cult\clock_powerdrain.dm"
#include "code\game\gamemodes\clock_cult\clock_proselytizer.dm"
#include "code\game\gamemodes\clock_cult\clock_ratvar.dm"
#include "code\game\gamemodes\clock_cult\clock_scripture.dm"
@@ -363,14 +365,6 @@
#include "code\game\gamemodes\gang\gang_datum.dm"
#include "code\game\gamemodes\gang\gang_pen.dm"
#include "code\game\gamemodes\gang\recaller.dm"
-#include "code\game\gamemodes\handofgod\_handofgod.dm"
-#include "code\game\gamemodes\handofgod\actions.dm"
-#include "code\game\gamemodes\handofgod\god.dm"
-#include "code\game\gamemodes\handofgod\items.dm"
-#include "code\game\gamemodes\handofgod\objectives.dm"
-#include "code\game\gamemodes\handofgod\powers.dm"
-#include "code\game\gamemodes\handofgod\structures.dm"
-#include "code\game\gamemodes\handofgod\traps.dm"
#include "code\game\gamemodes\malfunction\Malf_Modules.dm"
#include "code\game\gamemodes\meteor\meteor.dm"
#include "code\game\gamemodes\meteor\meteors.dm"
@@ -430,6 +424,7 @@
#include "code\game\machinery\igniter.dm"
#include "code\game\machinery\iv_drip.dm"
#include "code\game\machinery\lightswitch.dm"
+#include "code\game\machinery\limbgrower.dm"
#include "code\game\machinery\machinery.dm"
#include "code\game\machinery\magnet.dm"
#include "code\game\machinery\mass_driver.dm"
@@ -558,7 +553,6 @@
#include "code\game\objects\effects\bump_teleporter.dm"
#include "code\game\objects\effects\contraband.dm"
#include "code\game\objects\effects\forcefields.dm"
-#include "code\game\objects\effects\gibs.dm"
#include "code\game\objects\effects\glowshroom.dm"
#include "code\game\objects\effects\landmarks.dm"
#include "code\game\objects\effects\manifest.dm"
@@ -603,6 +597,7 @@
#include "code\game\objects\items\documents.dm"
#include "code\game\objects\items\latexballoon.dm"
#include "code\game\objects\items\nuke_tools.dm"
+#include "code\game\objects\items\religion.dm"
#include "code\game\objects\items\shooting_range.dm"
#include "code\game\objects\items\toys.dm"
#include "code\game\objects\items\trash.dm"
@@ -748,6 +743,7 @@
#include "code\game\objects\structures\bedsheet_bin.dm"
#include "code\game\objects\structures\destructible_structures.dm"
#include "code\game\objects\structures\displaycase.dm"
+#include "code\game\objects\structures\divine.dm"
#include "code\game\objects\structures\door_assembly.dm"
#include "code\game\objects\structures\dresser.dm"
#include "code\game\objects\structures\electricchair.dm"
@@ -783,6 +779,7 @@
#include "code\game\objects\structures\tables_racks.dm"
#include "code\game\objects\structures\tank_dispenser.dm"
#include "code\game\objects\structures\target_stake.dm"
+#include "code\game\objects\structures\traps.dm"
#include "code\game\objects\structures\watercloset.dm"
#include "code\game\objects\structures\windoor_assembly.dm"
#include "code\game\objects\structures\window.dm"
@@ -1315,10 +1312,20 @@
#include "code\modules\mob\living\say.dm"
#include "code\modules\mob\living\status_procs.dm"
#include "code\modules\mob\living\ventcrawling.dm"
+#include "code\modules\mob\living\brain\brain.dm"
+#include "code\modules\mob\living\brain\brain_item.dm"
+#include "code\modules\mob\living\brain\death.dm"
+#include "code\modules\mob\living\brain\emote.dm"
+#include "code\modules\mob\living\brain\life.dm"
+#include "code\modules\mob\living\brain\MMI.dm"
+#include "code\modules\mob\living\brain\posibrain.dm"
+#include "code\modules\mob\living\brain\say.dm"
+#include "code\modules\mob\living\brain\status_procs.dm"
#include "code\modules\mob\living\carbon\carbon.dm"
#include "code\modules\mob\living\carbon\carbon_defense.dm"
#include "code\modules\mob\living\carbon\carbon_defines.dm"
#include "code\modules\mob\living\carbon\carbon_movement.dm"
+#include "code\modules\mob\living\carbon\damage_procs.dm"
#include "code\modules\mob\living\carbon\death.dm"
#include "code\modules\mob\living\carbon\emote.dm"
#include "code\modules\mob\living\carbon\examine.dm"
@@ -1329,6 +1336,7 @@
#include "code\modules\mob\living\carbon\update_icons.dm"
#include "code\modules\mob\living\carbon\alien\alien.dm"
#include "code\modules\mob\living\carbon\alien\alien_defense.dm"
+#include "code\modules\mob\living\carbon\alien\damage_procs.dm"
#include "code\modules\mob\living\carbon\alien\death.dm"
#include "code\modules\mob\living\carbon\alien\life.dm"
#include "code\modules\mob\living\carbon\alien\login.dm"
@@ -1337,10 +1345,12 @@
#include "code\modules\mob\living\carbon\alien\say.dm"
#include "code\modules\mob\living\carbon\alien\screen.dm"
#include "code\modules\mob\living\carbon\alien\status_procs.dm"
+#include "code\modules\mob\living\carbon\alien\update_icons.dm"
#include "code\modules\mob\living\carbon\alien\humanoid\alien_powers.dm"
#include "code\modules\mob\living\carbon\alien\humanoid\death.dm"
#include "code\modules\mob\living\carbon\alien\humanoid\emote.dm"
#include "code\modules\mob\living\carbon\alien\humanoid\humanoid.dm"
+#include "code\modules\mob\living\carbon\alien\humanoid\humanoid_defense.dm"
#include "code\modules\mob\living\carbon\alien\humanoid\inventory.dm"
#include "code\modules\mob\living\carbon\alien\humanoid\life.dm"
#include "code\modules\mob\living\carbon\alien\humanoid\queen.dm"
@@ -1353,28 +1363,17 @@
#include "code\modules\mob\living\carbon\alien\larva\emote.dm"
#include "code\modules\mob\living\carbon\alien\larva\inventory.dm"
#include "code\modules\mob\living\carbon\alien\larva\larva.dm"
+#include "code\modules\mob\living\carbon\alien\larva\larva_defense.dm"
#include "code\modules\mob\living\carbon\alien\larva\life.dm"
#include "code\modules\mob\living\carbon\alien\larva\powers.dm"
#include "code\modules\mob\living\carbon\alien\larva\update_icons.dm"
#include "code\modules\mob\living\carbon\alien\special\alien_embryo.dm"
#include "code\modules\mob\living\carbon\alien\special\facehugger.dm"
-#include "code\modules\mob\living\carbon\brain\brain.dm"
-#include "code\modules\mob\living\carbon\brain\brain_item.dm"
-#include "code\modules\mob\living\carbon\brain\death.dm"
-#include "code\modules\mob\living\carbon\brain\emote.dm"
-#include "code\modules\mob\living\carbon\brain\life.dm"
-#include "code\modules\mob\living\carbon\brain\MMI.dm"
-#include "code\modules\mob\living\carbon\brain\posibrain.dm"
-#include "code\modules\mob\living\carbon\brain\say.dm"
-#include "code\modules\mob\living\carbon\brain\status_procs.dm"
+#include "code\modules\mob\living\carbon\human\damage_procs.dm"
#include "code\modules\mob\living\carbon\human\death.dm"
#include "code\modules\mob\living\carbon\human\emote.dm"
#include "code\modules\mob\living\carbon\human\examine.dm"
#include "code\modules\mob\living\carbon\human\human.dm"
-#include "code\modules\mob\living\carbon\human\human_attackalien.dm"
-#include "code\modules\mob\living\carbon\human\human_attackhand.dm"
-#include "code\modules\mob\living\carbon\human\human_attackpaw.dm"
-#include "code\modules\mob\living\carbon\human\human_damage.dm"
#include "code\modules\mob\living\carbon\human\human_defense.dm"
#include "code\modules\mob\living\carbon\human\human_defines.dm"
#include "code\modules\mob\living\carbon\human\human_helpers.dm"
@@ -1384,6 +1383,7 @@
#include "code\modules\mob\living\carbon\human\say.dm"
#include "code\modules\mob\living\carbon\human\species.dm"
#include "code\modules\mob\living\carbon\human\species_types.dm"
+#include "code\modules\mob\living\carbon\human\status_procs.dm"
#include "code\modules\mob\living\carbon\human\update_icons.dm"
#include "code\modules\mob\living\carbon\human\whisper.dm"
#include "code\modules\mob\living\carbon\monkey\death.dm"
@@ -1391,16 +1391,20 @@
#include "code\modules\mob\living\carbon\monkey\inventory.dm"
#include "code\modules\mob\living\carbon\monkey\life.dm"
#include "code\modules\mob\living\carbon\monkey\monkey.dm"
+#include "code\modules\mob\living\carbon\monkey\monkey_defense.dm"
#include "code\modules\mob\living\carbon\monkey\punpun.dm"
#include "code\modules\mob\living\carbon\monkey\update_icons.dm"
+#include "code\modules\mob\living\silicon\damage_procs.dm"
#include "code\modules\mob\living\silicon\death.dm"
#include "code\modules\mob\living\silicon\examine.dm"
#include "code\modules\mob\living\silicon\laws.dm"
#include "code\modules\mob\living\silicon\login.dm"
#include "code\modules\mob\living\silicon\say.dm"
#include "code\modules\mob\living\silicon\silicon.dm"
+#include "code\modules\mob\living\silicon\silicon_defense.dm"
#include "code\modules\mob\living\silicon\status_procs.dm"
#include "code\modules\mob\living\silicon\ai\ai.dm"
+#include "code\modules\mob\living\silicon\ai\ai_defense.dm"
#include "code\modules\mob\living\silicon\ai\death.dm"
#include "code\modules\mob\living\silicon\ai\examine.dm"
#include "code\modules\mob\living\silicon\ai\laws.dm"
@@ -1417,6 +1421,7 @@
#include "code\modules\mob\living\silicon\pai\examine.dm"
#include "code\modules\mob\living\silicon\pai\life.dm"
#include "code\modules\mob\living\silicon\pai\pai.dm"
+#include "code\modules\mob\living\silicon\pai\pai_defense.dm"
#include "code\modules\mob\living\silicon\pai\personality.dm"
#include "code\modules\mob\living\silicon\pai\say.dm"
#include "code\modules\mob\living\silicon\pai\software.dm"
@@ -1428,11 +1433,14 @@
#include "code\modules\mob\living\silicon\robot\life.dm"
#include "code\modules\mob\living\silicon\robot\login.dm"
#include "code\modules\mob\living\silicon\robot\robot.dm"
+#include "code\modules\mob\living\silicon\robot\robot_defense.dm"
#include "code\modules\mob\living\silicon\robot\robot_modules.dm"
#include "code\modules\mob\living\silicon\robot\robot_movement.dm"
#include "code\modules\mob\living\silicon\robot\say.dm"
+#include "code\modules\mob\living\simple_animal\animal_defense.dm"
#include "code\modules\mob\living\simple_animal\constructs.dm"
#include "code\modules\mob\living\simple_animal\corpse.dm"
+#include "code\modules\mob\living\simple_animal\damage_procs.dm"
#include "code\modules\mob\living\simple_animal\parrot.dm"
#include "code\modules\mob\living\simple_animal\shade.dm"
#include "code\modules\mob\living\simple_animal\simple_animal.dm"
@@ -1756,6 +1764,7 @@
#include "code\modules\research\designs\biogenerator_designs.dm"
#include "code\modules\research\designs\comp_board_designs.dm"
#include "code\modules\research\designs\computer_part_designs.dm"
+#include "code\modules\research\designs\limbgrower_designs.dm"
#include "code\modules\research\designs\machine_designs.dm"
#include "code\modules\research\designs\mecha_designs.dm"
#include "code\modules\research\designs\mechfabricator_designs.dm"
@@ -1853,6 +1862,7 @@
#include "code\modules\surgery\bodyparts\dismemberment.dm"
#include "code\modules\surgery\bodyparts\head.dm"
#include "code\modules\surgery\bodyparts\helpers.dm"
+#include "code\modules\surgery\bodyparts\robot_bodyparts.dm"
#include "code\modules\surgery\organs\augments_arms.dm"
#include "code\modules\surgery\organs\augments_chest.dm"
#include "code\modules\surgery\organs\augments_eyes.dm"