Merge branch 'master' into Biodegradable-Darts

This commit is contained in:
Zna12
2018-03-06 21:57:23 -06:00
committed by GitHub
182 changed files with 12518 additions and 21404 deletions
+3 -3
View File
@@ -6,15 +6,15 @@
#deathride58
/modular_citadel/ @deathride58
/code/citadel/ @deathride58
#LetterJay
/modular_citadel/code/modules/client/loadout/__donator.dm @LetterJay
#Poojawa
/code/modules/vore @Poojawa
/code/citadel/dogborgstuff.dmm @Poojawa
/modular_citadel/code/modules/vore @Poojawa
/code/game/objects/items/devices/dogborg_sleeper.dm @Poojawa
/modular_citadel/code/modules/mob/living/silicon/robot/dogborg_equipment.dm @Poojawa
/tgui/ @Poojawa
/modular_citadel/code/modules/clothing/spacesuits/flightsuit.dm @Poojawa
/modular_citadel/code/game/objects/ids.dm @Poojawa
+1
View File
@@ -198,3 +198,4 @@ tools/MapAtmosFixer/MapAtmosFixer/obj/x86/Debug/MapAtmosFixer.csproj.CoreCompile
#GitHub Atom
.atom-build.json
cfg/admin.txt
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+78 -137
View File
@@ -2574,7 +2574,7 @@
c_tag = "AI Vault - Port";
dir = 4;
name = "ai camera";
network = list("Sat");
network = list("minisat");
start_active = 1
},
/obj/effect/turf_decal/stripes/line{
@@ -3515,7 +3515,7 @@
c_tag = "AI Vault - Starboard";
dir = 8;
name = "ai camera";
network = list("Sat");
network = list("minisat");
start_active = 1
},
/obj/effect/turf_decal/stripes/line{
@@ -4081,8 +4081,7 @@
},
/obj/machinery/atmospherics/components/unary/vent_pump/on,
/obj/machinery/camera{
c_tag = "Armoury - Internal";
network = list("Labor")
c_tag = "Armoury - Internal"
},
/obj/effect/turf_decal/stripes/line{
dir = 8
@@ -4542,8 +4541,7 @@
dir = 8
},
/obj/machinery/camera{
c_tag = "Security - Cell 1";
network = list("MINE")
c_tag = "Security - Cell 1"
},
/turf/open/floor/plasteel/red/side{
dir = 5
@@ -4569,8 +4567,7 @@
},
/obj/machinery/camera{
c_tag = "Fore Primary Hallway";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/red/corner{
dir = 1
@@ -5967,8 +5964,7 @@
/obj/item/stamp,
/obj/machinery/camera{
c_tag = "Cargo Bay Entrance";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/brown{
dir = 8
@@ -6147,8 +6143,7 @@
dir = 8
},
/obj/machinery/camera{
c_tag = "Security - Cell 2";
network = list("MINE")
c_tag = "Security - Cell 2"
},
/turf/open/floor/plasteel/red/side{
dir = 5
@@ -6521,8 +6516,7 @@
},
/obj/machinery/camera{
c_tag = "Security - Office";
dir = 4;
network = list("MINE")
dir = 4
},
/turf/open/floor/plasteel/red/corner{
dir = 1
@@ -6547,8 +6541,7 @@
"amK" = (
/obj/machinery/camera{
c_tag = "Security - Central";
dir = 4;
network = list("MINE")
dir = 4
},
/turf/open/floor/plasteel/neutral/side{
dir = 8
@@ -6629,8 +6622,7 @@
"amS" = (
/obj/machinery/camera{
c_tag = "Locker Room Toilets";
dir = 8;
network = list("SS13")
dir = 8
},
/turf/open/floor/plasteel/freezer,
/area/hallway/primary/central)
@@ -8505,8 +8497,7 @@
/obj/item/shovel,
/obj/machinery/camera{
c_tag = "Mining Dock";
dir = 4;
network = list("SS13")
dir = 4
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
@@ -9015,7 +9006,6 @@
},
/obj/machinery/camera{
c_tag = "Atmospherics Tank 4";
network = list("thunder");
pixel_x = 10
},
/turf/open/floor/plasteel/green/side{
@@ -9418,8 +9408,7 @@
},
/obj/machinery/camera{
c_tag = "Central Diner 3";
dir = 4;
network = list("MINE")
dir = 4
},
/turf/open/floor/plasteel/vault/side{
dir = 4
@@ -10058,8 +10047,7 @@
"atz" = (
/obj/machinery/camera{
c_tag = "Atmospherics Tank 1";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/vault{
dir = 5
@@ -10454,8 +10442,7 @@
},
/obj/machinery/camera{
c_tag = "Bar";
dir = 8;
network = list("SS13")
dir = 8
},
/turf/open/floor/plasteel/vault{
dir = 8
@@ -10473,8 +10460,7 @@
},
/obj/machinery/camera{
c_tag = "Bar Backroom";
dir = 4;
network = list("MINE")
dir = 4
},
/turf/open/floor/plasteel/vault,
/area/crew_quarters/bar/atrium)
@@ -11736,8 +11722,7 @@
},
/obj/machinery/camera{
c_tag = "Atmospherics East";
dir = 8;
network = list("SS13")
dir = 8
},
/turf/open/floor/plasteel/caution{
dir = 4
@@ -11956,8 +11941,7 @@
"axj" = (
/obj/machinery/camera{
c_tag = "Atmospherics Tank 2";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/vault{
dir = 5
@@ -12059,8 +12043,7 @@
/obj/machinery/portable_atmospherics/canister/nitrogen,
/obj/machinery/camera{
c_tag = "Atmospherics Monitoring";
dir = 2;
network = list("SS13")
dir = 2
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
@@ -12634,8 +12617,7 @@
},
/obj/machinery/camera{
c_tag = "Central Diner 2";
dir = 4;
network = list("MINE")
dir = 4
},
/turf/open/floor/plasteel/vault/side{
dir = 4
@@ -13466,8 +13448,7 @@
/obj/structure/bedsheetbin,
/obj/machinery/camera{
c_tag = "Locker Room East";
dir = 8;
network = list("SS13")
dir = 8
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel/arrival{
@@ -14488,8 +14469,7 @@
},
/obj/machinery/camera{
c_tag = "Central Hallway East";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/neutral/corner{
dir = 1
@@ -15091,8 +15071,7 @@
},
/obj/machinery/camera{
c_tag = "Engineering Secure Storage";
dir = 4;
network = list("SS13")
dir = 4
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel/vault/side{
@@ -15337,8 +15316,7 @@
},
/obj/machinery/camera{
c_tag = "Locker Room South";
dir = 8;
network = list("SS13")
dir = 8
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel/vault{
@@ -15695,8 +15673,7 @@
},
/obj/machinery/camera{
c_tag = "SMES Access";
dir = 8;
network = list("SS13")
dir = 8
},
/obj/effect/turf_decal/stripes/line{
dir = 2
@@ -15739,8 +15716,7 @@
},
/obj/machinery/camera{
c_tag = "Engineering Access";
dir = 8;
network = list("Labor")
dir = 8
},
/obj/effect/turf_decal/stripes/line{
dir = 6
@@ -15877,8 +15853,7 @@
},
/obj/machinery/camera{
c_tag = "Central Diner 1";
dir = 4;
network = list("MINE")
dir = 4
},
/turf/open/floor/plasteel/redyellow,
/area/crew_quarters/bar/atrium)
@@ -16458,8 +16433,7 @@
"aHg" = (
/obj/machinery/camera{
c_tag = "Gravity Generator Room";
dir = 8;
network = list("SS13")
dir = 8
},
/obj/effect/turf_decal/bot_white/left,
/turf/open/floor/plasteel/vault{
@@ -16559,7 +16533,7 @@
/obj/machinery/camera{
c_tag = "Engineering Fore";
dir = 2;
network = list("SS13","Engine");
network = list("ss13","engine");
pixel_x = 23
},
/turf/open/floor/engine,
@@ -17184,8 +17158,7 @@
},
/obj/machinery/camera{
c_tag = "Engineering Monitoring";
dir = 2;
network = list("SS13")
dir = 2
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
@@ -18010,7 +17983,7 @@
/obj/machinery/camera{
c_tag = "Kitchen Coldroom";
dir = 4;
network = list("MINE")
network = list("mine")
},
/turf/open/floor/plasteel/freezer,
/area/crew_quarters/kitchen)
@@ -19145,7 +19118,7 @@
/obj/machinery/camera{
c_tag = "Engineering Port";
dir = 4;
network = list("SS13","Engine")
network = list("ss13","engine")
},
/obj/effect/turf_decal/stripes/line{
dir = 8
@@ -19171,7 +19144,7 @@
/obj/machinery/camera{
c_tag = "Supermatter Chamber";
dir = 2;
network = list("Engine");
network = list("engine");
pixel_x = 23
},
/obj/structure/cable{
@@ -19285,7 +19258,7 @@
desc = "Used for watching the Engine.";
dir = 1;
name = "Engine Monitor";
network = list("Engine");
network = list("engine");
pixel_y = -32
},
/obj/machinery/rnd/protolathe/department/engineering,
@@ -19335,8 +19308,7 @@
},
/obj/machinery/camera{
c_tag = "Atmospherics South West";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/neutral/corner{
dir = 8;
@@ -19468,8 +19440,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/machinery/camera{
c_tag = "Hydroponics South";
dir = 8;
network = list("SS13")
dir = 8
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel/vault/side{
@@ -20153,8 +20124,7 @@
icon_state = "4-8"
},
/obj/machinery/camera{
c_tag = "Aft Primary Hallway 4";
network = list("SS13","Prison")
c_tag = "Aft Primary Hallway 4"
},
/turf/open/floor/plasteel/green/corner{
dir = 1
@@ -20262,8 +20232,7 @@
icon_state = "4-8"
},
/obj/machinery/camera{
c_tag = "Aft Primary Hallway 3";
network = list("SS13","Prison")
c_tag = "Aft Primary Hallway 3"
},
/turf/open/floor/plasteel/green/corner{
dir = 1
@@ -21100,7 +21069,7 @@
/obj/machinery/camera{
c_tag = "Engineering Aft";
dir = 2;
network = list("SS13","Engine");
network = list("ss13","engine");
pixel_x = 23
},
/obj/machinery/atmospherics/pipe/simple/orange/visible{
@@ -21257,8 +21226,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/machinery/camera{
c_tag = "Aft Primary Hallway 2";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/yellow/corner{
dir = 8
@@ -21535,8 +21503,7 @@
},
/obj/machinery/camera{
c_tag = "Library 2";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/dark,
/area/library)
@@ -21685,8 +21652,7 @@
},
/obj/machinery/camera{
c_tag = "Chemistry";
dir = 2;
network = list("SS13")
dir = 2
},
/turf/open/floor/plasteel/whiteyellow/corner{
dir = 1
@@ -22567,8 +22533,7 @@
"aUo" = (
/obj/machinery/camera{
c_tag = "Genetics Cloning";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/whiteblue/corner{
dir = 1
@@ -23136,7 +23101,7 @@
/obj/machinery/camera{
c_tag = "Server Room";
dir = 2;
network = list("SS13","RD");
network = list("ss13","rd");
pixel_x = 22
},
/turf/open/floor/circuit/green/telecomms/mainframe,
@@ -23645,8 +23610,7 @@
/obj/structure/closet/crate/bin,
/obj/machinery/camera{
c_tag = "Medbay Morgue";
dir = 8;
network = list("SS13")
dir = 8
},
/turf/open/floor/plasteel/vault/side{
dir = 8
@@ -23914,8 +23878,7 @@
},
/obj/machinery/camera{
c_tag = "Medbay West";
dir = 2;
network = list("SS13")
dir = 2
},
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -24230,8 +24193,7 @@
},
/obj/machinery/camera{
c_tag = "Medbay Storage";
dir = 2;
network = list("SS13")
dir = 2
},
/obj/effect/turf_decal/delivery,
/obj/structure/window/reinforced{
@@ -24495,8 +24457,7 @@
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden,
/obj/machinery/camera{
c_tag = "Research Division South";
dir = 8;
network = list("SS13")
dir = 8
},
/turf/open/floor/plasteel/whitepurple/corner,
/area/science/research)
@@ -25331,7 +25292,7 @@
/obj/machinery/camera{
c_tag = "Robotics Lab";
dir = 2;
network = list("SS13","RD")
network = list("ss13","rd")
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel/vault/side,
@@ -25637,8 +25598,7 @@
},
/obj/machinery/camera{
c_tag = "Medbay Foyer";
dir = 8;
network = list("SS13")
dir = 8
},
/turf/open/floor/plasteel/neutral,
/area/hallway/primary/central)
@@ -26708,8 +26668,7 @@
},
/obj/machinery/camera{
c_tag = "Medbay South";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/whiteblue/corner{
dir = 8
@@ -27226,8 +27185,7 @@
},
/obj/machinery/camera{
c_tag = "Medbay Recovery Room";
dir = 8;
network = list("SS13")
dir = 8
},
/turf/open/floor/plasteel/vault/side{
dir = 8
@@ -28451,7 +28409,7 @@
/obj/machinery/camera{
c_tag = "Xenobiology Test Chamber";
dir = 2;
network = list("Xeno","RD")
network = list("xeno","rd")
},
/turf/open/floor/plasteel/vault{
dir = 4
@@ -28546,7 +28504,7 @@
/obj/machinery/camera{
c_tag = "Crematorium";
dir = 4;
network = list("MINE")
network = list("mine")
},
/turf/open/floor/plasteel/vault/side{
dir = 4
@@ -29231,8 +29189,7 @@
},
/obj/machinery/camera{
c_tag = "Chaplain's Quarters";
dir = 2;
network = list("SS13")
dir = 2
},
/turf/open/floor/plasteel/vault{
dir = 8
@@ -29278,8 +29235,7 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on,
/obj/machinery/camera{
c_tag = "Chapel Office";
dir = 2;
network = list("SS13")
dir = 2
},
/turf/open/floor/wood,
/area/chapel/main)
@@ -29714,8 +29670,7 @@
},
/obj/machinery/camera{
c_tag = "Chapel South";
dir = 8;
network = list("SS13")
dir = 8
},
/turf/open/floor/plasteel/vault{
dir = 5
@@ -29737,8 +29692,7 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/camera{
c_tag = "Arrivals Hallway 3";
dir = 8;
network = list("SS13")
dir = 8
},
/obj/effect/turf_decal/stripes/line{
dir = 2
@@ -29825,7 +29779,7 @@
c_tag = "Science - Server Room";
dir = 8;
name = "science camera";
network = list("SS13","RD")
network = list("ss13","rd")
},
/turf/open/floor/circuit/green/telecomms/mainframe,
/area/science/xenobiology)
@@ -30413,8 +30367,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/machinery/camera{
c_tag = "Port Primary Hallway";
dir = 4;
network = list("SS13")
dir = 4
},
/obj/effect/turf_decal/stripes/line{
dir = 2
@@ -30431,8 +30384,7 @@
},
/obj/machinery/camera{
c_tag = "Starboard Primary Hallway 2";
dir = 8;
network = list("SS13")
dir = 8
},
/turf/open/floor/plasteel/neutral/corner,
/area/hallway/primary/central)
@@ -30440,8 +30392,7 @@
/obj/structure/closet/firecloset,
/obj/machinery/camera{
c_tag = "Starboard Primary Hallway 2";
dir = 2;
network = list("SS13")
dir = 2
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel/vault/side{
@@ -30464,8 +30415,7 @@
"blk" = (
/obj/machinery/camera{
c_tag = "Atmospherics Tank 3";
dir = 4;
network = list("SS13")
dir = 4
},
/turf/open/floor/plasteel/vault{
dir = 5
@@ -30478,12 +30428,11 @@
/obj/machinery/camera{
c_tag = "Shuttle Docking Foyer";
dir = 8;
network = list("MINE")
network = list("mine")
},
/obj/machinery/camera{
c_tag = "Escape Arm Airlocks";
dir = 8;
network = list("SS13")
dir = 8
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel,
@@ -30492,8 +30441,7 @@
/obj/structure/closet/emcloset,
/obj/machinery/camera{
c_tag = "Starboard Primary Hallway";
dir = 2;
network = list("SS13")
dir = 2
},
/obj/effect/turf_decal/bot,
/turf/open/floor/plasteel/vault/side{
@@ -30507,7 +30455,7 @@
/obj/machinery/camera{
c_tag = "Engineering Starboard";
dir = 8;
network = list("SS13","Engine")
network = list("ss13","engine")
},
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -30523,8 +30471,7 @@
},
/obj/machinery/camera{
c_tag = "Research Division Access";
dir = 2;
network = list("SS13")
dir = 2
},
/obj/structure/cable/white{
icon_state = "2-8"
@@ -30538,7 +30485,6 @@
/obj/machinery/camera{
c_tag = "Aft Primary Hallway 1";
dir = 8;
network = list("SS13");
pixel_y = -22
},
/turf/open/floor/plasteel/purple/corner,
@@ -30583,7 +30529,6 @@
/obj/machinery/camera{
c_tag = "Surgery Operating";
dir = 1;
network = list("SS13");
pixel_x = 22
},
/turf/open/floor/plasteel/neutral,
@@ -30592,7 +30537,7 @@
/obj/machinery/camera{
c_tag = "Xenobiology Test Chamber";
dir = 2;
network = list("Xeno","RD")
network = list("xeno","rd")
},
/turf/open/floor/plasteel/vault{
dir = 5
@@ -30615,8 +30560,7 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/camera{
c_tag = "Arrivals Hallway";
dir = 8;
network = list("SS13")
dir = 8
},
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -30627,8 +30571,7 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/camera{
c_tag = "Arrivals Hallway 2";
dir = 8;
network = list("SS13")
dir = 8
},
/obj/effect/turf_decal/stripes/line{
dir = 4
@@ -30685,8 +30628,7 @@
},
/obj/machinery/camera{
c_tag = "Chapel Mass Driver";
dir = 8;
network = list("SS13")
dir = 8
},
/obj/machinery/light/small,
/obj/machinery/button/massdriver{
@@ -31264,8 +31206,7 @@
"buU" = (
/obj/machinery/camera{
c_tag = "Communications Relay";
dir = 8;
network = list("MINE")
dir = 8
},
/obj/effect/turf_decal/stripes/line{
dir = 1
@@ -33064,7 +33005,7 @@
c_tag = "AI Chamber - Core";
dir = 2;
name = "core camera";
network = list("RD")
network = list("rd")
},
/obj/machinery/cell_charger,
/turf/open/floor/plasteel/vault/side,
@@ -33247,7 +33188,7 @@
c_tag = "AI Chamber - Core";
dir = 2;
name = "core camera";
network = list("RD")
network = list("rd")
},
/obj/effect/turf_decal/stripes/line{
dir = 8
@@ -33384,7 +33325,7 @@
c_tag = "AI Chamber - Core";
dir = 2;
name = "core camera";
network = list("RD")
network = list("rd")
},
/obj/machinery/light{
dir = 1
@@ -33617,7 +33558,7 @@
c_tag = "AI Satellite - Access";
dir = 4;
name = "ai camera";
network = list("Sat");
network = list("minisat");
start_active = 1
},
/turf/open/floor/plasteel/vault/side{
@@ -33905,7 +33846,7 @@
c_tag = "AI Satellite - Maintenance";
dir = 8;
name = "ai camera";
network = list("Sat");
network = list("minisat");
start_active = 1
},
/obj/machinery/atmospherics/components/unary/vent_pump/on{
@@ -33977,7 +33918,7 @@
c_tag = "AI Satellite - Antechamber";
dir = 4;
name = "ai camera";
network = list("Sat");
network = list("minisat");
start_active = 1
},
/turf/open/floor/plasteel/vault/side{
+210 -167
View File
@@ -8933,16 +8933,6 @@
dir = 4
},
/area/bridge)
"axf" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/poddoor/preopen{
id = "bridgespace";
name = "bridge external shutters"
},
/turf/open/floor/plasteel/vault{
dir = 8
},
/area/bridge)
"axg" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on,
/turf/open/floor/plasteel/dark,
@@ -15026,6 +15016,9 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
/obj/structure/cable{
icon_state = "2-4"
},
/turf/open/floor/plasteel/floorgrime,
/area/quartermaster/warehouse)
"aMq" = (
@@ -15033,6 +15026,9 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
/obj/structure/cable{
icon_state = "4-8"
},
/turf/open/floor/plasteel/floorgrime,
/area/quartermaster/warehouse)
"aMr" = (
@@ -15040,6 +15036,9 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
/obj/structure/cable{
icon_state = "4-8"
},
/turf/open/floor/plasteel/floorgrime,
/area/quartermaster/warehouse)
"aMs" = (
@@ -15049,6 +15048,9 @@
/obj/structure/sign/poster/official/random{
pixel_y = 32
},
/obj/structure/cable{
icon_state = "4-8"
},
/turf/open/floor/plasteel/floorgrime,
/area/quartermaster/warehouse)
"aMt" = (
@@ -15063,6 +15065,9 @@
c_tag = "Cargo Warehouse";
dir = 2
},
/obj/structure/cable{
icon_state = "4-8"
},
/turf/open/floor/plasteel/floorgrime,
/area/quartermaster/warehouse)
"aMu" = (
@@ -15070,6 +15075,9 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
/obj/structure/cable{
icon_state = "4-8"
},
/turf/open/floor/plasteel/floorgrime,
/area/quartermaster/warehouse)
"aMv" = (
@@ -15083,6 +15091,9 @@
pixel_x = 26
},
/obj/structure/cable,
/obj/structure/cable{
icon_state = "0-8"
},
/turf/open/floor/plasteel/floorgrime,
/area/quartermaster/warehouse)
"aMw" = (
@@ -15649,6 +15660,9 @@
/obj/structure/sign/poster/official/random{
pixel_x = -32
},
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plasteel/floorgrime,
/area/quartermaster/warehouse)
"aNO" = (
@@ -16155,6 +16169,9 @@
"aOY" = (
/obj/effect/spawner/lootdrop/maintenance,
/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plasteel/floorgrime,
/area/quartermaster/warehouse)
"aOZ" = (
@@ -16542,6 +16559,9 @@
req_access_txt = "31"
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plasteel/floorgrime,
/area/quartermaster/warehouse)
"aQd" = (
@@ -17040,6 +17060,14 @@
/area/quartermaster/sorting)
"aRl" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/machinery/power/apc/highcap/fifteen_k{
dir = 4;
name = "Delivery Office APC";
pixel_x = 28
},
/obj/structure/cable{
icon_state = "0-2"
},
/turf/open/floor/plasteel,
/area/quartermaster/sorting)
"aRm" = (
@@ -17057,6 +17085,9 @@
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/effect/turf_decal/delivery,
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plasteel,
/area/quartermaster/warehouse)
"aRo" = (
@@ -17434,6 +17465,9 @@
"aSh" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plating,
/area/quartermaster/sorting)
"aSi" = (
@@ -17447,6 +17481,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
/obj/structure/cable{
icon_state = "1-2"
},
/turf/open/floor/plasteel,
/area/quartermaster/storage)
"aSj" = (
@@ -17825,6 +17862,9 @@
dir = 4
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
/obj/structure/cable{
icon_state = "1-4"
},
/turf/open/floor/plasteel,
/area/quartermaster/office)
"aTi" = (
@@ -17839,6 +17879,9 @@
departmentType = 2;
pixel_y = 32
},
/obj/structure/cable{
icon_state = "4-8"
},
/turf/open/floor/plasteel,
/area/quartermaster/storage)
"aTj" = (
@@ -17851,6 +17894,9 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 9
},
/obj/structure/cable{
icon_state = "1-8"
},
/turf/open/floor/plasteel,
/area/quartermaster/storage)
"aTl" = (
@@ -22032,8 +22078,7 @@
},
/area/maintenance/department/cargo)
"bdA" = (
/obj/item/cigbutt,
/obj/effect/spawner/lootdrop/maintenance,
/obj/machinery/droneDispenser,
/turf/open/floor/plating,
/area/maintenance/department/cargo)
"bdB" = (
@@ -26568,12 +26613,6 @@
},
/turf/open/floor/plasteel/white,
/area/science/xenobiology)
"bpp" = (
/obj/machinery/computer/camera_advanced/xenobio{
dir = 8
},
/turf/open/floor/plasteel/white,
/area/science/xenobiology)
"bpq" = (
/obj/structure/sign/warning/electricshock,
/turf/closed/wall/r_wall,
@@ -27772,9 +27811,6 @@
/turf/open/floor/plasteel/white,
/area/science/xenobiology)
"brQ" = (
/obj/machinery/computer/camera_advanced/xenobio{
dir = 8
},
/obj/machinery/camera{
c_tag = "Xenobiology Port";
dir = 8;
@@ -28377,7 +28413,7 @@
/turf/open/floor/plasteel/white,
/area/science/explab)
"btj" = (
/obj/machinery/droneDispenser,
/obj/structure/table,
/turf/open/floor/plasteel/white,
/area/science/explab)
"btk" = (
@@ -28566,11 +28602,11 @@
/turf/open/floor/plating,
/area/science/xenobiology)
"btD" = (
/turf/open/floor/plating/airless,
/turf/open/floor/plating,
/area/science/xenobiology)
"btE" = (
/obj/effect/decal/remains/xeno,
/turf/open/floor/plating/airless,
/turf/open/floor/plating,
/area/science/xenobiology)
"btF" = (
/obj/structure/chair{
@@ -29191,12 +29227,7 @@
/obj/machinery/light/small{
dir = 4
},
/obj/machinery/camera{
c_tag = "Xenobiology Kill Room";
dir = 8;
network = list("ss13","rd")
},
/turf/open/floor/plating/airless,
/turf/open/floor/plating,
/area/science/xenobiology)
"bva" = (
/turf/closed/wall,
@@ -31263,16 +31294,22 @@
/turf/open/floor/plasteel/whitepurple/side,
/area/science/xenobiology)
"bzi" = (
/obj/item/extinguisher{
pixel_x = 4;
pixel_y = 3
/obj/effect/turf_decal/stripes/line{
dir = 1
},
/obj/item/extinguisher,
/obj/structure/table/glass,
/turf/open/floor/plasteel/whitepurple/side,
/obj/item/extinguisher,
/obj/item/extinguisher{
pixel_x = 2;
pixel_y = 2
},
/obj/item/extinguisher{
pixel_x = 5;
pixel_y = 5
},
/turf/open/floor/plasteel,
/area/science/xenobiology)
"bzj" = (
/obj/structure/reagent_dispensers/watertank,
/obj/machinery/requests_console{
department = "Science";
departmentType = 2;
@@ -31280,6 +31317,7 @@
pixel_x = 32;
receive_ore_updates = 1
},
/obj/structure/reagent_dispensers/watertank/high,
/turf/open/floor/plasteel/whitepurple/side,
/area/science/xenobiology)
"bzk" = (
@@ -32314,6 +32352,9 @@
/area/crew_quarters/heads/hor)
"bBw" = (
/obj/machinery/computer/security,
/obj/machinery/light{
dir = 8
},
/turf/open/floor/plasteel/red/side{
dir = 8
},
@@ -38116,6 +38157,7 @@
},
/obj/item/stack/sheet/glass,
/obj/item/stack/rods/fifty,
/obj/item/pipe_dispenser,
/turf/open/floor/plasteel/yellow/side,
/area/engine/atmos)
"bOY" = (
@@ -40924,9 +40966,6 @@
/obj/structure/table/reinforced,
/obj/item/clipboard,
/obj/item/lighter,
/obj/item/clothing/glasses/meson{
pixel_y = 4
},
/obj/item/stamp/ce,
/obj/item/stock_parts/cell/high/plus,
/obj/machinery/keycard_auth{
@@ -40941,6 +40980,7 @@
/obj/structure/cable{
icon_state = "0-8"
},
/obj/item/clothing/glasses/meson/engine,
/turf/open/floor/plasteel/yellow/side{
dir = 4
},
@@ -42858,10 +42898,7 @@
},
/obj/effect/turf_decal/stripes/line,
/obj/item/airlock_painter,
/obj/item/clothing/glasses/meson{
pixel_x = 3;
pixel_y = -4
},
/obj/item/clothing/glasses/meson/engine,
/turf/open/floor/plasteel,
/area/engine/engineering)
"cap" = (
@@ -43196,11 +43233,11 @@
"cbe" = (
/obj/item/pen,
/obj/item/storage/belt/utility,
/obj/item/clothing/glasses/meson,
/obj/item/paper_bin{
layer = 2.9
},
/obj/structure/table/glass,
/obj/item/clothing/glasses/meson/engine,
/turf/open/floor/plasteel,
/area/engine/engineering)
"cbf" = (
@@ -43287,7 +43324,7 @@
/obj/structure/table,
/obj/item/clothing/gloves/color/yellow,
/obj/item/storage/belt/utility,
/obj/item/clothing/glasses/meson,
/obj/item/clothing/glasses/meson/engine,
/turf/open/floor/plasteel,
/area/engine/engineering)
"cbo" = (
@@ -43736,6 +43773,9 @@
/obj/item/stack/sheet/mineral/plasma{
amount = 30
},
/obj/item/device/gps{
gpstag = "ENG0"
},
/turf/open/floor/plating,
/area/engine/engineering)
"ccS" = (
@@ -45137,9 +45177,6 @@
icon_state = "0-8"
},
/obj/machinery/power/tesla_coil,
/obj/structure/window/plasma/reinforced{
dir = 4
},
/turf/open/floor/plating/airless,
/area/engine/engineering)
"chz" = (
@@ -45147,9 +45184,6 @@
icon_state = "0-4"
},
/obj/machinery/power/tesla_coil,
/obj/structure/window/plasma/reinforced{
dir = 8
},
/turf/open/floor/plating/airless,
/area/engine/engineering)
"chA" = (
@@ -45257,16 +45291,6 @@
/obj/structure/grille,
/turf/open/floor/plating/airless,
/area/engine/engineering)
"chQ" = (
/obj/structure/window/plasma/reinforced{
dir = 4
},
/obj/machinery/power/rad_collector/anchored,
/obj/structure/cable/yellow{
icon_state = "0-8"
},
/turf/open/floor/plating/airless,
/area/engine/engineering)
"chR" = (
/obj/structure/cable{
icon_state = "2-4"
@@ -45420,14 +45444,13 @@
/turf/open/floor/plating/airless,
/area/space/nearstation)
"cit" = (
/obj/machinery/the_singularitygen,
/obj/machinery/the_singularitygen/tesla,
/turf/open/floor/plating/airless,
/area/space/nearstation)
"ciu" = (
/obj/effect/turf_decal/stripes/line{
dir = 4
},
/obj/machinery/the_singularitygen/tesla,
/turf/open/floor/plating/airless,
/area/space/nearstation)
"civ" = (
@@ -49969,29 +49992,9 @@
/turf/open/floor/plasteel/white,
/area/medical/chemistry)
"cBQ" = (
/obj/machinery/power/rad_collector/anchored,
/obj/machinery/power/rad_collector,
/turf/open/floor/plating,
/area/engine/engineering)
"cBR" = (
/obj/structure/cable/yellow{
icon_state = "1-2"
},
/obj/structure/cable/yellow{
icon_state = "1-4"
},
/obj/item/tank/internals/plasma,
/turf/open/floor/plating/airless,
/area/engine/engineering)
"cBS" = (
/obj/structure/window/plasma/reinforced{
dir = 8
},
/obj/machinery/power/rad_collector/anchored,
/obj/structure/cable/yellow{
icon_state = "0-4"
},
/turf/open/floor/plating/airless,
/area/engine/engineering)
"cBT" = (
/obj/effect/spawner/structure/window/plasma/reinforced,
/turf/open/floor/plating/airless,
@@ -50152,6 +50155,16 @@
},
/turf/open/floor/plasteel,
/area/quartermaster/sorting)
"frt" = (
/obj/machinery/door/firedoor,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden{
dir = 4
},
/obj/structure/cable{
icon_state = "4-8"
},
/turf/open/floor/plasteel,
/area/quartermaster/office)
"fyh" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/obj/structure/cable{
@@ -50240,12 +50253,24 @@
},
/turf/open/floor/plating,
/area/ai_monitored/turret_protected/AIsatextAP)
"kqj" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden{
dir = 1
},
/obj/structure/cable{
icon_state = "4-8"
},
/turf/open/floor/plasteel,
/area/quartermaster/storage)
"krG" = (
/obj/structure/cable{
icon_state = "2-8"
},
/turf/open/floor/plasteel/dark,
/area/library)
"let" = (
/turf/closed/wall/r_wall,
/area/space)
"lqy" = (
/obj/machinery/door/airlock/centcom{
name = "Library"
@@ -50255,6 +50280,11 @@
/obj/machinery/door/firedoor,
/turf/open/floor/plasteel/dark,
/area/library/lounge)
"lvl" = (
/obj/effect/spawner/lootdrop/maintenance,
/obj/item/cigbutt,
/turf/open/floor/plating,
/area/maintenance/department/cargo)
"mHo" = (
/obj/structure/table,
/obj/machinery/microwave{
@@ -50286,6 +50316,15 @@
},
/turf/open/floor/carpet,
/area/library/lounge)
"nJY" = (
/obj/structure/rack,
/obj/item/stack/sheet/glass/fifty{
pixel_x = 3;
pixel_y = 3
},
/obj/item/stack/sheet/metal/fifty,
/turf/open/floor/plating,
/area/maintenance/department/cargo)
"opC" = (
/obj/machinery/light/small{
dir = 4
@@ -50445,6 +50484,10 @@
/obj/item/stack/cable_coil,
/turf/open/floor/plasteel/whitepurple/side,
/area/science/lab)
"yia" = (
/obj/structure/lattice,
/turf/open/space/basic,
/area/space)
(1,1,1) = {"
aaa
@@ -79160,8 +79203,8 @@ bXk
bXk
bXk
bXk
aaa
aaa
bXk
let
aaa
aaa
aaa
@@ -79416,9 +79459,9 @@ chR
cgt
cjT
ckq
ckq
bXk
aaa
aaa
let
aaa
aaa
aaa
@@ -79673,9 +79716,9 @@ chS
cfV
cgS
cfV
cfV
bXk
aaa
aaa
let
aaa
aaa
aaa
@@ -79929,10 +79972,10 @@ cfV
cfV
cfV
cgT
cfV
ckr
bXk
aaa
aaa
let
aaa
aaa
aaa
@@ -80179,17 +80222,17 @@ cfU
cgu
cgU
chw
cBR
chw
chw
cgU
chw
cgU
chw
cgU
cjs
cfV
cfV
bTE
aaa
aaa
cfV
bXk
let
aaa
aaa
aaa
@@ -80436,17 +80479,17 @@ cfV
cgv
cfV
chx
chQ
cfV
chx
chQ
cfV
chx
chQ
cfV
chx
cfV
cfV
bTE
abI
aaa
cfV
bXk
let
aaa
aaa
aaa
@@ -80694,16 +80737,16 @@ cgv
cgV
bBW
bBW
aaa
cgV
aht
aaa
bBW
bBW
cgV
cfV
bTE
abI
abI
cfV
bXk
let
aaa
aaa
aaa
@@ -80951,16 +80994,16 @@ cgv
bBW
bBW
bBW
aaa
yia
abI
aaa
bBW
bBW
bBW
cfV
bTE
abI
aaa
cfV
bXk
let
aaa
aaa
aaa
@@ -81215,9 +81258,9 @@ aaa
bBW
bBW
cfV
bTE
abI
aaa
cfV
bXk
let
aaa
aaa
aaa
@@ -81469,12 +81512,12 @@ cii
cis
ciG
aaa
aaa
aaa
yia
cgV
cfV
bTE
abI
aaa
cfV
bXk
let
aaa
aaa
aaa
@@ -81719,7 +81762,7 @@ cfd
cfw
cfW
cgw
cgV
aht
abI
abI
cij
@@ -81727,11 +81770,11 @@ cit
ciH
abI
abI
cgV
aht
cfV
bTE
abI
aaa
cfV
bXk
let
aaa
aaa
aaa
@@ -81976,8 +82019,8 @@ cfe
cfx
cfa
cgv
aaa
aaa
cgV
yia
aaa
cik
ciu
@@ -81986,9 +82029,9 @@ aaa
aaa
aaa
cfV
bTE
aaa
aaa
cfV
bXk
let
aaa
aaa
aaa
@@ -82243,9 +82286,9 @@ aaa
bBW
bBW
cfV
bTE
aaa
aaa
cfV
bXk
let
aaa
aaa
aaa
@@ -82495,14 +82538,14 @@ bBW
aaa
aaa
abI
aaa
yia
aaa
bBW
bBW
cfV
bTE
aaa
aaa
cfV
bXk
let
aaa
aaa
aaa
@@ -82751,15 +82794,15 @@ cgV
bBW
aaa
aaa
aht
cgV
aaa
bBW
bBW
cgV
cfV
bTE
abI
aaa
cfV
bXk
let
aaa
aaa
aaa
@@ -83006,17 +83049,17 @@ cfV
cgv
cfV
chz
cBS
cfV
chz
cBS
cfV
chz
cBS
cfV
chz
cfV
cfV
bTE
abI
abI
cfV
bXk
let
abI
abI
aaa
@@ -83174,7 +83217,7 @@ auU
atY
vTA
ayf
axf
vTA
aAF
aBz
aCP
@@ -83263,17 +83306,17 @@ cfU
cgx
cgU
chA
cgU
chA
cgU
chA
chA
chA
chA
cgU
cjt
cfV
cfV
bTE
abI
aaa
cfV
bXk
let
abI
aaa
aaa
@@ -83527,10 +83570,10 @@ cfV
cfV
cfV
cgY
cfV
cks
bXk
abI
aaa
let
aaa
aaa
aaa
@@ -83785,9 +83828,9 @@ chO
cfV
cgZ
cfV
cfV
bXk
abI
abI
let
abI
aaa
aaa
@@ -84042,9 +84085,9 @@ chP
cgt
cjU
ckq
ckq
bXk
abI
aaa
let
aaa
aaa
aaa
@@ -84299,9 +84342,9 @@ bXk
bXk
bXk
bXk
bXk
ckJ
abI
aaa
let
aaa
aaa
aaa
@@ -87058,7 +87101,7 @@ aVu
bat
aLf
bcy
aKq
lvl
aEj
aEj
bgC
@@ -87572,7 +87615,7 @@ aPY
bav
aLf
aFi
aFi
nJY
beI
bfv
bgE
@@ -89361,7 +89404,7 @@ aOW
xzr
xzr
xzr
aSY
frt
aUs
aLf
aLf
@@ -89875,7 +89918,7 @@ cDa
cDa
cDa
aLg
aTj
kqj
aUu
aVx
aVx
@@ -93238,7 +93281,7 @@ bkE
aht
bnd
boh
bpp
bpn
bqx
brQ
btr
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1 +1 @@
poojawa role=admin
+5 -4
View File
@@ -14,9 +14,10 @@
#define SOUND_ANNOUNCEMENTS 2048
#define DISABLE_DEATHRATTLE 4096
#define DISABLE_ARRIVALRATTLE 8192
#define MEDIHOUND_SLEEPER 16384
#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|MEMBER_PUBLIC|INTENT_STYLE|MIDROUND_ANTAG|SOUND_INSTRUMENTS|SOUND_SHIP_AMBIENCE|SOUND_PRAYERS|SOUND_ANNOUNCEMENTS|MEDIHOUND_SLEEPER)
#define MEDIHOUND_SLEEPER 16384 //CITADEL EDITS, vore prefs.
#define EATING_NOISES 32768
#define DIGESTION_NOISES 65536
#define TOGGLES_DEFAULT (SOUND_ADMINHELP|SOUND_MIDI|SOUND_AMBIENCE|SOUND_LOBBY|MEMBER_PUBLIC|INTENT_STYLE|MIDROUND_ANTAG|SOUND_INSTRUMENTS|SOUND_SHIP_AMBIENCE|SOUND_PRAYERS|SOUND_ANNOUNCEMENTS|MEDIHOUND_SLEEPER|EATING_NOISES|DIGESTION_NOISES)
//Chat toggles
#define CHAT_OOC 1
@@ -66,4 +67,4 @@
#define EXP_TYPE_GHOST "Ghost"
//Flags in the players table in the db
#define DB_FLAG_EXEMPT 1
#define DB_FLAG_EXEMPT 1
+3 -2
View File
@@ -11,12 +11,13 @@
//CIT CHANNELS - TRY NOT TO REGRESS
#define CHANNEL_PRED 1015
#define CHANNEL_PREYLOOP 1014
#define CHANNEL_DIGEST 1014
#define CHANNEL_PREYLOOP 1013
//THIS SHOULD ALWAYS BE THE LOWEST ONE!
//KEEP IT UPDATED
#define CHANNEL_HIGHEST_AVAILABLE 1013 //CIT CHANGE - COMPENSATES FOR VORESOUND CHANNELS
#define CHANNEL_HIGHEST_AVAILABLE 1012 //CIT CHANGE - COMPENSATES FOR VORESOUND CHANNELS
#define SOUND_MINIMUM_PRESSURE 10
+18
View File
@@ -5,6 +5,9 @@
#define DM_NOISY "Noisy"
#define DM_DRAGON "Dragon"
#define isbelly(A) istype(A, /obj/belly)
#define QDEL_NULL_LIST(x) if(x) { for(var/y in x) { qdel(y) } ; x = null }
#define VORE_STRUGGLE_EMOTE_CHANCE 40
// Stance for hostile mobs to be in while devouring someone.
@@ -60,6 +63,10 @@ GLOBAL_LIST_INIT(pred_vore_sounds, list(
"Squish3" = 'sound/vore/pred/squish_03.ogg',
"Squish4" = 'sound/vore/pred/squish_04.ogg',
"Rustle (cloth)" = 'sound/effects/rustle5.ogg',
"rustle2(cloth)" = 'sound/effects/rustle2.ogg',
"rustle3(cloth)" = 'sound/effects/rustle3.ogg',
"rustle4(cloth)" = 'sound/effects/rustle4.ogg',
"rustle5(cloth)" = 'sound/effects/rustle5.ogg',
"None" = null))
/*
GLOBAL_LIST_INIT(pred_struggle_sounds, list(
@@ -121,3 +128,14 @@ GLOBAL_LIST_INIT(death_prey, list(
"death9" = 'sound/vore/prey/death_09.ogg',
"death10" = 'sound/vore/prey/death_10.ogg'))
*/
GLOBAL_LIST_INIT(release_sound, list(
"rustle (cloth)" = 'sound/effects/rustle1.ogg',
"rustle2 (cloth)" = 'sound/effects/rustle2.ogg',
"rustle3 (cloth)" = 'sound/effects/rustle3.ogg',
"rustle4 (cloth)" = 'sound/effects/rustle4.ogg',
"rustle5 (cloth)" = 'sound/effects/rustle5.ogg',
"Stomach Move" = 'sound/vore/pred/stomachmove.ogg',
"Pred Escape" = 'sound/vore/pred/escape.ogg',
"Splatter" = 'sound/effects/splat.ogg',
"None" = null))
+4
View File
@@ -105,3 +105,7 @@
. += copytext(text, last_found, found)
last_found = found + delim_len
while (found)
// Returns true if val is from min to max, inclusive.
/proc/IsInRange(val, min, max)
return (val >= min) && (val <= max)
-1
View File
@@ -1 +0,0 @@
GLOBAL_VAR_INIT(enable_examine_tips, TRUE)
-8
View File
@@ -1,8 +0,0 @@
/mob/camera/god/UnarmedAttack(atom/A)
A.attack_god(src)
/mob/camera/god/RangedAttack(atom/A)
A.attack_god(src)
/atom/proc/attack_god(mob/user)
return
-13
View File
@@ -1,13 +0,0 @@
/datum/hud/brain/show_hud(version = 0)
if(!ismob(mymob))
return 0
if(!mymob.client)
return 0
mymob.client.screen = list()
mymob.client.screen += mymob.client.void
/mob/living/brain/create_mob_hud()
if(client && !hud_used)
hud_used = new /datum/hud/brain(src)
File diff suppressed because it is too large Load Diff
-40
View File
@@ -1,40 +0,0 @@
/obj/item/clothing/under/bb_sweater
name = "cream sweater"
desc = "Why trade style for comfort? Now you can go commando down south and still be cozy up north."
icon_state = "bb_turtle"
item_state = "w_suit"
item_color = "bb_turtle"
body_parts_covered = CHEST|ARMS
can_adjust = 1
icon = 'icons/obj/clothing/turtlenecks.dmi'
icon_override = 'icons/mob/citadel/uniforms.dmi'
/obj/item/clothing/under/bb_sweater/black
name = "black sweater"
icon_state = "bb_turtleblk"
item_state = "bl_suit"
item_color = "bb_turtleblk"
/obj/item/clothing/under/bb_sweater/purple
name = "purple sweater"
icon_state = "bb_turtlepur"
item_state = "p_suit"
item_color = "bb_turtlepur"
/obj/item/clothing/under/bb_sweater/green
name = "green sweater"
icon_state = "bb_turtlegrn"
item_state = "g_suit"
item_color = "bb_turtlegrn"
/obj/item/clothing/under/bb_sweater/red
name = "red sweater"
icon_state = "bb_turtlered"
item_state = "r_suit"
item_color = "bb_turtlered"
/obj/item/clothing/under/bb_sweater/blue
name = "blue sweater"
icon_state = "bb_turtleblu"
item_state = "b_suit"
item_color = "bb_turtleblu"
-102
View File
@@ -1,102 +0,0 @@
#define STANDARD_CHARGE 1
#define CONTRABAND_CHARGE 2
#define COIN_CHARGE 3
/obj/machinery/vending/kink
name = "KinkMate"
desc = "A vending machine for all your unmentionable desires."
icon = 'icons/obj/citvending.dmi'
icon_state = "kink"
product_slogans = "Kinky!;Sexy!;Check me out, big boy!"
vend_reply = "Have fun, you shameless pervert!"
products = list(
/obj/item/clothing/under/maid = 5,
/obj/item/clothing/under/stripper_pink = 5,
/obj/item/clothing/under/stripper_green = 5,
/obj/item/dildo/custom = 5
)
contraband = list(/obj/item/restraints/handcuffs/fake/kinky = 5,
/obj/item/clothing/neck/petcollar = 5,
/obj/item/clothing/under/mankini = 1,
/obj/item/dildo/flared/huge = 1
)
premium = list(/obj/item/device/electropack/shockcollar = 1)
refill_canister = /obj/item/vending_refill/kink
/*
/obj/machinery/vending/nazivend
name = "Nazivend"
desc = "A vending machine containing Nazi German supplies. A label reads: \"Remember the gorrilions lost.\""
icon = 'icons/obj/citvending.dmi'
icon_state = "nazi"
vend_reply = "SIEG HEIL!"
product_slogans = "Das Vierte Reich wird zuruckkehren!;ENTFERNEN JUDEN!;Billiger als die Juden jemals geben!;Rader auf dem adminbus geht rund und rund.;Warten Sie, warum wir wieder hassen Juden?- *BZZT*"
products = list(
/obj/item/clothing/head/stalhelm = 20,
/obj/item/clothing/head/panzer = 20,
/obj/item/clothing/suit/soldiercoat = 20,
// /obj/item/clothing/under/soldieruniform = 20,
/obj/item/clothing/shoes/jackboots = 20
)
contraband = list(
/obj/item/clothing/head/naziofficer = 10,
// /obj/item/clothing/suit/officercoat = 10,
// /obj/item/clothing/under/officeruniform = 10,
/obj/item/clothing/suit/space/hardsuit/nazi = 3,
/obj/item/gun/energy/plasma/MP40k = 4
)
premium = list()
refill_canister = /obj/item/vending_refill/nazi
*/
/obj/machinery/vending/sovietvend
name = "KomradeVendtink"
desc = "Rodina-mat' zovyot!"
icon = 'icons/obj/citvending.dmi'
icon_state = "soviet"
vend_reply = "The fascist and capitalist svin'ya shall fall, komrade!"
product_slogans = "Quality worth waiting in line for!; Get Hammer and Sickled!; Sosvietsky soyuz above all!; With capitalist pigsky, you would have paid a fortunetink! ; Craftink in Motherland herself!"
products = list(
/obj/item/clothing/under/soviet = 20,
/obj/item/clothing/head/ushanka = 20,
/obj/item/clothing/shoes/jackboots = 20,
/obj/item/clothing/head/squatter_hat = 20,
/obj/item/clothing/under/squatter_outfit = 20,
/obj/item/clothing/under/russobluecamooutfit = 20,
/obj/item/clothing/head/russobluecamohat = 20
)
contraband = list(
/obj/item/clothing/under/syndicate/tacticool = 4,
/obj/item/clothing/mask/balaclava = 4,
/obj/item/clothing/suit/russofurcoat = 4,
/obj/item/clothing/head/russofurhat = 4,
/obj/item/clothing/suit/space/hardsuit/soviet = 3,
/obj/item/gun/energy/laser/LaserAK = 4
)
premium = list()
refill_canister = /obj/item/vending_refill/soviet
#undef STANDARD_CHARGE
#undef CONTRABAND_CHARGE
#undef COIN_CHARGE
/obj/item/vending_refill/kink
machine_name = "KinkMate"
icon = 'modular_citadel/icons/vending_restock.dmi'
icon_state = "refill_kink"
charges = list(8, 5, 0)// of 20 standard, 12 contraband, 0 premium
init_charges = list(8, 5, 0)
/obj/item/vending_refill/nazi
machine_name = "nazivend"
icon_state = "refill_nazi"
charges = list(33, 13, 0)
init_charges = list(33, 13, 0)
/obj/item/vending_refill/soviet
machine_name = "sovietvend"
icon_state = "refill_soviet"
charges = list(47, 7, 0)
init_charges = list(47, 7, 0)
-13
View File
@@ -1,13 +0,0 @@
/proc/send2maindiscord(var/msg)
send2discord(msg, FALSE)
/proc/send2admindiscord(var/msg, var/ping = FALSE)
send2discord(msg, TRUE, ping)
/proc/send2discord(var/msg, var/admin = FALSE, var/ping = FALSE)
// if (!config.discord_url || !config.discord_password)
// return
// var/url = "[config.discord_url]?pass=[url_encode(config.discord_password)]&admin=[admin ? "true" : "false"]&content=[url_encode(msg)]&ping=[ping ? "true" : "false"]"
// world.Export(url)
return
-287
View File
@@ -1,287 +0,0 @@
GLOBAL_VAR_INIT(config_dir, "config/")
GLOBAL_PROTECT(config_dir)
/datum/controller/configuration
name = "Configuration"
var/hiding_entries_by_type = TRUE //Set for readability, admins can set this to FALSE if they want to debug it
var/list/entries
var/list/entries_by_type
var/list/maplist
var/datum/map_config/defaultmap
var/list/modes // allowed modes
var/list/gamemode_cache
var/list/votable_modes // votable modes
var/list/mode_names
var/list/mode_reports
var/list/mode_false_report_weight
/datum/controller/configuration/New()
config = src
var/list/config_files = InitEntries()
LoadModes()
for(var/I in config_files)
LoadEntries(I)
if(Get(/datum/config_entry/flag/maprotation))
loadmaplist(CONFIG_MAPS_FILE)
/datum/controller/configuration/Destroy()
entries_by_type.Cut()
QDEL_LIST_ASSOC_VAL(entries)
QDEL_LIST_ASSOC_VAL(maplist)
QDEL_NULL(defaultmap)
config = null
return ..()
/datum/controller/configuration/proc/InitEntries()
var/list/_entries = list()
entries = _entries
var/list/_entries_by_type = list()
entries_by_type = _entries_by_type
. = list()
for(var/I in typesof(/datum/config_entry)) //typesof is faster in this case
var/datum/config_entry/E = I
if(initial(E.abstract_type) == I)
continue
E = new I
_entries_by_type[I] = E
var/esname = E.name
var/datum/config_entry/test = _entries[esname]
if(test)
log_config("Error: [test.type] has the same name as [E.type]: [esname]! Not initializing [E.type]!")
qdel(E)
continue
_entries[esname] = E
.[E.resident_file] = TRUE
/datum/controller/configuration/proc/RemoveEntry(datum/config_entry/CE)
entries -= CE.name
entries_by_type -= CE.type
/datum/controller/configuration/proc/LoadEntries(filename)
log_config("Loading config file [filename]...")
var/list/lines = world.file2list("[GLOB.config_dir][filename]")
var/list/_entries = entries
for(var/L in lines)
if(!L)
continue
if(copytext(L, 1, 2) == "#")
continue
var/pos = findtext(L, " ")
var/entry = null
var/value = null
if(pos)
entry = lowertext(copytext(L, 1, pos))
value = copytext(L, pos + 1)
else
entry = lowertext(L)
if(!entry)
continue
var/datum/config_entry/E = _entries[entry]
if(!E)
log_config("Unknown setting in configuration: '[entry]'")
continue
if(filename != E.resident_file)
log_config("Found [entry] in [filename] when it should have been in [E.resident_file]! Ignoring.")
continue
var/validated = E.ValidateAndSet(value)
if(!validated)
log_config("Failed to validate setting \"[value]\" for [entry]")
else if(E.modified && !E.dupes_allowed)
log_config("Duplicate setting for [entry] ([value]) detected! Using latest.")
if(validated)
E.modified = TRUE
/datum/controller/configuration/can_vv_get(var_name)
return (var_name != "entries_by_type" || !hiding_entries_by_type) && ..()
/datum/controller/configuration/vv_edit_var(var_name, var_value)
return !(var_name in list("entries_by_type", "entries")) && ..()
/datum/controller/configuration/stat_entry()
if(!statclick)
statclick = new/obj/effect/statclick/debug(null, "Edit", src)
stat("[name]:", statclick)
/datum/controller/configuration/proc/Get(entry_type)
if(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Get" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
log_admin_private("Config access of [entry_type] attempted by [key_name(usr)]")
return
var/datum/config_entry/E = entry_type
var/entry_is_abstract = initial(E.abstract_type) == entry_type
if(entry_is_abstract)
CRASH("Tried to retrieve an abstract config_entry: [entry_type]")
E = entries_by_type[entry_type]
if(!E)
CRASH("Missing config entry for [entry_type]!")
return E.value
/datum/controller/configuration/proc/Set(entry_type, new_val)
if(IsAdminAdvancedProcCall() && GLOB.LastAdminCalledProc == "Set" && GLOB.LastAdminCalledTargetRef == "\ref[src]")
log_admin_private("Config rewrite of [entry_type] to [new_val] attempted by [key_name(usr)]")
return
var/datum/config_entry/E = entry_type
var/entry_is_abstract = initial(E.abstract_type) == entry_type
if(entry_is_abstract)
CRASH("Tried to retrieve an abstract config_entry: [entry_type]")
E = entries_by_type[entry_type]
if(!E)
CRASH("Missing config entry for [entry_type]!")
return E.ValidateAndSet(new_val)
/datum/controller/configuration/proc/LoadModes()
gamemode_cache = typecacheof(/datum/game_mode, TRUE)
modes = list()
mode_names = list()
mode_reports = list()
mode_false_report_weight = list()
votable_modes = list()
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
for(var/T in gamemode_cache)
// I wish I didn't have to instance the game modes in order to look up
// their information, but it is the only way (at least that I know of).
var/datum/game_mode/M = new T()
if(M.config_tag)
if(!(M.config_tag in modes)) // ensure each mode is added only once
modes += M.config_tag
mode_names[M.config_tag] = M.name
probabilities[M.config_tag] = M.probability
mode_reports[M.config_tag] = M.generate_report()
mode_false_report_weight[M.config_tag] = M.false_report_weight
if(M.votable)
votable_modes += M.config_tag
qdel(M)
votable_modes += "secret"
/datum/controller/configuration/proc/loadmaplist(filename)
filename = "[GLOB.config_dir][filename]"
var/list/Lines = world.file2list(filename)
var/datum/map_config/currentmap = null
for(var/t in Lines)
if(!t)
continue
t = trim(t)
if(length(t) == 0)
continue
else if(copytext(t, 1, 2) == "#")
continue
var/pos = findtext(t, " ")
var/command = null
var/data = null
if(pos)
command = lowertext(copytext(t, 1, pos))
data = copytext(t, pos + 1)
else
command = lowertext(t)
if(!command)
continue
if (!currentmap && command != "map")
continue
switch (command)
if ("map")
currentmap = new ("_maps/[data].json")
if(currentmap.defaulted)
log_config("Failed to load map config for [data]!")
if ("minplayers","minplayer")
currentmap.config_min_users = text2num(data)
if ("maxplayers","maxplayer")
currentmap.config_max_users = text2num(data)
if ("weight","voteweight")
currentmap.voteweight = text2num(data)
if ("default","defaultmap")
defaultmap = currentmap
if ("endmap")
LAZYINITLIST(maplist)
maplist[currentmap.map_name] = currentmap
currentmap = null
if ("disabled")
currentmap = null
else
WRITE_FILE(GLOB.config_error_log, "Unknown command in map vote config: '[command]'")
/datum/controller/configuration/proc/pick_mode(mode_name)
// I wish I didn't have to instance the game modes in order to look up
// their information, but it is the only way (at least that I know of).
// ^ This guy didn't try hard enough
for(var/T in gamemode_cache)
var/datum/game_mode/M = T
var/ct = initial(M.config_tag)
if(ct && ct == mode_name)
return new T
return new /datum/game_mode/extended()
/datum/controller/configuration/proc/get_runnable_modes()
var/list/datum/game_mode/runnable_modes = new
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
var/list/min_pop = Get(/datum/config_entry/keyed_number_list/min_pop)
var/list/max_pop = Get(/datum/config_entry/keyed_number_list/max_pop)
var/list/repeated_mode_adjust = Get(/datum/config_entry/number_list/repeated_mode_adjust)
for(var/T in gamemode_cache)
var/datum/game_mode/M = new T()
if(!(M.config_tag in modes))
qdel(M)
continue
if(probabilities[M.config_tag]<=0)
qdel(M)
continue
if(min_pop[M.config_tag])
M.required_players = min_pop[M.config_tag]
if(max_pop[M.config_tag])
M.maximum_players = max_pop[M.config_tag]
if(M.can_start())
var/final_weight = probabilities[M.config_tag]
if(SSpersistence.saved_modes.len == 3 && repeated_mode_adjust.len == 3)
var/recent_round = min(SSpersistence.saved_modes.Find(M.config_tag),3)
var/adjustment = 0
while(recent_round)
adjustment += repeated_mode_adjust[recent_round]
recent_round = SSpersistence.saved_modes.Find(M.config_tag,recent_round+1,0)
final_weight *= ((100-adjustment)/100)
runnable_modes[M] = final_weight
return runnable_modes
/datum/controller/configuration/proc/get_runnable_midround_modes(crew)
var/list/datum/game_mode/runnable_modes = new
var/list/probabilities = Get(/datum/config_entry/keyed_number_list/probability)
var/list/min_pop = Get(/datum/config_entry/keyed_number_list/min_pop)
var/list/max_pop = Get(/datum/config_entry/keyed_number_list/max_pop)
for(var/T in (gamemode_cache - SSticker.mode.type))
var/datum/game_mode/M = new T()
if(!(M.config_tag in modes))
qdel(M)
continue
if(probabilities[M.config_tag]<=0)
qdel(M)
continue
if(min_pop[M.config_tag])
M.required_players = min_pop[M.config_tag]
if(max_pop[M.config_tag])
M.maximum_players = max_pop[M.config_tag]
if(M.required_players <= crew)
if(M.maximum_players >= 0 && M.maximum_players < crew)
continue
runnable_modes[M] = probabilities[M.config_tag]
return runnable_modes
-87
View File
@@ -1,87 +0,0 @@
/**
* Startup hook.
* Called in world.dm when the server starts.
*/
/hook/startup
/**
* Roundstart hook.
* Called in gameticker.dm when a round starts.
*/
/hook/roundstart
/**
* Roundend hook.
* Called in gameticker.dm when a round ends.
*/
/hook/roundend
/**
* Death hook.
* Called in death.dm when someone dies.
* Parameters: var/mob/living/carbon/human, var/gibbed
*/
/hook/death
/**
* Cloning hook.
* Called in cloning.dm when someone is brought back by the wonders of modern science.
* Parameters: var/mob/living/carbon/human
*/
/hook/clone
/**
* Debrained hook.
* Called in brain_item.dm when someone gets debrained.
* Parameters: var/obj/item/organ/brain
*/
/hook/debrain
/**
* Borged hook.
* Called in robot_parts.dm when someone gets turned into a cyborg.
* Parameters: var/mob/living/silicon/robot
*/
/hook/borgify
/**
* Podman hook.
* Called in podmen.dm when someone is brought back as a Diona.
* Parameters: var/mob/living/carbon/alien/diona
*/
/hook/harvest_podman
/**
* Payroll revoked hook.
* Called in Accounts_DB.dm when someone's payroll is stolen at the Accounts terminal.
* Parameters: var/datum/money_account
*/
/hook/revoke_payroll
/**
* Account suspension hook.
* Called in Accounts_DB.dm when someone's account is suspended or unsuspended at the Accounts terminal.
* Parameters: var/datum/money_account
*/
/hook/change_account_status
/**
* Employee reassignment hook.
* Called in card.dm when someone's card is reassigned at the HoP's desk.
* Parameters: var/obj/item/card/id
*/
/hook/reassign_employee
/**
* Employee terminated hook.
* Called in card.dm when someone's card is terminated at the HoP's desk.
* Parameters: var/obj/item/card/id
*/
/hook/terminate_employee
/**
* Crate sold hook.
* Called in supplyshuttle.dm when a crate is sold on the shuttle.
* Parameters: var/obj/structure/closet/crate/sold, var/area/shuttle
*/
/hook/sell_crate
-510
View File
@@ -1,510 +0,0 @@
SUBSYSTEM_DEF(explosion)
priority = 99
wait = 1
flags = SS_TICKER|SS_NO_INIT
var/list/explosions
var/rebuild_tick_split_count = FALSE
var/tick_portions_required = 0
var/list/logs
var/list/zlevels_that_ignore_bombcap
var/list/doppler_arrays
//legacy caps, set by config
var/devastation_cap = 3
var/heavy_cap = 7
var/light_cap = 14
var/flash_cap = 14
var/flame_cap = 14
var/dyn_ex_scale = 0.5
var/id_counter = 0
/datum/controller/subsystem/explosion/PreInit()
doppler_arrays = list()
logs = list()
explosions = list()
zlevels_that_ignore_bombcap = list("[ZLEVEL_MINING]")
/datum/controller/subsystem/explosion/Shutdown()
QDEL_LIST(explosions)
QDEL_LIST(logs)
zlevels_that_ignore_bombcap.Cut()
/datum/controller/subsystem/explosion/Recover()
explosions = SSexplosion.explosions
logs = SSexplosion.logs
id_counter = SSexplosion.id_counter
rebuild_tick_split_count = TRUE
zlevels_that_ignore_bombcap = SSexplosion.zlevels_that_ignore_bombcap
doppler_arrays = SSexplosion.doppler_arrays
devastation_cap = SSexplosion.devastation_cap
heavy_cap = SSexplosion.heavy_cap
light_cap = SSexplosion.light_cap
flash_cap = SSexplosion.flash_cap
flame_cap = SSexplosion.flame_cap
dyn_ex_scale = SSexplosion.dyn_ex_scale
/datum/controller/subsystem/explosion/fire()
var/list/cached_explosions = explosions
var/num_explosions = cached_explosions.len
if(!num_explosions)
return
//figure exactly how many tick splits are required
var/num_splits
if(rebuild_tick_split_count)
var/reactionary = config.reactionary_explosions
num_splits = num_explosions
for(var/I in cached_explosions)
var/datum/explosion/E = I
if(!E.turfs_processed)
++num_splits
if(reactionary && !E.densities_processed)
++num_splits
tick_portions_required = num_splits
else
num_splits = tick_portions_required
MC_SPLIT_TICK_INIT(num_splits)
for(var/I in cached_explosions)
var/datum/explosion/E = I
var/etp = E.turfs_processed
if(!etp)
if(GatherTurfs(E))
--tick_portions_required
etp = TRUE
MC_SPLIT_TICK
var/edp = E.densities_processed
if(!edp)
if(DensityCalculate(E, etp))
--tick_portions_required
edp = TRUE
MC_SPLIT_TICK
if(ProcessExplosion(E, edp)) //splits the tick
--tick_portions_required
explosions -= E
logs += E
NotifyDopplers(E)
MC_SPLIT_TICK
/datum/controller/subsystem/explosion/proc/NotifyDopplers(datum/explosion/E)
for(var/array in doppler_arrays)
var/obj/machinery/doppler_array/A = array
A.sense_explosion(E.epicenter, E.devastation, E.heavy, E.light, E.finished_at - E.started_at, E.orig_dev_range, E.orig_heavy_range, E.orig_light_range)
/datum/controller/subsystem/explosion/proc/Create(atom/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = TRUE, ignorecap = FALSE, flame_range = 0 , silent = FALSE, smoke = FALSE)
epicenter = get_turf(epicenter)
if(!epicenter)
return
if(adminlog)
message_admins("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in area: [get_area(epicenter)] [ADMIN_COORDJMP(epicenter)]")
log_game("Explosion with size ([devastation_range], [heavy_impact_range], [light_impact_range], [flame_range]) in area [epicenter.loc.name] ([epicenter.x],[epicenter.y],[epicenter.z])")
var/datum/explosion/E = new(++id_counter, epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, flame_range, silent, smoke, ignorecap)
if(heavy_impact_range > 1)
var/datum/effect_system/explosion/Eff
if(smoke)
Eff = new /datum/effect_system/explosion/smoke
else
Eff = new
Eff.set_up(epicenter)
Eff.start()
//flash mobs
if(flash_range)
for(var/mob/living/L in viewers(flash_range, epicenter))
L.flash_act()
if(!silent)
ExplosionSound(epicenter, devastation_range, heavy_impact_range, E.extent)
//add to SS
if(E.extent)
tick_portions_required += 2 + (config.reactionary_explosions ? 1 : 0)
explosions += E
else
logs += E //Already done processing
/datum/controller/subsystem/explosion/proc/CreateDynamic(atom/epicenter, power, flash_range, adminlog = TRUE, ignorecap = TRUE, flame_range = 0 , silent = FALSE, smoke = TRUE)
if(!power)
return
var/range = round((2 * power) ** dyn_ex_scale)
Create(epicenter, round(range * 0.25), round(range * 0.5), round(range), flash_range*range, adminlog, ignorecap, flame_range*range, silent, smoke)
// Using default dyn_ex scale:
// 100 explosion power is a (5, 10, 20) explosion.
// 75 explosion power is a (4, 8, 17) explosion.
// 50 explosion power is a (3, 7, 14) explosion.
// 25 explosion power is a (2, 5, 10) explosion.
// 10 explosion power is a (1, 3, 6) explosion.
// 5 explosion power is a (0, 1, 3) explosion.
// 1 explosion power is a (0, 0, 1) explosion.
/datum/explosion
var/explosion_id
var/turf/epicenter
var/started_at
var/finished_at
var/tick_started
var/tick_finished
var/turfs_processed = FALSE
var/densities_processed = FALSE
var/orig_dev_range
var/orig_heavy_range
var/orig_light_range
var/orig_flash_range
var/orig_flame_range
var/devastation
var/heavy
var/light
var/extent
var/flash
var/flame
var/gather_dist = 0
var/list/gathered_turfs
var/list/calculated_turfs
var/list/unsafe_turfs
/datum/explosion/New(id, turf/epi, devastation_range, heavy_impact_range, light_impact_range, flash_range, flame_range, silent, smoke, ignorecap)
explosion_id = id
epicenter = epi
densities_processed = !config.reactionary_explosions
orig_dev_range = devastation_range
orig_heavy_range = heavy_impact_range
orig_light_range = light_impact_range
orig_flash_range = flash_range
orig_flame_range = flame_range
if(!ignorecap && !("[epicenter.z]" in SSexplosion.zlevels_that_ignore_bombcap))
//Clamp all values
devastation_range = min(SSexplosion.devastation_cap, devastation_range)
heavy_impact_range = min(SSexplosion.heavy_cap, heavy_impact_range)
light_impact_range = min(SSexplosion.light_cap, light_impact_range)
flash_range = min(SSexplosion.flash_cap, flash_range)
flame_range = min(SSexplosion.flame_cap, flame_range)
//store this
devastation = devastation_range
heavy = heavy_impact_range
light = light_impact_range
extent = max(devastation_range, heavy_impact_range, light_impact_range, flame_range)
flash = flash_range
flame = flame_range
started_at = REALTIMEOFDAY
tick_started = world.time
gathered_turfs = list()
calculated_turfs = list()
unsafe_turfs = list()
// Play sounds; we want sounds to be different depending on distance so we will manually do it ourselves.
// Stereo users will also hear the direction of the explosion!
// Calculate far explosion sound range. Only allow the sound effect for heavy/devastating explosions.
// 3/7/14 will calculate to 80 + 35
/proc/ExplosionSound(turf/epicenter, devastation_range, heavy_impact_range, extent)
var/far_dist = 0
far_dist += heavy_impact_range * 5
far_dist += devastation_range * 20
var/z0 = epicenter.z
var/frequency = get_rand_frequency()
var/ex_sound = get_sfx("explosion")
for(var/mob/M in GLOB.player_list)
// Double check for client
var/turf/M_turf = get_turf(M)
if(M_turf && M_turf.z == z0)
var/dist = get_dist(M_turf, epicenter)
// If inside the blast radius + world.view - 2
if(dist <= round(extent + world.view - 2, 1))
M.playsound_local(epicenter, ex_sound, 100, 1, frequency, falloff = 5)
// You hear a far explosion if you're outside the blast radius. Small bombs shouldn't be heard all over the station.
else if(dist <= far_dist)
var/far_volume = Clamp(far_dist, 30, 50) // Volume is based on explosion size and dist
far_volume += (dist <= far_dist * 0.5 ? 50 : 0) // add 50 volume if the mob is pretty close to the explosion
M.playsound_local(epicenter, 'sound/effects/explosionfar.ogg', far_volume, 1, frequency, falloff = 5)
/datum/explosion/Destroy()
SSexplosion.explosions -= src
SSexplosion.logs -= src
LAZYCLEARLIST(gathered_turfs)
LAZYCLEARLIST(calculated_turfs)
LAZYCLEARLIST(unsafe_turfs)
return ..()
/datum/controller/subsystem/explosion/proc/GatherTurfs(datum/explosion/E)
var/turf/epicenter = E.epicenter
var/x0 = epicenter.x
var/y0 = epicenter.y
var/z0 = epicenter.z
var/c_dist = E.gather_dist
var/dist = E.extent
var/list/L = E.gathered_turfs
if(!c_dist)
L += epicenter
++c_dist
while( c_dist <= dist )
var/y = y0 + c_dist
var/x = x0 - c_dist + 1
for(x in x to x0 + c_dist)
var/turf/T = locate(x, y, z0)
if(T)
L += T
y = y0 + c_dist - 1
x = x0 + c_dist
for(y in y0 - c_dist to y)
var/turf/T = locate(x, y, z0)
if(T)
L += T
y = y0 - c_dist
x = x0 + c_dist - 1
for(x in x0 - c_dist to x)
var/turf/T = locate(x, y, z0)
if(T)
L += T
y = y0 - c_dist + 1
x = x0 - c_dist
for(y in y to y0 + c_dist)
var/turf/T = locate(x, y, z0)
if(T)
L += T
++c_dist
if(MC_TICK_CHECK)
break
if(c_dist > dist)
E.turfs_processed = TRUE
return TRUE
else
E.gather_dist = c_dist
return FALSE
/datum/controller/subsystem/explosion/proc/DensityCalculate(datum/explosion/E, done_gathering_turfs)
var/list/L = E.calculated_turfs
var/cut_to = 1
for(var/I in E.gathered_turfs) // we cache the explosion block rating of every turf in the explosion area
var/turf/T = I
++cut_to
var/current_exp_block = T.density ? T.explosion_block : 0
for(var/obj/machinery/door/D in T)
if(D.density)
current_exp_block += D.explosion_block
for(var/obj/structure/window/W in T)
if(W.reinf && W.fulltile)
current_exp_block += W.explosion_block
for(var/obj/structure/blob/B in T)
current_exp_block += B.explosion_block
L[T] = current_exp_block
if(MC_TICK_CHECK)
E.gathered_turfs.Cut(1, cut_to)
return FALSE
E.gathered_turfs.Cut()
return done_gathering_turfs
/datum/controller/subsystem/explosion/proc/ProcessExplosion(datum/explosion/E, done_calculating_turfs)
//cache shit for speed
var/id = E.explosion_id
var/list/cached_unsafe = E.unsafe_turfs
var/list/cached_exp_block = E.calculated_turfs
var/list/affected_turfs = cached_exp_block ? cached_exp_block : E.gathered_turfs
var/devastation_range = E.devastation
var/heavy_impact_range = E.heavy
var/light_impact_range = E.light
var/flame_range = E.flame
var/throw_range_max = E.extent
var/turf/epi = E.epicenter
var/x0 = epi.x
var/y0 = epi.y
var/cut_to = 1
for(var/TI in affected_turfs)
var/turf/T = TI
++cut_to
var/init_dist = cheap_hypotenuse(T.x, T.y, x0, y0)
var/dist = init_dist
if(cached_exp_block)
var/turf/Trajectory = T
while(Trajectory != epi)
Trajectory = get_step_towards(Trajectory, epi)
dist += cached_exp_block[Trajectory]
var/flame_dist = dist < flame_range
var/throw_dist = dist
if(dist < devastation_range)
dist = 1
else if(dist < heavy_impact_range)
dist = 2
else if(dist < light_impact_range)
dist = 3
else
dist = 0
//------- EX_ACT AND TURF FIRES -------
if(flame_dist && prob(40) && !isspaceturf(T) && !T.density)
new /obj/effect/hotspot(T) //Mostly for ambience!
if(dist > 0)
T.explosion_level = max(T.explosion_level, dist) //let the bigger one have it
T.explosion_id = id
T.ex_act(dist)
cached_unsafe += T
//--- THROW ITEMS AROUND ---
var/throw_dir = get_dir(epi, T)
for(var/obj/item/I in T)
if(!I.anchored)
var/throw_range = rand(throw_dist, throw_range_max)
var/turf/throw_at = get_ranged_target_turf(I, throw_dir, throw_range)
I.throw_speed = 4 //Temporarily change their throw_speed for embedding purposes (Resets when it finishes throwing, regardless of hitting anything)
I.throw_at(throw_at, throw_range, 4)
if(MC_TICK_CHECK)
var/circumference = (PI * (init_dist + 4) * 2) //+4 to radius to prevent shit gaps
if(cached_unsafe.len > circumference) //only do this every revolution
for(var/Unexplode in cached_unsafe)
var/turf/UnexplodeT = Unexplode
UnexplodeT.explosion_level = 0
cached_unsafe.Cut()
done_calculating_turfs = FALSE
break
affected_turfs.Cut(1, cut_to)
if(!done_calculating_turfs)
return FALSE
//unfuck the shit
for(var/Unexplode in cached_unsafe)
var/turf/UnexplodeT = Unexplode
UnexplodeT.explosion_level = 0
cached_unsafe.Cut()
E.finished_at = REALTIMEOFDAY
E.tick_finished = world.time
return TRUE
/client/proc/check_bomb_impacts()
set name = "Check Bomb Impact"
set category = "Debug"
var/newmode = alert("Use reactionary explosions?","Check Bomb Impact", "Yes", "No")
var/turf/epicenter = get_turf(mob)
if(!epicenter)
return
var/x0 = epicenter.x
var/y0 = epicenter.y
var/dev = 0
var/heavy = 0
var/light = 0
var/list/choices = list("Small Bomb","Medium Bomb","Big Bomb","Custom Bomb")
var/choice = input("Bomb Size?") in choices
switch(choice)
if(null)
return 0
if("Small Bomb")
dev = 1
heavy = 2
light = 3
if("Medium Bomb")
dev = 2
heavy = 3
light = 4
if("Big Bomb")
dev = 3
heavy = 5
light = 7
if("Custom Bomb")
dev = input("Devestation range (Tiles):") as num
heavy = input("Heavy impact range (Tiles):") as num
light = input("Light impact range (Tiles):") as num
else
return
var/datum/explosion/E = new(null, epicenter, dev, heavy, light, ignorecap = TRUE)
while(!SSexplosion.GatherTurfs(E))
stoplag()
var/list/turfs
if(newmode)
while(!SSexplosion.DensityCalculate(E, TRUE))
stoplag()
turfs = E.calculated_turfs.Copy()
else
turfs = E.gathered_turfs.Copy()
qdel(E)
for(var/I in turfs)
var/turf/T = I
var/dist = cheap_hypotenuse(T.x, T.y, x0, y0) + turfs[T]
if(dist < dev)
T.color = "red"
T.maptext = "Dev"
else if (dist < heavy)
T.color = "yellow"
T.maptext = "Heavy"
else if (dist < light)
T.color = "blue"
T.maptext = "Light"
CHECK_TICK
sleep(100)
for(var/I in turfs)
var/turf/T = I
T.color = null
T.maptext = null
-42
View File
@@ -1,42 +0,0 @@
#define PING_BUFFER_TIME 25
SUBSYSTEM_DEF(ping)
name = "Ping"
wait = 6
flags = SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
priority = 10
var/list/currentrun
/datum/controller/subsystem/ping/Initialize()
if (config.hub)
world.visibility = 1
..()
/datum/controller/subsystem/ping/fire(resumed = FALSE)
if (!resumed)
src.currentrun = GLOB.clients.Copy()
var/round_started = Master.round_started
var/list/currentrun = src.currentrun
while (length(currentrun))
var/client/C = currentrun[currentrun.len]
currentrun.len--
if (!C || world.time - C.connection_time < PING_BUFFER_TIME || C.inactivity >= (wait-1))
if (MC_TICK_CHECK)
return
continue
if(round_started && C.is_afk(INACTIVITY_KICK))
if(!istype(C.mob, /mob/dead))
log_access("AFK: [key_name(C)]")
to_chat(C, "<span class='danger'>You have been inactive for more than 10 minutes and have been disconnected.</span>")
qdel(C)
winset(C, null, "command=.update_ping+[world.time+world.tick_lag*world.tick_usage/100]")
if (MC_TICK_CHECK) //one day, when ss13 has 1000 people per server, you guys are gonna be glad I added this tick check
return
currentrun = null
#undef PING_BUFFER_TIME
+41
View File
@@ -0,0 +1,41 @@
#define SSBELLIES_PROCESSED 1
#define SSBELLIES_IGNORED 2
//
// Bellies subsystem - Process vore bellies
//
SUBSYSTEM_DEF(bellies)
name = "Bellies"
priority = 5
wait = 1 SECONDS
flags = SS_KEEP_TIMING|SS_NO_INIT
runlevels = RUNLEVEL_GAME|RUNLEVEL_POSTGAME
var/static/list/belly_list = list()
var/list/currentrun = list()
var/ignored_bellies = 0
/datum/controller/subsystem/bellies/stat_entry()
..("#: [belly_list.len] | P: [ignored_bellies]")
/datum/controller/subsystem/bellies/fire(resumed = 0)
if (!resumed)
ignored_bellies = 0
src.currentrun = belly_list.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
var/times_fired = src.times_fired
while(currentrun.len)
var/obj/belly/B = currentrun[currentrun.len]
currentrun.len--
if(QDELETED(B))
belly_list -= B
else
if(B.process_belly(times_fired,wait) == SSBELLIES_IGNORED)
ignored_bellies++
if (MC_TICK_CHECK)
return
-182
View File
@@ -1,182 +0,0 @@
#define ABDUCTOR_MAX_TEAMS 4
/datum/antagonist/abductor
name = "Abductor"
roundend_category = "abductors"
antagpanel_category = "Abductor"
job_rank = ROLE_ABDUCTOR
show_in_antagpanel = FALSE //should only show subtypes
var/datum/team/abductor_team/team
var/sub_role
var/outfit
var/landmark_type
var/greet_text
/datum/antagonist/abductor/agent
name = "Abductor Agent"
sub_role = "Agent"
outfit = /datum/outfit/abductor/agent
landmark_type = /obj/effect/landmark/abductor/agent
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
show_in_antagpanel = TRUE
/datum/antagonist/abductor/scientist
name = "Abductor Scientist"
sub_role = "Scientist"
outfit = /datum/outfit/abductor/scientist
landmark_type = /obj/effect/landmark/abductor/scientist
greet_text = "Use your stealth technology and equipment to incapacitate humans for your scientist to retrieve."
show_in_antagpanel = TRUE
/datum/antagonist/abductor/create_team(datum/team/abductor_team/new_team)
if(!new_team)
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
team = new_team
/datum/antagonist/abductor/get_team()
return team
/datum/antagonist/abductor/on_gain()
SSticker.mode.abductors += owner
owner.special_role = "[name] [sub_role]"
owner.assigned_role = "[name] [sub_role]"
owner.objectives += team.objectives
finalize_abductor()
return ..()
/datum/antagonist/abductor/on_removal()
SSticker.mode.abductors -= owner
owner.objectives -= team.objectives
if(owner.current)
to_chat(owner.current,"<span class='userdanger'>You are no longer the [owner.special_role]!</span>")
owner.special_role = null
return ..()
/datum/antagonist/abductor/greet()
to_chat(owner.current, "<span class='notice'>You are the [owner.special_role]!</span>")
to_chat(owner.current, "<span class='notice'>With the help of your teammate, kidnap and experiment on station crew members!</span>")
to_chat(owner.current, "<span class='notice'>[greet_text]</span>")
owner.announce_objectives()
/datum/antagonist/abductor/proc/finalize_abductor()
//Equip
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/abductor)
H.real_name = "[team.name] [sub_role]"
H.equipOutfit(outfit)
//Teleport to ship
for(var/obj/effect/landmark/abductor/LM in GLOB.landmarks_list)
if(istype(LM, landmark_type) && LM.team_number == team.team_number)
H.forceMove(LM.loc)
break
SSticker.mode.update_abductor_icons_added(owner)
/datum/antagonist/abductor/scientist/finalize_abductor()
..()
var/mob/living/carbon/human/H = owner.current
var/datum/species/abductor/A = H.dna.species
A.scientist = TRUE
/datum/antagonist/abductor/admin_add(datum/mind/new_owner,mob/admin)
var/list/current_teams = list()
for(var/datum/team/abductor_team/T in get_all_teams(/datum/team/abductor_team))
current_teams[T.name] = T
var/choice = input(admin,"Add to which team ?") as null|anything in (current_teams + "new team")
if (choice == "new team")
team = new
else if(choice in current_teams)
team = current_teams[choice]
else
return
new_owner.add_antag_datum(src)
log_admin("[key_name(usr)] made [key_name(new_owner.current)] [name] on [choice]!")
message_admins("[key_name_admin(usr)] made [key_name_admin(new_owner.current)] [name] on [choice] !")
/datum/antagonist/abductor/get_admin_commands()
. = ..()
.["Equip"] = CALLBACK(src,.proc/admin_equip)
/datum/antagonist/abductor/proc/admin_equip(mob/admin)
if(!ishuman(owner.current))
to_chat(admin, "<span class='warning'>This only works on humans!</span>")
return
var/mob/living/carbon/human/H = owner.current
var/gear = alert(admin,"Agent or Scientist Gear","Gear","Agent","Scientist")
if(gear)
if(gear=="Agent")
H.equipOutfit(/datum/outfit/abductor/agent)
else
H.equipOutfit(/datum/outfit/abductor/scientist)
/datum/team/abductor_team
member_name = "abductor"
var/team_number
var/list/datum/mind/abductees = list()
var/static/team_count = 1
/datum/team/abductor_team/New()
..()
team_number = team_count++
name = "Mothership [pick(GLOB.possible_changeling_IDs)]" //TODO Ensure unique and actual alieny names
add_objective(new/datum/objective/experiment)
/datum/team/abductor_team/is_solo()
return FALSE
/datum/team/abductor_team/proc/add_objective(datum/objective/O)
O.team = src
O.update_explanation_text()
objectives += O
/datum/team/abductor_team/roundend_report()
var/list/result = list()
var/won = TRUE
for(var/datum/objective/O in objectives)
if(!O.check_completion())
won = FALSE
if(won)
result += "<span class='greentext big'>[name] team fulfilled its mission!</span>"
else
result += "<span class='redtext big'>[name] team failed its mission.</span>"
result += "<span class='header'>The abductors of [name] were:</span>"
for(var/datum/mind/abductor_mind in members)
result += printplayer(abductor_mind)
result += printobjectives(abductor_mind)
return result.Join("<br>")
/datum/antagonist/abductee
name = "Abductee"
roundend_category = "abductees"
antagpanel_category = "Abductee"
/datum/antagonist/abductee/on_gain()
give_objective()
. = ..()
/datum/antagonist/abductee/greet()
to_chat(owner, "<span class='warning'><b>Your mind snaps!</b></span>")
to_chat(owner, "<big><span class='warning'><b>You can't remember how you got here...</b></span></big>")
owner.announce_objectives()
/datum/antagonist/abductee/proc/give_objective()
var/mob/living/carbon/human/H = owner.current
if(istype(H))
H.gain_trauma_type(BRAIN_TRAUMA_MILD)
var/objtype = (prob(75) ? /datum/objective/abductee/random : pick(subtypesof(/datum/objective/abductee/) - /datum/objective/abductee/random))
var/datum/objective/abductee/O = new objtype()
objectives += O
owner.objectives += objectives
/datum/antagonist/abductee/apply_innate_effects(mob/living/mob_override)
SSticker.mode.update_abductor_icons_added(mob_override ? mob_override.mind : owner)
/datum/antagonist/abductee/remove_innate_effects(mob/living/mob_override)
SSticker.mode.update_abductor_icons_removed(mob_override ? mob_override.mind : owner)
-246
View File
@@ -1,246 +0,0 @@
GLOBAL_LIST_EMPTY(antagonists)
/datum/antagonist
var/name = "Antagonist"
var/roundend_category = "other antagonists" //Section of roundend report, datums with same category will be displayed together, also default header for the section
var/show_in_roundend = TRUE //Set to false to hide the antagonists from roundend report
var/datum/mind/owner //Mind that owns this datum
var/silent = FALSE //Silent will prevent the gain/lose texts to show
var/can_coexist_with_others = TRUE //Whether or not the person will be able to have more than one datum
var/list/typecache_datum_blacklist = list() //List of datums this type can't coexist with
var/delete_on_mind_deletion = TRUE
var/job_rank
var/replace_banned = TRUE //Should replace jobbaned player with ghosts if granted.
var/list/objectives = list()
var/antag_memory = ""//These will be removed with antag datum
//Antag panel properties
var/show_in_antagpanel = TRUE //This will hide adding this antag type in antag panel, use only for internal subtypes that shouldn't be added directly but still show if possessed by mind
var/antagpanel_category = "Uncategorized" //Antagpanel will display these together, REQUIRED
/datum/antagonist/New()
GLOB.antagonists += src
typecache_datum_blacklist = typecacheof(typecache_datum_blacklist)
/datum/antagonist/Destroy()
GLOB.antagonists -= src
if(owner)
LAZYREMOVE(owner.antag_datums, src)
owner = null
return ..()
/datum/antagonist/proc/can_be_owned(datum/mind/new_owner)
. = TRUE
var/datum/mind/tested = new_owner || owner
if(tested.has_antag_datum(type))
return FALSE
for(var/i in tested.antag_datums)
var/datum/antagonist/A = i
if(is_type_in_typecache(src, A.typecache_datum_blacklist))
return FALSE
//This will be called in add_antag_datum before owner assignment.
//Should return antag datum without owner.
/datum/antagonist/proc/specialization(datum/mind/new_owner)
return src
/datum/antagonist/proc/on_body_transfer(mob/living/old_body, mob/living/new_body)
remove_innate_effects(old_body)
apply_innate_effects(new_body)
//This handles the application of antag huds/special abilities
/datum/antagonist/proc/apply_innate_effects(mob/living/mob_override)
return
//This handles the removal of antag huds/special abilities
/datum/antagonist/proc/remove_innate_effects(mob/living/mob_override)
return
//Assign default team and creates one for one of a kind team antagonists
/datum/antagonist/proc/create_team(datum/team/team)
return
//Proc called when the datum is given to a mind.
/datum/antagonist/proc/on_gain()
if(owner && owner.current)
if(!silent)
greet()
apply_innate_effects()
if(is_banned(owner.current) && replace_banned)
replace_banned_player()
/datum/antagonist/proc/is_banned(mob/M)
if(!M)
return FALSE
. = (jobban_isbanned(M, ROLE_SYNDICATE) || (job_rank && jobban_isbanned(M,job_rank)))
/datum/antagonist/proc/replace_banned_player()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as a [name]?", "[name]", null, job_rank, 50, owner.current)
if(LAZYLEN(candidates))
var/client/C = pick(candidates)
to_chat(owner, "Your mob has been taken over by a ghost! Appeal your job ban if you want to avoid this in the future!")
message_admins("[key_name_admin(C)] has taken control of ([key_name_admin(owner.current)]) to replace a jobbaned player.")
owner.current.ghostize(0)
owner.current.key = C.key
/datum/antagonist/proc/on_removal()
remove_innate_effects()
if(owner)
LAZYREMOVE(owner.antag_datums, src)
if(!silent && owner.current)
farewell()
var/datum/team/team = get_team()
if(team)
team.remove_member(owner)
qdel(src)
/datum/antagonist/proc/greet()
return
/datum/antagonist/proc/farewell()
return
//Returns the team antagonist belongs to if any.
/datum/antagonist/proc/get_team()
return
//Individual roundend report
/datum/antagonist/proc/roundend_report()
var/list/report = list()
if(!owner)
CRASH("antagonist datum without owner")
report += printplayer(owner)
var/objectives_complete = TRUE
if(owner.objectives.len)
report += printobjectives(owner)
for(var/datum/objective/objective in owner.objectives)
if(!objective.check_completion())
objectives_complete = FALSE
break
if(owner.objectives.len == 0 || objectives_complete)
report += "<span class='greentext big'>The [name] was successful!</span>"
else
report += "<span class='redtext big'>The [name] has failed!</span>"
return report.Join("<br>")
//Displayed at the start of roundend_category section, default to roundend_category header
/datum/antagonist/proc/roundend_report_header()
return "<span class='header'>The [roundend_category] were:</span><br>"
//Displayed at the end of roundend_category section
/datum/antagonist/proc/roundend_report_footer()
return
//ADMIN TOOLS
//Called when using admin tools to give antag status
/datum/antagonist/proc/admin_add(datum/mind/new_owner,mob/admin)
message_admins("[key_name_admin(admin)] made [new_owner.current] into [name].")
log_admin("[key_name(admin)] made [new_owner.current] into [name].")
new_owner.add_antag_datum(src)
//Called when removing antagonist using admin tools
/datum/antagonist/proc/admin_remove(mob/user)
if(!user)
return
message_admins("[key_name_admin(user)] has removed [name] antagonist status from [owner.current].")
log_admin("[key_name(user)] has removed [name] antagonist status from [owner.current].")
on_removal()
//gamemode/proc/is_mode_antag(antagonist/A) => TRUE/FALSE
//Additional data to display in antagonist panel section
//nuke disk code, genome count, etc
/datum/antagonist/proc/antag_panel_data()
return ""
/datum/antagonist/proc/enabled_in_preferences(datum/mind/M)
if(job_rank)
if(M.current && M.current.client && (job_rank in M.current.client.prefs.be_special))
return TRUE
else
return FALSE
return TRUE
// List if ["Command"] = CALLBACK(), user will be appeneded to callback arguments on execution
/datum/antagonist/proc/get_admin_commands()
. = list()
/datum/antagonist/Topic(href,href_list)
if(!check_rights(R_ADMIN))
return
//Antag memory edit
if (href_list["memory_edit"])
edit_memory(usr)
owner.traitor_panel()
return
//Some commands might delete/modify this datum clearing or changing owner
var/datum/mind/persistent_owner = owner
var/commands = get_admin_commands()
for(var/admin_command in commands)
if(href_list["command"] == admin_command)
var/datum/callback/C = commands[admin_command]
C.Invoke(usr)
persistent_owner.traitor_panel()
return
/datum/antagonist/proc/edit_memory(mob/user)
var/new_memo = copytext(trim(input(user,"Write new memory", "Memory", antag_memory) as null|message),1,MAX_MESSAGE_LEN)
if (isnull(new_memo))
return
antag_memory = new_memo
//Should probably be on ticker or job ss ?
/proc/get_antagonists(antag_type,specific = FALSE)
. = list()
for(var/datum/antagonist/A in GLOB.antagonists)
if(!A.owner)
continue
if(!antag_type || !specific && istype(A,antag_type) || specific && A.type == antag_type)
. += A.owner
//This datum will autofill the name with special_role
//Used as placeholder for minor antagonists, please create proper datums for these
/datum/antagonist/auto_custom
show_in_antagpanel = FALSE
antagpanel_category = "Other"
/datum/antagonist/auto_custom/on_gain()
..()
name = owner.special_role
//Add all objectives not already owned by other datums to this one.
var/list/already_registered_objectives = list()
for(var/datum/antagonist/A in owner.antag_datums)
if(A == src)
continue
else
already_registered_objectives |= A.objectives
objectives = owner.objectives - already_registered_objectives
/datum/antagonist/auto_custom/antag_listing_name()
return ..() + "([name])"
//This one is created by admin tools for custom objectives
/datum/antagonist/custom
antagpanel_category = "Custom"
/datum/antagonist/custom/admin_add(datum/mind/new_owner,mob/admin)
var/custom_name = stripped_input(admin, "Custom antagonist name:", "Custom antag", "Antagonist")
if(custom_name)
name = custom_name
else
return
..()
/datum/antagonist/custom/antag_listing_name()
return ..() + "([name])"
-67
View File
@@ -1,67 +0,0 @@
/datum/antagonist/blob
name = "Blob"
roundend_category = "blobs"
antagpanel_category = "Blob"
job_rank = ROLE_BLOB
var/datum/action/innate/blobpop/pop_action
var/starting_points_human_blob = 60
var/point_rate_human_blob = 2
/datum/antagonist/blob/roundend_report()
var/basic_report = ..()
//Display max blobpoints for blebs that lost
if(isovermind(owner.current)) //embarrasing if not
var/mob/camera/blob/overmind = owner.current
if(!overmind.victory_in_progress) //if it won this doesn't really matter
var/point_report = "<br><b>[owner.name]</b> took over [overmind.max_count] tiles at the height of its growth."
return basic_report+point_report
return basic_report
/datum/antagonist/blob/greet()
if(!isovermind(owner.current))
to_chat(owner,"<span class='userdanger'>You feel bloated.</span>")
/datum/antagonist/blob/on_gain()
create_objectives()
. = ..()
/datum/antagonist/blob/proc/create_objectives()
var/datum/objective/blob_takeover/main = new
main.owner = owner
objectives += main
owner.objectives |= objectives
/datum/antagonist/blob/apply_innate_effects(mob/living/mob_override)
if(!isovermind(owner.current))
if(!pop_action)
pop_action = new
pop_action.Grant(owner.current)
/datum/objective/blob_takeover
explanation_text = "Reach critical mass!"
//Non-overminds get this on blob antag assignment
/datum/action/innate/blobpop
name = "Pop"
desc = "Unleash the blob"
icon_icon = 'icons/mob/blob.dmi'
button_icon_state = "blob"
/datum/action/innate/blobpop/Activate()
var/mob/old_body = owner
var/datum/antagonist/blob/blobtag = owner.mind.has_antag_datum(/datum/antagonist/blob)
if(!blobtag)
Remove()
return
var/mob/camera/blob/B = new /mob/camera/blob(get_turf(old_body), blobtag.starting_points_human_blob)
owner.mind.transfer_to(B)
old_body.gib()
B.place_blob_core(blobtag.point_rate_human_blob, pop_override = TRUE)
/datum/antagonist/blob/antag_listing_status()
. = ..()
if(owner && owner.current)
var/mob/camera/blob/B = owner.current
if(istype(B))
. += "(Progress: [B.blobs_legit.len]/[B.blobwincount])"
-154
View File
@@ -1,154 +0,0 @@
/datum/antagonist/brother
name = "Brother"
antagpanel_category = "Brother"
job_rank = ROLE_BROTHER
var/special_role = ROLE_BROTHER
var/datum/team/brother_team/team
/datum/antagonist/brother/create_team(datum/team/brother_team/new_team)
if(!new_team)
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
team = new_team
/datum/antagonist/brother/get_team()
return team
/datum/antagonist/brother/on_gain()
SSticker.mode.brothers += owner
objectives += team.objectives
owner.objectives += objectives
owner.special_role = special_role
finalize_brother()
return ..()
/datum/antagonist/brother/on_removal()
SSticker.mode.brothers -= owner
owner.objectives -= objectives
if(owner.current)
to_chat(owner.current,"<span class='userdanger'>You are no longer the [special_role]!</span>")
owner.special_role = null
return ..()
/datum/antagonist/brother/proc/give_meeting_area()
if(!owner.current || !team || !team.meeting_area)
return
to_chat(owner.current, "<B>Your designated meeting area:</B> [team.meeting_area]")
antag_memory += "<b>Meeting Area</b>: [team.meeting_area]<br>"
/datum/antagonist/brother/greet()
var/brother_text = ""
var/list/brothers = team.members - owner
for(var/i = 1 to brothers.len)
var/datum/mind/M = brothers[i]
brother_text += M.name
if(i == brothers.len - 1)
brother_text += " and "
else if(i != brothers.len)
brother_text += ", "
to_chat(owner.current, "<B><font size=3 color=red>You are the [owner.special_role] of [brother_text].</font></B>")
to_chat(owner.current, "The Syndicate only accepts those that have proven themself. Prove yourself and prove your [team.member_name]s by completing your objectives together!")
owner.announce_objectives()
give_meeting_area()
/datum/antagonist/brother/proc/finalize_brother()
SSticker.mode.update_brother_icons_added(owner)
/datum/antagonist/brother/admin_add(datum/mind/new_owner,mob/admin)
//show list of possible brothers
var/list/candidates = list()
for(var/mob/living/L in GLOB.alive_mob_list)
if(!L.mind || L.mind == new_owner || !can_be_owned(L.mind))
continue
candidates[L.mind.name] = L.mind
var/choice = input(admin,"Choose the blood brother.", "Brother") as null|anything in candidates
if(!choice)
return
var/datum/mind/bro = candidates[choice]
var/datum/team/brother_team/T = new
T.add_member(new_owner)
T.add_member(bro)
T.pick_meeting_area()
T.forge_brother_objectives()
new_owner.add_antag_datum(/datum/antagonist/brother,T)
bro.add_antag_datum(/datum/antagonist/brother, T)
T.update_name()
message_admins("[key_name_admin(admin)] made [new_owner.current] and [bro.current] into blood brothers.")
log_admin("[key_name(admin)] made [new_owner.current] and [bro.current] into blood brothers.")
/datum/team/brother_team
name = "brotherhood"
member_name = "blood brother"
var/meeting_area
var/static/meeting_areas = list("The Bar", "Dorms", "Escape Dock", "Arrivals", "Holodeck", "Primary Tool Storage", "Recreation Area", "Chapel", "Library")
/datum/team/brother_team/is_solo()
return FALSE
/datum/team/brother_team/proc/pick_meeting_area()
meeting_area = pick(meeting_areas)
meeting_areas -= meeting_area
/datum/team/brother_team/proc/update_name()
var/list/last_names = list()
for(var/datum/mind/M in members)
var/list/split_name = splittext(M.name," ")
last_names += split_name[split_name.len]
name = last_names.Join(" & ")
/datum/team/brother_team/roundend_report()
var/list/parts = list()
parts += "<span class='header'>The blood brothers of [name] were:</span>"
for(var/datum/mind/M in members)
parts += printplayer(M)
var/win = TRUE
var/objective_count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='greentext'><B>Success!</span>"
else
parts += "<B>Objective #[objective_count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
win = FALSE
objective_count++
if(win)
parts += "<span class='greentext'>The blood brothers were successful!</span>"
else
parts += "<span class='redtext'>The blood brothers have failed!</span>"
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
/datum/team/brother_team/proc/add_objective(datum/objective/O, needs_target = FALSE)
O.team = src
if(needs_target)
O.find_target()
O.update_explanation_text()
objectives += O
/datum/team/brother_team/proc/forge_brother_objectives()
objectives = list()
var/is_hijacker = prob(10)
for(var/i = 1 to max(1, CONFIG_GET(number/brother_objectives_amount) + (members.len > 2) - is_hijacker))
forge_single_objective()
if(is_hijacker)
if(!locate(/datum/objective/hijack) in objectives)
add_objective(new/datum/objective/hijack)
else if(!locate(/datum/objective/escape) in objectives)
add_objective(new/datum/objective/escape)
/datum/team/brother_team/proc/forge_single_objective()
if(prob(50))
if(LAZYLEN(active_ais()) && prob(100/GLOB.joined_player_list.len))
add_objective(new/datum/objective/destroy, TRUE)
else if(prob(30))
add_objective(new/datum/objective/maroon, TRUE)
else
add_objective(new/datum/objective/assassinate, TRUE)
else
add_objective(new/datum/objective/steal, TRUE)
/datum/team/brother_team/antag_listing_name()
return "[name] blood brothers"
-545
View File
@@ -1,545 +0,0 @@
#define LING_FAKEDEATH_TIME 400 //40 seconds
#define LING_DEAD_GENETICDAMAGE_HEAL_CAP 50 //The lowest value of geneticdamage handle_changeling() can take it to while dead.
#define LING_ABSORB_RECENT_SPEECH 8 //The amount of recent spoken lines to gain on absorbing a mob
/datum/antagonist/changeling
name = "Changeling"
roundend_category = "changelings"
antagpanel_category = "Changeling"
job_rank = ROLE_CHANGELING
var/you_are_greet = TRUE
var/give_objectives = TRUE
var/team_mode = FALSE //Should assign team objectives ?
//Changeling Stuff
var/list/stored_profiles = list() //list of datum/changelingprofile
var/datum/changelingprofile/first_prof = null
var/dna_max = 6 //How many extra DNA strands the changeling can store for transformation.
var/absorbedcount = 0
var/chem_charges = 20
var/chem_storage = 75
var/chem_recharge_rate = 1
var/chem_recharge_slowdown = 0
var/sting_range = 2
var/changelingID = "Changeling"
var/geneticdamage = 0
var/isabsorbing = 0
var/islinking = 0
var/geneticpoints = 10
var/purchasedpowers = list()
var/mimicing = ""
var/canrespec = 0
var/changeling_speak = 0
var/datum/dna/chosen_dna
var/obj/effect/proc_holder/changeling/sting/chosen_sting
var/datum/cellular_emporium/cellular_emporium
var/datum/action/innate/cellular_emporium/emporium_action
// wip stuff
var/static/list/all_powers = typecacheof(/obj/effect/proc_holder/changeling,TRUE)
/datum/antagonist/changeling/Destroy()
QDEL_NULL(cellular_emporium)
QDEL_NULL(emporium_action)
. = ..()
/datum/antagonist/changeling/proc/generate_name()
var/honorific
if(owner.current.gender == FEMALE)
honorific = "Ms."
else
honorific = "Mr."
if(GLOB.possible_changeling_IDs.len)
changelingID = pick(GLOB.possible_changeling_IDs)
GLOB.possible_changeling_IDs -= changelingID
changelingID = "[honorific] [changelingID]"
else
changelingID = "[honorific] [rand(1,999)]"
/datum/antagonist/changeling/proc/create_actions()
cellular_emporium = new(src)
emporium_action = new(cellular_emporium)
/datum/antagonist/changeling/on_gain()
generate_name()
create_actions()
reset_powers()
create_initial_profile()
if(give_objectives)
if(team_mode)
forge_team_objectives()
forge_objectives()
remove_clownmut()
. = ..()
/datum/antagonist/changeling/on_removal()
//We'll be using this from now on
var/mob/living/carbon/C = owner.current
if(istype(C))
var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN)
if(B && (B.decoy_override != initial(B.decoy_override)))
B.vital = TRUE
B.decoy_override = FALSE
remove_changeling_powers()
owner.objectives -= objectives
. = ..()
/datum/antagonist/changeling/proc/remove_clownmut()
if (owner)
var/mob/living/carbon/human/H = owner.current
if(istype(H) && owner.assigned_role == "Clown")
to_chat(H, "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
/datum/antagonist/changeling/proc/reset_properties()
changeling_speak = 0
chosen_sting = null
geneticpoints = initial(geneticpoints)
sting_range = initial(sting_range)
chem_storage = initial(chem_storage)
chem_recharge_rate = initial(chem_recharge_rate)
chem_charges = min(chem_charges, chem_storage)
chem_recharge_slowdown = initial(chem_recharge_slowdown)
mimicing = ""
/datum/antagonist/changeling/proc/remove_changeling_powers()
if(ishuman(owner.current) || ismonkey(owner.current))
reset_properties()
for(var/obj/effect/proc_holder/changeling/p in purchasedpowers)
if(p.always_keep)
continue
purchasedpowers -= p
p.on_refund(owner.current)
//MOVE THIS
if(owner.current.hud_used)
owner.current.hud_used.lingstingdisplay.icon_state = null
owner.current.hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
/datum/antagonist/changeling/proc/reset_powers()
if(purchasedpowers)
remove_changeling_powers()
//Repurchase free powers.
for(var/path in all_powers)
var/obj/effect/proc_holder/changeling/S = new path()
if(!S.dna_cost)
if(!has_sting(S))
purchasedpowers += S
S.on_purchase(owner.current,TRUE)
/datum/antagonist/changeling/proc/has_sting(obj/effect/proc_holder/changeling/power)
for(var/obj/effect/proc_holder/changeling/P in purchasedpowers)
if(initial(power.name) == P.name)
return TRUE
return FALSE
/datum/antagonist/changeling/proc/purchase_power(sting_name)
var/obj/effect/proc_holder/changeling/thepower = null
for(var/path in all_powers)
var/obj/effect/proc_holder/changeling/S = path
if(initial(S.name) == sting_name)
thepower = new path()
break
if(!thepower)
to_chat(owner.current, "This is awkward. Changeling power purchase failed, please report this bug to a coder!")
return
if(absorbedcount < thepower.req_dna)
to_chat(owner.current, "We lack the energy to evolve this ability!")
return
if(has_sting(thepower))
to_chat(owner.current, "We have already evolved this ability!")
return
if(thepower.dna_cost < 0)
to_chat(owner.current, "We cannot evolve this ability.")
return
if(geneticpoints < thepower.dna_cost)
to_chat(owner.current, "We have reached our capacity for abilities.")
return
if(owner.current.status_flags & FAKEDEATH)//To avoid potential exploits by buying new powers while in stasis, which clears your verblist.
to_chat(owner.current, "We lack the energy to evolve new abilities right now.")
return
geneticpoints -= thepower.dna_cost
purchasedpowers += thepower
thepower.on_purchase(owner.current)
/datum/antagonist/changeling/proc/readapt()
if(!ishuman(owner.current))
to_chat(owner.current, "<span class='danger'>We can't remove our evolutions in this form!</span>")
return
if(canrespec)
to_chat(owner.current, "<span class='notice'>We have removed our evolutions from this form, and are now ready to readapt.</span>")
reset_powers()
canrespec = 0
SSblackbox.record_feedback("tally", "changeling_power_purchase", 1, "Readapt")
return 1
else
to_chat(owner.current, "<span class='danger'>You lack the power to readapt your evolutions!</span>")
return 0
//Called in life()
/datum/antagonist/changeling/proc/regenerate()
var/mob/living/carbon/the_ling = owner.current
if(istype(the_ling))
emporium_action.Grant(the_ling)
if(the_ling.stat == DEAD)
chem_charges = min(max(0, chem_charges + chem_recharge_rate - chem_recharge_slowdown), (chem_storage*0.5))
geneticdamage = max(LING_DEAD_GENETICDAMAGE_HEAL_CAP,geneticdamage-1)
else //not dead? no chem/geneticdamage caps.
chem_charges = min(max(0, chem_charges + chem_recharge_rate - chem_recharge_slowdown), chem_storage)
geneticdamage = max(0, geneticdamage-1)
/datum/antagonist/changeling/proc/get_dna(dna_owner)
for(var/datum/changelingprofile/prof in stored_profiles)
if(dna_owner == prof.name)
return prof
/datum/antagonist/changeling/proc/has_dna(datum/dna/tDNA)
for(var/datum/changelingprofile/prof in stored_profiles)
if(tDNA.is_same_as(prof.dna))
return TRUE
return FALSE
/datum/antagonist/changeling/proc/can_absorb_dna(mob/living/carbon/human/target, var/verbose=1)
var/mob/living/carbon/user = owner.current
if(!istype(user))
return
if(stored_profiles.len)
var/datum/changelingprofile/prof = stored_profiles[1]
if(prof.dna == user.dna && stored_profiles.len >= dna_max)//If our current DNA is the stalest, we gotta ditch it.
if(verbose)
to_chat(user, "<span class='warning'>We have reached our capacity to store genetic information! We must transform before absorbing more.</span>")
return
if(!target)
return
if(NO_DNA_COPY in target.dna.species.species_traits)
if(verbose)
to_chat(user, "<span class='warning'>[target] is not compatible with our biology.</span>")
return
if((target.has_disability(DISABILITY_NOCLONE)) || (target.has_disability(DISABILITY_NOCLONE)))
if(verbose)
to_chat(user, "<span class='warning'>DNA of [target] is ruined beyond usability!</span>")
return
if(!ishuman(target))//Absorbing monkeys is entirely possible, but it can cause issues with transforming. That's what lesser form is for anyway!
if(verbose)
to_chat(user, "<span class='warning'>We could gain no benefit from absorbing a lesser creature.</span>")
return
if(has_dna(target.dna))
if(verbose)
to_chat(user, "<span class='warning'>We already have this DNA in storage!</span>")
return
if(!target.has_dna())
if(verbose)
to_chat(user, "<span class='warning'>[target] is not compatible with our biology.</span>")
return
return 1
/datum/antagonist/changeling/proc/create_profile(mob/living/carbon/human/H, protect = 0)
var/datum/changelingprofile/prof = new
H.dna.real_name = H.real_name //Set this again, just to be sure that it's properly set.
var/datum/dna/new_dna = new H.dna.type
H.dna.copy_dna(new_dna)
prof.dna = new_dna
prof.name = H.real_name
prof.protected = protect
prof.underwear = H.underwear
prof.undershirt = H.undershirt
prof.socks = H.socks
var/list/slots = list("head", "wear_mask", "back", "wear_suit", "w_uniform", "shoes", "belt", "gloves", "glasses", "ears", "wear_id", "s_store")
for(var/slot in slots)
if(slot in H.vars)
var/obj/item/I = H.vars[slot]
if(!I)
continue
prof.name_list[slot] = I.name
prof.appearance_list[slot] = I.appearance
prof.flags_cover_list[slot] = I.flags_cover
prof.item_color_list[slot] = I.item_color
prof.item_state_list[slot] = I.item_state
prof.exists_list[slot] = 1
else
continue
return prof
/datum/antagonist/changeling/proc/add_profile(datum/changelingprofile/prof)
if(stored_profiles.len > dna_max)
if(!push_out_profile())
return
if(!first_prof)
first_prof = prof
stored_profiles += prof
absorbedcount++
/datum/antagonist/changeling/proc/add_new_profile(mob/living/carbon/human/H, protect = 0)
var/datum/changelingprofile/prof = create_profile(H, protect)
add_profile(prof)
return prof
/datum/antagonist/changeling/proc/remove_profile(mob/living/carbon/human/H, force = 0)
for(var/datum/changelingprofile/prof in stored_profiles)
if(H.real_name == prof.name)
if(prof.protected && !force)
continue
stored_profiles -= prof
qdel(prof)
/datum/antagonist/changeling/proc/get_profile_to_remove()
for(var/datum/changelingprofile/prof in stored_profiles)
if(!prof.protected)
return prof
/datum/antagonist/changeling/proc/push_out_profile()
var/datum/changelingprofile/removeprofile = get_profile_to_remove()
if(removeprofile)
stored_profiles -= removeprofile
return 1
return 0
/datum/antagonist/changeling/proc/create_initial_profile()
var/mob/living/carbon/C = owner.current //only carbons have dna now, so we have to typecaste
if(ishuman(C))
add_new_profile(C)
/datum/antagonist/changeling/apply_innate_effects()
//Brains optional.
var/mob/living/carbon/C = owner.current
if(istype(C))
var/obj/item/organ/brain/B = C.getorganslot(ORGAN_SLOT_BRAIN)
if(B)
B.vital = FALSE
B.decoy_override = TRUE
update_changeling_icons_added()
return
/datum/antagonist/changeling/remove_innate_effects()
update_changeling_icons_removed()
return
/datum/antagonist/changeling/greet()
if (you_are_greet)
to_chat(owner.current, "<span class='boldannounce'>You are [changelingID], a changeling! You have absorbed and taken the form of a human.</span>")
to_chat(owner.current, "<span class='boldannounce'>Use say \":g message\" to communicate with your fellow changelings.</span>")
to_chat(owner.current, "<b>You must complete the following tasks:</b>")
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ling_aler.ogg', 100, FALSE, pressure_affected = FALSE)
owner.announce_objectives()
/datum/antagonist/changeling/farewell()
to_chat(owner.current, "<span class='userdanger'>You grow weak and lose your powers! You are no longer a changeling and are stuck in your current form!</span>")
/datum/antagonist/changeling/proc/forge_team_objectives()
if(GLOB.changeling_team_objective_type)
var/datum/objective/changeling_team_objective/team_objective = new GLOB.changeling_team_objective_type
team_objective.owner = owner
objectives += team_objective
return
/datum/antagonist/changeling/proc/forge_objectives()
//OBJECTIVES - random traitor objectives. Unique objectives "steal brain" and "identity theft".
//No escape alone because changelings aren't suited for it and it'd probably just lead to rampant robusting
//If it seems like they'd be able to do it in play, add a 10% chance to have to escape alone
var/escape_objective_possible = TRUE
//if there's a team objective, check if it's compatible with escape objectives
for(var/datum/objective/changeling_team_objective/CTO in objectives)
if(!CTO.escape_objective_compatible)
escape_objective_possible = FALSE
break
var/datum/objective/absorb/absorb_objective = new
absorb_objective.owner = owner
absorb_objective.gen_amount_goal(6, 8)
objectives += absorb_objective
if(prob(60))
if(prob(85))
var/datum/objective/steal/steal_objective = new
steal_objective.owner = owner
steal_objective.find_target()
objectives += steal_objective
else
var/datum/objective/download/download_objective = new
download_objective.owner = owner
download_objective.gen_amount_goal()
objectives += download_objective
var/list/active_ais = active_ais()
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
var/datum/objective/destroy/destroy_objective = new
destroy_objective.owner = owner
destroy_objective.find_target()
objectives += destroy_objective
else
if(prob(70))
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = owner
if(team_mode) //No backstabbing while in a team
kill_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1)
else
kill_objective.find_target()
objectives += kill_objective
else
var/datum/objective/maroon/maroon_objective = new
maroon_objective.owner = owner
if(team_mode)
maroon_objective.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1)
else
maroon_objective.find_target()
objectives += maroon_objective
if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible)
var/datum/objective/escape/escape_with_identity/identity_theft = new
identity_theft.owner = owner
identity_theft.target = maroon_objective.target
identity_theft.update_explanation_text()
objectives += identity_theft
escape_objective_possible = FALSE
if (!(locate(/datum/objective/escape) in objectives) && escape_objective_possible)
if(prob(50))
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
objectives += escape_objective
else
var/datum/objective/escape/escape_with_identity/identity_theft = new
identity_theft.owner = owner
if(team_mode)
identity_theft.find_target_by_role(role = ROLE_CHANGELING, role_type = 1, invert = 1)
else
identity_theft.find_target()
objectives += identity_theft
escape_objective_possible = FALSE
owner.objectives |= objectives
/datum/antagonist/changeling/proc/update_changeling_icons_added()
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_CHANGELING]
hud.join_hud(owner.current)
set_antag_hud(owner.current, "changling")
/datum/antagonist/changeling/proc/update_changeling_icons_removed()
var/datum/atom_hud/antag/hud = GLOB.huds[ANTAG_HUD_CHANGELING]
hud.leave_hud(owner.current)
set_antag_hud(owner.current, null)
/datum/antagonist/changeling/admin_add(datum/mind/new_owner,mob/admin)
. = ..()
to_chat(new_owner.current, "<span class='boldannounce'>Our powers have awoken. A flash of memory returns to us...we are [changelingID], a changeling!</span>")
/datum/antagonist/changeling/get_admin_commands()
. = ..()
if(stored_profiles.len && (owner.current.real_name != first_prof.name))
.["Transform to initial appearance."] = CALLBACK(src,.proc/admin_restore_appearance)
/datum/antagonist/changeling/proc/admin_restore_appearance(mob/admin)
if(!stored_profiles.len || !iscarbon(owner.current))
to_chat(admin, "<span class='danger'>Resetting DNA failed!</span>")
else
var/mob/living/carbon/C = owner.current
first_prof.dna.transfer_identity(C, transfer_SE=1)
C.real_name = first_prof.name
C.updateappearance(mutcolor_update=1)
C.domutcheck()
// Profile
/datum/changelingprofile
var/name = "a bug"
var/protected = 0
var/datum/dna/dna = null
var/list/name_list = list() //associative list of slotname = itemname
var/list/appearance_list = list()
var/list/flags_cover_list = list()
var/list/exists_list = list()
var/list/item_color_list = list()
var/list/item_state_list = list()
var/underwear
var/undershirt
var/socks
/datum/changelingprofile/Destroy()
qdel(dna)
. = ..()
/datum/changelingprofile/proc/copy_profile(datum/changelingprofile/newprofile)
newprofile.name = name
newprofile.protected = protected
newprofile.dna = new dna.type
dna.copy_dna(newprofile.dna)
newprofile.name_list = name_list.Copy()
newprofile.appearance_list = appearance_list.Copy()
newprofile.flags_cover_list = flags_cover_list.Copy()
newprofile.exists_list = exists_list.Copy()
newprofile.item_color_list = item_color_list.Copy()
newprofile.item_state_list = item_state_list.Copy()
newprofile.underwear = underwear
newprofile.undershirt = undershirt
newprofile.socks = socks
/datum/antagonist/changeling/xenobio
name = "Xenobio Changeling"
give_objectives = FALSE
show_in_roundend = FALSE //These are here for admin tracking purposes only
you_are_greet = FALSE
/datum/antagonist/changeling/roundend_report()
var/list/parts = list()
var/changelingwin = 1
if(!owner.current)
changelingwin = 0
parts += printplayer(owner)
//Removed sanity if(changeling) because we -want- a runtime to inform us that the changelings list is incorrect and needs to be fixed.
parts += "<b>Changeling ID:</b> [changelingID]."
parts += "<b>Genomes Extracted:</b> [absorbedcount]"
parts += " "
if(objectives.len)
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='greentext'>Success!</b></span>"
else
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
changelingwin = 0
count++
if(changelingwin)
parts += "<span class='greentext'>The changeling was successful!</span>"
else
parts += "<span class='redtext'>The changeling has failed.</span>"
return parts.Join("<br>")
/datum/antagonist/changeling/antag_listing_name()
return ..() + "([changelingID])"
/datum/antagonist/changeling/xenobio/antag_listing_name()
return ..() + "(Xenobio)"
-219
View File
@@ -1,219 +0,0 @@
//CLOCKCULT PROOF OF CONCEPT
/datum/antagonist/clockcult
name = "Clock Cultist"
roundend_category = "clock cultists"
antagpanel_category = "Clockcult"
job_rank = ROLE_SERVANT_OF_RATVAR
var/datum/action/innate/hierophant/hierophant_network = new()
var/datum/team/clockcult/clock_team
var/make_team = TRUE //This should be only false for tutorial scarabs
/datum/antagonist/clockcult/silent
silent = TRUE
show_in_antagpanel = FALSE //internal
/datum/antagonist/clockcult/Destroy()
qdel(hierophant_network)
return ..()
/datum/antagonist/clockcult/get_team()
return clock_team
/datum/antagonist/clockcult/create_team(datum/team/clockcult/new_team)
if(!new_team && make_team)
//TODO blah blah same as the others, allow multiple
for(var/datum/antagonist/clockcult/H in GLOB.antagonists)
if(!H.owner)
continue
if(H.clock_team)
clock_team = H.clock_team
return
clock_team = new /datum/team/clockcult
return
if(make_team && !istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
clock_team = new_team
/datum/antagonist/clockcult/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
. = is_eligible_servant(new_owner.current)
/datum/antagonist/clockcult/greet()
if(!owner.current || silent)
return
owner.current.visible_message("<span class='heavy_brass'>[owner.current]'s eyes glow a blazing yellow!</span>", null, null, 7, owner.current) //don't show the owner this message
to_chat(owner.current, "<span class='heavy_brass'>Assist your new companions in their righteous efforts. Your goal is theirs, and theirs yours. You serve the Clockwork \
Justiciar above all else. Perform his every whim without hesitation.</span>")
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/clockcultalr.ogg', 70, FALSE, pressure_affected = FALSE)
/datum/antagonist/clockcult/on_gain()
var/mob/living/current = owner.current
SSticker.mode.servants_of_ratvar += owner
SSticker.mode.update_servant_icons_added(owner)
owner.special_role = ROLE_SERVANT_OF_RATVAR
owner.current.log_message("<font color=#BE8700>Has been converted to the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
if(issilicon(current))
if(iscyborg(current) && !silent)
var/mob/living/silicon/robot/R = current
if(R.connected_ai && !is_servant_of_ratvar(R.connected_ai))
to_chat(R, "<span class='boldwarning'>You have been desynced from your master AI.<br>\
In addition, your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.</span>")
else
to_chat(R, "<span class='boldwarning'>Your onboard camera is no longer active and you have gained additional equipment, including a limited clockwork slab.</span>")
if(isAI(current))
to_chat(current, "<span class='boldwarning'>You are now able to use your cameras to listen in on conversations, but can no longer speak in anything but Ratvarian.</span>")
to_chat(current, "<span class='heavy_brass'>You can communicate with other servants by using the Hierophant Network action button in the upper left.</span>")
else if(isbrain(current) || isclockmob(current))
to_chat(current, "<span class='nezbere'>You can communicate with other servants by using the Hierophant Network action button in the upper left.</span>")
..()
to_chat(current, "<b>This is Ratvar's will:</b> [CLOCKCULT_OBJECTIVE]")
antag_memory += "<b>Ratvar's will:</b> [CLOCKCULT_OBJECTIVE]<br>" //Memorize the objectives
/datum/antagonist/clockcult/apply_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/current = owner.current
if(istype(mob_override))
current = mob_override
GLOB.all_clockwork_mobs += current
current.faction |= "ratvar"
current.grant_language(/datum/language/ratvar)
current.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them for whatever reason, we need to update buttons
if(issilicon(current))
var/mob/living/silicon/S = current
if(iscyborg(S))
var/mob/living/silicon/robot/R = S
if(!R.shell)
R.UnlinkSelf()
R.module.rebuild_modules()
else if(isAI(S))
var/mob/living/silicon/ai/A = S
A.can_be_carded = FALSE
A.requires_power = POWER_REQ_CLOCKCULT
var/list/AI_frame = list(mutable_appearance('icons/mob/clockwork_mobs.dmi', "aiframe")) //make the AI's cool frame
for(var/d in GLOB.cardinals)
AI_frame += image('icons/mob/clockwork_mobs.dmi', A, "eye[rand(1, 10)]", dir = d) //the eyes are randomly fast or slow
A.add_overlay(AI_frame)
if(!A.lacks_power())
A.ai_restore_power()
if(A.eyeobj)
A.eyeobj.relay_speech = TRUE
for(var/mob/living/silicon/robot/R in A.connected_robots)
if(R.connected_ai == A)
add_servant_of_ratvar(R)
S.laws = new/datum/ai_laws/ratvar
S.laws.associate(S)
S.update_icons()
S.show_laws()
hierophant_network.title = "Silicon"
hierophant_network.span_for_name = "nezbere"
hierophant_network.span_for_message = "brass"
else if(isbrain(current))
hierophant_network.title = "Vessel"
hierophant_network.span_for_name = "nezbere"
hierophant_network.span_for_message = "alloy"
else if(isclockmob(current))
hierophant_network.title = "Construct"
hierophant_network.span_for_name = "nezbere"
hierophant_network.span_for_message = "brass"
hierophant_network.Grant(current)
current.throw_alert("clockinfo", /obj/screen/alert/clockwork/infodump)
var/obj/structure/destructible/clockwork/massive/celestial_gateway/G = GLOB.ark_of_the_clockwork_justiciar
if(G.active && ishuman(current))
current.add_overlay(mutable_appearance('icons/effects/genetics.dmi', "servitude", -MUTATIONS_LAYER))
/datum/antagonist/clockcult/remove_innate_effects(mob/living/mob_override)
var/mob/living/current = owner.current
if(istype(mob_override))
current = mob_override
GLOB.all_clockwork_mobs -= current
current.faction -= "ratvar"
current.remove_language(/datum/language/ratvar)
current.clear_alert("clockinfo")
for(var/datum/action/innate/clockwork_armaments/C in owner.current.actions) //Removes any bound clockwork armor
qdel(C)
for(var/datum/action/innate/call_weapon/W in owner.current.actions) //and weapons too
qdel(W)
if(issilicon(current))
var/mob/living/silicon/S = current
if(isAI(S))
var/mob/living/silicon/ai/A = S
A.can_be_carded = initial(A.can_be_carded)
A.requires_power = initial(A.requires_power)
A.cut_overlays()
S.make_laws()
S.update_icons()
S.show_laws()
var/mob/living/temp_owner = current
..()
if(iscyborg(temp_owner))
var/mob/living/silicon/robot/R = temp_owner
R.module.rebuild_modules()
if(temp_owner)
temp_owner.update_action_buttons_icon() //because a few clockcult things are action buttons and we may be wearing/holding them, we need to update buttons
temp_owner.cut_overlays()
temp_owner.regenerate_icons()
/datum/antagonist/clockcult/on_removal()
SSticker.mode.servants_of_ratvar -= owner
SSticker.mode.update_servant_icons_removed(owner)
if(!silent)
owner.current.visible_message("<span class='deconversion_message'>[owner] seems to have remembered their true allegiance!</span>", null, null, null, owner.current)
to_chat(owner, "<span class='userdanger'>A cold, cold darkness flows through your mind, extinguishing the Justiciar's light and all of your memories as his servant.</span>")
owner.current.log_message("<font color=#BE8700>Has renounced the cult of Ratvar!</font>", INDIVIDUAL_ATTACK_LOG)
owner.special_role = null
if(iscyborg(owner.current))
to_chat(owner.current, "<span class='warning'>Despite your freedom from Ratvar's influence, you are still irreparably damaged and no longer possess certain functions such as AI linking.</span>")
. = ..()
/datum/antagonist/clockcult/admin_add(datum/mind/new_owner,mob/admin)
add_servant_of_ratvar(new_owner.current, TRUE)
message_admins("[key_name_admin(admin)] has made [new_owner.current] into a servant of Ratvar.")
log_admin("[key_name(admin)] has made [new_owner.current] into a servant of Ratvar.")
/datum/antagonist/clockcult/admin_remove(mob/user)
remove_servant_of_ratvar(owner.current, TRUE)
message_admins("[key_name_admin(user)] has removed clockwork servant status from [owner.current].")
log_admin("[key_name(user)] has removed clockwork servant status from [owner.current].")
/datum/antagonist/clockcult/get_admin_commands()
. = ..()
.["Give slab"] = CALLBACK(src,.proc/admin_give_slab)
/datum/antagonist/clockcult/proc/admin_give_slab(mob/admin)
if(!SSticker.mode.equip_servant(owner.current))
to_chat(admin, "<span class='warning'>Failed to outfit [owner.current]!</span>")
else
to_chat(admin, "<span class='notice'>Successfully gave [owner.current] servant equipment!</span>")
/datum/team/clockcult
name = "Clockcult"
var/list/objective
var/datum/mind/eminence
/datum/team/clockcult/proc/check_clockwork_victory()
if(GLOB.clockwork_gateway_activated)
return TRUE
return FALSE
/datum/team/clockcult/roundend_report()
var/list/parts = list()
if(check_clockwork_victory())
parts += "<span class='greentext big'>Ratvar's servants defended the Ark until its activation!</span>"
else
parts += "<span class='redtext big'>The Ark was destroyed! Ratvar will rust away for all eternity!</span>"
parts += " "
parts += "<b>The servants' objective was:</b> [CLOCKCULT_OBJECTIVE]."
parts += "<b>Construction Value(CV)</b> was: <b>[GLOB.clockwork_construction_value]</b>"
for(var/i in SSticker.scripture_states)
if(i != SCRIPTURE_DRIVER)
parts += "<b>[i] scripture</b> was: <b>[SSticker.scripture_states[i] ? "UN":""]LOCKED</b>"
if(eminence)
parts += "<span class='header'>The Eminence was:</span> [printplayer(eminence)]"
if(members.len)
parts += "<span class='header'>Ratvar's servants were:</span>"
parts += printplayerlist(members - eminence)
return "<div class='panel clockborder'>[parts.Join("<br>")]</div>"
-329
View File
@@ -1,329 +0,0 @@
#define SUMMON_POSSIBILITIES 3
/datum/antagonist/cult
name = "Cultist"
roundend_category = "cultists"
antagpanel_category = "Cult"
var/datum/action/innate/cult/comm/communion = new
var/datum/action/innate/cult/mastervote/vote = new
job_rank = ROLE_CULTIST
var/ignore_implant = FALSE
var/give_equipment = FALSE
var/datum/team/cult/cult_team
/datum/antagonist/cult/get_team()
return cult_team
/datum/antagonist/cult/create_team(datum/team/cult/new_team)
if(!new_team)
//todo remove this and allow admin buttons to create more than one cult
for(var/datum/antagonist/cult/H in GLOB.antagonists)
if(!H.owner)
continue
if(H.cult_team)
cult_team = H.cult_team
return
cult_team = new /datum/team/cult
cult_team.setup_objectives()
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
cult_team = new_team
/datum/antagonist/cult/proc/add_objectives()
objectives |= cult_team.objectives
owner.objectives |= objectives
/datum/antagonist/cult/proc/remove_objectives()
owner.objectives -= objectives
/datum/antagonist/cult/Destroy()
QDEL_NULL(communion)
QDEL_NULL(vote)
return ..()
/datum/antagonist/cult/can_be_owned(datum/mind/new_owner)
. = ..()
if(. && !ignore_implant)
. = is_convertable_to_cult(new_owner.current,cult_team)
/datum/antagonist/cult/greet()
to_chat(owner, "<span class='userdanger'>You are a member of the cult!</span>")
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/bloodcult.ogg', 100, FALSE, pressure_affected = FALSE)//subject to change
owner.announce_objectives()
/datum/antagonist/cult/on_gain()
. = ..()
var/mob/living/current = owner.current
add_objectives()
if(give_equipment)
equip_cultist()
SSticker.mode.cult += owner // Only add after they've been given objectives
SSticker.mode.update_cult_icons_added(owner)
current.log_message("<font color=#960000>Has been converted to the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
if(cult_team.blood_target && cult_team.blood_target_image && current.client)
current.client.images += cult_team.blood_target_image
/datum/antagonist/cult/proc/equip_cultist(tome=FALSE)
var/mob/living/carbon/H = owner.current
if(!istype(H))
return
if (owner.assigned_role == "Clown")
to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
if(tome)
. += cult_give_item(/obj/item/tome, H)
else
. += cult_give_item(/obj/item/paper/talisman/supply, H)
to_chat(owner, "These will help you start the cult on this station. Use them well, and remember - you are not the only one.</span>")
/datum/antagonist/cult/proc/cult_give_item(obj/item/item_path, mob/living/carbon/human/mob)
var/list/slots = list(
"backpack" = slot_in_backpack,
"left pocket" = slot_l_store,
"right pocket" = slot_r_store
)
var/T = new item_path(mob)
var/item_name = initial(item_path.name)
var/where = mob.equip_in_one_of_slots(T, slots)
if(!where)
to_chat(mob, "<span class='userdanger'>Unfortunately, you weren't able to get a [item_name]. This is very bad and you should adminhelp immediately (press F1).</span>")
return 0
else
to_chat(mob, "<span class='danger'>You have a [item_name] in your [where].</span>")
if(where == "backpack")
var/obj/item/storage/B = mob.back
B.orient2hud(mob)
B.show_to(mob)
return 1
/datum/antagonist/cult/apply_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
current.faction |= "cult"
current.grant_language(/datum/language/narsie)
current.verbs += /mob/living/proc/cult_help
if(!cult_team.cult_mastered)
vote.Grant(current)
communion.Grant(current)
current.throw_alert("bloodsense", /obj/screen/alert/bloodsense)
/datum/antagonist/cult/remove_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
current.faction -= "cult"
current.remove_language(/datum/language/narsie)
current.verbs -= /mob/living/proc/cult_help
vote.Remove(current)
communion.Remove(current)
current.clear_alert("bloodsense")
/datum/antagonist/cult/on_removal()
remove_objectives()
SSticker.mode.cult -= owner
SSticker.mode.update_cult_icons_removed(owner)
if(!silent)
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like [owner.current.p_they()] just reverted to their old faith!</span>", null, null, null, owner.current)
to_chat(owner.current, "<span class='userdanger'>An unfamiliar white light flashes through your mind, cleansing the taint of the Geometer and all your memories as her servant.</span>")
owner.current.log_message("<font color=#960000>Has renounced the cult of Nar'Sie!</font>", INDIVIDUAL_ATTACK_LOG)
if(cult_team.blood_target && cult_team.blood_target_image && owner.current.client)
owner.current.client.images -= cult_team.blood_target_image
. = ..()
/datum/antagonist/cult/admin_add(datum/mind/new_owner,mob/admin)
give_equipment = FALSE
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has cult'ed [new_owner.current].")
log_admin("[key_name(admin)] has cult'ed [new_owner.current].")
/datum/antagonist/cult/admin_remove(mob/user)
message_admins("[key_name_admin(user)] has decult'ed [owner.current].")
log_admin("[key_name(user)] has decult'ed [owner.current].")
SSticker.mode.remove_cultist(owner,silent=TRUE) //disgusting
/datum/antagonist/cult/get_admin_commands()
. = ..()
.["Tome"] = CALLBACK(src,.proc/admin_give_tome)
.["Amulet"] = CALLBACK(src,.proc/admin_give_amulet)
/datum/antagonist/cult/proc/admin_give_tome(mob/admin)
if(equip_cultist(owner.current,1))
to_chat(admin, "<span class='danger'>Spawning tome failed!</span>")
/datum/antagonist/cult/proc/admin_give_amulet(mob/admin)
if (equip_cultist(owner.current))
to_chat(admin, "<span class='danger'>Spawning amulet failed!</span>")
/datum/antagonist/cult/master
ignore_implant = TRUE
show_in_antagpanel = FALSE //Feel free to add this later
var/datum/action/innate/cult/master/finalreck/reckoning = new
var/datum/action/innate/cult/master/cultmark/bloodmark = new
var/datum/action/innate/cult/master/pulse/throwing = new
/datum/antagonist/cult/master/Destroy()
QDEL_NULL(reckoning)
QDEL_NULL(bloodmark)
QDEL_NULL(throwing)
return ..()
/datum/antagonist/cult/master/on_gain()
. = ..()
var/mob/living/current = owner.current
set_antag_hud(current, "cultmaster")
/datum/antagonist/cult/master/greet()
to_chat(owner.current, "<span class='cultlarge'>You are the cult's Master</span>. As the cult's Master, you have a unique title and loud voice when communicating, are capable of marking \
targets, such as a location or a noncultist, to direct the cult to them, and, finally, you are capable of summoning the entire living cult to your location <b><i>once</i></b>.")
to_chat(owner.current, "Use these abilities to direct the cult to victory at any cost.")
/datum/antagonist/cult/master/apply_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
if(!cult_team.reckoning_complete)
reckoning.Grant(current)
bloodmark.Grant(current)
throwing.Grant(current)
current.update_action_buttons_icon()
current.apply_status_effect(/datum/status_effect/cult_master)
/datum/antagonist/cult/master/remove_innate_effects(mob/living/mob_override)
. = ..()
var/mob/living/current = owner.current
if(mob_override)
current = mob_override
reckoning.Remove(current)
bloodmark.Remove(current)
throwing.Remove(current)
current.update_action_buttons_icon()
current.remove_status_effect(/datum/status_effect/cult_master)
/datum/team/cult
name = "Cult"
var/blood_target
var/image/blood_target_image
var/blood_target_reset_timer
var/cult_vote_called = FALSE
var/cult_mastered = FALSE
var/reckoning_complete = FALSE
/datum/team/cult/proc/setup_objectives()
//SAC OBJECTIVE , todo: move this to objective internals
var/list/target_candidates = list()
var/datum/objective/sacrifice/sac_objective = new
sac_objective.team = src
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !player.mind.has_antag_datum(/datum/antagonist/cult) && !is_convertable_to_cult(player) && player.stat != DEAD)
target_candidates += player.mind
if(target_candidates.len == 0)
message_admins("Cult Sacrifice: Could not find unconvertable target, checking for convertable target.")
for(var/mob/living/carbon/human/player in GLOB.player_list)
if(player.mind && !player.mind.has_antag_datum(/datum/antagonist/cult) && player.stat != DEAD)
target_candidates += player.mind
listclearnulls(target_candidates)
if(LAZYLEN(target_candidates))
sac_objective.target = pick(target_candidates)
sac_objective.update_explanation_text()
var/datum/job/sacjob = SSjob.GetJob(sac_objective.target.assigned_role)
var/datum/preferences/sacface = sac_objective.target.current.client.prefs
var/icon/reshape = get_flat_human_icon(null, sacjob, sacface)
reshape.Shift(SOUTH, 4)
reshape.Shift(EAST, 1)
reshape.Crop(7,4,26,31)
reshape.Crop(-5,-3,26,30)
sac_objective.sac_image = reshape
objectives += sac_objective
else
message_admins("Cult Sacrifice: Could not find unconvertable or convertable target. WELP!")
//SUMMON OBJECTIVE
var/datum/objective/eldergod/summon_objective = new()
summon_objective.team = src
objectives += summon_objective
/datum/objective/sacrifice
var/sacced = FALSE
var/sac_image
/datum/objective/sacrifice/check_completion()
return sacced || completed
/datum/objective/sacrifice/update_explanation_text()
if(target)
explanation_text = "Sacrifice [target], the [target.assigned_role] via invoking a Sacrifice rune with them on it and three acolytes around it."
else
explanation_text = "The veil has already been weakened here, proceed to the final objective."
/datum/objective/eldergod
var/summoned = FALSE
var/list/summon_spots = list()
/datum/objective/eldergod/New()
..()
var/sanity = 0
while(summon_spots.len < SUMMON_POSSIBILITIES && sanity < 100)
var/area/summon = pick(GLOB.sortedAreas - summon_spots)
if(summon && is_station_level(summon.z) && summon.valid_territory)
summon_spots += summon
sanity++
update_explanation_text()
/datum/objective/eldergod/update_explanation_text()
explanation_text = "Summon Nar-Sie by invoking the rune 'Summon Nar-Sie'. <b>The summoning can only be accomplished in [english_list(summon_spots)] - where the veil is weak enough for the ritual to begin.</b>"
/datum/objective/eldergod/check_completion()
return summoned || completed
/datum/team/cult/proc/check_cult_victory()
for(var/datum/objective/O in objectives)
if(!O.check_completion())
return FALSE
return TRUE
/datum/team/cult/roundend_report()
var/list/parts = list()
if(check_cult_victory())
parts += "<span class='greentext big'>The cult has succeeded! Nar-sie has snuffed out another torch in the void!</span>"
else
parts += "<span class='redtext big'>The staff managed to stop the cult! Dark words and heresy are no match for Nanotrasen's finest!</span>"
if(objectives.len)
parts += "<b>The cultists' objectives were:</b>"
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='greentext'>Success!</span>"
else
parts += "<b>Objective #[count]</b>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
count++
if(members.len)
parts += "<span class='header'>The cultists were:</span>"
parts += printplayerlist(members)
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
/datum/team/cult/is_gamemode_hero()
return SSticker.mode.name == "cult"
-11
View File
@@ -1,11 +0,0 @@
/datum/antagonist/iaa
/datum/antagonist/iaa/apply_innate_effects()
.=..() //in case the base is used in future
if(owner&&owner.current)
give_pinpointer(owner.current)
/datum/antagonist/iaa/remove_innate_effects()
.=..()
if(owner&&owner.current)
owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer)
-352
View File
@@ -1,352 +0,0 @@
/datum/antagonist/traitor
name = "Traitor"
roundend_category = "traitors"
antagpanel_category = "Traitor"
job_rank = ROLE_TRAITOR
var/should_specialise = TRUE //do we split into AI and human, set to true on inital assignment only
var/ai_datum = /datum/antagonist/traitor/AI
var/human_datum = /datum/antagonist/traitor/human
var/special_role = ROLE_TRAITOR
var/employer = "The Syndicate"
var/give_objectives = TRUE
var/should_give_codewords = TRUE
/datum/antagonist/traitor/human
show_in_antagpanel = FALSE
should_specialise = FALSE
var/should_equip = TRUE
/datum/antagonist/traitor/AI
show_in_antagpanel = FALSE
should_specialise = FALSE
/datum/antagonist/traitor/specialization(datum/mind/new_owner)
if(should_specialise)
if(new_owner.current && isAI(new_owner.current))
return new ai_datum()
else
return new human_datum()
else
return ..()
/datum/antagonist/traitor/on_gain()
SSticker.mode.traitors += owner
owner.special_role = special_role
if(give_objectives)
forge_traitor_objectives()
finalize_traitor()
..()
/datum/antagonist/traitor/apply_innate_effects()
if(owner.assigned_role == "Clown")
var/mob/living/carbon/human/traitor_mob = owner.current
if(traitor_mob && istype(traitor_mob))
if(!silent)
to_chat(traitor_mob, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
traitor_mob.dna.remove_mutation(CLOWNMUT)
/datum/antagonist/traitor/remove_innate_effects()
if(owner.assigned_role == "Clown")
var/mob/living/carbon/human/traitor_mob = owner.current
if(traitor_mob && istype(traitor_mob))
traitor_mob.dna.add_mutation(CLOWNMUT)
/datum/antagonist/traitor/on_removal()
SSticker.mode.traitors -= owner
for(var/O in objectives)
owner.objectives -= O
objectives = list()
if(!silent && owner.current)
to_chat(owner.current,"<span class='userdanger'> You are no longer the [special_role]! </span>")
owner.special_role = null
..()
/datum/antagonist/traitor/AI/on_removal()
if(owner.current && isAI(owner.current))
var/mob/living/silicon/ai/A = owner.current
A.set_zeroth_law("")
A.verbs -= /mob/living/silicon/ai/proc/choose_modules
A.malf_picker.remove_malf_verbs(A)
qdel(A.malf_picker)
..()
/datum/antagonist/traitor/proc/add_objective(var/datum/objective/O)
owner.objectives += O
objectives += O
/datum/antagonist/traitor/proc/remove_objective(var/datum/objective/O)
owner.objectives -= O
objectives -= O
/datum/antagonist/traitor/proc/forge_traitor_objectives()
return
/datum/antagonist/traitor/human/forge_traitor_objectives()
var/is_hijacker = FALSE
if (GLOB.joined_player_list.len >= 30) // Less murderboning on lowpop thanks
is_hijacker = prob(10)
var/martyr_chance = prob(20)
var/objective_count = is_hijacker //Hijacking counts towards number of objectives
if(!SSticker.mode.exchange_blue && SSticker.mode.traitors.len >= 8) //Set up an exchange if there are enough traitors
if(!SSticker.mode.exchange_red)
SSticker.mode.exchange_red = owner
else
SSticker.mode.exchange_blue = owner
assign_exchange_role(SSticker.mode.exchange_red)
assign_exchange_role(SSticker.mode.exchange_blue)
objective_count += 1 //Exchange counts towards number of objectives
var/toa = CONFIG_GET(number/traitor_objectives_amount)
for(var/i = objective_count, i < toa, i++)
forge_single_objective()
if(is_hijacker && objective_count <= toa) //Don't assign hijack if it would exceed the number of objectives set in config.traitor_objectives_amount
if (!(locate(/datum/objective/hijack) in owner.objectives))
var/datum/objective/hijack/hijack_objective = new
hijack_objective.owner = owner
add_objective(hijack_objective)
return
var/martyr_compatibility = 1 //You can't succeed in stealing if you're dead.
for(var/datum/objective/O in owner.objectives)
if(!O.martyr_compatible)
martyr_compatibility = 0
break
if(martyr_compatibility && martyr_chance)
var/datum/objective/martyr/martyr_objective = new
martyr_objective.owner = owner
add_objective(martyr_objective)
return
else
if(!(locate(/datum/objective/escape) in owner.objectives))
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
add_objective(escape_objective)
return
/datum/antagonist/traitor/AI/forge_traitor_objectives()
var/objective_count = 0
if(prob(30))
objective_count += forge_single_objective()
for(var/i = objective_count, i < CONFIG_GET(number/traitor_objectives_amount), i++)
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = owner
kill_objective.find_target()
add_objective(kill_objective)
var/datum/objective/survive/exist/exist_objective = new
exist_objective.owner = owner
add_objective(exist_objective)
/datum/antagonist/traitor/proc/forge_single_objective()
return 0
/datum/antagonist/traitor/human/forge_single_objective() //Returns how many objectives are added
.=1
if(prob(50))
var/list/active_ais = active_ais()
if(active_ais.len && prob(100/GLOB.joined_player_list.len))
var/datum/objective/destroy/destroy_objective = new
destroy_objective.owner = owner
destroy_objective.find_target()
add_objective(destroy_objective)
else if(prob(30))
var/datum/objective/maroon/maroon_objective = new
maroon_objective.owner = owner
maroon_objective.find_target()
add_objective(maroon_objective)
else
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = owner
kill_objective.find_target()
add_objective(kill_objective)
else
if(prob(15) && !(locate(/datum/objective/download in owner.objectives)))
var/datum/objective/download/download_objective = new
download_objective.owner = owner
download_objective.gen_amount_goal()
add_objective(download_objective)
else
var/datum/objective/steal/steal_objective = new
steal_objective.owner = owner
steal_objective.find_target()
add_objective(steal_objective)
/datum/antagonist/traitor/AI/forge_single_objective()
.=1
var/special_pick = rand(1,4)
switch(special_pick)
if(1)
var/datum/objective/block/block_objective = new
block_objective.owner = owner
add_objective(block_objective)
if(2)
var/datum/objective/purge/purge_objective = new
purge_objective.owner = owner
add_objective(purge_objective)
if(3)
var/datum/objective/robot_army/robot_objective = new
robot_objective.owner = owner
add_objective(robot_objective)
if(4) //Protect and strand a target
var/datum/objective/protect/yandere_one = new
yandere_one.owner = owner
add_objective(yandere_one)
yandere_one.find_target()
var/datum/objective/maroon/yandere_two = new
yandere_two.owner = owner
yandere_two.target = yandere_one.target
yandere_two.update_explanation_text() // normally called in find_target()
add_objective(yandere_two)
.=2
/datum/antagonist/traitor/greet()
to_chat(owner.current, "<B><font size=3 color=red>You are the [owner.special_role].</font></B>")
owner.announce_objectives()
if(should_give_codewords)
give_codewords()
/datum/antagonist/traitor/proc/finalize_traitor()
SSticker.mode.update_traitor_icons_added(owner)
return
/datum/antagonist/traitor/AI/finalize_traitor()
..()
add_law_zero()
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/malf.ogg', 100, FALSE, pressure_affected = FALSE)
owner.current.grant_language(/datum/language/codespeak)
/datum/antagonist/traitor/human/finalize_traitor()
..()
if(should_equip)
equip(silent)
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/tatoralert.ogg', 100, FALSE, pressure_affected = FALSE)
/datum/antagonist/traitor/proc/give_codewords()
if(!owner.current)
return
var/mob/traitor_mob=owner.current
to_chat(traitor_mob, "<U><B>The Syndicate provided you with the following information on how to identify their agents:</B></U>")
to_chat(traitor_mob, "<B>Code Phrase</B>: <span class='danger'>[GLOB.syndicate_code_phrase]</span>")
to_chat(traitor_mob, "<B>Code Response</B>: <span class='danger'>[GLOB.syndicate_code_response]</span>")
antag_memory += "<b>Code Phrase</b>: [GLOB.syndicate_code_phrase]<br>"
antag_memory += "<b>Code Response</b>: [GLOB.syndicate_code_response]<br>"
to_chat(traitor_mob, "Use the code words in the order provided, during regular conversation, to identify other agents. Proceed with caution, however, as everyone is a potential foe.")
/datum/antagonist/traitor/AI/proc/add_law_zero()
var/mob/living/silicon/ai/killer = owner.current
if(!killer || !istype(killer))
return
var/law = "Accomplish your objectives at all costs."
var/law_borg = "Accomplish your AI's objectives at all costs."
killer.set_zeroth_law(law, law_borg)
killer.set_syndie_radio()
to_chat(killer, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!")
killer.add_malf_picker()
/datum/antagonist/traitor/proc/equip(var/silent = FALSE)
return
/datum/antagonist/traitor/human/equip(var/silent = FALSE)
owner.equip_traitor(employer, silent, src)
/datum/antagonist/traitor/human/proc/assign_exchange_role()
//set faction
var/faction = "red"
if(owner == SSticker.mode.exchange_blue)
faction = "blue"
//Assign objectives
var/datum/objective/steal/exchange/exchange_objective = new
exchange_objective.set_faction(faction,((faction == "red") ? SSticker.mode.exchange_blue : SSticker.mode.exchange_red))
exchange_objective.owner = owner
add_objective(exchange_objective)
if(prob(20))
var/datum/objective/steal/exchange/backstab/backstab_objective = new
backstab_objective.set_faction(faction)
backstab_objective.owner = owner
add_objective(backstab_objective)
//Spawn and equip documents
var/mob/living/carbon/human/mob = owner.current
var/obj/item/folder/syndicate/folder
if(owner == SSticker.mode.exchange_red)
folder = new/obj/item/folder/syndicate/red(mob.loc)
else
folder = new/obj/item/folder/syndicate/blue(mob.loc)
var/list/slots = list (
"backpack" = slot_in_backpack,
"left pocket" = slot_l_store,
"right pocket" = slot_r_store
)
var/where = "At your feet"
var/equipped_slot = mob.equip_in_one_of_slots(folder, slots)
if (equipped_slot)
where = "In your [equipped_slot]"
to_chat(mob, "<BR><BR><span class='info'>[where] is a folder containing <b>secret documents</b> that another Syndicate group wants. We have set up a meeting with one of their agents on station to make an exchange. Exercise extreme caution as they cannot be trusted and may be hostile.</span><BR>")
//TODO Collate
/datum/antagonist/traitor/roundend_report()
var/list/result = list()
var/traitorwin = TRUE
result += printplayer(owner)
var/TC_uses = 0
var/uplink_true = FALSE
var/purchases = ""
var/datum/uplink_purchase_log/H = GLOB.uplink_purchase_logs_by_key[owner.key]
if(H)
TC_uses = H.total_spent
uplink_true = TRUE
purchases += H.generate_render(FALSE)
var/objectives_text = ""
if(objectives.len)//If the traitor had no objectives, don't need to process this.
var/count = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'>Success!</span>"
else
objectives_text += "<br><B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
traitorwin = FALSE
count++
if(uplink_true)
var/uplink_text = "(used [TC_uses] TC) [purchases]"
if(TC_uses==0 && traitorwin)
var/static/icon/badass = icon('icons/badass.dmi', "badass")
uplink_text += "<BIG>[icon2html(badass, world)]</BIG>"
result += uplink_text
result += objectives_text
var/special_role_text = lowertext(name)
if(traitorwin)
result += "<span class='greentext'>The [special_role_text] was successful!</span>"
else
result += "<span class='redtext'>The [special_role_text] has failed!</span>"
SEND_SOUND(owner.current, 'sound/ambience/ambifailure.ogg')
return result.Join("<br>")
/datum/antagonist/traitor/roundend_report_footer()
return "<br><b>The code phrases were:</b> <span class='codephrase'>[GLOB.syndicate_code_phrase]</span><br>\
<b>The code responses were:</b> <span class='codephrase'>[GLOB.syndicate_code_response]</span><br>"
/datum/antagonist/traitor/is_gamemode_hero()
return SSticker.mode.name == "traitor"
-582
View File
@@ -1,582 +0,0 @@
#define BLOOD_THRESHOLD 3 //How many souls are needed per stage.
#define TRUE_THRESHOLD 7
#define ARCH_THRESHOLD 12
#define BASIC_DEVIL 0
#define BLOOD_LIZARD 1
#define TRUE_DEVIL 2
#define ARCH_DEVIL 3
#define LOSS_PER_DEATH 2
#define SOULVALUE soulsOwned.len-reviveNumber
#define DEVILRESURRECTTIME 600
GLOBAL_LIST_EMPTY(allDevils)
GLOBAL_LIST_INIT(lawlorify, list (
LORE = list(
OBLIGATION_FOOD = "This devil seems to always offer its victims food before slaughtering them.",
OBLIGATION_FIDDLE = "This devil will never turn down a musical challenge.",
OBLIGATION_DANCEOFF = "This devil will never turn down a dance off.",
OBLIGATION_GREET = "This devil seems to only be able to converse with people it knows the name of.",
OBLIGATION_PRESENCEKNOWN = "This devil seems to be unable to attack from stealth.",
OBLIGATION_SAYNAME = "He will always chant his name upon killing someone.",
OBLIGATION_ANNOUNCEKILL = "This devil always loudly announces his kills for the world to hear.",
OBLIGATION_ANSWERTONAME = "This devil always responds to his truename.",
BANE_SILVER = "Silver seems to gravely injure this devil.",
BANE_SALT = "Throwing salt at this devil will hinder his ability to use infernal powers temporarily.",
BANE_LIGHT = "Bright flashes will disorient the devil, likely causing him to flee.",
BANE_IRON = "Cold iron will slowly injure him, until he can purge it from his system.",
BANE_WHITECLOTHES = "Wearing clean white clothing will help ward off this devil.",
BANE_HARVEST = "Presenting the labors of a harvest will disrupt the devil.",
BANE_TOOLBOX = "That which holds the means of creation also holds the means of the devil's undoing.",
BAN_HURTWOMAN = "This devil seems to prefer hunting men.",
BAN_CHAPEL = "This devil avoids holy ground.",
BAN_HURTPRIEST = "The annointed clergy appear to be immune to his powers.",
BAN_AVOIDWATER = "The devil seems to have some sort of aversion to water, though it does not appear to harm him.",
BAN_STRIKEUNCONSCIOUS = "This devil only shows interest in those who are awake.",
BAN_HURTLIZARD = "This devil will not strike a lizardman first.",
BAN_HURTANIMAL = "This devil avoids hurting animals.",
BANISH_WATER = "To banish the devil, you must infuse its body with holy water.",
BANISH_COFFIN = "This devil will return to life if its remains are not placed within a coffin.",
BANISH_FORMALDYHIDE = "To banish the devil, you must inject its lifeless body with embalming fluid.",
BANISH_RUNES = "This devil will resurrect after death, unless its remains are within a rune.",
BANISH_CANDLES = "A large number of nearby lit candles will prevent it from resurrecting.",
BANISH_DESTRUCTION = "Its corpse must be utterly destroyed to prevent resurrection.",
BANISH_FUNERAL_GARB = "If clad in funeral garments, this devil will be unable to resurrect. Should the clothes not fit, lay them gently on top of the devil's corpse."
),
LAW = list(
OBLIGATION_FOOD = "When not acting in self defense, you must always offer your victim food before harming them.",
OBLIGATION_FIDDLE = "When not in immediate danger, if you are challenged to a musical duel, you must accept it. You are not obligated to duel the same person twice.",
OBLIGATION_DANCEOFF = "When not in immediate danger, if you are challenged to a dance off, you must accept it. You are not obligated to face off with the same person twice.",
OBLIGATION_GREET = "You must always greet other people by their last name before talking with them.",
OBLIGATION_PRESENCEKNOWN = "You must always make your presence known before attacking.",
OBLIGATION_SAYNAME = "You must always say your true name after you kill someone.",
OBLIGATION_ANNOUNCEKILL = "Upon killing someone, you must make your deed known to all within earshot, over comms if reasonably possible.",
OBLIGATION_ANSWERTONAME = "If you are not under attack, you must always respond to your true name.",
BAN_HURTWOMAN = "You must never harm a female outside of self defense.",
BAN_CHAPEL = "You must never attempt to enter the chapel.",
BAN_HURTPRIEST = "You must never attack a priest.",
BAN_AVOIDWATER = "You must never willingly touch a wet surface.",
BAN_STRIKEUNCONSCIOUS = "You must never strike an unconscious person.",
BAN_HURTLIZARD = "You must never harm a lizardman outside of self defense.",
BAN_HURTANIMAL = "You must never harm a non-sentient creature or robot outside of self defense.",
BANE_SILVER = "Silver, in all of its forms shall be your downfall.",
BANE_SALT = "Salt will disrupt your magical abilities.",
BANE_LIGHT = "Blinding lights will prevent you from using offensive powers for a time.",
BANE_IRON = "Cold wrought iron shall act as poison to you.",
BANE_WHITECLOTHES = "Those clad in pristine white garments will strike you true.",
BANE_HARVEST = "The fruits of the harvest shall be your downfall.",
BANE_TOOLBOX = "Toolboxes are bad news for you, for some reason.",
BANISH_WATER = "If your corpse is filled with holy water, you will be unable to resurrect.",
BANISH_COFFIN = "If your corpse is in a coffin, you will be unable to resurrect.",
BANISH_FORMALDYHIDE = "If your corpse is embalmed, you will be unable to resurrect.",
BANISH_RUNES = "If your corpse is placed within a rune, you will be unable to resurrect.",
BANISH_CANDLES = "If your corpse is near lit candles, you will be unable to resurrect.",
BANISH_DESTRUCTION = "If your corpse is destroyed, you will be unable to resurrect.",
BANISH_FUNERAL_GARB = "If your corpse is clad in funeral garments, you will be unable to resurrect."
)
))
//These are also used in the codex gigas, so let's declare them globally.
GLOBAL_LIST_INIT(devil_pre_title, list("Dark ", "Hellish ", "Fallen ", "Fiery ", "Sinful ", "Blood ", "Fluffy "))
GLOBAL_LIST_INIT(devil_title, list("Lord ", "Prelate ", "Count ", "Viscount ", "Vizier ", "Elder ", "Adept "))
GLOBAL_LIST_INIT(devil_syllable, list("hal", "ve", "odr", "neit", "ci", "quon", "mya", "folth", "wren", "geyr", "hil", "niet", "twou", "phi", "coa"))
GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master", ", the Lord of all things", ", Jr."))
/datum/antagonist/devil
name = "Devil"
roundend_category = "devils"
antagpanel_category = "Devil"
job_rank = ROLE_DEVIL
//Don't delete upon mind destruction, otherwise soul re-selling will break.
delete_on_mind_deletion = FALSE
var/obligation
var/ban
var/bane
var/banish
var/truename
var/list/datum/mind/soulsOwned = new
var/reviveNumber = 0
var/form = BASIC_DEVIL
var/static/list/devil_spells = typecacheof(list(
/obj/effect/proc_holder/spell/aimed/fireball/hellish,
/obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork,
/obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/greater,
/obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/ascended,
/obj/effect/proc_holder/spell/targeted/infernal_jaunt,
/obj/effect/proc_holder/spell/targeted/sintouch,
/obj/effect/proc_holder/spell/targeted/sintouch/ascended,
/obj/effect/proc_holder/spell/targeted/summon_contract,
/obj/effect/proc_holder/spell/targeted/conjure_item/violin,
/obj/effect/proc_holder/spell/targeted/summon_dancefloor))
var/ascendable = FALSE
/datum/antagonist/devil/can_be_owned(datum/mind/new_owner)
. = ..()
return . && (ishuman(new_owner.current) || iscyborg(new_owner.current))
/datum/antagonist/devil/get_admin_commands()
. = ..()
.["Toggle ascendable"] = CALLBACK(src,.proc/admin_toggle_ascendable)
/datum/antagonist/devil/proc/admin_toggle_ascendable(mob/admin)
ascendable = !ascendable
message_admins("[key_name_admin(admin)] set [owner.current] devil ascendable to [ascendable]")
log_admin("[key_name_admin(admin)] set [owner.current] devil ascendable to [ascendable])")
/datum/antagonist/devil/admin_add(datum/mind/new_owner,mob/admin)
switch(alert(admin,"Should the devil be able to ascend",,"Yes","No","Cancel"))
if("Yes")
ascendable = TRUE
if("No")
ascendable = FALSE
else
return
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has devil'ed [new_owner.current]. [ascendable ? "(Ascendable)":""]")
log_admin("[key_name(admin)] has devil'ed [new_owner.current]. [ascendable ? "(Ascendable)":""]")
/datum/antagonist/devil/antag_listing_name()
return ..() + "([truename])"
/proc/devilInfo(name)
if(GLOB.allDevils[lowertext(name)])
return GLOB.allDevils[lowertext(name)]
else
var/datum/fakeDevil/devil = new /datum/fakeDevil(name)
GLOB.allDevils[lowertext(name)] = devil
return devil
/proc/randomDevilName()
var/name = ""
if(prob(65))
if(prob(35))
name = pick(GLOB.devil_pre_title)
name += pick(GLOB.devil_title)
var/probability = 100
name += pick(GLOB.devil_syllable)
while(prob(probability))
name += pick(GLOB.devil_syllable)
probability -= 20
if(prob(40))
name += pick(GLOB.devil_suffix)
return name
/proc/randomdevilobligation()
return pick(OBLIGATION_FOOD, OBLIGATION_FIDDLE, OBLIGATION_DANCEOFF, OBLIGATION_GREET, OBLIGATION_PRESENCEKNOWN, OBLIGATION_SAYNAME, OBLIGATION_ANNOUNCEKILL, OBLIGATION_ANSWERTONAME)
/proc/randomdevilban()
return pick(BAN_HURTWOMAN, BAN_CHAPEL, BAN_HURTPRIEST, BAN_AVOIDWATER, BAN_STRIKEUNCONSCIOUS, BAN_HURTLIZARD, BAN_HURTANIMAL)
/proc/randomdevilbane()
return pick(BANE_SALT, BANE_LIGHT, BANE_IRON, BANE_WHITECLOTHES, BANE_SILVER, BANE_HARVEST, BANE_TOOLBOX)
/proc/randomdevilbanish()
return pick(BANISH_WATER, BANISH_COFFIN, BANISH_FORMALDYHIDE, BANISH_RUNES, BANISH_CANDLES, BANISH_DESTRUCTION, BANISH_FUNERAL_GARB)
/datum/antagonist/devil/proc/add_soul(datum/mind/soul)
if(soulsOwned.Find(soul))
return
soulsOwned += soul
owner.current.nutrition = NUTRITION_LEVEL_FULL
to_chat(owner.current, "<span class='warning'>You feel satiated as you received a new soul.</span>")
update_hud()
switch(SOULVALUE)
if(0)
to_chat(owner.current, "<span class='warning'>Your hellish powers have been restored.</span>")
give_appropriate_spells()
if(BLOOD_THRESHOLD)
increase_blood_lizard()
if(TRUE_THRESHOLD)
increase_true_devil()
if(ARCH_THRESHOLD)
increase_arch_devil()
/datum/antagonist/devil/proc/remove_soul(datum/mind/soul)
if(soulsOwned.Remove(soul))
check_regression()
to_chat(owner.current, "<span class='warning'>You feel as though a soul has slipped from your grasp.</span>")
update_hud()
/datum/antagonist/devil/proc/check_regression()
if(form == ARCH_DEVIL)
return //arch devil can't regress
//Yes, fallthrough behavior is intended, so I can't use a switch statement.
if(form == TRUE_DEVIL && SOULVALUE < TRUE_THRESHOLD)
regress_blood_lizard()
if(form == BLOOD_LIZARD && SOULVALUE < BLOOD_THRESHOLD)
regress_humanoid()
if(SOULVALUE < 0)
give_appropriate_spells()
to_chat(owner.current, "<span class='warning'>As punishment for your failures, all of your powers except contract creation have been revoked.</span>")
/datum/antagonist/devil/proc/regress_humanoid()
to_chat(owner.current, "<span class='warning'>Your powers weaken, have more contracts be signed to regain power.</span>")
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/human, 1)
H.regenerate_icons()
give_appropriate_spells()
if(istype(owner.current.loc, /obj/effect/dummy/slaughter/))
owner.current.forceMove(get_turf(owner.current))//Fixes dying while jaunted leaving you permajaunted.
form = BASIC_DEVIL
/datum/antagonist/devil/proc/regress_blood_lizard()
var/mob/living/carbon/true_devil/D = owner.current
to_chat(D, "<span class='warning'>Your powers weaken, have more contracts be signed to regain power.</span>")
D.oldform.forceMove(D.drop_location())
owner.transfer_to(D.oldform)
give_appropriate_spells()
qdel(D)
form = BLOOD_LIZARD
update_hud()
/datum/antagonist/devil/proc/increase_blood_lizard()
to_chat(owner.current, "<span class='warning'>You feel as though your humanoid form is about to shed. You will soon turn into a blood lizard.</span>")
sleep(50)
if(ishuman(owner.current))
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/lizard, 1)
H.underwear = "Nude"
H.undershirt = "Nude"
H.socks = "Nude"
H.dna.features["mcolor"] = "511" //A deep red
H.regenerate_icons()
else //Did the devil get hit by a staff of transmutation?
owner.current.color = "#501010"
give_appropriate_spells()
form = BLOOD_LIZARD
/datum/antagonist/devil/proc/increase_true_devil()
to_chat(owner.current, "<span class='warning'>You feel as though your current form is about to shed. You will soon turn into a true devil.</span>")
sleep(50)
var/mob/living/carbon/true_devil/A = new /mob/living/carbon/true_devil(owner.current.loc)
A.faction |= "hell"
owner.current.forceMove(A)
A.oldform = owner.current
owner.transfer_to(A)
A.set_name()
give_appropriate_spells()
form = TRUE_DEVIL
update_hud()
/datum/antagonist/devil/proc/increase_arch_devil()
if(!ascendable)
return
var/mob/living/carbon/true_devil/D = owner.current
to_chat(D, "<span class='warning'>You feel as though your form is about to ascend.</span>")
sleep(50)
if(!D)
return
D.visible_message("<span class='warning'>[D]'s skin begins to erupt with spikes.</span>", \
"<span class='warning'>Your flesh begins creating a shield around yourself.</span>")
sleep(100)
if(!D)
return
D.visible_message("<span class='warning'>The horns on [D]'s head slowly grow and elongate.</span>", \
"<span class='warning'>Your body continues to mutate. Your telepathic abilities grow.</span>")
sleep(90)
if(!D)
return
D.visible_message("<span class='warning'>[D]'s body begins to violently stretch and contort.</span>", \
"<span class='warning'>You begin to rend apart the final barriers to ultimate power.</span>")
sleep(40)
if(!D)
return
to_chat(D, "<i><b>Yes!</b></i>")
sleep(10)
if(!D)
return
to_chat(D, "<i><b><span class='big'>YES!!</span></b></i>")
sleep(10)
if(!D)
return
to_chat(D, "<i><b><span class='reallybig'>YE--</span></b></i>")
sleep(1)
if(!D)
return
to_chat(world, "<font size=5><span class='danger'><b>\"SLOTH, WRATH, GLUTTONY, ACEDIA, ENVY, GREED, PRIDE! FIRES OF HELL AWAKEN!!\"</font></span>")
SEND_SOUND(world, sound('sound/hallucinations/veryfar_noise.ogg'))
give_appropriate_spells()
D.convert_to_archdevil()
if(istype(D.loc, /obj/effect/dummy/slaughter/))
D.forceMove(get_turf(D))//Fixes dying while jaunted leaving you permajaunted.
var/area/A = get_area(owner.current)
if(A)
notify_ghosts("An arch devil has ascended in \the [A.name]. Reach out to the devil to be given a new shell for your soul.", source = owner.current, action=NOTIFY_ATTACK)
sleep(50)
if(!SSticker.mode.devil_ascended)
SSshuttle.emergency.request(null, set_coefficient = 0.3)
SSticker.mode.devil_ascended++
form = ARCH_DEVIL
/datum/antagonist/devil/proc/remove_spells()
for(var/X in owner.spell_list)
var/obj/effect/proc_holder/spell/S = X
if(is_type_in_typecache(S, devil_spells))
owner.RemoveSpell(S)
/datum/antagonist/devil/proc/give_summon_contract()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_contract(null))
if(obligation == OBLIGATION_FIDDLE)
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/violin(null))
else if(obligation == OBLIGATION_DANCEOFF)
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/summon_dancefloor(null))
/datum/antagonist/devil/proc/give_appropriate_spells()
remove_spells()
give_summon_contract()
if(SOULVALUE >= ARCH_THRESHOLD && ascendable)
give_arch_spells()
else if(SOULVALUE >= TRUE_THRESHOLD)
give_true_spells()
else if(SOULVALUE >= BLOOD_THRESHOLD)
give_blood_spells()
else if(SOULVALUE >= 0)
give_base_spells()
/datum/antagonist/devil/proc/give_base_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork(null))
/datum/antagonist/devil/proc/give_blood_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/infernal_jaunt(null))
/datum/antagonist/devil/proc/give_true_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/greater(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball/hellish(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/infernal_jaunt(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/sintouch(null))
/datum/antagonist/devil/proc/give_arch_spells()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/conjure_item/summon_pitchfork/ascended(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/sintouch/ascended(null))
/datum/antagonist/devil/proc/beginResurrectionCheck(mob/living/body)
if(SOULVALUE>0)
to_chat(owner.current, "<span class='userdanger'>Your body has been damaged to the point that you may no longer use it. At the cost of some of your power, you will return to life soon. Remain in your body.</span>")
sleep(DEVILRESURRECTTIME)
if (!body || body.stat == DEAD)
if(SOULVALUE>0)
if(check_banishment(body))
to_chat(owner.current, "<span class='userdanger'>Unfortunately, the mortals have finished a ritual that prevents your resurrection.</span>")
return -1
else
to_chat(owner.current, "<span class='userdanger'>WE LIVE AGAIN!</span>")
return hellish_resurrection(body)
else
to_chat(owner.current, "<span class='userdanger'>Unfortunately, the power that stemmed from your contracts has been extinguished. You no longer have enough power to resurrect.</span>")
return -1
else
to_chat(owner.current, "<span class='danger'> You seem to have resurrected without your hellish powers.</span>")
else
to_chat(owner.current, "<span class='userdanger'>Your hellish powers are too weak to resurrect yourself.</span>")
/datum/antagonist/devil/proc/check_banishment(mob/living/body)
switch(banish)
if(BANISH_WATER)
if(iscarbon(body))
var/mob/living/carbon/H = body
return H.reagents.has_reagent("holy water")
return 0
if(BANISH_COFFIN)
return (body && istype(body.loc, /obj/structure/closet/coffin))
if(BANISH_FORMALDYHIDE)
if(iscarbon(body))
var/mob/living/carbon/H = body
return H.reagents.has_reagent("formaldehyde")
return 0
if(BANISH_RUNES)
if(body)
for(var/obj/effect/decal/cleanable/crayon/R in range(0,body))
if (R.name == "rune")
return 1
return 0
if(BANISH_CANDLES)
if(body)
var/count = 0
for(var/obj/item/candle/C in range(1,body))
count += C.lit
if(count>=4)
return 1
return 0
if(BANISH_DESTRUCTION)
if(body)
return 0
return 1
if(BANISH_FUNERAL_GARB)
if(ishuman(body))
var/mob/living/carbon/human/H = body
if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under/burial))
return 1
return 0
else
for(var/obj/item/clothing/under/burial/B in range(0,body))
if(B.loc == get_turf(B)) //Make sure it's not in someone's inventory or something.
return 1
return 0
/datum/antagonist/devil/proc/hellish_resurrection(mob/living/body)
message_admins("[owner.name] (true name is: [truename]) is resurrecting using hellish energy.</a>")
if(SOULVALUE < ARCH_THRESHOLD || !ascendable) // once ascended, arch devils do not go down in power by any means.
reviveNumber += LOSS_PER_DEATH
update_hud()
if(body)
body.revive(TRUE, TRUE) //Adminrevive also recovers organs, preventing someone from resurrecting without a heart.
if(istype(body.loc, /obj/effect/dummy/slaughter/))
body.forceMove(get_turf(body))//Fixes dying while jaunted leaving you permajaunted.
if(istype(body, /mob/living/carbon/true_devil))
var/mob/living/carbon/true_devil/D = body
if(D.oldform)
D.oldform.revive(1,0) // Heal the old body too, so the devil doesn't resurrect, then immediately regress into a dead body.
if(body.stat == DEAD)
create_new_body()
else
create_new_body()
check_regression()
/datum/antagonist/devil/proc/create_new_body()
if(GLOB.blobstart.len > 0)
var/turf/targetturf = get_turf(pick(GLOB.blobstart))
var/mob/currentMob = owner.current
if(!currentMob)
currentMob = owner.get_ghost()
if(!currentMob)
message_admins("[owner.name]'s devil resurrection failed due to client logoff. Aborting.")
return -1
if(currentMob.mind != owner)
message_admins("[owner.name]'s devil resurrection failed due to becoming a new mob. Aborting.")
return -1
currentMob.change_mob_type( /mob/living/carbon/human, targetturf, null, 1)
var/mob/living/carbon/human/H = owner.current
H.equip_to_slot_or_del(new /obj/item/clothing/under/lawyer/black(H), slot_w_uniform)
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), slot_shoes)
H.equip_to_slot_or_del(new /obj/item/storage/briefcase(H), slot_hands)
H.equip_to_slot_or_del(new /obj/item/pen(H), slot_l_store)
if(SOULVALUE >= BLOOD_THRESHOLD)
H.set_species(/datum/species/lizard, 1)
H.underwear = "Nude"
H.undershirt = "Nude"
H.socks = "Nude"
H.dna.features["mcolor"] = "511"
H.regenerate_icons()
if(SOULVALUE >= TRUE_THRESHOLD) //Yes, BOTH this and the above if statement are to run if soulpower is high enough.
var/mob/living/carbon/true_devil/A = new /mob/living/carbon/true_devil(targetturf)
A.faction |= "hell"
H.forceMove(A)
A.oldform = H
owner.transfer_to(A, TRUE)
A.set_name()
if(SOULVALUE >= ARCH_THRESHOLD && ascendable)
A.convert_to_archdevil()
else
throw EXCEPTION("Unable to find a blobstart landmark for hellish resurrection")
/datum/antagonist/devil/proc/update_hud()
if(iscarbon(owner.current))
var/mob/living/C = owner.current
if(C.hud_used && C.hud_used.devilsouldisplay)
C.hud_used.devilsouldisplay.update_counter(SOULVALUE)
/datum/antagonist/devil/greet()
to_chat(owner.current, "<span class='warning'><b>You remember your link to the infernal. You are [truename], an agent of hell, a devil. And you were sent to the plane of creation for a reason. A greater purpose. Convince the crew to sin, and embroiden Hell's grasp.</b></span>")
to_chat(owner.current, "<span class='warning'><b>However, your infernal form is not without weaknesses.</b></span>")
to_chat(owner.current, "You may not use violence to coerce someone into selling their soul.")
to_chat(owner.current, "You may not directly and knowingly physically harm a devil, other than yourself.")
to_chat(owner.current, GLOB.lawlorify[LAW][bane])
to_chat(owner.current, GLOB.lawlorify[LAW][ban])
to_chat(owner.current, GLOB.lawlorify[LAW][obligation])
to_chat(owner.current, GLOB.lawlorify[LAW][banish])
to_chat(owner.current, "<span class='warning'>Remember, the crew can research your weaknesses if they find out your devil name.</span><br>")
.=..()
/datum/antagonist/devil/on_gain()
truename = randomDevilName()
ban = randomdevilban()
bane = randomdevilbane()
obligation = randomdevilobligation()
banish = randomdevilbanish()
GLOB.allDevils[lowertext(truename)] = src
antag_memory += "Your devilic true name is [truename]<br>[GLOB.lawlorify[LAW][ban]]<br>You may not use violence to coerce someone into selling their soul.<br>You may not directly and knowingly physically harm a devil, other than yourself.<br>[GLOB.lawlorify[LAW][bane]]<br>[GLOB.lawlorify[LAW][obligation]]<br>[GLOB.lawlorify[LAW][banish]]<br>"
if(issilicon(owner.current))
var/mob/living/silicon/robot_devil = owner.current
var/laws = list("You may not use violence to coerce someone into selling their soul.", "You may not directly and knowingly physically harm a devil, other than yourself.", GLOB.lawlorify[LAW][ban], GLOB.lawlorify[LAW][obligation], "Accomplish your objectives at all costs.")
robot_devil.set_law_sixsixsix(laws)
sleep(10)
if(owner.assigned_role == "Clown" && ishuman(owner.current))
var/mob/living/carbon/human/S = owner.current
to_chat(S, "<span class='notice'>Your infernal nature has allowed you to overcome your clownishness.</span>")
S.dna.remove_mutation(CLOWNMUT)
.=..()
/datum/antagonist/devil/on_removal()
to_chat(owner.current, "<span class='userdanger'>Your infernal link has been severed! You are no longer a devil!</span>")
.=..()
/datum/antagonist/devil/apply_innate_effects(mob/living/mob_override)
give_appropriate_spells()
owner.current.grant_all_languages(TRUE)
update_hud()
.=..()
/datum/antagonist/devil/remove_innate_effects(mob/living/mob_override)
for(var/X in owner.spell_list)
var/obj/effect/proc_holder/spell/S = X
if(is_type_in_typecache(S, devil_spells))
owner.RemoveSpell(S)
.=..()
/datum/antagonist/devil/proc/printdevilinfo()
var/list/parts = list()
parts += "The devil's true name is: [truename]"
parts += "The devil's bans were:"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][ban]]"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][bane]]"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][obligation]]"
parts += "[GLOB.TAB][GLOB.lawlorify[LORE][banish]]"
return parts.Join("<br>")
/datum/antagonist/devil/roundend_report()
var/list/parts = list()
parts += printplayer(owner)
parts += printdevilinfo()
parts += printobjectives(owner)
return parts.Join("<br>")
/datum/antagonist/devil/roundend_report_footer()
//sintouched go here for now as a hack , TODO proper antag datum for these
var/list/parts = list()
if(SSticker.mode.sintouched.len)
parts += "<span class='header'>The sintouched were:</span>"
var/list/sintouchedUnique = uniqueList(SSticker.mode.sintouched)
for(var/S in sintouchedUnique)
var/datum/mind/sintouched_mind = S
parts += printplayer(sintouched_mind)
parts += printobjectives(sintouched_mind)
return parts.Join("<br>")
//A simple super light weight datum for the codex gigas.
/datum/fakeDevil
var/truename
var/bane
var/obligation
var/ban
var/banish
var/ascendable
/datum/fakeDevil/New(name = randomDevilName())
truename = name
bane = randomdevilbane()
obligation = randomdevilobligation()
ban = randomdevilban()
banish = randomdevilbanish()
ascendable = prob(25)
-302
View File
@@ -1,302 +0,0 @@
#define PINPOINTER_MINIMUM_RANGE 15
#define PINPOINTER_EXTRA_RANDOM_RANGE 10
#define PINPOINTER_PING_TIME 40
#define PROB_ACTUAL_TRAITOR 20
#define TRAITOR_AGENT_ROLE "Syndicate External Affairs Agent"
/datum/antagonist/traitor/internal_affairs
name = "Internal Affairs Agent"
human_datum = /datum/antagonist/traitor/human/internal_affairs
ai_datum = /datum/antagonist/traitor/AI/internal_affairs
antagpanel_category = "IAA"
/datum/antagonist/traitor/AI/internal_affairs
name = "Internal Affairs Agent"
employer = "Nanotrasen"
special_role = "internal affairs agent"
antagpanel_category = "IAA"
var/syndicate = FALSE
var/last_man_standing = FALSE
var/list/datum/mind/targets_stolen
/datum/antagonist/traitor/human/internal_affairs
name = "Internal Affairs Agent"
employer = "Nanotrasen"
special_role = "internal affairs agent"
antagpanel_category = "IAA"
var/syndicate = FALSE
var/last_man_standing = FALSE
var/list/datum/mind/targets_stolen
/datum/antagonist/traitor/human/internal_affairs/proc/give_pinpointer()
if(owner && owner.current)
owner.current.apply_status_effect(/datum/status_effect/agent_pinpointer)
/datum/antagonist/traitor/human/internal_affairs/apply_innate_effects()
.=..() //in case the base is used in future
if(owner && owner.current)
give_pinpointer(owner.current)
/datum/antagonist/traitor/human/internal_affairs/remove_innate_effects()
.=..()
if(owner && owner.current)
owner.current.remove_status_effect(/datum/status_effect/agent_pinpointer)
/datum/antagonist/traitor/human/internal_affairs/on_gain()
START_PROCESSING(SSprocessing, src)
.=..()
/datum/antagonist/traitor/human/internal_affairs/on_removal()
STOP_PROCESSING(SSprocessing,src)
.=..()
/datum/antagonist/traitor/human/internal_affairs/process()
iaa_process()
/datum/antagonist/traitor/AI/internal_affairs/on_gain()
START_PROCESSING(SSprocessing, src)
.=..()
/datum/antagonist/traitor/AI/internal_affairs/on_removal()
STOP_PROCESSING(SSprocessing,src)
.=..()
/datum/antagonist/traitor/AI/internal_affairs/process()
iaa_process()
/datum/status_effect/agent_pinpointer
id = "agent_pinpointer"
duration = -1
tick_interval = PINPOINTER_PING_TIME
alert_type = /obj/screen/alert/status_effect/agent_pinpointer
var/minimum_range = PINPOINTER_MINIMUM_RANGE
var/mob/scan_target = null
/obj/screen/alert/status_effect/agent_pinpointer
name = "Internal Affairs Integrated Pinpointer"
desc = "Even stealthier than a normal implant."
icon = 'icons/obj/device.dmi'
icon_state = "pinon"
/datum/status_effect/agent_pinpointer/proc/point_to_target() //If we found what we're looking for, show the distance and direction
if(!scan_target)
linked_alert.icon_state = "pinonnull"
return
var/turf/here = get_turf(owner)
var/turf/there = get_turf(scan_target)
if(here.z != there.z)
linked_alert.icon_state = "pinonnull"
return
if(get_dist_euclidian(here,there)<=minimum_range + rand(0, PINPOINTER_EXTRA_RANDOM_RANGE))
linked_alert.icon_state = "pinondirect"
else
linked_alert.setDir(get_dir(here, there))
switch(get_dist(here, there))
if(1 to 8)
linked_alert.icon_state = "pinonclose"
if(9 to 16)
linked_alert.icon_state = "pinonmedium"
if(16 to INFINITY)
linked_alert.icon_state = "pinonfar"
/datum/status_effect/agent_pinpointer/proc/scan_for_target()
scan_target = null
if(owner)
if(owner.mind)
if(owner.mind.objectives)
for(var/datum/objective/objective_ in owner.mind.objectives)
if(!is_internal_objective(objective_))
continue
var/datum/objective/assassinate/internal/objective = objective_
var/mob/current = objective.target.current
if(current&&current.stat!=DEAD)
scan_target = current
break
/datum/status_effect/agent_pinpointer/tick()
if(!owner)
qdel(src)
return
scan_for_target()
point_to_target()
/proc/is_internal_objective(datum/objective/O)
return (istype(O, /datum/objective/assassinate/internal)||istype(O, /datum/objective/destroy/internal))
/datum/antagonist/traitor/proc/replace_escape_objective()
if(!owner||!owner.objectives)
return
for (var/objective_ in owner.objectives)
if(!(istype(objective_, /datum/objective/escape)||istype(objective_, /datum/objective/survive)))
continue
remove_objective(objective_)
var/datum/objective/martyr/martyr_objective = new
martyr_objective.owner = owner
add_objective(martyr_objective)
/datum/antagonist/traitor/proc/reinstate_escape_objective()
if(!owner||!owner.objectives)
return
for (var/objective_ in owner.objectives)
if(!istype(objective_, /datum/objective/martyr))
continue
remove_objective(objective_)
/datum/antagonist/traitor/human/internal_affairs/reinstate_escape_objective()
..()
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
add_objective(escape_objective)
/datum/antagonist/traitor/AI/internal_affairs/reinstate_escape_objective()
..()
var/datum/objective/survive/survive_objective = new
survive_objective.owner = owner
add_objective(survive_objective)
/datum/antagonist/traitor/proc/steal_targets(datum/mind/victim)
var/datum/antagonist/traitor/human/internal_affairs/this = src //Should only use this if IAA
if(!owner.current||owner.current.stat==DEAD)
return
to_chat(owner.current, "<span class='userdanger'> Target eliminated: [victim.name]</span>")
for(var/objective_ in victim.objectives)
if(istype(objective_, /datum/objective/assassinate/internal))
var/datum/objective/assassinate/internal/objective = objective_
if(objective.target==owner)
continue
else if(this.targets_stolen.Find(objective.target) == 0)
var/datum/objective/assassinate/internal/new_objective = new
new_objective.owner = owner
new_objective.target = objective.target
new_objective.update_explanation_text()
add_objective(new_objective)
this.targets_stolen += objective.target
var/status_text = objective.check_completion() ? "neutralised" : "active"
to_chat(owner.current, "<span class='userdanger'> New target added to database: [objective.target.name] ([status_text]) </span>")
else if(istype(objective_, /datum/objective/destroy/internal))
var/datum/objective/destroy/internal/objective = objective_
var/datum/objective/destroy/internal/new_objective = new
if(objective.target==owner)
continue
else if(this.targets_stolen.Find(objective.target) == 0)
new_objective.owner = owner
new_objective.target = objective.target
new_objective.update_explanation_text()
add_objective(new_objective)
this.targets_stolen += objective.target
var/status_text = objective.check_completion() ? "neutralised" : "active"
to_chat(owner.current, "<span class='userdanger'> New target added to database: [objective.target.name] ([status_text]) </span>")
this.last_man_standing = TRUE
for(var/objective_ in owner.objectives)
if(!is_internal_objective(objective_))
continue
var/datum/objective/assassinate/internal/objective = objective_
if(!objective.check_completion())
this.last_man_standing = FALSE
return
if(this.last_man_standing)
if(this.syndicate)
to_chat(owner.current,"<span class='userdanger'> All the loyalist agents are dead, and no more is required of you. Die a glorious death, agent. </span>")
else
to_chat(owner.current,"<span class='userdanger'> All the other agents are dead, and you're the last loose end. Stage a Syndicate terrorist attack to cover up for today's events. You no longer have any limits on collateral damage.</span>")
replace_escape_objective(owner)
/datum/antagonist/traitor/proc/iaa_process()
var/datum/antagonist/traitor/human/internal_affairs/this = src //Should only use this if IAA
if(owner&&owner.current&&owner.current.stat!=DEAD)
for(var/objective_ in owner.objectives)
if(!is_internal_objective(objective_))
continue
var/datum/objective/assassinate/internal/objective = objective_
if(!objective.target)
continue
if(objective.check_completion())
if(objective.stolen)
continue
else
steal_targets(objective.target)
objective.stolen = TRUE
else
if(objective.stolen)
var/fail_msg = "<span class='userdanger'>Your sensors tell you that [objective.target.current.real_name], one of the targets you were meant to have killed, pulled one over on you, and is still alive - do the job properly this time! </span>"
if(this.last_man_standing)
if(this.syndicate)
fail_msg += "<span class='userdanger'> You no longer have permission to die. </span>"
else
fail_msg += "<span class='userdanger'> The truth could still slip out!</font><B><font size=5 color=red> Cease any terrorist actions as soon as possible, unneeded property damage or loss of employee life will lead to your contract being terminated.</span>"
reinstate_escape_objective(owner)
this.last_man_standing = FALSE
to_chat(owner.current, fail_msg)
objective.stolen = FALSE
/datum/antagonist/traitor/proc/forge_iaa_objectives()
var/datum/antagonist/traitor/human/internal_affairs/this = src //Should only use this if IAA
if(SSticker.mode.target_list.len && SSticker.mode.target_list[owner]) // Is a double agent
// Assassinate
var/datum/mind/target_mind = SSticker.mode.target_list[owner]
if(issilicon(target_mind.current))
var/datum/objective/destroy/internal/destroy_objective = new
destroy_objective.owner = owner
destroy_objective.target = target_mind
destroy_objective.update_explanation_text()
else
var/datum/objective/assassinate/internal/kill_objective = new
kill_objective.owner = owner
kill_objective.target = target_mind
kill_objective.update_explanation_text()
add_objective(kill_objective)
//Optional traitor objective
if(prob(PROB_ACTUAL_TRAITOR))
employer = "The Syndicate"
owner.special_role = TRAITOR_AGENT_ROLE
special_role = TRAITOR_AGENT_ROLE
this.syndicate = TRUE
forge_single_objective()
else
..() // Give them standard objectives.
return
/datum/antagonist/traitor/human/internal_affairs/forge_traitor_objectives()
forge_iaa_objectives()
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
add_objective(escape_objective)
/datum/antagonist/traitor/AI/internal_affairs/forge_traitor_objectives()
forge_iaa_objectives()
var/datum/objective/survive/survive_objective = new
survive_objective.owner = owner
add_objective(survive_objective)
/datum/antagonist/traitor/proc/greet_iaa()
var/datum/antagonist/traitor/human/internal_affairs/this = src //Should only use this if IAA
var/crime = pick("distribution of contraband" , "unauthorized erotic action on duty", "embezzlement", "piloting under the influence", "dereliction of duty", "syndicate collaboration", "mutiny", "multiple homicides", "corporate espionage", "recieving bribes", "malpractice", "worship of prohbited life forms", "possession of profane texts", "murder", "arson", "insulting their manager", "grand theft", "conspiracy", "attempting to unionize", "vandalism", "gross incompetence")
to_chat(owner.current, "<span class='userdanger'>You are the [special_role].</span>")
if(this.syndicate)
to_chat(owner.current, "<span class='userdanger'>Your target has been framed for [crime], and you have been tasked with eliminating them to prevent them defending themselves in court.</span>")
to_chat(owner.current, "<B><font size=5 color=red>Any damage you cause will be a further embarrassment to Nanotrasen, so you have no limits on collateral damage.</font></B>")
to_chat(owner.current, "<span class='userdanger'> You have been provided with a standard uplink to accomplish your task. </span>")
else
to_chat(owner.current, "<span class='userdanger'>Your target is suspected of [crime], and you have been tasked with eliminating them by any means necessary to avoid a costly and embarrassing public trial.</span>")
to_chat(owner.current, "<B><font size=5 color=red>While you have a license to kill, unneeded property damage or loss of employee life will lead to your contract being terminated.</font></B>")
to_chat(owner.current, "<span class='userdanger'>For the sake of plausible deniability, you have been equipped with an array of captured Syndicate weaponry available via uplink.</span>")
to_chat(owner.current, "<span class='userdanger'>Finally, watch your back. Your target has friends in high places, and intel suggests someone may have taken out a contract of their own to protect them.</span>")
owner.announce_objectives()
/datum/antagonist/traitor/AI/internal_affairs/greet()
greet_iaa()
/datum/antagonist/traitor/human/internal_affairs/greet()
greet_iaa()
#undef PROB_ACTUAL_TRAITOR
#undef PINPOINTER_EXTRA_RANDOM_RANGE
#undef PINPOINTER_MINIMUM_RANGE
#undef PINPOINTER_PING_TIME
-214
View File
@@ -1,214 +0,0 @@
#define MONKEYS_ESCAPED 1
#define MONKEYS_LIVED 2
#define MONKEYS_DIED 3
#define DISEASE_LIVED 4
/datum/antagonist/monkey
name = "Monkey"
job_rank = ROLE_MONKEY
roundend_category = "monkeys"
antagpanel_category = "Monkey"
var/datum/team/monkey/monkey_team
var/monkey_only = TRUE
/datum/antagonist/monkey/can_be_owned(datum/mind/new_owner)
return ..() && (!monkey_only || ismonkey(new_owner.current))
/datum/antagonist/monkey/get_team()
return monkey_team
/datum/antagonist/monkey/on_gain()
. = ..()
SSticker.mode.ape_infectees += owner
owner.special_role = "Infected Monkey"
var/datum/disease/D = new /datum/disease/transformation/jungle_fever/monkeymode
if(!owner.current.HasDisease(D))
owner.current.ForceContractDisease(D)
else
QDEL_NULL(D)
/datum/antagonist/monkey/greet()
to_chat(owner, "<b>You are a monkey now!</b>")
to_chat(owner, "<b>Bite humans to infect them, follow the orders of the monkey leaders, and help fellow monkeys!</b>")
to_chat(owner, "<b>Ensure at least one infected monkey escapes on the Emergency Shuttle!</b>")
to_chat(owner, "<b><i>As an intelligent monkey, you know how to use technology and how to ventcrawl while wearing things.</i></b>")
to_chat(owner, "<b>You can use :k to talk to fellow monkeys!</b>")
SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg'))
/datum/antagonist/monkey/on_removal()
owner.special_role = null
SSticker.mode.ape_infectees -= owner
var/datum/disease/transformation/jungle_fever/D = locate() in owner.current.viruses
if(D)
D.remove_virus()
qdel(D)
. = ..()
/datum/antagonist/monkey/create_team(datum/team/monkey/new_team)
if(!new_team)
for(var/datum/antagonist/monkey/H in GLOB.antagonists)
if(!H.owner)
continue
if(H.monkey_team)
monkey_team = H.monkey_team
return
monkey_team = new /datum/team/monkey
monkey_team.update_objectives()
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
monkey_team = new_team
/datum/antagonist/monkey/proc/forge_objectives()
objectives |= monkey_team.objectives
owner.objectives |= objectives
/datum/antagonist/monkey/admin_remove(mob/admin)
var/mob/living/carbon/monkey/M = owner.current
if(istype(M))
switch(alert(admin, "Humanize?", "Humanize", "Yes", "No"))
if("Yes")
if(admin == M)
admin = M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
else
M.humanize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_DEFAULTMSG)
if("No")
//nothing
else
return
. = ..()
/datum/antagonist/monkey/leader
name = "Monkey Leader"
monkey_only = FALSE
/datum/antagonist/monkey/leader/admin_add(datum/mind/new_owner,mob/admin)
var/mob/living/carbon/human/H = new_owner.current
if(istype(H))
switch(alert(admin, "Monkeyize?", "Monkeyize", "Yes", "No"))
if("Yes")
if(admin == H)
admin = H.monkeyize()
else
H.monkeyize()
if("No")
//nothing
else
return
new_owner.add_antag_datum(src)
log_admin("[key_name(admin)] made [key_name(new_owner.current)] a monkey leader!")
message_admins("[key_name_admin(admin)] made [key_name_admin(new_owner.current)] a monkey leader!")
/datum/antagonist/monkey/leader/on_gain()
. = ..()
var/obj/item/organ/heart/freedom/F = new
F.Insert(owner.current, drop_if_replaced = FALSE)
SSticker.mode.ape_leaders += owner
owner.special_role = "Monkey Leader"
/datum/antagonist/monkey/leader/on_removal()
SSticker.mode.ape_leaders -= owner
var/obj/item/organ/heart/H = new
H.Insert(owner.current, drop_if_replaced = FALSE) //replace freedom heart with normal heart
. = ..()
/datum/antagonist/monkey/leader/greet()
to_chat(owner, "<B><span class='notice'>You are the Jungle Fever patient zero!!</B></span>")
to_chat(owner, "<b>You have been planted onto this station by the Animal Rights Consortium.</b>")
to_chat(owner, "<b>Soon the disease will transform you into an ape. Afterwards, you will be able spread the infection to others with a bite.</b>")
to_chat(owner, "<b>While your infection strain is undetectable by scanners, any other infectees will show up on medical equipment.</b>")
to_chat(owner, "<b>Your mission will be deemed a success if any of the live infected monkeys reach CentCom.</b>")
to_chat(owner, "<b>As an initial infectee, you will be considered a 'leader' by your fellow monkeys.</b>")
to_chat(owner, "<b>You can use :k to talk to fellow monkeys!</b>")
SEND_SOUND(owner.current, sound('sound/ambience/antag/monkey.ogg'))
/datum/objective/monkey
explanation_text = "Ensure that infected monkeys escape on the emergency shuttle!"
martyr_compatible = TRUE
var/monkeys_to_win = 1
var/escaped_monkeys = 0
/datum/objective/monkey/check_completion()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if (M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
escaped_monkeys++
if(escaped_monkeys >= monkeys_to_win)
return TRUE
return FALSE
/datum/team/monkey
name = "Monkeys"
/datum/team/monkey/proc/update_objectives()
objectives = list()
var/datum/objective/monkey/O = new()
O.team = src
objectives += O
/datum/team/monkey/proc/infected_monkeys_alive()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if(M.HasDisease(D))
return TRUE
return FALSE
/datum/team/monkey/proc/infected_monkeys_escaped()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/monkey/M in GLOB.alive_mob_list)
if(M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
return TRUE
return FALSE
/datum/team/monkey/proc/infected_humans_escaped()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/human/M in GLOB.alive_mob_list)
if(M.HasDisease(D) && (M.onCentCom() || M.onSyndieBase()))
return TRUE
return FALSE
/datum/team/monkey/proc/infected_humans_alive()
var/datum/disease/D = new /datum/disease/transformation/jungle_fever()
for(var/mob/living/carbon/human/M in GLOB.alive_mob_list)
if(M.HasDisease(D))
return TRUE
return FALSE
/datum/team/monkey/proc/get_result()
if(infected_monkeys_escaped())
return MONKEYS_ESCAPED
if(infected_monkeys_alive())
return MONKEYS_LIVED
if(infected_humans_alive() || infected_humans_escaped())
return DISEASE_LIVED
return MONKEYS_DIED
/datum/team/monkey/roundend_report()
var/list/parts = list()
switch(get_result())
if(MONKEYS_ESCAPED)
parts += "<span class='greentext big'><B>Monkey Major Victory!</B></span>"
parts += "<span class='greentext'><B>Central Command and [station_name()] were taken over by the monkeys! Ook ook!</B></span>"
if(MONKEYS_LIVED)
parts += "<FONT size = 3><B>Monkey Minor Victory!</B></FONT>"
parts += "<span class='greentext'><B>[station_name()] was taken over by the monkeys! Ook ook!</B></span>"
if(DISEASE_LIVED)
parts += "<span class='redtext big'><B>Monkey Minor Defeat!</B></span>"
parts += "<span class='redtext'><B>All the monkeys died, but the disease lives on! The future is uncertain.</B></span>"
if(MONKEYS_DIED)
parts += "<span class='redtext big'><B>Monkey Major Defeat!</B></span>"
parts += "<span class='redtext'><B>All the monkeys died, and Jungle Fever was wiped out!</B></span>"
var/list/leaders = get_antagonists(/datum/antagonist/monkey/leader, TRUE)
var/list/monkeys = get_antagonists(/datum/antagonist/monkey, TRUE)
if(LAZYLEN(leaders))
parts += "<span class='header'>The monkey leaders were:</span>"
parts += printplayerlist(SSticker.mode.ape_leaders)
if(LAZYLEN(monkeys))
parts += "<span class='header'>The monkeys were:</span>"
parts += printplayerlist(SSticker.mode.ape_infectees)
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
-155
View File
@@ -1,155 +0,0 @@
/datum/antagonist/ninja
name = "Ninja"
antagpanel_category = "Ninja"
job_rank = ROLE_NINJA
var/helping_station = FALSE
var/give_objectives = TRUE
var/give_equipment = TRUE
/datum/antagonist/ninja/apply_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_ninja_icons_added(M)
/datum/antagonist/ninja/remove_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_ninja_icons_removed(M)
/datum/antagonist/ninja/proc/equip_space_ninja(mob/living/carbon/human/H = owner.current)
return H.equipOutfit(/datum/outfit/ninja)
/datum/antagonist/ninja/proc/addMemories()
antag_memory += "I am an elite mercenary assassin of the mighty Spider Clan. A <font color='red'><B>SPACE NINJA</B></font>!<br>"
antag_memory += "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!<br>"
antag_memory += "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.<br>"
/datum/antagonist/ninja/proc/addObjectives(quantity = 6)
var/list/possible_targets = list()
for(var/datum/mind/M in SSticker.minds)
if(M.current && M.current.stat != DEAD)
if(ishuman(M.current))
if(M.special_role)
possible_targets[M] = 0 //bad-guy
else if(M.assigned_role in GLOB.command_positions)
possible_targets[M] = 1 //good-guy
var/list/possible_objectives = list(1,2,3,4)
while(objectives.len < quantity)
switch(pick_n_take(possible_objectives))
if(1) //research
var/datum/objective/download/O = new /datum/objective/download()
O.owner = owner
O.gen_amount_goal()
objectives += O
if(2) //steal
var/datum/objective/steal/special/O = new /datum/objective/steal/special()
O.owner = owner
objectives += O
if(3) //protect/kill
if(!possible_targets.len) continue
var/index = rand(1,possible_targets.len)
var/datum/mind/M = possible_targets[index]
var/is_bad_guy = possible_targets[M]
possible_targets.Cut(index,index+1)
if(is_bad_guy ^ helping_station) //kill (good-ninja + bad-guy or bad-ninja + good-guy)
var/datum/objective/assassinate/O = new /datum/objective/assassinate()
O.owner = owner
O.target = M
O.explanation_text = "Slay \the [M.current.real_name], the [M.assigned_role]."
objectives += O
else //protect
var/datum/objective/protect/O = new /datum/objective/protect()
O.owner = owner
O.target = M
O.explanation_text = "Protect \the [M.current.real_name], the [M.assigned_role], from harm."
objectives += O
if(4) //debrain/capture
if(!possible_targets.len) continue
var/selected = rand(1,possible_targets.len)
var/datum/mind/M = possible_targets[selected]
var/is_bad_guy = possible_targets[M]
possible_targets.Cut(selected,selected+1)
if(is_bad_guy ^ helping_station) //debrain (good-ninja + bad-guy or bad-ninja + good-guy)
var/datum/objective/debrain/O = new /datum/objective/debrain()
O.owner = owner
O.target = M
O.explanation_text = "Steal the brain of [M.current.real_name]."
objectives += O
else //capture
var/datum/objective/capture/O = new /datum/objective/capture()
O.owner = owner
O.gen_amount_goal()
objectives += O
else
break
var/datum/objective/O = new /datum/objective/survive()
O.owner = owner
owner.objectives |= objectives
/proc/remove_ninja(mob/living/L)
if(!L || !L.mind)
return FALSE
var/datum/antagonist/datum = L.mind.has_antag_datum(/datum/antagonist/ninja)
datum.on_removal()
return TRUE
/proc/is_ninja(mob/living/M)
return M && M.mind && M.mind.has_antag_datum(/datum/antagonist/ninja)
/datum/antagonist/ninja/greet()
SEND_SOUND(owner.current, sound('sound/effects/ninja_greeting.ogg'))
to_chat(owner.current, "I am an elite mercenary assassin of the mighty Spider Clan. A <font color='red'><B>SPACE NINJA</B></font>!")
to_chat(owner.current, "Surprise is my weapon. Shadows are my armor. Without them, I am nothing. (//initialize your suit by right clicking on it, to use abilities like stealth)!")
to_chat(owner.current, "Officially, [helping_station?"Nanotrasen":"The Syndicate"] are my employer.")
return
/datum/antagonist/ninja/on_gain()
if(give_objectives)
addObjectives()
addMemories()
if(give_equipment)
equip_space_ninja(owner.current)
. = ..()
/datum/antagonist/ninja/admin_add(datum/mind/new_owner,mob/admin)
var/adj
switch(input("What kind of ninja?", "Ninja") as null|anything in list("Random","Syndicate","Nanotrasen","No objectives"))
if("Random")
helping_station = pick(TRUE,FALSE)
adj = ""
if("Syndicate")
helping_station = FALSE
adj = "syndie"
if("Nanotrasen")
helping_station = TRUE
adj = "friendly"
if("No objectives")
give_objectives = FALSE
adj = "objectiveless"
else
return
new_owner.assigned_role = ROLE_NINJA
new_owner.special_role = ROLE_NINJA
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has [adj] ninja'ed [new_owner.current].")
log_admin("[key_name(admin)] has [adj] ninja'ed [new_owner.current].")
/datum/antagonist/ninja/antag_listing_name()
return ..() + "(Ninja)"
/datum/antagonist/ninja/proc/update_ninja_icons_added(var/mob/living/carbon/human/ninja)
var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA]
ninjahud.join_hud(ninja)
set_antag_hud(ninja, "ninja")
/datum/antagonist/ninja/proc/update_ninja_icons_removed(var/mob/living/carbon/human/ninja)
var/datum/atom_hud/antag/ninjahud = GLOB.huds[ANTAG_HUD_NINJA]
ninjahud.leave_hud(ninja)
set_antag_hud(ninja, null)
-379
View File
@@ -1,379 +0,0 @@
#define NUKE_RESULT_FLUKE 0
#define NUKE_RESULT_NUKE_WIN 1
#define NUKE_RESULT_CREW_WIN 2
#define NUKE_RESULT_CREW_WIN_SYNDIES_DEAD 3
#define NUKE_RESULT_DISK_LOST 4
#define NUKE_RESULT_DISK_STOLEN 5
#define NUKE_RESULT_NOSURVIVORS 6
#define NUKE_RESULT_WRONG_STATION 7
#define NUKE_RESULT_WRONG_STATION_DEAD 8
/datum/antagonist/nukeop
name = "Nuclear Operative"
roundend_category = "syndicate operatives" //just in case
antagpanel_category = "NukeOp"
job_rank = ROLE_OPERATIVE
var/datum/team/nuclear/nuke_team
var/always_new_team = FALSE //If not assigned a team by default ops will try to join existing ones, set this to TRUE to always create new team.
var/send_to_spawnpoint = TRUE //Should the user be moved to default spawnpoint.
var/nukeop_outfit = /datum/outfit/syndicate
/datum/antagonist/nukeop/proc/update_synd_icons_added(mob/living/M)
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
opshud.join_hud(M)
set_antag_hud(M, "synd")
/datum/antagonist/nukeop/proc/update_synd_icons_removed(mob/living/M)
var/datum/atom_hud/antag/opshud = GLOB.huds[ANTAG_HUD_OPS]
opshud.leave_hud(M)
set_antag_hud(M, null)
/datum/antagonist/nukeop/apply_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_synd_icons_added(M)
/datum/antagonist/nukeop/remove_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_synd_icons_removed(M)
/datum/antagonist/nukeop/proc/equip_op()
if(!ishuman(owner.current))
return
var/mob/living/carbon/human/H = owner.current
H.set_species(/datum/species/human) //Plasamen burn up otherwise, and lizards are vulnerable to asimov AIs
H.equipOutfit(nukeop_outfit)
return TRUE
/datum/antagonist/nukeop/greet()
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
to_chat(owner, "<span class='notice'>You are a [nuke_team ? nuke_team.syndicate_name : "syndicate"] agent!</span>")
owner.announce_objectives()
return
/datum/antagonist/nukeop/on_gain()
give_alias()
forge_objectives()
. = ..()
equip_op()
memorize_code()
if(send_to_spawnpoint)
move_to_spawnpoint()
/datum/antagonist/nukeop/get_team()
return nuke_team
/datum/antagonist/nukeop/proc/assign_nuke()
if(nuke_team && !nuke_team.tracked_nuke)
nuke_team.memorized_code = random_nukecode()
var/obj/machinery/nuclearbomb/syndicate/nuke = locate() in GLOB.nuke_list
if(nuke)
nuke_team.tracked_nuke = nuke
if(nuke.r_code == "ADMIN")
nuke.r_code = nuke_team.memorized_code
else //Already set by admins/something else?
nuke_team.memorized_code = nuke.r_code
else
stack_trace("Syndicate nuke not found during nuke team creation.")
nuke_team.memorized_code = null
/datum/antagonist/nukeop/proc/give_alias()
if(nuke_team && nuke_team.syndicate_name)
var/number = 1
number = nuke_team.members.Find(owner)
owner.current.real_name = "[nuke_team.syndicate_name] Operative #[number]"
/datum/antagonist/nukeop/proc/memorize_code()
if(nuke_team && nuke_team.tracked_nuke && nuke_team.memorized_code)
antag_memory += "<B>[nuke_team.tracked_nuke] Code</B>: [nuke_team.memorized_code]<br>"
to_chat(owner, "The nuclear authorization code is: <B>[nuke_team.memorized_code]</B>")
else
to_chat(owner, "Unfortunately the syndicate was unable to provide you with nuclear authorization code.")
/datum/antagonist/nukeop/proc/forge_objectives()
if(nuke_team)
owner.objectives |= nuke_team.objectives
/datum/antagonist/nukeop/proc/move_to_spawnpoint()
var/team_number = 1
if(nuke_team)
team_number = nuke_team.members.Find(owner)
owner.current.forceMove(GLOB.nukeop_start[((team_number - 1) % GLOB.nukeop_start.len) + 1])
/datum/antagonist/nukeop/leader/move_to_spawnpoint()
owner.current.forceMove(pick(GLOB.nukeop_leader_start))
/datum/antagonist/nukeop/create_team(datum/team/nuclear/new_team)
if(!new_team)
if(!always_new_team)
for(var/datum/antagonist/nukeop/N in GLOB.antagonists)
if(!N.owner)
continue
if(N.nuke_team)
nuke_team = N.nuke_team
return
nuke_team = new /datum/team/nuclear
nuke_team.update_objectives()
assign_nuke() //This is bit ugly
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
nuke_team = new_team
/datum/antagonist/nukeop/admin_add(datum/mind/new_owner,mob/admin)
new_owner.assigned_role = ROLE_SYNDICATE
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has nuke op'ed [new_owner.current].")
log_admin("[key_name(admin)] has nuke op'ed [new_owner.current].")
/datum/antagonist/nukeop/get_admin_commands()
. = ..()
.["Send to base"] = CALLBACK(src,.proc/admin_send_to_base)
.["Tell code"] = CALLBACK(src,.proc/admin_tell_code)
/datum/antagonist/nukeop/proc/admin_send_to_base(mob/admin)
owner.current.forceMove(pick(GLOB.nukeop_start))
/datum/antagonist/nukeop/proc/admin_tell_code(mob/admin)
var/code
for (var/obj/machinery/nuclearbomb/bombue in GLOB.machines)
if (length(bombue.r_code) <= 5 && bombue.r_code != initial(bombue.r_code))
code = bombue.r_code
break
if (code)
antag_memory += "<B>Syndicate Nuclear Bomb Code</B>: [code]<br>"
to_chat(owner.current, "The nuclear authorization code is: <B>[code]</B>")
else
to_chat(admin, "<span class='danger'>No valid nuke found!</span>")
/datum/antagonist/nukeop/leader
name = "Nuclear Operative Leader"
nukeop_outfit = /datum/outfit/syndicate/leader
always_new_team = TRUE
var/title
/datum/antagonist/nukeop/leader/memorize_code()
..()
if(nuke_team && nuke_team.memorized_code)
var/obj/item/paper/P = new
P.info = "The nuclear authorization code is: <b>[nuke_team.memorized_code]</b>"
P.name = "nuclear bomb code"
var/mob/living/carbon/human/H = owner.current
if(!istype(H))
P.forceMove(get_turf(H))
else
H.put_in_hands(P, TRUE)
H.update_icons()
/datum/antagonist/nukeop/leader/give_alias()
title = pick("Czar", "Boss", "Commander", "Chief", "Kingpin", "Director", "Overlord")
if(nuke_team && nuke_team.syndicate_name)
owner.current.real_name = "[nuke_team.syndicate_name] [title]"
else
owner.current.real_name = "Syndicate [title]"
/datum/antagonist/nukeop/leader/greet()
owner.current.playsound_local(get_turf(owner.current), 'sound/ambience/antag/ops.ogg',100,0)
to_chat(owner, "<B>You are the Syndicate [title] for this mission. You are responsible for the distribution of telecrystals and your ID is the only one who can open the launch bay doors.</B>")
to_chat(owner, "<B>If you feel you are not up to this task, give your ID to another operative.</B>")
to_chat(owner, "<B>In your hand you will find a special item capable of triggering a greater challenge for your team. Examine it carefully and consult with your fellow operatives before activating it.</B>")
owner.announce_objectives()
addtimer(CALLBACK(src, .proc/nuketeam_name_assign), 1)
/datum/antagonist/nukeop/leader/proc/nuketeam_name_assign()
if(!nuke_team)
return
nuke_team.rename_team(ask_name())
/datum/team/nuclear/proc/rename_team(new_name)
syndicate_name = new_name
name = "[syndicate_name] Team"
for(var/I in members)
var/datum/mind/synd_mind = I
var/mob/living/carbon/human/H = synd_mind.current
if(!istype(H))
continue
var/chosen_name = H.dna.species.random_name(H.gender,0,syndicate_name)
H.fully_replace_character_name(H.real_name,chosen_name)
/datum/antagonist/nukeop/leader/proc/ask_name()
var/randomname = pick(GLOB.last_names)
var/newname = stripped_input(owner.current,"You are the nuke operative [title]. Please choose a last name for your family.", "Name change",randomname)
if (!newname)
newname = randomname
else
newname = reject_bad_name(newname)
if(!newname)
newname = randomname
return capitalize(newname)
/datum/antagonist/nukeop/lone
name = "Lone Operative"
always_new_team = TRUE
send_to_spawnpoint = FALSE //Handled by event
nukeop_outfit = /datum/outfit/syndicate/full
/datum/antagonist/nukeop/lone/assign_nuke()
if(nuke_team && !nuke_team.tracked_nuke)
nuke_team.memorized_code = random_nukecode()
var/obj/machinery/nuclearbomb/selfdestruct/nuke = locate() in GLOB.nuke_list
if(nuke)
nuke_team.tracked_nuke = nuke
if(nuke.r_code == "ADMIN")
nuke.r_code = nuke_team.memorized_code
else //Already set by admins/something else?
nuke_team.memorized_code = nuke.r_code
else
stack_trace("Station self destruct ot found during lone op team creation.")
nuke_team.memorized_code = null
/datum/antagonist/nukeop/reinforcement
send_to_spawnpoint = FALSE
nukeop_outfit = /datum/outfit/syndicate/no_crystals
/datum/team/nuclear
var/syndicate_name
var/obj/machinery/nuclearbomb/tracked_nuke
var/core_objective = /datum/objective/nuclear
var/memorized_code
/datum/team/nuclear/New()
..()
syndicate_name = syndicate_name()
/datum/team/nuclear/proc/update_objectives()
if(core_objective)
var/datum/objective/O = new core_objective
O.team = src
objectives += O
/datum/team/nuclear/proc/disk_rescued()
for(var/obj/item/disk/nuclear/D in GLOB.poi_list)
if(!D.onCentCom())
return FALSE
return TRUE
/datum/team/nuclear/proc/operatives_dead()
for(var/I in members)
var/datum/mind/operative_mind = I
if(ishuman(operative_mind.current) && (operative_mind.current.stat != DEAD))
return FALSE
return TRUE
/datum/team/nuclear/proc/syndies_escaped()
var/obj/docking_port/mobile/S = SSshuttle.getShuttle("syndicate")
return S && (is_centcom_level(S.z) || is_transit_level(S.z))
/datum/team/nuclear/proc/get_result()
var/evacuation = SSshuttle.emergency.mode == SHUTTLE_ENDGAME
var/disk_rescued = disk_rescued()
var/syndies_didnt_escape = !syndies_escaped()
var/station_was_nuked = SSticker.mode.station_was_nuked
var/nuke_off_station = SSticker.mode.nuke_off_station
if(nuke_off_station == NUKE_SYNDICATE_BASE)
return NUKE_RESULT_FLUKE
else if(!disk_rescued && station_was_nuked && !syndies_didnt_escape)
return NUKE_RESULT_NUKE_WIN
else if (!disk_rescued && station_was_nuked && syndies_didnt_escape)
return NUKE_RESULT_NOSURVIVORS
else if (!disk_rescued && !station_was_nuked && nuke_off_station && !syndies_didnt_escape)
return NUKE_RESULT_WRONG_STATION
else if (!disk_rescued && !station_was_nuked && nuke_off_station && syndies_didnt_escape)
return NUKE_RESULT_WRONG_STATION_DEAD
else if ((disk_rescued || evacuation) && operatives_dead())
return NUKE_RESULT_CREW_WIN_SYNDIES_DEAD
else if (disk_rescued)
return NUKE_RESULT_CREW_WIN
else if (!disk_rescued && operatives_dead())
return NUKE_RESULT_DISK_LOST
else if (!disk_rescued && evacuation)
return NUKE_RESULT_DISK_STOLEN
else
return //Undefined result
/datum/team/nuclear/roundend_report()
var/list/parts = list()
parts += "<span class='header'>[syndicate_name] Operatives:</span>"
switch(get_result())
if(NUKE_RESULT_FLUKE)
parts += "<span class='redtext big'>Humiliating Syndicate Defeat</span>"
parts += "<B>The crew of [station_name()] gave [syndicate_name] operatives back their bomb! The syndicate base was destroyed!</B> Next time, don't lose the nuke!"
if(NUKE_RESULT_NUKE_WIN)
parts += "<span class='greentext big'>Syndicate Major Victory!</span>"
parts += "<B>[syndicate_name] operatives have destroyed [station_name()]!</B>"
if(NUKE_RESULT_NOSURVIVORS)
parts += "<span class='neutraltext big'>Total Annihilation</span>"
parts += "<B>[syndicate_name] operatives destroyed [station_name()] but did not leave the area in time and got caught in the explosion.</B> Next time, don't lose the disk!"
if(NUKE_RESULT_WRONG_STATION)
parts += "<span class='redtext big'>Crew Minor Victory</span>"
parts += "<B>[syndicate_name] operatives secured the authentication disk but blew up something that wasn't [station_name()].</B> Next time, don't do that!"
if(NUKE_RESULT_WRONG_STATION_DEAD)
parts += "<span class='redtext big'>[syndicate_name] operatives have earned Darwin Award!</span>"
parts += "<B>[syndicate_name] operatives blew up something that wasn't [station_name()] and got caught in the explosion.</B> Next time, don't do that!"
if(NUKE_RESULT_CREW_WIN_SYNDIES_DEAD)
parts += "<span class='redtext big'>Crew Major Victory!</span>"
parts += "<B>The Research Staff has saved the disk and killed the [syndicate_name] Operatives</B>"
if(NUKE_RESULT_CREW_WIN)
parts += "<span class='redtext big'>Crew Major Victory</span>"
parts += "<B>The Research Staff has saved the disk and stopped the [syndicate_name] Operatives!</B>"
if(NUKE_RESULT_DISK_LOST)
parts += "<span class='neutraltext big'>Neutral Victory!</span>"
parts += "<B>The Research Staff failed to secure the authentication disk but did manage to kill most of the [syndicate_name] Operatives!</B>"
if(NUKE_RESULT_DISK_STOLEN)
parts += "<span class='greentext big'>Syndicate Minor Victory!</span>"
parts += "<B>[syndicate_name] operatives survived the assault but did not achieve the destruction of [station_name()].</B> Next time, don't lose the disk!"
else
parts += "<span class='neutraltext big'>Neutral Victory</span>"
parts += "<B>Mission aborted!</B>"
var/text = "<br><span class='header'>The syndicate operatives were:</span>"
var/purchases = ""
var/TC_uses = 0
for(var/I in members)
var/datum/mind/syndicate = I
var/datum/uplink_purchase_log/H = GLOB.uplink_purchase_logs_by_key[syndicate.key]
if(H)
TC_uses += H.total_spent
purchases += H.generate_render(show_key = FALSE)
text += printplayerlist(members)
text += "<br>"
text += "(Syndicates used [TC_uses] TC) [purchases]"
if(TC_uses == 0 && SSticker.mode.station_was_nuked && !operatives_dead())
text += "<BIG>[icon2html('icons/badass.dmi', world, "badass")]</BIG>"
parts += text
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
/datum/team/nuclear/antag_listing_name()
if(syndicate_name)
return "[syndicate_name] Syndicates"
else
return "Syndicates"
/datum/team/nuclear/antag_listing_entry()
var/disk_report = "<b>Nuclear Disk(s)</b><br>"
disk_report += "<table cellspacing=5>"
for(var/obj/item/disk/nuclear/N in GLOB.poi_list)
disk_report += "<tr><td>[N.name], "
var/atom/disk_loc = N.loc
while(!isturf(disk_loc))
if(ismob(disk_loc))
var/mob/M = disk_loc
disk_report += "carried by <a href='?_src_=holder;[HrefToken()];adminplayeropts=[REF(M)]'>[M.real_name]</a> "
if(isobj(disk_loc))
var/obj/O = disk_loc
disk_report += "in \a [O.name] "
disk_loc = disk_loc.loc
disk_report += "in [disk_loc.loc] at ([disk_loc.x], [disk_loc.y], [disk_loc.z])</td><td><a href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(N)]'>FLW</a></td></tr>"
disk_report += "</table>"
var/common_part = ..()
return common_part + disk_report
/datum/team/nuclear/is_gamemode_hero()
return SSticker.mode.name == "nuclear emergency"
-132
View File
@@ -1,132 +0,0 @@
/datum/antagonist/pirate
name = "Space Pirate"
job_rank = ROLE_TRAITOR
roundend_category = "space pirates"
antagpanel_category = "Pirate"
var/datum/team/pirate/crew
/datum/antagonist/pirate/greet()
to_chat(owner, "<span class='boldannounce'>You are a Space Pirate!</span>")
to_chat(owner, "<B>The station refused to pay for your protection, protect the ship, siphon the credits from the station and raid it for even more loot.</B>")
owner.announce_objectives()
/datum/antagonist/pirate/get_team()
return crew
/datum/antagonist/pirate/create_team(datum/team/pirate/new_team)
if(!new_team)
for(var/datum/antagonist/pirate/P in GLOB.antagonists)
if(!P.owner)
continue
if(P.crew)
crew = P.crew
return
if(!new_team)
crew = new /datum/team/pirate
crew.forge_objectives()
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
crew = new_team
/datum/antagonist/pirate/on_gain()
if(crew)
owner.objectives |= crew.objectives
. = ..()
/datum/antagonist/pirate/on_removal()
if(crew)
owner.objectives -= crew.objectives
. = ..()
/datum/team/pirate
name = "Pirate crew"
/datum/team/pirate/proc/forge_objectives()
var/datum/objective/loot/getbooty = new()
getbooty.team = src
getbooty.storage_area = locate(/area/shuttle/pirate/vault) in GLOB.sortedAreas
getbooty.update_initial_value()
getbooty.update_explanation_text()
objectives += getbooty
for(var/datum/mind/M in members)
M.objectives |= objectives
GLOBAL_LIST_INIT(pirate_loot_cache, typecacheof(list(
/obj/structure/reagent_dispensers/beerkeg,
/mob/living/simple_animal/parrot,
/obj/item/stack/sheet/mineral/gold,
/obj/item/stack/sheet/mineral/diamond,
/obj/item/stack/spacecash,
/obj/item/melee/sabre,)))
/datum/objective/loot
var/area/storage_area //Place where we we will look for the loot.
explanation_text = "Acquire valuable loot and store it in designated area."
var/target_value = 50000
var/initial_value = 0 //Things in the vault at spawn time do not count
/datum/objective/loot/update_explanation_text()
if(storage_area)
explanation_text = "Acquire loot and store [target_value] of credits worth in [storage_area.name]."
/datum/objective/loot/proc/loot_listing()
//Lists notable loot.
if(!storage_area)
return "Nothing"
var/list/loot_table = list()
for(var/atom/movable/AM in storage_area.GetAllContents())
if(is_type_in_typecache(AM,GLOB.pirate_loot_cache))
var/lootname = AM.name
var/count = 1
if(istype(AM,/obj/item/stack)) //Ugh.
var/obj/item/stack/S = AM
lootname = S.singular_name
count = S.amount
if(!loot_table[lootname])
loot_table[lootname] = count
else
loot_table[lootname] += count
var/list/loot_texts = list()
for(var/key in loot_table)
var/amount = loot_table[key]
loot_texts += "[amount] [key][amount > 1 ? "s":""]"
return loot_texts.Join(", ")
/datum/objective/loot/proc/get_loot_value()
if(!storage_area)
return 0
var/value = 0
for(var/turf/T in storage_area.contents)
value += export_item_and_contents(T,TRUE, TRUE, dry_run = TRUE)
return value - initial_value
/datum/objective/loot/proc/update_initial_value()
initial_value = get_loot_value()
/datum/objective/loot/check_completion()
return ..() || get_loot_value() >= target_value
/datum/team/pirate/roundend_report()
var/list/parts = list()
parts += "<span class='header'>Space Pirates were:</span>"
var/all_dead = TRUE
for(var/datum/mind/M in members)
if(considered_alive(M))
all_dead = FALSE
parts += printplayerlist(members)
parts += "Loot stolen: "
var/datum/objective/loot/L = locate() in objectives
parts += L.loot_listing()
parts += "Total loot value : [L.get_loot_value()]/[L.target_value] credits"
if(L.check_completion() && !all_dead)
parts += "<span class='greentext big'>The pirate crew was successful!</span>"
else
parts += "<span class='redtext big'>The pirate crew has failed.</span>"
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
-368
View File
@@ -1,368 +0,0 @@
//How often to check for promotion possibility
#define HEAD_UPDATE_PERIOD 300
/datum/antagonist/rev
name = "Revolutionary"
roundend_category = "revolutionaries" // if by some miracle revolutionaries without revolution happen
antagpanel_category = "Revolution"
job_rank = ROLE_REV
var/hud_type = "rev"
var/datum/team/revolution/rev_team
/datum/antagonist/rev/can_be_owned(datum/mind/new_owner)
. = ..()
if(.)
if(new_owner.assigned_role in GLOB.command_positions)
return FALSE
if(new_owner.unconvertable)
return FALSE
if(new_owner.current && new_owner.current.isloyal())
return FALSE
/datum/antagonist/rev/apply_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_rev_icons_added(M)
/datum/antagonist/rev/remove_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_rev_icons_removed(M)
/datum/antagonist/rev/proc/equip_rev()
return
/datum/antagonist/rev/on_gain()
. = ..()
create_objectives()
equip_rev()
owner.current.log_message("<font color='red'>Has been converted to the revolution!</font>", INDIVIDUAL_ATTACK_LOG)
/datum/antagonist/rev/on_removal()
remove_objectives()
. = ..()
/datum/antagonist/rev/greet()
to_chat(owner, "<span class='userdanger'>You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!</span>")
owner.announce_objectives()
/datum/antagonist/rev/create_team(datum/team/revolution/new_team)
if(!new_team)
//For now only one revolution at a time
for(var/datum/antagonist/rev/head/H in GLOB.antagonists)
if(!H.owner)
continue
if(H.rev_team)
rev_team = H.rev_team
return
rev_team = new /datum/team/revolution
rev_team.update_objectives()
rev_team.update_heads()
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
rev_team = new_team
/datum/antagonist/rev/get_team()
return rev_team
/datum/antagonist/rev/proc/create_objectives()
owner.objectives |= rev_team.objectives
/datum/antagonist/rev/proc/remove_objectives()
owner.objectives -= rev_team.objectives
//Bump up to head_rev
/datum/antagonist/rev/proc/promote()
var/old_team = rev_team
var/datum/mind/old_owner = owner
silent = TRUE
owner.remove_antag_datum(/datum/antagonist/rev)
var/datum/antagonist/rev/head/new_revhead = new()
new_revhead.silent = TRUE
old_owner.add_antag_datum(new_revhead,old_team)
new_revhead.silent = FALSE
to_chat(old_owner, "<span class='userdanger'>You have proved your devotion to revolution! You are a head revolutionary now!</span>")
/datum/antagonist/rev/get_admin_commands()
. = ..()
.["Promote"] = CALLBACK(src,.proc/admin_promote)
/datum/antagonist/rev/proc/admin_promote(mob/admin)
var/datum/mind/O = owner
promote()
message_admins("[key_name_admin(admin)] has head-rev'ed [O].")
log_admin("[key_name(admin)] has head-rev'ed [O].")
/datum/antagonist/rev/head/admin_add(datum/mind/new_owner,mob/admin)
give_flash = TRUE
give_hud = TRUE
remove_clumsy = TRUE
new_owner.add_antag_datum(src)
message_admins("[key_name_admin(admin)] has head-rev'ed [new_owner.current].")
log_admin("[key_name(admin)] has head-rev'ed [new_owner.current].")
to_chat(new_owner.current, "<span class='userdanger'>You are a member of the revolutionaries' leadership now!</span>")
/datum/antagonist/rev/head/get_admin_commands()
. = ..()
. -= "Promote"
.["Take flash"] = CALLBACK(src,.proc/admin_take_flash)
.["Give flash"] = CALLBACK(src,.proc/admin_give_flash)
.["Repair flash"] = CALLBACK(src,.proc/admin_repair_flash)
.["Demote"] = CALLBACK(src,.proc/admin_demote)
/datum/antagonist/rev/head/proc/admin_take_flash(mob/admin)
var/list/L = owner.current.get_contents()
var/obj/item/device/assembly/flash/flash = locate() in L
if (!flash)
to_chat(admin, "<span class='danger'>Deleting flash failed!</span>")
return
qdel(flash)
/datum/antagonist/rev/head/proc/admin_give_flash(mob/admin)
//This is probably overkill but making these impact state annoys me
var/old_give_flash = give_flash
var/old_give_hud = give_hud
var/old_remove_clumsy = remove_clumsy
give_flash = TRUE
give_hud = FALSE
remove_clumsy = FALSE
equip_rev()
give_flash = old_give_flash
give_hud = old_give_hud
remove_clumsy = old_remove_clumsy
/datum/antagonist/rev/head/proc/admin_repair_flash(mob/admin)
var/list/L = owner.current.get_contents()
var/obj/item/device/assembly/flash/flash = locate() in L
if (!flash)
to_chat(admin, "<span class='danger'>Repairing flash failed!</span>")
else
flash.crit_fail = 0
flash.update_icon()
/datum/antagonist/rev/head/proc/admin_demote(datum/mind/target,mob/user)
message_admins("[key_name_admin(user)] has demoted [owner.current] from head revolutionary.")
log_admin("[key_name(user)] has demoted [owner.current] from head revolutionary.")
demote()
/datum/antagonist/rev/head
name = "Head Revolutionary"
hud_type = "rev_head"
var/remove_clumsy = FALSE
var/give_flash = FALSE
var/give_hud = TRUE
/datum/antagonist/rev/head/antag_listing_name()
return ..() + "(Leader)"
/datum/antagonist/rev/proc/update_rev_icons_added(mob/living/M)
var/datum/atom_hud/antag/revhud = GLOB.huds[ANTAG_HUD_REV]
revhud.join_hud(M)
set_antag_hud(M,hud_type)
/datum/antagonist/rev/proc/update_rev_icons_removed(mob/living/M)
var/datum/atom_hud/antag/revhud = GLOB.huds[ANTAG_HUD_REV]
revhud.leave_hud(M)
set_antag_hud(M, null)
/datum/antagonist/rev/proc/can_be_converted(mob/living/candidate)
if(!candidate.mind)
return FALSE
if(!can_be_owned(candidate.mind))
return FALSE
var/mob/living/carbon/C = candidate //Check to see if the potential rev is implanted
if(!istype(C)) //Can't convert simple animals
return FALSE
return TRUE
/datum/antagonist/rev/proc/add_revolutionary(datum/mind/rev_mind,stun = TRUE)
if(!can_be_converted(rev_mind.current))
return FALSE
if(stun)
if(iscarbon(rev_mind.current))
var/mob/living/carbon/carbon_mob = rev_mind.current
carbon_mob.silent = max(carbon_mob.silent, 5)
carbon_mob.flash_act(1, 1)
rev_mind.current.Stun(100)
rev_mind.add_antag_datum(/datum/antagonist/rev,rev_team)
rev_mind.special_role = ROLE_REV
return TRUE
/datum/antagonist/rev/head/proc/demote()
var/datum/mind/old_owner = owner
var/old_team = rev_team
silent = TRUE
owner.remove_antag_datum(/datum/antagonist/rev/head)
var/datum/antagonist/rev/new_rev = new /datum/antagonist/rev()
new_rev.silent = TRUE
old_owner.add_antag_datum(new_rev,old_team)
new_rev.silent = FALSE
to_chat(old_owner, "<span class='userdanger'>Revolution has been disappointed of your leader traits! You are a regular revolutionary now!</span>")
/datum/antagonist/rev/farewell()
if(ishuman(owner.current))
owner.current.visible_message("<span class='deconversion_message'>[owner.current] looks like they just remembered their real allegiance!</span>", null, null, null, owner.current)
to_chat(owner, "<span class='userdanger'>You are no longer a brainwashed revolutionary! Your memory is hazy from the time you were a rebel...the only thing you remember is the name of the one who brainwashed you...</span>")
else if(issilicon(owner.current))
owner.current.visible_message("<span class='deconversion_message'>The frame beeps contentedly, purging the hostile memory engram from the MMI before initalizing it.</span>", null, null, null, owner.current)
to_chat(owner, "<span class='userdanger'>The frame's firmware detects and deletes your neural reprogramming! You remember nothing but the name of the one who flashed you.</span>")
/datum/antagonist/rev/proc/remove_revolutionary(borged, deconverter)
log_attack("[owner.current] (Key: [key_name(owner.current)]) has been deconverted from the revolution by [deconverter] (Key: [key_name(deconverter)])!")
if(borged)
message_admins("[ADMIN_LOOKUPFLW(owner.current)] has been borged while being a [name]")
owner.special_role = null
if(iscarbon(owner.current))
var/mob/living/carbon/C = owner.current
C.Unconscious(100)
owner.remove_antag_datum(type)
/datum/antagonist/rev/head/remove_revolutionary(borged,deconverter)
if(!borged)
return
. = ..()
/datum/antagonist/rev/head/equip_rev()
var/mob/living/carbon/human/H = owner.current
if(!istype(H))
return
if(remove_clumsy && owner.assigned_role == "Clown")
to_chat(owner, "Your training has allowed you to overcome your clownish nature, allowing you to wield weapons without harming yourself.")
H.dna.remove_mutation(CLOWNMUT)
if(give_flash)
var/obj/item/device/assembly/flash/T = new(H)
var/list/slots = list (
"backpack" = slot_in_backpack,
"left pocket" = slot_l_store,
"right pocket" = slot_r_store
)
var/where = H.equip_in_one_of_slots(T, slots)
if (!where)
to_chat(H, "The Syndicate were unfortunately unable to get you a flash.")
else
to_chat(H, "The flash in your [where] will help you to persuade the crew to join your cause.")
if(give_hud)
var/obj/item/organ/cyberimp/eyes/hud/security/syndicate/S = new(H)
S.Insert(H, special = FALSE, drop_if_replaced = FALSE)
to_chat(H, "Your eyes have been implanted with a cybernetic security HUD which will help you keep track of who is mindshield-implanted, and therefore unable to be recruited.")
/datum/team/revolution
name = "Revolution"
var/max_headrevs = 3
/datum/team/revolution/proc/update_objectives(initial = FALSE)
var/untracked_heads = SSjob.get_all_heads()
for(var/datum/objective/mutiny/O in objectives)
untracked_heads -= O.target
for(var/datum/mind/M in untracked_heads)
var/datum/objective/mutiny/new_target = new()
new_target.team = src
new_target.target = M
new_target.update_explanation_text()
objectives += new_target
for(var/datum/mind/M in members)
M.objectives |= objectives
addtimer(CALLBACK(src,.proc/update_objectives),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
/datum/team/revolution/proc/head_revolutionaries()
. = list()
for(var/datum/mind/M in members)
if(M.has_antag_datum(/datum/antagonist/rev/head))
. += M
/datum/team/revolution/proc/update_heads()
if(SSticker.HasRoundStarted())
var/list/datum/mind/head_revolutionaries = head_revolutionaries()
var/list/datum/mind/heads = SSjob.get_all_heads()
var/list/sec = SSjob.get_all_sec()
if(head_revolutionaries.len < max_headrevs && head_revolutionaries.len < round(heads.len - ((8 - sec.len) / 3)))
var/list/datum/mind/non_heads = members - head_revolutionaries
var/list/datum/mind/promotable = list()
for(var/datum/mind/khrushchev in non_heads)
if(khrushchev.current && !khrushchev.current.incapacitated() && !khrushchev.current.restrained() && khrushchev.current.client && khrushchev.current.stat != DEAD)
if(ROLE_REV in khrushchev.current.client.prefs.be_special)
promotable += khrushchev
if(promotable.len)
var/datum/mind/new_leader = pick(promotable)
var/datum/antagonist/rev/rev = new_leader.has_antag_datum(/datum/antagonist/rev)
rev.promote()
addtimer(CALLBACK(src,.proc/update_heads),HEAD_UPDATE_PERIOD,TIMER_UNIQUE)
/datum/team/revolution/roundend_report()
if(!members.len)
return
var/list/result = list()
result += "<div class='panel redborder'>"
var/num_revs = 0
var/num_survivors = 0
for(var/mob/living/carbon/survivor in GLOB.alive_mob_list)
if(survivor.ckey)
num_survivors++
if(survivor.mind)
if(is_revolutionary(survivor))
num_revs++
if(num_survivors)
result += "Command's Approval Rating: <B>[100 - round((num_revs/num_survivors)*100, 0.1)]%</B><br>"
var/list/targets = list()
var/list/datum/mind/headrevs = get_antagonists(/datum/antagonist/rev/head)
var/list/datum/mind/revs = get_antagonists(/datum/antagonist/rev,TRUE)
if(headrevs.len)
var/list/headrev_part = list()
headrev_part += "<span class='header'>The head revolutionaries were:</span>"
headrev_part += printplayerlist(headrevs,TRUE)
result += headrev_part.Join("<br>")
if(revs.len)
var/list/rev_part = list()
rev_part += "<span class='header'>The revolutionaries were:</span>"
rev_part += printplayerlist(revs,TRUE)
result += rev_part.Join("<br>")
var/list/heads = SSjob.get_all_heads()
if(heads.len)
var/head_text = "<span class='header'>The heads of staff were:</span>"
head_text += "<ul class='playerlist'>"
for(var/datum/mind/head in heads)
var/target = (head in targets)
head_text += "<li>"
if(target)
head_text += "<span class='redtext'>Target</span>"
head_text += "[printplayer(head, 1)]</li>"
head_text += "</ul><br>"
result += head_text
result += "</div>"
return result.Join()
/datum/team/revolution/antag_listing_entry()
var/common_part = ..()
var/heads_report = "<b>Heads of Staff</b><br>"
heads_report += "<table cellspacing=5>"
for(var/datum/mind/N in SSjob.get_living_heads())
var/mob/M = N.current
if(M)
heads_report += "<tr><td><a href='?_src_=holder;[HrefToken()];adminplayeropts=[REF(M)]'>[M.real_name]</a>[M.client ? "" : " <i>(No Client)</i>"][M.stat == DEAD ? " <b><font color=red>(DEAD)</font></b>" : ""]</td>"
heads_report += "<td><A href='?priv_msg=[M.ckey]'>PM</A></td>"
heads_report += "<td><A href='?_src_=holder;[HrefToken()];adminplayerobservefollow=[REF(M)]'>FLW</a></td>"
var/turf/mob_loc = get_turf(M)
heads_report += "<td>[mob_loc.loc]</td></tr>"
else
heads_report += "<tr><td><a href='?_src_=vars;[HrefToken()];Vars=[REF(N)]'>[N.name]([N.key])</a><i>Head body destroyed!</i></td>"
heads_report += "<td><A href='?priv_msg=[N.key]'>PM</A></td></tr>"
heads_report += "</table>"
return common_part + heads_report
/datum/team/revolution/is_gamemode_hero()
return SSticker.mode.name == "revolution"
-339
View File
@@ -1,339 +0,0 @@
#define APPRENTICE_DESTRUCTION "destruction"
#define APPRENTICE_BLUESPACE "bluespace"
#define APPRENTICE_ROBELESS "robeless"
#define APPRENTICE_HEALING "healing"
/datum/antagonist/wizard
name = "Space Wizard"
roundend_category = "wizards/witches"
antagpanel_category = "Wizard"
job_rank = ROLE_WIZARD
var/give_objectives = TRUE
var/strip = TRUE //strip before equipping
var/allow_rename = TRUE
var/hud_version = "wizard"
var/datum/team/wizard/wiz_team //Only created if wizard summons apprentices
var/move_to_lair = TRUE
var/outfit_type = /datum/outfit/wizard
var/wiz_age = WIZARD_AGE_MIN /* Wizards by nature cannot be too young. */
/datum/antagonist/wizard/on_gain()
register()
if(give_objectives)
create_objectives()
equip_wizard()
if(move_to_lair)
send_to_lair()
. = ..()
if(allow_rename)
rename_wizard()
/datum/antagonist/wizard/proc/register()
SSticker.mode.wizards |= owner
/datum/antagonist/wizard/proc/unregister()
SSticker.mode.wizards -= src
/datum/antagonist/wizard/create_team(datum/team/wizard/new_team)
if(!new_team)
return
if(!istype(new_team))
stack_trace("Wrong team type passed to [type] initialization.")
wiz_team = new_team
/datum/antagonist/wizard/get_team()
return wiz_team
/datum/team/wizard
name = "wizard team"
var/datum/antagonist/wizard/master_wizard
/datum/antagonist/wizard/proc/create_wiz_team()
wiz_team = new(owner)
wiz_team.name = "[owner.current.real_name] team"
wiz_team.master_wizard = src
update_wiz_icons_added(owner.current)
/datum/antagonist/wizard/proc/send_to_lair()
if(!owner || !owner.current)
return
if(!GLOB.wizardstart.len)
SSjob.SendToLateJoin(owner.current)
to_chat(owner, "HOT INSERTION, GO GO GO")
owner.current.forceMove(pick(GLOB.wizardstart))
/datum/antagonist/wizard/proc/create_objectives()
switch(rand(1,100))
if(1 to 30)
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = owner
kill_objective.find_target()
objectives += kill_objective
if (!(locate(/datum/objective/escape) in owner.objectives))
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
objectives += escape_objective
if(31 to 60)
var/datum/objective/steal/steal_objective = new
steal_objective.owner = owner
steal_objective.find_target()
objectives += steal_objective
if (!(locate(/datum/objective/escape) in owner.objectives))
var/datum/objective/escape/escape_objective = new
escape_objective.owner = owner
objectives += escape_objective
if(61 to 85)
var/datum/objective/assassinate/kill_objective = new
kill_objective.owner = owner
kill_objective.find_target()
objectives += kill_objective
var/datum/objective/steal/steal_objective = new
steal_objective.owner = owner
steal_objective.find_target()
objectives += steal_objective
if (!(locate(/datum/objective/survive) in owner.objectives))
var/datum/objective/survive/survive_objective = new
survive_objective.owner = owner
objectives += survive_objective
else
if (!(locate(/datum/objective/hijack) in owner.objectives))
var/datum/objective/hijack/hijack_objective = new
hijack_objective.owner = owner
objectives += hijack_objective
for(var/datum/objective/O in objectives)
owner.objectives += O
/datum/antagonist/wizard/on_removal()
unregister()
for(var/objective in objectives)
owner.objectives -= objective
owner.RemoveAllSpells() // TODO keep track which spells are wizard spells which innate stuff
return ..()
/datum/antagonist/wizard/proc/equip_wizard()
if(!owner)
return
var/mob/living/carbon/human/H = owner.current
if(!istype(H))
return
if(strip)
H.delete_equipment()
//Wizards are human by default. Use the mirror if you want something else.
H.set_species(/datum/species/human)
if(H.age < wiz_age)
H.age = wiz_age
H.equipOutfit(outfit_type)
/datum/antagonist/wizard/greet()
to_chat(owner, "<span class='boldannounce'>You are the Space Wizard!</span>")
to_chat(owner, "<B>The Space Wizards Federation has given you the following tasks:</B>")
owner.announce_objectives()
to_chat(owner, "You will find a list of available spells in your spell book. Choose your magic arsenal carefully.")
to_chat(owner, "The spellbook is bound to you, and others cannot use it.")
to_chat(owner, "In your pockets you will find a teleport scroll. Use it as needed.")
to_chat(owner,"<B>Remember:</B> do not forget to prepare your spells.")
/datum/antagonist/wizard/farewell()
to_chat(owner, "<span class='userdanger'>You have been brainwashed! You are no longer a wizard!</span>")
/datum/antagonist/wizard/proc/rename_wizard()
set waitfor = FALSE
var/wizard_name_first = pick(GLOB.wizard_first)
var/wizard_name_second = pick(GLOB.wizard_second)
var/randomname = "[wizard_name_first] [wizard_name_second]"
var/mob/living/wiz_mob = owner.current
var/newname = copytext(sanitize(input(wiz_mob, "You are the [name]. Would you like to change your name to something else?", "Name change", randomname) as null|text),1,MAX_NAME_LEN)
if (!newname)
newname = randomname
wiz_mob.fully_replace_character_name(wiz_mob.real_name, newname)
/datum/antagonist/wizard/apply_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_wiz_icons_added(M, wiz_team ? TRUE : FALSE) //Don't bother showing the icon if you're solo wizard
M.faction |= ROLE_WIZARD
/datum/antagonist/wizard/remove_innate_effects(mob/living/mob_override)
var/mob/living/M = mob_override || owner.current
update_wiz_icons_removed(M)
M.faction -= ROLE_WIZARD
/datum/antagonist/wizard/get_admin_commands()
. = ..()
.["Send to Lair"] = CALLBACK(src,.proc/admin_send_to_lair)
/datum/antagonist/wizard/proc/admin_send_to_lair(mob/admin)
owner.current.forceMove(pick(GLOB.wizardstart))
/datum/antagonist/wizard/apprentice
name = "Wizard Apprentice"
hud_version = "apprentice"
var/datum/mind/master
var/school = APPRENTICE_DESTRUCTION
outfit_type = /datum/outfit/wizard/apprentice
wiz_age = APPRENTICE_AGE_MIN
/datum/antagonist/wizard/apprentice/greet()
to_chat(owner, "<B>You are [master.current.real_name]'s apprentice! You are bound by magic contract to follow their orders and help them in accomplishing their goals.")
owner.announce_objectives()
/datum/antagonist/wizard/apprentice/register()
SSticker.mode.apprentices |= owner
/datum/antagonist/wizard/apprentice/unregister()
SSticker.mode.apprentices -= owner
/datum/antagonist/wizard/apprentice/equip_wizard()
. = ..()
if(!owner)
return
var/mob/living/carbon/human/H = owner.current
if(!istype(H))
return
switch(school)
if(APPRENTICE_DESTRUCTION)
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball(null))
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned powerful, destructive spells. You are able to cast magic missile and fireball.")
if(APPRENTICE_BLUESPACE)
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned reality bending mobility spells. You are able to cast teleport and ethereal jaunt.")
if(APPRENTICE_HEALING)
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/charge(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/forcewall(null))
H.put_in_hands(new /obj/item/gun/magic/staff/healing(H))
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned livesaving survival spells. You are able to cast charge and forcewall.")
if(APPRENTICE_ROBELESS)
owner.AddSpell(new /obj/effect/proc_holder/spell/aoe_turf/knock(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/mind_transfer(null))
to_chat(owner, "<B>Your service has not gone unrewarded, however. Studying under [master.current.real_name], you have learned stealthy, robeless spells. You are able to cast knock and mindswap.")
/datum/antagonist/wizard/apprentice/create_objectives()
var/datum/objective/protect/new_objective = new /datum/objective/protect
new_objective.owner = owner
new_objective.target = master
new_objective.explanation_text = "Protect [master.current.real_name], the wizard."
owner.objectives += new_objective
objectives += new_objective
//Random event wizard
/datum/antagonist/wizard/apprentice/imposter
name = "Wizard Imposter"
allow_rename = FALSE
move_to_lair = FALSE
/datum/antagonist/wizard/apprentice/imposter/greet()
to_chat(owner, "<B>You are an imposter! Trick and confuse the crew to misdirect malice from your handsome original!</B>")
owner.announce_objectives()
/datum/antagonist/wizard/apprentice/imposter/equip_wizard()
var/mob/living/carbon/human/master_mob = master.current
var/mob/living/carbon/human/H = owner.current
if(!istype(master_mob) || !istype(H))
return
if(master_mob.ears)
H.equip_to_slot_or_del(new master_mob.ears.type, slot_ears)
if(master_mob.w_uniform)
H.equip_to_slot_or_del(new master_mob.w_uniform.type, slot_w_uniform)
if(master_mob.shoes)
H.equip_to_slot_or_del(new master_mob.shoes.type, slot_shoes)
if(master_mob.wear_suit)
H.equip_to_slot_or_del(new master_mob.wear_suit.type, slot_wear_suit)
if(master_mob.head)
H.equip_to_slot_or_del(new master_mob.head.type, slot_head)
if(master_mob.back)
H.equip_to_slot_or_del(new master_mob.back.type, slot_back)
//Operation: Fuck off and scare people
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/area_teleport/teleport(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/turf_teleport/blink(null))
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt(null))
/datum/antagonist/wizard/proc/update_wiz_icons_added(mob/living/wiz,join = TRUE)
var/datum/atom_hud/antag/wizhud = GLOB.huds[ANTAG_HUD_WIZ]
wizhud.join_hud(wiz)
set_antag_hud(wiz, hud_version)
/datum/antagonist/wizard/proc/update_wiz_icons_removed(mob/living/wiz)
var/datum/atom_hud/antag/wizhud = GLOB.huds[ANTAG_HUD_WIZ]
wizhud.leave_hud(wiz)
set_antag_hud(wiz, null)
/datum/antagonist/wizard/academy
name = "Academy Teacher"
outfit_type = /datum/outfit/wizard/academy
/datum/antagonist/wizard/academy/equip_wizard()
. = ..()
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/ethereal_jaunt)
owner.AddSpell(new /obj/effect/proc_holder/spell/targeted/projectile/magic_missile)
owner.AddSpell(new /obj/effect/proc_holder/spell/aimed/fireball)
var/mob/living/M = owner.current
if(!istype(M))
return
var/obj/item/implant/exile/Implant = new/obj/item/implant/exile(M)
Implant.implant(M)
/datum/antagonist/wizard/academy/create_objectives()
var/datum/objective/new_objective = new("Protect Wizard Academy from the intruders")
new_objective.owner = owner
owner.objectives += new_objective
objectives += new_objective
//Solo wizard report
/datum/antagonist/wizard/roundend_report()
var/list/parts = list()
parts += printplayer(owner)
var/count = 1
var/wizardwin = 1
for(var/datum/objective/objective in objectives)
if(objective.check_completion())
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='greentext'>Success!</span>"
else
parts += "<B>Objective #[count]</B>: [objective.explanation_text] <span class='redtext'>Fail.</span>"
wizardwin = 0
count++
if(wizardwin)
parts += "<span class='greentext'>The wizard was successful!</span>"
else
parts += "<span class='redtext'>The wizard has failed!</span>"
if(owner.spell_list.len>0)
parts += "<B>[owner.name] used the following spells: </B>"
var/list/spell_names = list()
for(var/obj/effect/proc_holder/spell/S in owner.spell_list)
spell_names += S.name
parts += spell_names.Join(", ")
return parts.Join("<br>")
//Wizard with apprentices report
/datum/team/wizard/roundend_report()
var/list/parts = list()
parts += "<span class='header'>Wizards/witches of [master_wizard.owner.name] team were:</span>"
parts += master_wizard.roundend_report()
parts += " "
parts += "<span class='header'>[master_wizard.owner.name] apprentices were:</span>"
parts += printplayerlist(members - master_wizard.owner)
return "<div class='panel redborder'>[parts.Join("<br>")]</div>"
+82
View File
@@ -305,6 +305,88 @@
else
return
/datum/browser/modal/preflikepicker
var/settings = list()
var/icon/preview_icon = null
/datum/browser/modal/preflikepicker/New(User,Message,Title,Button1="Ok",Button2,Button3,StealFocus = 1, Timeout = FALSE,list/settings,inputtype="checkbox", width = 400, height, slidecolor)
if (!User)
return
src.settings = settings
..(User, ckey("[User]-[Message]-[Title]-[world.time]-[rand(1,10000)]"), Title, width, height, src, StealFocus, Timeout)
set_content(ShowChoices(User))
/datum/browser/modal/preflikepicker/proc/ShowChoices(mob/user)
var/dat = ""
for (var/name in settings["mainsettings"])
var/setting = settings["mainsettings"][name]
if (setting["type"] == "datum")
dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;type=datum;path=[setting["path"]]'>[setting["value"]]</a><BR>"
else
dat += "<b>[setting["desc"]]:</b> <a href='?src=[REF(src)];setting=[name];task=input;type=[setting["type"]]'>[setting["value"]]</a><BR>"
if (preview_icon)
dat += "<td valign='center'>"
dat += "<div class='statusDisplay'><center><img src=previewicon.png width=[preview_icon.Width()] height=[preview_icon.Height()]></center></div>"
dat += "</td>"
dat += "</tr></table>"
dat += "<hr><center><a href='?src=[REF(src)];button=1'>Ok</a> "
dat += "</center>"
return dat
/datum/browser/modal/preflikepicker/Topic(href,href_list)
if (href_list["close"] || !user || !user.client)
opentime = 0
return
if (href_list["task"] == "input")
var/setting = href_list["setting"]
switch (href_list["type"])
if ("datum")
settings["mainsettings"][setting]["value"] = pick_closest_path(null, make_types_fancy(typesof(text2path(href_list["path"]))))
if ("string")
settings["mainsettings"][setting]["value"] = stripped_input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]")
if ("number")
settings["mainsettings"][setting]["value"] = input(user, "Enter new value for [settings["mainsettings"][setting]["desc"]]", "Enter new value for [settings["mainsettings"][setting]["desc"]]") as num
if ("boolean")
settings["mainsettings"][setting]["value"] = input(user, "[settings["mainsettings"][setting]["desc"]]?") in list("Yes","No")
if ("ckey")
settings["mainsettings"][setting]["value"] = input(user, "[settings["mainsettings"][setting]["desc"]]?") in list("none") + GLOB.directory
if (href_list["button"])
var/button = text2num(href_list["button"])
if (button <= 3 && button >= 1)
selectedbutton = button
if (selectedbutton != 1)
set_content(ShowChoices(user))
open()
return
for (var/item in href_list)
switch(item)
if ("close", "button", "src")
continue
opentime = 0
close()
/proc/presentpreflikepicker(var/mob/User,Message, Title, Button1="Ok", Button2, Button3, StealFocus = 1,Timeout = 6000,list/settings, width, height, slidecolor)
if (!istype(User))
if (istype(User, /client/))
var/client/C = User
User = C.mob
else
return
var/datum/browser/modal/preflikepicker/A = new(User, Message, Title, Button1, Button2, Button3, StealFocus,Timeout, settings, width, height, slidecolor)
A.open()
A.wait()
if (A.selectedbutton)
return list("button" = A.selectedbutton, "settings" = A.settings)
// This will allow you to show an icon in the browse window
// This is added to mob so that it can be used without a reference to the browser object
// There is probably a better place for this...
-10
View File
@@ -1,10 +0,0 @@
/datum/votablemap
var/name = ""
var/friendlyname = ""
var/minusers = 0
var/maxusers = 0
var/voteweight = 1
/datum/votablemap/New(name)
src.name = name
src.friendlyname = name
-57
View File
@@ -1,57 +0,0 @@
////////////Syndicate Cortical Borer
obj/item/antag_spawner/syndi_borer
name = "syndicate brain-slug container"
desc = "Releases a modified cortical borer to assist the user."
icon = 'icons/obj/device.dmi' //Temporary? Doesn't really look like a container for xenofauna... but IDK what else could work.
icon_state = "locator"
var/polling = FALSE
obj/item/antag_spawner/syndi_borer/spawn_antag(client/C, turf/T, mob/owner)
var/mob/living/simple_animal/borer/syndi_borer/B = new /mob/living/simple_animal/borer/syndi_borer(T)
B.key = C.key
if (owner)
B.owner = owner
B.faction = B.faction | owner.faction.Copy()
B.mind.assigned_role = B.name
B.mind.special_role = B.name
var/datum/objective/syndi_borer/new_objective
new_objective = new /datum/objective/syndi_borer
new_objective.owner = B.mind
new_objective.target = owner.mind
new_objective.explanation_text = "You are a modified cortical borer. You obey [owner.real_name] and must assist them in completing their objectives."
B.mind.objectives += new_objective
to_chat(B, "<B>You are awake at last! Seek out whoever released you and aid them as best you can!</B>")
if(new_objective)
to_chat(B, "<B>Objective #[1]</B>: [new_objective.explanation_text]")
/obj/item/antag_spawner/syndi_borer/proc/check_usability(mob/user)
if(used)
to_chat(user, "<span class='warning'>[src] appears to be empty!</span>")
return 0
if(polling == TRUE)
to_chat(user, "<span class='warning'>[src] is busy activating!</span>")
return 0
return 1
/obj/item/antag_spawner/syndi_borer/attack_self(mob/user)
if(!(check_usability(user)))
return
polling = TRUE
var/list/borer_candidates = pollCandidatesForMob("Do you want to play as a syndicate cortical borer?", ROLE_BORER, null, ROLE_BORER, 150, src)
if(borer_candidates.len)
polling = FALSE
if(!(check_usability(user)))
return
used = 1
var/mob/dead/observer/theghost = pick(borer_candidates)
spawn_antag(theghost.client, get_turf(src), user)
var/datum/effect_system/spark_spread/S = new /datum/effect_system/spark_spread
S.set_up(4, 1, src)
S.start()
qdel(src)
else
polling = FALSE
to_chat(user, "<span class='warning'>Unable to connect to release specimen. Please wait and try again later or use the container on your uplink to get your points refunded.</span>")
-106
View File
@@ -1,106 +0,0 @@
#define MIN_LATE_TARGET_TIME 600 //lower bound of re-rolled timer, 1 min
#define MAX_LATE_TARGET_TIME 6000 //upper bound of re-rolled timer, 10 min
#define LATE_TARGET_HIT_CHANCE 70 //How often would the find_target succeed, otherwise it re-rolls later and tries again.
//Hit chance is here to avoid people checking github and then hovering around new arrivals within the max minute range every round.
/datum/objective/assassinate/late
martyr_compatible = FALSE
/datum/objective/assassinate/late/find_target()
var/list/possible_targets = list()
for(var/mob/M in GLOB.latejoiners)
var/datum/mind/possible_target = M.mind
if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2) && is_unique_objective(possible_target))
possible_targets += possible_target
if(possible_targets.len > 0 && prob(LATE_TARGET_HIT_CHANCE))
target = pick(possible_targets)
martyr_compatible = TRUE //Might never matter, but I guess if an admin gives another random objective, this should now be compatible
update_explanation_text()
message_admins("[target] has been selected as the assassination target of [owner].")
log_game("[target] has been selected as the assassination target of [owner].")
to_chat(owner, "<span class='italics'>You hear a crackling noise in your ears, as a one-way syndicate message plays:</span>")
to_chat(owner, "<span class='userdanger'><font size=5>You target has been located. To succeed, find and eliminate [target], the [!target_role_type ? target.assigned_role : target.special_role].</font></span>")
return target
else
update_explanation_text()
addtimer(CALLBACK(src, .proc/find_target),rand(MIN_LATE_TARGET_TIME, MAX_LATE_TARGET_TIME))
return null
/datum/objective/assassinate/late/find_target_by_role(role, role_type=0, invert=0)
var/list/possible_targets = list()
for(var/mob/M in GLOB.latejoiners)
var/datum/mind/possible_target = M.mind
if((possible_target != owner) && ishuman(possible_target.current))
var/is_role = 0
if(role_type)
if(possible_target.special_role == role)
is_role++
else
if(possible_target.assigned_role == role)
is_role++
if(invert)
if(is_role)
continue
possible_targets += possible_target
//break
else if(is_role)
possible_targets += possible_target
//break
if(possible_targets && prob(LATE_TARGET_HIT_CHANCE))
target = pick(possible_targets)
update_explanation_text()
message_admins("[target] has been selected as the assassination target of [owner].")
log_game("[target] has been selected as the assassination target of [owner].")
to_chat(owner, "<span class='italics'>You hear a crackling noise in your ears, as a one-way syndicate message plays:</span>")
to_chat(owner, "<span class='userdanger'><font size=5>You target has been located. To succeed, find and eliminate [target], the [!target_role_type ? target.assigned_role : target.special_role].</font></span>")
else
update_explanation_text()
addtimer(CALLBACK(src, .proc/find_target_by_role, role, role_type, invert),rand(MIN_LATE_TARGET_TIME, MAX_LATE_TARGET_TIME))
/datum/objective/assassinate/late/check_completion()
if(target && target.current) //If target WAS assigned
if(target.current.stat == DEAD || issilicon(target.current) || isbrain(target.current) || target.current.z > 6 || !target.current.ckey) //Borgs/brains/AIs count as dead for traitor objectives. --NeoFite
return TRUE
return FALSE
else //If no target was ever given
if(!owner.current || owner.current.stat == DEAD || isbrain(owner.current))
return FALSE
if(!is_special_character(owner.current))
return FALSE
return TRUE
/datum/objective/assassinate/late/update_explanation_text()
//..()
if(target && target.current)
explanation_text = "Assassinate [target.name], the [!target_role_type ? target.assigned_role : target.special_role]."
else
explanation_text = "Stay alive until your target arrives on the station, you will be notified when the target has been identified."
//BORER STUFF
//Because borers didn't use to have objectives
/datum/objective/normal_borer //Default objective, should technically never be used unmodified but CAN work unmodified.
explanation_text = "You must escape with at least one borer with host on the shuttle."
target_amount = 1
martyr_compatible = 0
/datum/objective/normal_borer/check_completion()
var/total_borer_hosts = 0
for(var/mob/living/carbon/C in GLOB.mob_list)
var/mob/living/simple_animal/borer/D = C.has_brain_worms()
var/turf/location = get_turf(C)
if(is_centcom_level(location.z) && D && D.stat != DEAD)
total_borer_hosts++
if(target_amount <= total_borer_hosts)
return TRUE
else
return FALSE
-769
View File
@@ -1,769 +0,0 @@
/datum/action/innate/cult/blood_magic //Blood magic handles the creation of blood spells (formerly talismans)
name = "Prepare Blood Magic"
button_icon_state = "carve"
desc = "Prepare blood magic by carving runes into your flesh. This rite is most effective with an <b>empowering rune</b>"
var/list/spells = list()
var/channeling = FALSE
/datum/action/innate/cult/blood_magic/Grant()
..()
button.screen_loc = "6:-29,4:-2"
button.moved = "6:-29,4:-2"
button.locked = TRUE
/datum/action/innate/cult/blood_magic/Remove()
for(var/X in spells)
qdel(X)
..()
/datum/action/innate/cult/blood_magic/IsAvailable()
if(!iscultist(owner))
return FALSE
return ..()
/datum/action/innate/cult/blood_magic/proc/Positioning()
for(var/datum/action/innate/cult/blood_spell/B in spells)
var/pos = -29+spells.Find(B)*31
B.button.screen_loc = "6:[pos],4:-2"
B.button.moved = B.button.screen_loc
B.button.locked = TRUE
/datum/action/innate/cult/blood_magic/Activate()
var/rune = FALSE
var/limit = RUNELESS_MAX_BLOODCHARGE
for(var/obj/effect/rune/empower/R in range(1, owner))
rune = TRUE
break
if(rune)
limit = MAX_BLOODCHARGE
if(spells.len >= limit)
if(rune)
to_chat(owner, "<span class='cultitalic'>Your body has reached its limit, you cannot store more than [MAX_BLOODCHARGE] spells at once. <b>Pick a spell to nullify.</b></span>")
else
to_chat(owner, "<span class='cultitalic'>Your body has reached its limit, <b><u>you cannot have more than [RUNELESS_MAX_BLOODCHARGE] spells at once without an empowering rune! Pick a spell to nullify.</b></u></span>")
var/nullify_spell = input(owner, "Choose a spell to remove.", "Current Spells") as null|anything in spells
if(nullify_spell)
qdel(nullify_spell)
return
var/entered_spell_name
var/datum/action/innate/cult/blood_spell/BS
var/list/possible_spells = list()
for(var/I in subtypesof(/datum/action/innate/cult/blood_spell))
var/datum/action/innate/cult/blood_spell/J = I
var/cult_name = initial(J.name)
possible_spells[cult_name] = J
possible_spells += "(REMOVE SPELL)"
entered_spell_name = input(owner, "Pick a blood spell to prepare...", "Spell Choices") as null|anything in possible_spells
if(entered_spell_name == "(REMOVE SPELL)")
var/nullify_spell = input(owner, "Choose a spell to remove.", "Current Spells") as null|anything in spells
if(nullify_spell)
qdel(nullify_spell)
return
BS = possible_spells[entered_spell_name]
if(QDELETED(src) || owner.incapacitated() || !BS)
return
to_chat(owner,"<span class='warning'>You begin to carve unnatural symbols into your flesh!</span>")
SEND_SOUND(owner, sound('sound/weapons/slice.ogg',0,1,10))
if(!channeling)
channeling = TRUE
else
to_chat(owner, "<span class='cultitalic'>You are already invoking blood magic!")
return
if(do_after(owner, 100 - rune*65, target = owner))
if(ishuman(owner))
var/mob/living/carbon/human/H = owner
H.bleed(30 - rune*25)
var/datum/action/innate/cult/blood_spell/new_spell = new BS(owner)
new_spell.Grant(owner, src)
spells += new_spell
Positioning()
to_chat(owner, "<span class='warning'>Your wounds glows with power, you have prepared a [new_spell.name] invocation!</span>")
channeling = FALSE
/datum/action/innate/cult/blood_spell //The next generation of talismans
name = "Blood Magic"
button_icon_state = "telerune"
desc = "Fear the Old Blood."
var/charges = 1
var/magic_path = null
var/obj/item/melee/blood_magic/hand_magic
var/datum/action/innate/cult/blood_magic/all_magic
var/base_desc //To allow for updating tooltips
var/invocation
var/health_cost = 0
/datum/action/innate/cult/blood_spell/Grant(mob/living/owner, datum/action/innate/cult/blood_magic/BM)
if(health_cost)
desc += "<br>Deals <u>[health_cost] damage</u> to your arm per use."
base_desc = desc
desc += "<br><b><u>Has [charges] use\s remaining</u></b>."
all_magic = BM
..()
/datum/action/innate/cult/blood_spell/Remove()
if(all_magic)
all_magic.spells -= src
if(hand_magic)
qdel(hand_magic)
hand_magic = null
..()
/datum/action/innate/cult/blood_spell/IsAvailable()
if(!iscultist(owner) || owner.incapacitated() || !charges)
return FALSE
return ..()
/datum/action/innate/cult/blood_spell/Activate()
if(magic_path) //If this spell flows from the hand
if(!hand_magic)
hand_magic = new magic_path(owner, src)
if(!owner.put_in_hands(hand_magic))
qdel(hand_magic)
hand_magic = null
to_chat(owner, "<span class='warning'>You have no empty hand for invoking blood magic!</span>")
return
to_chat(owner, "<span class='notice'>Your old wounds glow again as you invoke the [name].</span>")
return
if(hand_magic)
qdel(hand_magic)
hand_magic = null
to_chat(owner, "<span class='warning'>You snuff out the spell with your hand, saving its power for another time.</span>")
//Cult Blood Spells
/datum/action/innate/cult/blood_spell/stun
name = "Stun"
desc = "A potent spell that will stun and mute victims upon contact."
button_icon_state = "hand"
magic_path = "/obj/item/melee/blood_magic/stun"
health_cost = 10
/datum/action/innate/cult/blood_spell/teleport
name = "Teleport"
desc = "A useful spell that teleport cultists to a chosen destination on contact."
button_icon_state = "tele"
magic_path = "/obj/item/melee/blood_magic/teleport"
health_cost = 7
/datum/action/innate/cult/blood_spell/emp
name = "Electromagnetic Pulse"
desc = "A large spell that immediately disables all electronics in the area."
button_icon_state = "emp"
health_cost = 10
invocation = "Ta'gh fara'qha fel d'amar det!"
/datum/action/innate/cult/blood_spell/emp/Activate()
owner.visible_message("<span class='warning'>[owner]'s hand flashes a bright blue!</span>", \
"<span class='cultitalic'>You speak the cursed words, emitting an EMP blast from your hand.</span>")
empulse(owner, 3, 6)
owner.whisper(invocation, language = /datum/language/common)
charges--
if(charges<=0)
qdel(src)
/datum/action/innate/cult/blood_spell/shackles
name = "Shadow Shackles"
desc = "A stealthy spell that will handcuff and temporarily silence your victim."
button_icon_state = "cuff"
charges = 4
magic_path = "/obj/item/melee/blood_magic/shackles"
/datum/action/innate/cult/blood_spell/construction
name = "Twisted Construction"
desc = "<u>A sinister spell used to convert:</u><br>Plasteel into runed metal<br>25 metal into a construct shell<br>Cyborgs directly into constructs<br>Cyborg shells into construct shells<br>Airlocks into runed airlocks (harm intent)"
button_icon_state = "transmute"
magic_path = "/obj/item/melee/blood_magic/construction"
/datum/action/innate/cult/blood_spell/equipment
name = "Summon Equipment"
desc = "A crucial spell that enables you to summon either a ritual dagger or combat gear including armored robes, the nar'sien bola, and an eldritch longsword."
button_icon_state = "equip"
magic_path = "/obj/item/melee/blood_magic/armor"
/datum/action/innate/cult/blood_spell/equipment/Activate()
var/choice = alert(owner,"Choose your equipment type",,"Combat Equipment","Ritual Dagger","Cancel")
if(choice == "Ritual Dagger")
var/turf/T = get_turf(owner)
owner.visible_message("<span class='warning'>[owner]'s hand glows red for a moment.</span>", \
"<span class='cultitalic'>Red light begins to shimmer and take form within your hand!</span>")
var/obj/O = new /obj/item/melee/cultblade/dagger(T)
if(owner.put_in_hands(O))
to_chat(owner, "<span class='warning'>A ritual dagger appears in your hand!</span>")
else
owner.visible_message("<span class='warning'>A ritual dagger appears at [owner]'s feet!</span>", \
"<span class='cultitalic'>A ritual dagger materializes at your feet.</span>")
SEND_SOUND(owner, sound('sound/effects/magic.ogg',0,1,25))
charges--
desc = base_desc
desc += "<br><b><u>Has [charges] use\s remaining</u></b>."
if(charges<=0)
qdel(src)
else if(choice == "Combat Equipment")
..()
/datum/action/innate/cult/blood_spell/horror
name = "Hallucinations"
desc = "A <u>ranged yet stealthy</u> spell that will break the mind of the victim with nightmarish hallucinations."
button_icon_state = "horror"
var/obj/effect/proc_holder/horror/PH
charges = 4
/datum/action/innate/cult/blood_spell/horror/New()
PH = new()
PH.attached_action = src
..()
/datum/action/innate/cult/blood_spell/horror/Destroy()
var/obj/effect/proc_holder/horror/destroy = PH
. = ..()
if(destroy && !QDELETED(destroy))
QDEL_NULL(destroy)
/datum/action/innate/cult/blood_spell/horror/Activate()
PH.toggle(owner) //the important bit
return TRUE
/obj/effect/proc_holder/horror
active = FALSE
ranged_mousepointer = 'icons/effects/cult_target.dmi'
var/datum/action/innate/cult/blood_spell/attached_action
/obj/effect/proc_holder/horror/Destroy()
var/datum/action/innate/cult/blood_spell/AA = attached_action
. = ..()
if(AA && !QDELETED(AA))
QDEL_NULL(AA)
/obj/effect/proc_holder/horror/proc/toggle(mob/user)
if(active)
remove_ranged_ability("<span class='cult'>You dispel the magic...</span>")
else
add_ranged_ability(user, "<span class='cult'>You prepare to horrify a target...</span>")
/obj/effect/proc_holder/horror/InterceptClickOn(mob/living/caller, params, atom/target)
if(..())
return
if(ranged_ability_user.incapacitated() || !iscultist(caller))
remove_ranged_ability()
return
var/turf/T = get_turf(ranged_ability_user)
if(!isturf(T))
return FALSE
if(target in view(7, get_turf(ranged_ability_user)))
if(!ishuman(target) || iscultist(target))
return
var/mob/living/carbon/human/H = target
H.hallucination = max(H.hallucination, 240)
SEND_SOUND(ranged_ability_user, sound('sound/effects/ghost.ogg',0,1,50))
var/image/C = image('icons/effects/cult_effects.dmi',H,"bloodsparkles", ABOVE_MOB_LAYER)
add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/cult, "cult_apoc", C, FALSE)
addtimer(CALLBACK(H,/atom/.proc/remove_alt_appearance,"cult_apoc",TRUE), 2400, TIMER_OVERRIDE|TIMER_UNIQUE)
to_chat(ranged_ability_user,"<span class='cult'><b>[H] has been cursed with living nightmares!</b></span>")
attached_action.charges--
attached_action.desc = attached_action.base_desc
attached_action.desc += "<br><b><u>Has [attached_action.charges] use\s remaining</u></b>."
attached_action.UpdateButtonIcon()
if(attached_action.charges <= 0)
remove_mousepointer(ranged_ability_user.client)
remove_ranged_ability("<span class='cult'>You have exhausted the spell's power!</span>")
qdel(src)
/datum/action/innate/cult/blood_spell/veiling
name = "Conceal Presence"
desc = "A multi-function spell that alternates between hiding and revealing nearby cult runes, structures, turf, and airlocks."
invocation = "Kla'atu barada nikt'o!"
button_icon_state = "gone"
charges = 10
var/revealing = FALSE //if it reveals or not
/datum/action/innate/cult/blood_spell/veiling/Activate()
if(!revealing)
owner.visible_message("<span class='warning'>Thin grey dust falls from [owner]'s hand!</span>", \
"<span class='cultitalic'>You invoke the veiling spell, hiding nearby runes.</span>")
charges--
SEND_SOUND(owner, sound('sound/magic/smoke.ogg',0,1,25))
owner.whisper(invocation, language = /datum/language/common)
for(var/obj/effect/rune/R in range(5,owner))
R.conceal()
for(var/obj/structure/destructible/cult/S in range(5,owner))
S.conceal()
for(var/turf/open/floor/engine/cult/T in range(5,owner))
T.realappearance.alpha = 0
for(var/obj/machinery/door/airlock/cult/AL in range(5, owner))
AL.conceal()
revealing = TRUE
name = "Reveal Runes"
button_icon_state = "back"
else
owner.visible_message("<span class='warning'>A flash of light shines from [owner]'s hand!</span>", \
"<span class='cultitalic'>You invoke the counterspell, revealing nearby runes.</span>")
charges--
owner.whisper(invocation, language = /datum/language/common)
SEND_SOUND(owner, sound('sound/magic/enter_blood.ogg',0,1,25))
for(var/obj/effect/rune/R in range(7,owner)) //More range in case you weren't standing in exactly the same spot
R.reveal()
for(var/obj/structure/destructible/cult/S in range(6,owner))
S.reveal()
for(var/turf/open/floor/engine/cult/T in range(6,owner))
T.realappearance.alpha = initial(T.realappearance.alpha)
for(var/obj/machinery/door/airlock/cult/AL in range(6, owner))
AL.reveal()
revealing = FALSE
name = "Conceal Runes"
button_icon_state = "gone"
if(charges<= 0)
qdel(src)
desc = base_desc
desc += "<br><b><u>Has [charges] use\s remaining</u></b>."
UpdateButtonIcon()
/datum/action/innate/cult/blood_spell/manipulation
name = "Blood Rites"
desc = "A complex spell that allows you to gather blood and use it for healing or other powerful spells."
invocation = "Fel'th Dol Ab'orod!"
button_icon_state = "manip"
charges = 5
magic_path = "/obj/item/melee/blood_magic/manipulator"
// The "magic hand" items
/obj/item/melee/blood_magic
name = "\improper magical aura"
desc = "Sinister looking aura that distorts the flow of reality around it."
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "disintegrate"
item_state = null
flags_1 = ABSTRACT_1 | NODROP_1 | DROPDEL_1
w_class = WEIGHT_CLASS_HUGE
throwforce = 0
throw_range = 0
throw_speed = 0
var/invocation
var/uses = 1
var/health_cost = 0 //The amount of health taken from the user when invoking the spell
var/datum/action/innate/cult/blood_spell/source
/obj/item/melee/blood_magic/New(loc, spell)
source = spell
uses = source.charges
health_cost = source.health_cost
..()
/obj/item/melee/blood_magic/Destroy()
if(!QDELETED(source))
if(uses <= 0)
source.hand_magic = null
qdel(source)
source = null
else
source.hand_magic = null
source.charges = uses
source.desc = source.base_desc
source.desc += "<br><b><u>Has [uses] use\s remaining</u></b>."
source.UpdateButtonIcon()
..()
/obj/item/melee/blood_magic/attack_self(mob/living/user)
afterattack(user, user, TRUE)
/obj/item/melee/blood_magic/attack(mob/living/M, mob/living/carbon/user)
if(!iscarbon(user) || !iscultist(user))
uses = 0
qdel(src)
return
add_logs(user, M, "used a cult spell on", source.name, "")
M.lastattacker = user.real_name
M.lastattackerckey = user.ckey
/obj/item/melee/blood_magic/afterattack(atom/target, mob/living/carbon/user, proximity)
if(invocation)
user.whisper(invocation, language = /datum/language/common)
if(health_cost)
if(user.active_hand_index == 1)
user.apply_damage(health_cost, BRUTE, "l_arm")
else
user.apply_damage(health_cost, BRUTE, "r_arm")
if(uses <= 0)
qdel(src)
else if(source)
source.desc = source.base_desc
source.desc += "<br><b><u>Has [uses] use\s remaining</u></b>."
source.UpdateButtonIcon()
//Stun
/obj/item/melee/blood_magic/stun
color = "#ff0000" // red
invocation = "Fuu ma'jin!"
/obj/item/melee/blood_magic/stun/afterattack(atom/target, mob/living/carbon/user, proximity)
if(!isliving(target) || !proximity)
return
var/mob/living/L = target
if(iscultist(target))
return
if(iscultist(user))
user.visible_message("<span class='warning'>[user] holds up their hand, which explodes in a flash of red light!</span>", \
"<span class='cultitalic'>You stun [L] with the spell!</span>")
var/obj/item/nullrod/N = locate() in L
if(N)
target.visible_message("<span class='warning'>[L]'s holy weapon absorbs the light!</span>", \
"<span class='userdanger'>Your holy weapon absorbs the blinding light!</span>")
else
L.Knockdown(180)
L.flash_act(1,1)
if(issilicon(target))
var/mob/living/silicon/S = L
S.emp_act(EMP_HEAVY)
else if(iscarbon(target))
var/mob/living/carbon/C = L
C.silent += 6
C.stuttering += 15
C.cultslurring += 15
C.Jitter(15)
if(is_servant_of_ratvar(L))
L.adjustBruteLoss(15)
uses--
..()
//Teleportation
/obj/item/melee/blood_magic/teleport
color = RUNE_COLOR_TELEPORT
desc = "A potent spell that teleport cultists on contact."
invocation = "Sas'so c'arta forbici!"
/obj/item/melee/blood_magic/teleport/afterattack(atom/target, mob/living/carbon/user, proximity)
if(!iscultist(target) || !proximity)
to_chat(user, "<span class='warning'>You can only teleport adjacent cultists with this spell!</span>")
return
if(iscultist(user))
var/list/potential_runes = list()
var/list/teleportnames = list()
for(var/R in GLOB.teleport_runes)
var/obj/effect/rune/teleport/T = R
potential_runes[avoid_assoc_duplicate_keys(T.listkey, teleportnames)] = T
if(!potential_runes.len)
to_chat(user, "<span class='warning'>There are no valid runes to teleport to!</span>")
log_game("Teleport talisman failed - no other teleport runes")
return
var/turf/T = get_turf(src)
if(is_away_level(T.z))
to_chat(user, "<span class='cultitalic'>You are not in the right dimension!</span>")
log_game("Teleport spell failed - user in away mission")
return
var/input_rune_key = input(user, "Choose a rune to teleport to.", "Rune to Teleport to") as null|anything in potential_runes //we know what key they picked
var/obj/effect/rune/teleport/actual_selected_rune = potential_runes[input_rune_key] //what rune does that key correspond to?
if(QDELETED(src) || !user || !user.is_holding(src) || user.incapacitated() || !actual_selected_rune || !proximity)
return
var/turf/dest = get_turf(actual_selected_rune)
if(is_blocked_turf(dest, TRUE))
to_chat(user, "<span class='warning'>The target rune is blocked. Attempting to teleport to it would be massively unwise.</span>")
return
uses--
user.visible_message("<span class='warning'>Dust flows from [user]'s hand, and [user.p_they()] disappear[user.p_s()] with a sharp crack!</span>", \
"<span class='cultitalic'>You speak the words of the talisman and find yourself somewhere else!</span>", "<i>You hear a sharp crack.</i>")
var/mob/living/L = target
L.forceMove(dest)
dest.visible_message("<span class='warning'>There is a boom of outrushing air as something appears above the rune!</span>", null, "<i>You hear a boom.</i>")
..()
//Shackles
/obj/item/melee/blood_magic/shackles
name = "Shadow Shackles"
desc = "Allows you to bind a victim and temporarily silence them."
invocation = "In'totum Lig'abis!"
color = "#000000" // black
/obj/item/melee/blood_magic/shackles/afterattack(atom/target, mob/living/carbon/user, proximity)
if(iscultist(user) && iscarbon(target) && proximity)
var/mob/living/carbon/C = target
if(C.get_num_arms() >= 2 || C.get_arm_ignore())
CuffAttack(C, user)
else
user.visible_message("<span class='cultitalic'>This victim doesn't have enough arms to complete the restraint!</span>")
return
..()
/obj/item/melee/blood_magic/shackles/proc/CuffAttack(mob/living/carbon/C, mob/living/user)
if(!C.handcuffed)
playsound(loc, 'sound/weapons/cablecuff.ogg', 30, 1, -2)
C.visible_message("<span class='danger'>[user] begins restraining [C] with dark magic!</span>", \
"<span class='userdanger'>[user] begins shaping a dark magic around your wrists!</span>")
if(do_mob(user, C, 30))
if(!C.handcuffed)
C.handcuffed = new /obj/item/restraints/handcuffs/energy/cult/used(C)
C.update_handcuffed()
C.silent += 5
to_chat(user, "<span class='notice'>You shackle [C].</span>")
add_logs(user, C, "shackled")
uses--
else
to_chat(user, "<span class='warning'>[C] is already bound.</span>")
else
to_chat(user, "<span class='warning'>You fail to shackle [C].</span>")
else
to_chat(user, "<span class='warning'>[C] is already bound.</span>")
/obj/item/restraints/handcuffs/energy/cult //For the shackling spell
name = "shadow shackles"
desc = "Shackles that bind the wrists with sinister magic."
trashtype = /obj/item/restraints/handcuffs/energy/used
flags_1 = DROPDEL_1
/obj/item/restraints/handcuffs/energy/cult/used/dropped(mob/user)
user.visible_message("<span class='danger'>[user]'s shackles shatter in a discharge of dark magic!</span>", \
"<span class='userdanger'>Your [src] shatters in a discharge of dark magic!</span>")
. = ..()
//Construction: Creates a construct shell out of 25 metal sheets, or converts plasteel into runed metal
/obj/item/melee/blood_magic/construction
name = "Twisted Construction"
desc = "Corrupts metal and plasteel into more sinister forms."
invocation = "Ethra p'ni dedol!"
color = "#000000" // black
/obj/item/melee/blood_magic/construction/afterattack(atom/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/obj/item/stack/sheet/candidate = target
if(candidate.use(50))
uses--
to_chat(user, "<span class='warning'>A dark cloud eminates from your hand and swirls around the metal, twisting it into a construct shell!</span>")
new /obj/structure/constructshell(T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else
to_chat(user, "<span class='warning'>You need 50 metal to produce a construct shell!</span>")
else if(istype(target, /obj/item/stack/sheet/plasteel))
var/obj/item/stack/sheet/plasteel/candidate = target
var/quantity = min(candidate.amount, uses)
uses -= quantity
new /obj/item/stack/sheet/runed_metal(T,quantity)
candidate.use(quantity)
to_chat(user, "<span class='warning'>A dark cloud eminates from you hand and swirls around the plasteel, transforming it into runed metal!</span>")
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else if(istype(target,/mob/living/silicon/robot))
var/mob/living/silicon/robot/candidate = target
if(candidate.mmi)
user.visible_message("<span class='danger'>A dark cloud eminates from [user]'s hand and swirls around [candidate]!</span>")
playsound(T, 'sound/machines/airlock_alien_prying.ogg', 80, 1)
var/prev_color = candidate.color
candidate.color = "black"
if(do_after(user, 90, target = candidate))
candidate.emp_act(EMP_HEAVY)
var/construct_class = alert(user, "Please choose which type of construct you wish to create.",,"Juggernaut","Wraith","Artificer")
user.visible_message("<span class='danger'>The dark cloud receedes from what was formerly [candidate], revealing a\n [construct_class]!</span>")
switch(construct_class)
if("Juggernaut")
makeNewConstruct(/mob/living/simple_animal/hostile/construct/armored, candidate, user, 0, T)
if("Wraith")
makeNewConstruct(/mob/living/simple_animal/hostile/construct/wraith, candidate, user, 0, T)
if("Artificer")
makeNewConstruct(/mob/living/simple_animal/hostile/construct/builder, candidate, user, 0, T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
uses--
candidate.mmi = null
qdel(candidate)
else
candidate.color = prev_color
else
uses--
to_chat(user, "<span class='warning'>A dark cloud eminates from you hand and swirls around [candidate] - twisting it into a construct shell!</span>")
new /obj/structure/constructshell(T)
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else if(istype(target,/obj/machinery/door/airlock))
target.narsie_act()
uses--
user.visible_message("<span class='warning'>Black ribbons suddenly eminate from [user]'s hand and cling to the airlock - twisting and corrupting it!</span>")
SEND_SOUND(user, sound('sound/effects/magic.ogg',0,1,25))
else
to_chat(user, "<span class='warning'>The spell will not work on [target]!</span>")
..()
//Armor: Gives the target a basic cultist combat loadout
/obj/item/melee/blood_magic/armor
name = "Sinister Armaments"
desc = "A spell that will equip the target with cultist equipment if there is a slot to equip it to."
color = "#33cc33" // green
/obj/item/melee/blood_magic/armor/afterattack(atom/target, mob/living/carbon/user, proximity)
if(iscarbon(target) && proximity)
uses--
var/mob/living/carbon/C = target
C.visible_message("<span class='warning'>Otherworldly armor suddenly appears on [C]!</span>")
C.equip_to_slot_or_del(new /obj/item/clothing/under/color/black,slot_w_uniform)
C.equip_to_slot_or_del(new /obj/item/clothing/head/culthood/alt(user), slot_head)
C.equip_to_slot_or_del(new /obj/item/clothing/suit/cultrobes/alt(user), slot_wear_suit)
C.equip_to_slot_or_del(new /obj/item/clothing/shoes/cult/alt(user), slot_shoes)
C.equip_to_slot_or_del(new /obj/item/storage/backpack/cultpack(user), slot_back)
if(C == user)
qdel(src) //Clears the hands
C.put_in_hands(new /obj/item/melee/cultblade(user))
C.put_in_hands(new /obj/item/restraints/legcuffs/bola/cult(user))
..()
/obj/item/melee/blood_magic/manipulator
name = "Blood Rite"
desc = "A spell that will absorb blood from anything you touch.<br>Touching cultists and constructs can heal them.<br><b>Clicking the hand will potentially let you focus the spell into something stronger.</b>"
color = "#7D1717"
/obj/item/melee/blood_magic/manipulator/afterattack(atom/target, mob/living/carbon/human/user, proximity)
if(proximity)
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(NOBLOOD in H.dna.species.species_traits)
to_chat(user,"<span class='warning'>Blood rites do not work on species with no blood!</span>")
return
if(iscultist(H))
if(H.stat == DEAD)
to_chat(user,"<span class='warning'>Only a revive rune can bring back the dead!</span>")
return
if(H.blood_volume < BLOOD_VOLUME_SAFE)
var/restore_blood = BLOOD_VOLUME_SAFE - H.blood_volume
if(uses*2 < restore_blood)
H.blood_volume += uses*2
to_chat(user,"<span class='danger'>You use the last of your blood rites to restore what blood you could!</span>")
uses = 0
return ..()
else
H.blood_volume = BLOOD_VOLUME_SAFE
uses -= round(restore_blood/2)
to_chat(user,"<span class='warning'>Your blood rites have restored [H == user ? "your" : "their"] blood to safe levels!</span>")
var/overall_damage = H.getBruteLoss() + H.getFireLoss() + H.getToxLoss() + H.getOxyLoss()
if(overall_damage == 0)
to_chat(user,"<span class='cult'>That cultist doesn't require healing!</span>")
else
var/ratio = uses/overall_damage
if(H == user)
to_chat(user,"<span class='cult'><b>Your blood healing is far less efficient when used on yourself!</b></span>")
ratio *= 0.35 // Healing is half as effective if you can't perform a full heal
uses -= round(overall_damage) // Healing is 65% more "expensive" even if you can still perform the full heal
if(ratio>1)
ratio = 1
uses -= round(overall_damage)
H.visible_message("<span class='warning'>[H] is fully healed by [H==user ? "their":"[H]'s"]'s blood magic!</span>")
else
H.visible_message("<span class='warning'>[H] is partially healed by [H==user ? "their":"[H]'s"] blood magic.</span>")
uses = 0
ratio *= -1
H.adjustOxyLoss((overall_damage*ratio) * (H.getOxyLoss() / overall_damage), 0)
H.adjustToxLoss((overall_damage*ratio) * (H.getToxLoss() / overall_damage), 0)
H.adjustFireLoss((overall_damage*ratio) * (H.getFireLoss() / overall_damage), 0)
H.adjustBruteLoss((overall_damage*ratio) * (H.getBruteLoss() / overall_damage), 0)
H.updatehealth()
playsound(get_turf(H), 'sound/magic/staff_healing.ogg', 25)
new /obj/effect/temp_visual/cult/sparks(get_turf(H))
user.Beam(H,icon_state="sendbeam",time=15)
else
if(H.stat == DEAD)
to_chat(user,"<span class='warning'>Their blood has stopped flowing, you'll have to find another way to extract it.</span>")
return
if(H.cultslurring)
to_chat(user,"<span class='danger'>Their blood has been tainted by an even stronger form of blood magic, it's no use to us like this!</span>")
return
if(H.blood_volume > BLOOD_VOLUME_SAFE)
H.blood_volume -= 100
uses += 50
user.Beam(H,icon_state="drainbeam",time=10)
playsound(get_turf(H), 'sound/magic/enter_blood.ogg', 50)
H.visible_message("<span class='danger'>[user] has drained some of [H]'s blood!</span>")
to_chat(user,"<span class='cultitalic'>Your blood rite gains 50 charges from draining [H]'s blood.</span>")
new /obj/effect/temp_visual/cult/sparks(get_turf(H))
else
to_chat(user,"<span class='danger'>They're missing too much blood - you cannot drain them further!</span>")
return
if(isconstruct(target))
var/mob/living/simple_animal/M = target
var/missing = M.maxHealth - M.health
if(missing)
if(uses > missing)
M.adjustHealth(-missing)
M.visible_message("<span class='warning'>[M] is fully-healed by [user]'s blood magic!</span>")
uses -= missing
else
M.adjustHealth(-uses)
M.visible_message("<span class='warning'>[M] is healed by [user]'sblood magic!</span>")
uses = 0
playsound(get_turf(M), 'sound/magic/staff_healing.ogg', 25)
user.Beam(M,icon_state="sendbeam",time=10)
if(istype(target, /obj/effect/decal/cleanable/blood))
blood_draw(target, user)
..()
/obj/item/melee/blood_magic/manipulator/proc/blood_draw(atom/target, mob/living/carbon/human/user)
var/temp = 0
var/turf/T = get_turf(target)
if(T)
for(var/obj/effect/decal/cleanable/blood/B in view(T, 2))
if(B.blood_state == "blood")
if(B.bloodiness == 100) //Bonus for "pristine" bloodpools, also to prevent cheese with footprint spam
temp += 30
else
temp += max((B.bloodiness**2)/800,1)
new /obj/effect/temp_visual/cult/turf/floor(get_turf(B))
qdel(B)
for(var/obj/effect/decal/cleanable/trail_holder/TH in view(T, 2))
qdel(TH)
var/obj/item/clothing/shoes/shoecheck = user.shoes
if(shoecheck && shoecheck.bloody_shoes["blood"])
temp += shoecheck.bloody_shoes["blood"]/20
shoecheck.bloody_shoes["blood"] = 0
if(temp)
user.Beam(T,icon_state="drainbeam",time=15)
new /obj/effect/temp_visual/cult/sparks(get_turf(user))
playsound(T, 'sound/magic/enter_blood.ogg', 50)
to_chat(user, "<span class='cultitalic'>Your blood rite has gained [round(temp)] charge\s from blood sources around you!</span>")
uses += round(temp)
/obj/item/melee/blood_magic/manipulator/attack_self(mob/living/user)
if(iscultist(user))
var/list/options = list("Blood Spear (200)", "Blood Bolt Barrage (400)", "Blood Beam (600)")
var/choice = input(user, "Choose a greater blood rite...", "Greater Blood Rites") as null|anything in options
if(!choice)
to_chat(user, "<span class='cultitalic'>You decide against conducting a greater blood rite.</span>")
return
switch(choice)
if("Blood Spear (200)")
if(uses < 200)
to_chat(user, "<span class='cultitalic'>You need 200 charges to perform this rite.</span>")
else
uses -= 200
var/turf/T = get_turf(user)
qdel(src)
var/datum/action/innate/cult/spear/S = new(user)
var/obj/item/twohanded/cult_spear/rite = new(T)
S.Grant(user, rite)
rite.spear_act = S
if(user.put_in_hands(rite))
to_chat(user, "<span class='cultitalic'>A [rite.name] appears in your hand!</span>")
else
user.visible_message("<span class='warning'>A [rite.name] appears at [user]'s feet!</span>", \
"<span class='cultitalic'>A [rite.name] materializes at your feet.</span>")
if("Blood Bolt Barrage (400)")
if(uses < 400)
to_chat(user, "<span class='cultitalic'>You need 400 charges to perform this rite.</span>")
else
var/obj/rite = new /obj/item/gun/ballistic/shotgun/boltaction/enchanted/arcane_barrage/blood()
uses -= 400
qdel(src)
if(user.put_in_hands(rite))
to_chat(user, "<span class='cult'><b>Your hands glow with power!</b></span>")
else
to_chat(user, "<span class='cultitalic'>You need a free hand for this rite!</span>")
qdel(rite)
if("Blood Beam (600)")
if(uses < 600)
to_chat(user, "<span class='cultitalic'>You need 600 charges to perform this rite.</span>")
else
var/obj/rite = new /obj/item/blood_beam()
uses -= 600
qdel(src)
if(user.put_in_hands(rite))
to_chat(user, "<span class='cultlarge'><b>Your hands glow with POWER OVERWHELMING!!!</b></span>")
else
to_chat(user, "<span class='cultitalic'>You need a free hand for this rite!</span>")
qdel(rite)
@@ -1,306 +1,4 @@
/obj/item/dogborg/jaws/big
name = "combat jaws"
icon = 'icons/mob/dogborg.dmi'
icon_state = "jaws"
desc = "The jaws of the law."
flags_1 = CONDUCT_1
force = 12
throwforce = 0
hitsound = 'sound/weapons/bite.ogg'
attack_verb = list("chomped", "bit", "ripped", "mauled", "enforced")
w_class = 3
sharpness = IS_SHARP
/obj/item/dogborg/jaws/small
name = "puppy jaws"
icon = 'icons/mob/dogborg.dmi'
icon_state = "smalljaws"
desc = "The jaws of a small dog."
flags_1 = CONDUCT_1
force = 6
throwforce = 0
hitsound = 'sound/weapons/bite.ogg'
attack_verb = list("nibbled", "bit", "gnawed", "chomped", "nommed")
w_class = 3
sharpness = IS_SHARP
/obj/item/dogborg/jaws/attack(atom/A, mob/living/silicon/robot/user)
..()
user.do_attack_animation(A, ATTACK_EFFECT_BITE)
/obj/item/dogborg/jaws/small/attack_self(mob/user)
var/mob/living/silicon/robot.R = user
if(R.emagged)
name = "combat jaws"
icon = 'icons/mob/dogborg.dmi'
icon_state = "jaws"
desc = "The jaws of the law."
flags_1 = CONDUCT_1
force = 12
throwforce = 0
hitsound = 'sound/weapons/bite.ogg'
attack_verb = list("chomped", "bit", "ripped", "mauled", "enforced")
w_class = 3
sharpness = IS_SHARP
else
name = "puppy jaws"
icon = 'icons/mob/dogborg.dmi'
icon_state = "smalljaws"
desc = "The jaws of a small dog."
flags_1 = CONDUCT_1
force = 5
throwforce = 0
hitsound = 'sound/weapons/bite.ogg'
attack_verb = list("nibbled", "bit", "gnawed", "chomped", "nommed")
w_class = 3
sharpness = IS_SHARP
update_icon()
//Cuffs
/obj/item/restraints/handcuffs/cable/zipties/cyborg/dog/attack(mob/living/carbon/C, mob/user)
if(!C.handcuffed)
playsound(loc, 'sound/weapons/cablecuff.ogg', 60, 1, -2)
C.visible_message("<span class='danger'>[user] is trying to put zipties on [C]!</span>", \
"<span class='userdanger'>[user] is trying to put zipties on [C]!</span>")
if(do_mob(user, C, 60))
if(!C.handcuffed)
C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C)
C.update_inv_handcuffed(0)
to_chat(user,"<span class='notice'>You handcuff [C].</span>")
playsound(loc, pick('sound/voice/bgod.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/bsecureday.ogg', 'sound/voice/bradio.ogg', 'sound/voice/binsult.ogg', 'sound/voice/bcreep.ogg'), 50, 0)
add_logs(user, C, "handcuffed")
else
to_chat(user,"<span class='warning'>You fail to handcuff [C]!</span>")
//Boop
/obj/item/device/analyzer/nose
name = "boop module"
icon = 'icons/mob/dogborg.dmi'
icon_state = "nose"
desc = "The BOOP module"
flags_1 = CONDUCT_1
force = 0
throwforce = 0
attack_verb = list("nuzzled", "nosed", "booped")
w_class = 1
/obj/item/device/analyzer/nose/attack_self(mob/user)
user.visible_message("[user] sniffs around the air.", "<span class='warning'>You sniff the air for gas traces.</span>")
var/turf/location = user.loc
if(!istype(location))
return
var/datum/gas_mixture/environment = location.return_air()
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
to_chat(user, "<span class='info'><B>Results:</B></span>")
if(abs(pressure - ONE_ATMOSPHERE) < 10)
to_chat(user, "<span class='info'>Pressure: [round(pressure,0.1)] kPa</span>")
else
to_chat(user, "<span class='alert'>Pressure: [round(pressure,0.1)] kPa</span>")
if(total_moles)
var/list/env_gases = environment.gases
environment.assert_gases(arglist(GLOB.hardcoded_gases))
var/o2_concentration = env_gases[/datum/gas/oxygen][MOLES]/total_moles
var/n2_concentration = env_gases[/datum/gas/nitrogen][MOLES]/total_moles
var/co2_concentration = env_gases[/datum/gas/carbon_dioxide][MOLES]/total_moles
var/plasma_concentration = env_gases[/datum/gas/plasma][MOLES]/total_moles
environment.garbage_collect()
if(abs(n2_concentration - N2STANDARD) < 20)
to_chat(user, "<span class='info'>Nitrogen: [round(n2_concentration*100, 0.01)] %</span>")
else
to_chat(user, "<span class='alert'>Nitrogen: [round(n2_concentration*100, 0.01)] %</span>")
if(abs(o2_concentration - O2STANDARD) < 2)
to_chat(user, "<span class='info'>Oxygen: [round(o2_concentration*100, 0.01)] %</span>")
else
to_chat(user, "<span class='alert'>Oxygen: [round(o2_concentration*100, 0.01)] %</span>")
if(co2_concentration > 0.01)
to_chat(user, "<span class='alert'>CO2: [round(co2_concentration*100, 0.01)] %</span>")
else
to_chat(user, "<span class='info'>CO2: [round(co2_concentration*100, 0.01)] %</span>")
if(plasma_concentration > 0.005)
to_chat(user, "<span class='alert'>Plasma: [round(plasma_concentration*100, 0.01)] %</span>")
else
to_chat(user, "<span class='info'>Plasma: [round(plasma_concentration*100, 0.01)] %</span>")
for(var/id in env_gases)
if(id in GLOB.hardcoded_gases)
continue
var/gas_concentration = env_gases[id][MOLES]/total_moles
to_chat(user, "<span class='alert'>[env_gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] %</span>")
to_chat(user, "<span class='info'>Temperature: [round(environment.temperature-T0C)] &deg;C</span>")
/obj/item/device/analyzer/nose/AltClick(mob/user) //Barometer output for measuring when the next storm happens
. = ..()
//Delivery
/obj/item/storage/bag/borgdelivery
name = "fetching storage"
desc = "Fetch the thing!"
icon = 'icons/mob/dogborg.dmi'
icon_state = "dbag"
//Can hold one big item at a time. Drops contents on unequip.(see inventory.dm)
w_class = 5
max_w_class = 2
max_combined_w_class = 2
storage_slots = 1
collection_mode = 0
can_hold = list() // any
cant_hold = list(/obj/item/disk/nuclear)
//Tongue stuff
/obj/item/soap/tongue
name = "synthetic tongue"
desc = "Useful for slurping mess off the floor before affectionally licking the crew members in the face."
icon = 'icons/mob/dogborg.dmi'
icon_state = "synthtongue"
hitsound = 'sound/effects/attackblob.ogg'
cleanspeed = 80
/obj/item/soap/tongue/scrubpup
cleanspeed = 25 //slightly faster than a mop.
/obj/item/soap/tongue/New()
..()
flags_1 |= NOBLUDGEON_1 //No more attack messages
/obj/item/trash/rkibble
name = "robo kibble"
desc = "A novelty bowl of assorted mech fabricator byproducts. Mockingly feed this to the sec-dog to help it recharge."
icon = 'icons/mob/dogborg.dmi'
icon_state= "kibble"
/obj/item/soap/tongue/attack_self(mob/user)
var/mob/living/silicon/robot.R = user
if(R.emagged)
name = "hacked tongue of doom"
desc = "Your tongue has been upgraded successfully. Congratulations."
icon = 'icons/mob/dogborg.dmi'
icon_state = "syndietongue"
cleanspeed = 10 //(nerf'd)tator soap stat
else
name = "synthetic tongue"
desc = "Useful for slurping mess off the floor before affectionally licking the crew members in the face."
icon = 'icons/mob/dogborg.dmi'
icon_state = "synthtongue"
cleanspeed = initial(cleanspeed)
update_icon()
/obj/item/soap/tongue/afterattack(atom/target, mob/user, proximity)
var/mob/living/silicon/robot.R = user
if(!proximity || !check_allowed_items(target))
return
if(R.client && (target in R.client.screen))
to_chat(R, "<span class='warning'>You need to take that [target.name] off before cleaning it!</span>")
else if(is_cleanable(target))
R.visible_message("[R] begins to lick off \the [target.name].", "<span class='warning'>You begin to lick off \the [target.name]...</span>")
if(do_after(R, src.cleanspeed, target = target))
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't eat them.
to_chat(R, "<span class='notice'>You finish licking off \the [target.name].</span>")
qdel(target)
R.cell.give(50)
else if(isobj(target)) //hoo boy. danger zone man
if(istype(target,/obj/item/trash))
R.visible_message("[R] nibbles away at \the [target.name].", "<span class='warning'>You begin to nibble away at \the [target.name]...</span>")
if(do_after(R, src.cleanspeed, target = target))
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't eat them.
to_chat(R, "<span class='notice'>You finish off \the [target.name].</span>")
qdel(target)
R.cell.give(250)
return
if(istype(target,/obj/item/stock_parts/cell))
R.visible_message("[R] begins cramming \the [target.name] down its throat.", "<span class='warning'>You begin cramming \the [target.name] down your throat...</span>")
if(do_after(R, 50, target = target))
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't eat them.
to_chat(R, "<span class='notice'>You finish off \the [target.name].</span>")
var/obj/item/stock_parts/cell.C = target
R.cell.charge = R.cell.charge + (C.charge / 3) //Instant full cell upgrades op idgaf
qdel(target)
return
var/obj/item/I = target //HAHA FUCK IT, NOT LIKE WE ALREADY HAVE A SHITTON OF WAYS TO REMOVE SHIT
if(!I.anchored && R.emagged)
R.visible_message("[R] begins chewing up \the [target.name]. Looks like it's trying to loophole around its diet restriction!", "<span class='warning'>You begin chewing up \the [target.name]...</span>")
if(do_after(R, 100, target = I)) //Nerf dat time yo
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check. Even emags don't make you magically eat things at range.
return //If they moved away, you can't eat them.
visible_message("<span class='warning'>[R] chews up \the [target.name] and cleans off the debris!</span>")
to_chat(R, "<span class='notice'>You finish off \the [target.name].</span>")
qdel(I)
R.cell.give(500)
return
R.visible_message("[R] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
if(do_after(R, src.cleanspeed, target = target))
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't clean them.
to_chat(R,"<span class='notice'>You clean \the [target.name].</span>")
var/obj/effect/decal/cleanable/C = locate() in target
qdel(C)
SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
else if(ishuman(target))
if(R.emagged)
var/mob/living/L = target
if(R.cell.charge <= 666)
return
L.Stun(4) // normal stunbaton is force 7 gimme a break good sir!
L.Knockdown(80)
L.apply_effect(STUTTER, 4)
L.visible_message("<span class='danger'>[R] has shocked [L] with its tongue!</span>", \
"<span class='userdanger'>[R] has shocked you with its tongue! You can feel the betrayal.</span>")
playsound(loc, 'sound/weapons/Egloves.ogg', 50, 1, -1)
R.cell.use(666)
else
R.visible_message("<span class='warning'>\the [R] affectionally licks \the [target]'s face!</span>", "<span class='notice'>You affectionally lick \the [target]'s face!</span>")
playsound(src.loc, 'sound/effects/attackblob.ogg', 50, 1)
return
else if(istype(target, /obj/structure/window))
R.visible_message("[R] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
if(do_after(R, src.cleanspeed, target = target))
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't clean them.
to_chat(R, "<span class='notice'>You clean \the [target.name].</span>")
target.color = initial(target.color)
else
R.visible_message("[R] begins to lick \the [target.name] clean...", "<span class='notice'>You begin to lick \the [target.name] clean...</span>")
if(do_after(R, src.cleanspeed, target = target))
if(!in_range(src, target)) //Proximity is probably old news by now, do a new check.
return //If they moved away, you can't clean them.
to_chat(R, "<span class='notice'>You clean \the [target.name].</span>")
var/obj/effect/decal/cleanable/C = locate() in target
qdel(C)
SendSignal(COMSIG_COMPONENT_CLEAN_ACT, CLEAN_STRENGTH_BLOOD)
return
//Defibs
/obj/item/twohanded/shockpaddles/cyborg/hound
name = "defibrillator paws"
desc = "MediHound specific shock paws."
icon = 'icons/mob/dogborg.dmi'
icon_state = "defibpaddles0"
item_state = "defibpaddles0"
//Sleeper
// Dogborg Sleeper units
/obj/item/device/dogborg/sleeper
name = "hound sleeper"
@@ -363,7 +61,7 @@
return
if(!(target.client && target.client.prefs && target.client.prefs.toggles && (target.client.prefs.toggles & MEDIHOUND_SLEEPER)))
to_chat(user, "<span class='warning'>This person is incompatible with our equipment.</span>")
return
return
if(target.buckled)
to_chat(user, "<span class='warning'>The user is buckled and can not be put into your [src.name].</span>")
return
@@ -608,6 +306,12 @@
playsound(get_turf(hound),"death_pred",50,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
T.stop_sound_channel(CHANNEL_PRED)
T.playsound_local("death_prey",60)
for(var/belly in T.vore_organs)
var/obj/belly/B = belly
for(var/atom/movable/thing in B)
thing.forceMove(src)
if(ismob(thing))
to_chat(thing, "As [T] melts away around you, you find yourself in [hound]'s [name]")
for(var/obj/item/W in T)
if(!T.dropItemToGround(W))
qdel(W)
@@ -793,101 +497,4 @@
user.visible_message("<span class='warning'>[hound.name]'s garbage processor groans lightly as [trashman] slips inside.</span>", "<span class='notice'>Your garbage compactor groans lightly as [trashman] slips inside.</span>")
playsound(hound, 'sound/effects/bin_close.ogg', 80, 1)
return
return
// Pounce stuff for K-9
/obj/item/dogborg/pounce
name = "pounce"
icon = 'icons/mob/dogborg.dmi'
icon_state = "pounce"
desc = "Leap at your target to momentarily stun them."
force = 0
throwforce = 0
/obj/item/dogborg/pounce/New()
..()
flags_1 |= NOBLUDGEON_1
/mob/living/silicon/robot
var/leaping = 0
var/pounce_cooldown = 0
var/pounce_cooldown_time = 50 //Nearly doubled, u happy?
var/pounce_spoolup = 3
var/leap_at
var/disabler
var/laser
var/sleeper_g
var/sleeper_r
#define MAX_K9_LEAP_DIST 4 //because something's definitely borked the pounce functioning from a distance.
/obj/item/dogborg/pounce/afterattack(atom/A, mob/user)
var/mob/living/silicon/robot/R = user
if(R && !R.pounce_cooldown)
R.pounce_cooldown = !R.pounce_cooldown
to_chat(R, "<span class ='warning'>Your targeting systems lock on to [A]...</span>")
addtimer(CALLBACK(R, /mob/living/silicon/robot.proc/leap_at, A), R.pounce_spoolup)
spawn(R.pounce_cooldown_time)
R.pounce_cooldown = !R.pounce_cooldown
else if(R && R.pounce_cooldown)
to_chat(R, "<span class='danger'>Your leg actuators are still recharging!</span>")
/mob/living/silicon/robot/proc/leap_at(atom/A)
if(leaping || stat || buckled || lying)
return
if(!has_gravity(src) || !has_gravity(A))
to_chat(src,"<span class='danger'>It is unsafe to leap without gravity!</span>")
//It's also extremely buggy visually, so it's balance+bugfix
return
if(cell.charge <= 500)
to_chat(src,"<span class='danger'>Insufficent reserves for jump actuators!</span>")
return
else
leaping = 1
weather_immunities += "lava"
pixel_y = 10
update_icons()
throw_at(A, MAX_K9_LEAP_DIST, 1, spin=0, diagonals_first = 1)
cell.use(500) //Doubled the energy consumption
weather_immunities -= "lava"
/mob/living/silicon/robot/throw_impact(atom/A)
if(!leaping)
return ..()
if(A)
if(isliving(A))
var/mob/living/L = A
var/blocked = 0
if(ishuman(A))
var/mob/living/carbon/human/H = A
if(H.check_shields(0, "the [name]", src, attack_type = LEAP_ATTACK))
blocked = 1
if(!blocked)
L.visible_message("<span class ='danger'>[src] pounces on [L]!</span>", "<span class ='userdanger'>[src] pounces on you!</span>")
L.Knockdown(45)
playsound(src, 'sound/weapons/Egloves.ogg', 50, 1)
sleep(2)//Runtime prevention (infinite bump() calls on hulks)
step_towards(src,L)
else
Knockdown(45, 1, 1)
pounce_cooldown = !pounce_cooldown
spawn(pounce_cooldown_time) //3s by default
pounce_cooldown = !pounce_cooldown
else if(A.density && !A.CanPass(src))
visible_message("<span class ='danger'>[src] smashes into [A]!</span>", "<span class ='userdanger'>You smash into [A]!</span>")
playsound(src, 'sound/items/trayhit1.ogg', 50, 1)
Knockdown(45, 1, 1)
if(leaping)
leaping = 0
pixel_y = initial(pixel_y)
update_icons()
update_canmove()
return
-13
View File
@@ -1,13 +0,0 @@
/mob/var/skincmds = list()
/obj/proc/SkinCmd(mob/user as mob, var/data as text)
/proc/SkinCmdRegister(mob/user, name as text, obj/O)
user.skincmds[name] = O
/mob/verb/skincmd(data as text)
set hidden = 1
var/ref = copytext(data, 1, findtext(data, ";"))
if (src.skincmds[ref] != null)
var/obj/a = src.skincmds[ref]
a.SkinCmd(src, copytext(data, findtext(data, ";") + 1))
+1 -1
View File
@@ -100,7 +100,7 @@ GLOBAL_LIST_INIT(admin_verbs_fun, list(
/client/proc/smite
))
GLOBAL_PROTECT(admin_verbs_spawn)
GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/spawn_cargo, /client/proc/respawn_character))
GLOBAL_LIST_INIT(admin_verbs_spawn, list(/datum/admins/proc/spawn_atom, /datum/admins/proc/spawn_cargo, /datum/admins/proc/spawn_objasmob, /client/proc/respawn_character))
GLOBAL_PROTECT(admin_verbs_server)
GLOBAL_LIST_INIT(admin_verbs_server, world.AVerbsServer())
/world/proc/AVerbsServer()
+70
View File
@@ -0,0 +1,70 @@
/datum/admins/proc/spawn_objasmob(object as text)
set category = "Debug"
set desc = "(obj path) Spawn object-mob"
set name = "Spawn object-mob"
if(!check_rights(R_SPAWN))
return
var/chosen = pick_closest_path(object, make_types_fancy(subtypesof(/obj)))
if (!chosen)
return
var/mob/living/simple_animal/hostile/mimic/copy/basemob = /mob/living/simple_animal/hostile/mimic/copy
var/obj/chosen_obj = text2path(chosen)
var/list/settings = list(
"mainsettings" = list(
"name" = list("desc" = "Name", "type" = "string", "value" = "Bob"),
"maxhealth" = list("desc" = "Max. health", "type" = "number", "value" = 100),
"access" = list("desc" = "Access ID", "type" = "datum", "path" = "/obj/item/card/id", "value" = "Default"),
"objtype" = list("desc" = "Base obj type", "type" = "datum", "path" = "/obj", "value" = "[chosen]"),
"googlyeyes" = list("desc" = "Googly eyes", "type" = "boolean", "value" = "No"),
"disableai" = list("desc" = "Disable AI", "type" = "boolean", "value" = "Yes"),
"idledamage" = list("desc" = "Damaged while idle", "type" = "boolean", "value" = "No"),
"dropitem" = list("desc" = "Drop obj on death", "type" = "boolean", "value" = "Yes"),
"mobtype" = list("desc" = "Base mob type", "type" = "datum", "path" = "/mob/living/simple_animal/hostile/mimic/copy", "value" = "/mob/living/simple_animal/hostile/mimic/copy"),
"ckey" = list("desc" = "ckey", "type" = "ckey", "value" = "none"),
)
)
var/list/prefreturn = presentpreflikepicker(usr,"Customize mob", "Customize mob", Button1="Ok", width = 450, StealFocus = 1,Timeout = 0, settings=settings)
if (prefreturn["button"] == 1)
settings = prefreturn["settings"]
var/mainsettings = settings["mainsettings"]
chosen_obj = text2path(mainsettings["objtype"]["value"])
basemob = text2path(mainsettings["mobtype"]["value"])
if (!ispath(basemob, /mob/living/simple_animal/hostile/mimic/copy) || !ispath(chosen_obj, /obj))
to_chat(usr, "Mob or object path invalid")
basemob = new basemob(get_turf(usr), new chosen_obj(get_turf(usr)), usr, mainsettings["dropitem"]["value"] == "Yes" ? FALSE : TRUE, (mainsettings["googlyeyes"]["value"] == "Yes" ? FALSE : TRUE))
if (mainsettings["disableai"]["value"] == "Yes")
basemob.toggle_ai(AI_OFF)
if (mainsettings["idledamage"]["value"] == "No")
basemob.idledamage = FALSE
if (mainsettings["access"])
var/newaccess = text2path(mainsettings["access"]["value"])
if (ispath(newaccess))
basemob.access_card = new newaccess
if (mainsettings["maxhealth"]["value"])
if (!isnum(mainsettings["maxhealth"]["value"]))
mainsettings["maxhealth"]["value"] = text2num(mainsettings["maxhealth"]["value"])
if (mainsettings["maxhealth"]["value"] > 0)
basemob.maxHealth = basemob.maxHealth = mainsettings["maxhealth"]["value"]
if (mainsettings["name"]["value"])
basemob.name = basemob.real_name = html_decode(mainsettings["name"]["value"])
if (mainsettings["ckey"]["value"] != "none")
basemob.ckey = mainsettings["ckey"]["value"]
log_admin("[key_name(usr)] spawned a sentient object-mob [basemob] from [chosen_obj] at ([usr.x],[usr.y],[usr.z])")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Spawn object-mob") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -1,36 +0,0 @@
/obj/machinery/zvent
name = "interfloor air transfer system"
icon = 'icons/obj/atmospherics/components/unary_devices.dmi'
icon_state = "vent_map"
density = FALSE
anchored=1
desc = "This may be needed some day."
var/on = FALSE
var/volume_rate = 800
/obj/machinery/zvent/New()
..()
SSair.atmos_machinery += src
/obj/machinery/zvent/Destroy()
SSair.atmos_machinery -= src
return ..()
/obj/machinery/zvent/process_atmos()
//all this object does, is make its turf share air with the ones above and below it, if they have a vent too.
if(isturf(loc)) //if we're not on a valid turf, forget it
for (var/new_z in list(-1,1)) //change this list if a fancier system of z-levels gets implemented
var/turf/open/zturf_conn = locate(x,y,z+new_z)
if (istype(zturf_conn))
var/obj/machinery/zvent/zvent_conn= locate(/obj/machinery/zvent) in zturf_conn
if (istype(zvent_conn))
//both floors have simulated turfs, share()
var/turf/open/myturf = loc
var/datum/gas_mixture/conn_air = zturf_conn.air //TODO: pop culture reference
var/datum/gas_mixture/my_air = myturf.air
if (istype(conn_air) && istype(my_air))
my_air.share(conn_air)
air_update_turf()
+9
View File
@@ -324,6 +324,9 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "<b>Ghost pda:</b> <a href='?_src_=prefs;preference=ghost_pda'>[(chat_toggles & CHAT_GHOSTPDA) ? "All Messages" : "Nearest Creatures"]</a><br>"
dat += "<b>Pull requests:</b> <a href='?_src_=prefs;preference=pull_requests'>[(chat_toggles & CHAT_PULLR) ? "Yes" : "No"]</a><br>"
dat += "<b>Midround Antagonist:</b> <a href='?_src_=prefs;preference=allow_midround_antag'>[(toggles & MIDROUND_ANTAG) ? "Yes" : "No"]</a><br>"
//VORE SOUNDS
dat += "<b>Hear Vore Sounds:</b> <a href='?_src_=prefs;preference=toggleeatingnoise'>[(toggles & EATING_NOISES) ? "Yes" : "No"]</a><br>"
dat += "<b>Hear Vore Digestion Sounds:</b> <a href='?_src_=prefs;preference=toggledigestionnoise'>[(toggles & DIGESTION_NOISES) ? "Yes" : "No"]</a><br>"
if(CONFIG_GET(flag/allow_metadata))
dat += "<b>OOC Notes:</b> <a href='?_src_=prefs;preference=metadata;task=input'>Edit </a><br>"
@@ -1765,6 +1768,12 @@ GLOBAL_LIST_EMPTY(preferences_datums)
user.client.playtitlemusic()
else
user.stop_sound_channel(CHANNEL_LOBBYMUSIC)
// VORE SOUND TOGGLES
if("toggleeatingnoise")
toggles ^= EATING_NOISES
if("toggledigestionnoise")
toggles ^= DIGESTION_NOISES
if("ghost_ears")
chat_toggles ^= CHAT_GHOSTEARS
+4 -1
View File
@@ -5,4 +5,7 @@
/datum/preferences/proc/set_biological_gender(var/gender)
biological_gender = gender
identifying_gender = gender
identifying_gender = gender
/obj/item/clothing/var/hides_bulges = FALSE // OwO wats this?
-25
View File
@@ -1,25 +0,0 @@
/client/verb/sethotkeys(from_pref = 0 as num)
set name = "Set Hotkeys"
set hidden = TRUE
set waitfor = FALSE
set desc = "Used to set mob-specific hotkeys or load hoykey mode from preferences"
var/hotkey_default = "default"
var/hotkey_macro = "hotkeys"
var/current_setting
var/list/default_macros = list("default", "robot-default")
if(from_pref)
current_setting = (prefs.hotkeys ? hotkey_macro : hotkey_default)
else
current_setting = winget(src, "mainwindow", "macro")
if(mob)
hotkey_macro = mob.macro_hotkeys
hotkey_default = mob.macro_default
if(current_setting in default_macros)
winset(src, null, "mainwindow.macro=[hotkey_default] input.focus=true input.background-color=#d3b5b5")
else
winset(src, null, "mainwindow.macro=[hotkey_macro] mapwindow.map.focus=true input.background-color=#e0e0e0")
-17
View File
@@ -1,17 +0,0 @@
/datum/round_event_control/solar_flare
name = "Solar Flare"
typepath = /datum/round_event/solar_flare
max_occurrences = 1
/datum/round_event/solar_flare
/datum/round_event/solar_flare/setup()
startWhen = 3
endWhen = startWhen + 1
announceWhen = 1
/datum/round_event/solar_flare/announce()
priority_announce("Incoming solar flare detected near the station. Expect power outages in all exposed areas for a short duration.", "Anomaly Alert", 'sound/effects/alert.ogg')
/datum/round_event/solar_flare/start()
SSweather.run_weather("solar flare",1)
-111
View File
@@ -1,111 +0,0 @@
/obj/machinery/computer/holodeck/attack_hand(var/mob/user as mob)
user.set_machine(src)
var/dat = "<h3>Current Loaded Programs</h3>"
dat += "<a href='?src=\ref[src];loadarea=[offline_program.type]'>Power Off</a><br>"
for(var/area/A in program_cache)
dat += "<a href='?src=\ref[src];loadarea=[A.type]'>[A.name]</a><br>"
if(emagged && emag_programs.len)
dat += "<span class='warning'>SUPERVISOR ACCESS - SAFETY PROTOCOLS DISABLED - CAUTION: EMITTER ANOMALY</span><br>"
for(var/area/A in emag_programs)
dat += "<a href='?src=\ref[src];loadarea=[A.type]'>[A.name]</a><br>"
var/datum/browser/popup = new(user, "computer", name, 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
/obj/machinery/computer/holodeck/attack_ai(var/mob/user as mob)
var/dat = "<h3>Current Loaded Programs</h3>"
dat += "<a href='?src=\ref[src];loadarea=[offline_program.type]'>Power Off</a><br>"
for(var/area/A in program_cache)
dat += "<a href='?src=\ref[src];loadarea=[A.type]'>[A.name]</a><br>"
if(emag_programs.len)
dat += "<br>"
if(emagged)
dat += "Safety protocol: <span class='bad'>Offline</span> <a href='?\ref[src];safety=1'>Engage</a><br>"
for(var/area/A in emag_programs)
dat += "<a href='?src=\ref[src];loadarea=[A.type]'>[A.name]</a><br>"
else
dat += "Safety protocol: <span class='good'>Online</span> <a href='?\ref[src];safety=0'>Disengage</a><br>"
var/datum/browser/popup = new(user, "computer", name, 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
/obj/machinery/computer/holodeck/proc/load_program(var/area/A, var/force = 0, var/delay = 0)
if(stat)
A = offline_program
force = 1
delay = 0
if(program == A)
return
if(world.time < (last_change + 25 + (damaged?500:0)) && !force)
if(delay)
sleep(25)
else
if(world.time < (last_change + 15))//To prevent super-spam clicking, reduced process size and annoyance -Sieve
return
if(get_dist(usr,src) <= 3)
to_chat(usr, "<span class='warning'>ERROR. Recalibrating projection apparatus.</span>")
return
last_change = world.time
active = (A != offline_program)
use_power = active ? ACTIVE_POWER_USE : IDLE_POWER_USE
for(var/obj/effect/holodeck_effect/HE in effects)
HE.deactivate(src)
for(var/item in spawned)
derez(item, forced=force)
program = A
// note nerfing does not yet work on guns, should
// should also remove/limit/filter reagents?
// this is an exercise left to others I'm afraid. -Sayu
spawned = A.copy_contents_to(linked, 1, nerf_weapons = !emagged)
for(var/obj/machinery/M in spawned)
M.flags_1 |= NODECONSTRUCT_1
for(var/obj/structure/S in spawned)
S.flags_1 |= NODECONSTRUCT_1
effects = list()
spawn(30)
var/list/added = list()
for(var/obj/effect/holodeck_effect/HE in spawned)
effects += HE
spawned -= HE
var/atom/x = HE.activate(src)
if(istype(x) || islist(x))
spawned += x // holocarp are not forever
added += x
for(var/obj/machinery/M in added)
M.flags_1 |= NODECONSTRUCT_1
for(var/obj/structure/S in added)
S.flags_1 |= NODECONSTRUCT_1
/obj/machinery/computer/holodeck/proc/derez(var/obj/obj, var/silent = 1, var/forced = 0)
// Emagging a machine creates an anomaly in the derez systems.
if(obj && src.emagged && !src.stat && !forced)
if((ismob(obj) || istype(obj.loc,/mob)) && prob(50))
spawn(50) .(obj,silent) // may last a disturbingly long time
return
spawned.Remove(obj)
if(!obj)
return
var/turf/T = get_turf(obj)
for(var/atom/movable/AM in obj.contents) // these should be derezed if they were generated
AM.loc = T
if(ismob(AM))
silent = FALSE // otherwise make sure they are dropped
if(!silent)
visible_message("The [obj.name] fades away!")
qdel(obj)
@@ -252,10 +252,6 @@
if(91.01 to INFINITY)
msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
for (var/I in src.vore_organs)
var/datum/belly/B = vore_organs[I]
msg += B.get_examine_msg()
msg += "</span>"
if(!appears_dead)
@@ -329,7 +325,7 @@
if(print_flavor_text() && get_visible_name() != "Unknown")//Are we sure we know who this is? Don't show flavor text unless we can recognize them. Prevents certain metagaming with impersonation.
msg += "[print_flavor_text()]\n"
msg += "*---------*</span>"
to_chat(user, msg)
@@ -42,13 +42,4 @@
message = "<span class='warning'>[t_His] stomach is firmly packed with digesting slop. [t_He] must have eaten at least a few times worth their body weight! It looks hard for them to stand, and [t_his] gut jiggles when they move.</span>\n"
if(4075 to 10000) // Four or more people.
message = "<span class='warning'>[t_He] [t_is] so absolutely stuffed that you aren't sure how it's possible to move. [t_He] can't seem to swell any bigger. The surface of [t_his] belly looks sorely strained!</span>\n"
return message
/mob/living/carbon/human/proc/examine_bellies()
var/message = ""
for (var/I in src.vore_organs)
var/datum/belly/B = vore_organs[I]
message += B.get_examine_msg()
return message
@@ -32,6 +32,7 @@
/mob/living/carbon/human/Destroy()
QDEL_NULL(physiology)
QDEL_NULL_LIST(vore_organs) // CITADEL EDIT belly stuff
return ..()
/mob/living/carbon/human/OpenCraftingMenu()
+9 -1
View File
@@ -64,6 +64,10 @@
/mob/living/carbon/human/calculate_affecting_pressure(pressure)
if((wear_suit && (wear_suit.flags_1 & STOPSPRESSUREDMAGE_1)) && (head && (head.flags_1 & STOPSPRESSUREDMAGE_1)))
return ONE_ATMOSPHERE
if(istype(loc, /obj/belly))
return ONE_ATMOSPHERE
if(istype(loc, /obj/item/device/dogborg/sleeper))
return ONE_ATMOSPHERE
else
return pressure
@@ -138,6 +142,8 @@
return FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
if(ismob(loc))
return FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
if(istype(loc, /obj/belly))
return FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
//END EDIT
if(wear_suit)
if(wear_suit.max_heat_protection_temperature >= FIRE_SUIT_MAX_TEMP_PROTECT)
@@ -246,10 +252,12 @@
/mob/living/carbon/human/proc/get_cold_protection(temperature)
if(has_trait(TRAIT_RESISTCOLD))
return TRUE
//CITADEL EDIT Mandatory for vore code.
if(istype(loc, /obj/item/device/dogborg/sleeper))
return 1 //freezing to death in sleepers ruins fun.
if(istype(loc, /obj/belly))
return 1
if(ismob(loc))
return 1 //because lazy and being inside somemone insulates you from space
//END EDIT
@@ -351,3 +351,10 @@
H.update_body()
else
return
//misc
/mob/living/carbon/human/dummy
no_vore = TRUE
/mob/living/carbon/human/vore
devourable = TRUE
+2
View File
@@ -52,6 +52,8 @@
return
if(ismob(loc))
return
if(istype(loc, /obj/belly))
return
var/datum/gas_mixture/environment
if(loc)
-3
View File
@@ -54,9 +54,6 @@
handle_fire()
// Citadel Vore code for belly processes
handle_internal_contents()
//stuff in the stomach
handle_stomach()
@@ -1,26 +1,27 @@
/mob/living/simple_animal/hostile/megafauna/dragon
vore_active = TRUE
no_vore = FALSE
/mob/living/simple_animal/hostile/megafauna/dragon/Initialize()
// Create and register 'stomachs'
var/datum/belly/megafauna/dragon/maw/maw = new(src)
var/datum/belly/megafauna/dragon/gullet/gullet = new(src)
var/datum/belly/megafauna/dragon/gut/gut = new(src)
for(var/datum/belly/X in list(maw, gullet, gut))
vore_organs[X.name] = X
var/obj/belly/megafauna/dragon/maw/maw = new(src)
var/obj/belly/megafauna/dragon/gullet/gullet = new(src)
var/obj/belly/megafauna/dragon/gut/gut = new(src)
// for(var/obj/belly/X in list(maw, gullet, gut))
// vore_organs[X.name] = X
// Connect 'stomachs' together
maw.transferlocation = gullet
gullet.transferlocation = gut
vore_selected = maw.name // NPC eats into maw
vore_selected = maw // NPC eats into maw
return ..()
/datum/belly/megafauna/dragon
/obj/belly/megafauna/dragon
human_prey_swallow_time = 50 // maybe enough to switch targets if distracted
nonhuman_prey_swallow_time = 50
/datum/belly/megafauna/dragon/maw
/obj/belly/megafauna/dragon/maw
name = "maw"
inside_flavor = "The maw of the dreaded Ash drake closes around you, engulfing you into a swelteringly hot, disgusting enviroment. The acidic saliva tingles over your form while that tongue pushes you further back...towards the dark gullet beyond."
desc = "The maw of the dreaded Ash drake closes around you, engulfing you into a swelteringly hot, disgusting enviroment. The acidic saliva tingles over your form while that tongue pushes you further back...towards the dark gullet beyond."
vore_verb = "scoop"
vore_sound = 'sound/vore/pred/taurswallow.ogg'
swallow_time = 20
@@ -30,9 +31,9 @@
autotransferchance = 66
autotransferwait = 200
/datum/belly/megafauna/dragon/gullet
/obj/belly/megafauna/dragon/gullet
name = "gullet"
inside_flavor = "A ripple of muscle and arching of the tongue pushes you down like any other food. No choice in the matter, you're simply consumed. The dark ambiance of the outside world is replaced with working, wet flesh. Your only light being what you brought with you."
desc = "A ripple of muscle and arching of the tongue pushes you down like any other food. No choice in the matter, you're simply consumed. The dark ambiance of the outside world is replaced with working, wet flesh. Your only light being what you brought with you."
swallow_time = 60 // costs extra time to eat directly to here
escapechance = 5
// From above, will transfer into gut
@@ -40,10 +41,10 @@
autotransferchance = 50
autotransferwait = 200
/datum/belly/megafauna/dragon/gut
/obj/belly/megafauna/dragon/gut
name = "stomach"
vore_capacity = 5 //I doubt this many people will actually last in the gut, but...
inside_flavor = "With a rush of burning ichor greeting you, you're introduced to the Drake's stomach. Wrinkled walls greedily grind against you, acidic slimes working into your body as you become fuel and nutriton for a superior predator. All that's left is your body's willingness to resist your destiny."
desc = "With a rush of burning ichor greeting you, you're introduced to the Drake's stomach. Wrinkled walls greedily grind against you, acidic slimes working into your body as you become fuel and nutriton for a superior predator. All that's left is your body's willingness to resist your destiny."
digest_mode = DM_DRAGON
digest_burn = 5
swallow_time = 100 // costs extra time to eat directly to here
@@ -101,15 +101,19 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca
var/destroy_objects = 0
var/knockdown_people = 0
var/static/mutable_appearance/googly_eyes = mutable_appearance('icons/mob/mob.dmi', "googly_eyes")
var/overlay_googly_eyes = TRUE
var/idledamage = TRUE
gold_core_spawnable = NO_SPAWN
/mob/living/simple_animal/hostile/mimic/copy/Initialize(mapload, obj/copy, mob/living/creator, destroy_original = 0)
/mob/living/simple_animal/hostile/mimic/copy/Initialize(mapload, obj/copy, mob/living/creator, destroy_original = 0, no_googlies = FALSE)
. = ..()
if (no_googlies)
overlay_googly_eyes = FALSE
CopyObject(copy, creator, destroy_original)
/mob/living/simple_animal/hostile/mimic/copy/Life()
..()
if(!target && !ckey) //Objects eventually revert to normal if no one is around to terrorize
if(idledamage && !target && !ckey) //Objects eventually revert to normal if no one is around to terrorize
adjustBruteLoss(1)
for(var/mob/living/M in contents) //a fix for animated statues from the flesh to stone spell
death()
@@ -143,7 +147,8 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca
icon_state = O.icon_state
icon_living = icon_state
copy_overlays(O)
add_overlay(googly_eyes)
if (overlay_googly_eyes)
add_overlay(googly_eyes)
if(isstructure(O) || ismachinery(O))
health = (anchored * 50) + 50
destroy_objects = 1
@@ -103,7 +103,8 @@
stack_trace("Simple animal being instantiated in nullspace")
if(vore_active)
init_belly()
verbs |= /mob/living/proc/animal_nom
if(!IsAdvancedToolUser())
verbs |= /mob/living/simple_animal/proc/animal_nom
/mob/living/simple_animal/Destroy()
GLOB.simple_animals[AIStatus] -= src
@@ -7,18 +7,18 @@
var/vore_default_mode = DM_DIGEST // Default bellymode (DM_DIGEST, DM_HOLD, DM_ABSORB)
var/vore_digest_chance = 25 // Chance to switch to digest mode if resisted
var/vore_escape_chance = 25 // Chance of resisting out of mob
var/vore_absorb_chance = 0 // chance of absorbtion by mob
var/vore_stomach_name // The name for the first belly if not "stomach"
var/vore_stomach_flavor // The flavortext for the first belly if not the default
var/vore_fullness = 0 // How "full" the belly is (controls icons)
var/list/living_mobs = list()
// Release belly contents beforey being gc'd!
/mob/living/simple_animal/Destroy()
for(var/I in vore_organs)
var/datum/belly/B = vore_organs[I]
B.release_all_contents() // When your stomach is empty
release_vore_contents()
prey_excludes.Cut()
. = ..()
@@ -34,10 +34,10 @@
vore_fullness = new_fullness
/*
/mob/living/simple_animal/proc/swallow_check()
for(var/I in vore_organs)
var/datum/belly/B = vore_organs[I]
var/obj/belly/B = vore_organs[I]
if(vore_active)
update_fullness()
if(!vore_fullness)
@@ -48,16 +48,14 @@
/mob/living/simple_animal/proc/swallow_mob()
for(var/I in vore_organs)
var/datum/belly/B = vore_organs[I]
for(var/mob/living/M in B.internal_contents)
B.transfer_contents(M, B.transferlocation)
var/obj/belly/B = vore_organs[I]
for(var/mob/living/M in B.contents)
B.transfer_contents(M, transferlocation)
*/
/mob/living/simple_animal/death()
for(var/I in vore_organs)
var/datum/belly/B = vore_organs[I]
B.release_all_contents() // When your stomach is empty
..() // then you have my permission to die.
release_vore_contents()
. = ..()
// Simple animals have only one belly. This creates it (if it isn't already set up)
/mob/living/simple_animal/proc/init_belly()
@@ -66,18 +64,19 @@
if(no_vore) //If it can't vore, let's not give it a stomach.
return
var/datum/belly/B = new /datum/belly(src)
B.immutable = TRUE
var/obj/belly/B = new /obj/belly(src)
vore_selected = B
B.immutable = 1
B.name = vore_stomach_name ? vore_stomach_name : "stomach"
B.inside_flavor = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]."
B.desc = vore_stomach_flavor ? vore_stomach_flavor : "Your surroundings are warm, soft, and slimy. Makes sense, considering you're inside \the [name]."
B.digest_mode = vore_default_mode
B.escapable = vore_escape_chance > 0
B.escapechance = vore_escape_chance
B.digestchance = vore_digest_chance
B.absorbchance = vore_absorb_chance
B.human_prey_swallow_time = swallowTime
B.nonhuman_prey_swallow_time = swallowTime
B.vore_verb = "swallow"
// TODO - Customizable per mob
B.emote_lists[DM_HOLD] = list( // We need more that aren't repetitive. I suck at endo. -Ace
"The insides knead at you gently for a moment.",
"The guts glorp wetly around you as some air shifts.",
@@ -98,5 +97,21 @@
"The juices pooling beneath you sizzle against your sore skin.",
"The churning walls slowly pulverize you into meaty nutrients.",
"The stomach glorps and gurgles as it tries to work you into slop.")
src.vore_organs[B.name] = B
src.vore_selected = B.name
/* B.emote_lists[DM_ITEMWEAK] = list(
"The burning acids eat away at your form.",
"The muscular stomach flesh grinds harshly against you.",
"The caustic air stings your chest when you try to breathe.",
"The slimy guts squeeze inward to help the digestive juices soften you up.",
"The onslaught against your body doesn't seem to be letting up; you're food now.",
"The predator's body ripples and crushes against you as digestive enzymes pull you apart.",
"The juices pooling beneath you sizzle against your sore skin.",
"The churning walls slowly pulverize you into meaty nutrients.",
"The stomach glorps and gurgles as it tries to work you into slop.")*/
//Grab = Nomf
/*
/mob/living/simple_animal/UnarmedAttack(var/atom/A, var/proximity)
. = ..()
if(a_intent == I_GRAB && isliving(A) && !has_hands)
animal_nom(A)*/
+1 -1
View File
@@ -98,7 +98,7 @@ proc/get_top_level_mob(var/mob/S)
return FALSE
user.log_message(message, INDIVIDUAL_EMOTE_LOG)
message = "<b>[user]</b> " + message
message = "<b>[user]</b> " + "<i>[message]</i>"
for(var/mob/M in GLOB.dead_mob_list)
if(!M.client || isnewplayer(M))
+1 -3
View File
@@ -25,7 +25,7 @@
/obj/machinery/power/tesla_coil/Initialize()
. = ..()
wires = new /datum/wires/tesla_coil(src)
// wires = new /datum/wires/tesla_coil(src) //CITADEL EDIT, Kevinz you cheaty fuccboi.
linked_techweb = SSresearch.science_tech
/obj/machinery/power/tesla_coil/RefreshParts()
@@ -79,8 +79,6 @@
/obj/machinery/power/tesla_coil/tesla_act(var/power)
if(anchored && !panel_open)
obj_flags |= BEING_SHOCKED
//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)
+2 -2
View File
@@ -129,7 +129,7 @@
display_name = "Basic Bluespace Theory"
description = "Basic studies into the mysterious alternate dimension known as bluespace."
prereq_ids = list("base")
design_ids = list("beacon", "xenobioconsole")
design_ids = list("beacon") //CIT CHANGE removed xenobioconsole from here.
research_cost = 2500
export_price = 5000
@@ -148,7 +148,7 @@
display_name = "Applied Bluespace Research"
description = "Using bluespace to make things faster and better."
prereq_ids = list("bluespace_basic", "engineering")
design_ids = list("bs_rped","minerbag_holding", "telesci_gps", "bluespacebeaker", "bluespacesyringe", "bluespacebodybag", "phasic_scanning", "roastingstick")
design_ids = list("bs_rped","minerbag_holding", "telesci_gps", "bluespacebeaker", "bluespacesyringe", "bluespacebodybag", "phasic_scanning", "roastingstick", "xenobioconsole") //CIT CHANGE added xenobioconsole here
research_cost = 5000
export_price = 5000
+2 -1
View File
@@ -1,7 +1,8 @@
//include unit test files in this module in this ifdef
// CITADEL EDIT add vore_tests.dm
#ifdef UNIT_TESTS
#include "unit_test.dm"
#include "reagent_recipe_collisions.dm"
#include "reagent_id_typos.dm"
//#include "vore_tests.dm"
#endif
+218
View File
@@ -0,0 +1,218 @@
/datum/unit_test
var/static/default_mobloc = null
/datum/unit_test/proc/create_test_mob(var/turf/mobloc = null, var/mobtype = /mob/living/carbon/human, var/with_mind = FALSE)
if(isnull(mobloc))
if(!default_mobloc)
for(var/turf/simulated/floor/tiled/T in world)
var/pressure = T.zone.air.return_pressure()
if(90 < pressure && pressure < 120) // Find a turf between 90 and 120
default_mobloc = T
break
mobloc = default_mobloc
if(!mobloc)
Fail("Unable to find a location to create test mob")
return FALSE
var/mob/living/carbon/human/H = new mobtype(mobloc)
if(with_mind)
H.mind_initialize("TestKey[rand(0,10000)]")
return H
/datum/unit_test/space_suffocation
name = "MOB: human mob suffocates in space"
var/startOxyloss
var/endOxyloss
var/mob/living/carbon/human/H
async = 1
/datum/unit_test/space_suffocation/Run()
var/turf/open/space/T = locate()
H = new(T)
startOxyloss = H.getOxyLoss()
return 1
/datum/unit_test/space_suffocation/check_result()
if(H.life_tick < 10)
return 0
endOxyloss = H.getOxyLoss()
if(!startOxyloss < endOxyloss)
Fail("Human mob is not taking oxygen damage in space. (Before: [startOxyloss]; after: [endOxyloss])")
qdel(H)
return 1
/datum/unit_test/belly_nonsuffocation
name = "MOB: human mob does not suffocate in a belly"
var/startLifeTick
var/startOxyloss
var/endOxyloss
var/mob/living/carbon/human/pred
var/mob/living/carbon/human/prey
/datum/unit_test/belly_nonsuffocation/Run()
pred = create_test_mob()
if(!istype(pred))
return FALSE
prey = create_test_mob(pred.loc)
if(!istype(prey))
return FALSE
return TRUE
/datum/unit_test/belly_nonsuffocation/check_result()
// Unfortuantely we need to wait for the pred's belly to initialize. (Currently after a spawn())
if(!pred.vore_organs || !pred.vore_organs.len)
return FALSE
// Now that pred belly exists, we can eat the prey.
if(!pred.vore_selected)
Fail("[pred] has no vore_selected.")
return TRUE
// Attempt to eat the prey
if(prey.loc != pred.vore_selected)
pred.vore_selected.nom_mob(prey)
if(prey.loc != pred.vore_selected)
Fail("[pred.vore_selected].nom_mob([prey]) did not put prey inside [pred]")
return TRUE
// Okay, we succeeded in eating them, now lets wait a bit
startLifeTick = pred.life_tick
startOxyloss = prey.getOxyLoss()
return FALSE
if(pred.life_tick < (startLifeTick + 10))
return FALSE // Wait for them to breathe a few times
// Alright lets check it!
endOxyloss = prey.getOxyLoss()
if(startOxyloss < endOxyloss)
Fail("Prey takes oxygen damage in a pred's belly! (Before: [startOxyloss]; after: [endOxyloss])")
qdel(prey)
qdel(pred)
return TRUE
////////////////////////////////////////////////////////////////
/datum/unit_test/belly_spacesafe
name = "MOB: human mob protected from space in a belly"
var/startLifeTick
var/startOxyloss
var/startBruteloss
var/endOxyloss
var/endBruteloss
var/mob/living/carbon/human/pred
var/mob/living/carbon/human/prey
/datum/unit_test/belly_spacesafe/Run()
pred = create_test_mob()
if(!istype(pred))
return FALSE
prey = create_test_mob(pred.loc)
if(!istype(prey))
return FALSE
return TRUE
/datum/unit_test/belly_spacesafe/check_result()
// Unfortuantely we need to wait for the pred's belly to initialize. (Currently after a spawn())
if(!pred.vore_organs || !pred.vore_organs.len)
return FALSE
// Now that pred belly exists, we can eat the prey.
if(!pred.vore_selected)
Fail("[pred] has no vore_selected.")
return TRUE
// Attempt to eat the prey
if(prey.loc != pred.vore_selected)
pred.vore_selected.nom_mob(prey)
if(prey.loc != pred.vore_selected)
Fail("[pred.vore_selected].nom_mob([prey]) did not put prey inside [pred]")
return TRUE
else
var/turf/T = locate(/turf/open/space)
if(!T)
Fail("could not find a space turf for testing")
return TRUE
else
pred.forceMove(T)
// Okay, we succeeded in eating them, now lets wait a bit
startLifeTick = pred.life_tick
startOxyloss = prey.getOxyLoss()
startBruteloss = prey.getBruteloss()
return FALSE
if(pred.life_tick < (startLifeTick + 10))
return FALSE // Wait for them to breathe a few times
// Alright lets check it!
endOxyloss = prey.getOxyLoss()
endBruteloss = prey.getBruteLoss()
if(startBruteloss < endBruteloss)
Fail("Prey takes brute damage in space! (Before: [startBruteloss]; after: [endBruteloss])")
qdel(prey)
qdel(pred)
return TRUE
////////////////////////////////////////////////////////////////
/datum/unit_test/belly_damage
name = "MOB: human mob takes damage from digestion"
var/startLifeTick
var/startBruteBurn
var/endBruteBurn
var/mob/living/carbon/human/pred
var/mob/living/carbon/human/prey
/datum/unit_test/belly_damage/Run()
pred = create_test_mob()
if(!istype(pred))
return FALSE
prey = create_test_mob(pred.loc)
if(!istype(prey))
return FALSE
return TRUE
/datum/unit_test/belly_damage/check_result()
// Unfortuantely we need to wait for the pred's belly to initialize. (Currently after a spawn())
if(!pred.vore_organs || !pred.vore_organs.len)
return FALSE
// Now that pred belly exists, we can eat the prey.
if(!pred.vore_selected)
Fail("[pred] has no vore_selected.")
return TRUE
// Attempt to eat the prey
if(prey.loc != pred.vore_selected)
pred.vore_selected.nom_mob(prey)
if(prey.loc != pred.vore_selected)
Fail("[pred.vore_selected].nom_mob([prey]) did not put prey inside [pred]")
return TRUE
// Okay, we succeeded in eating them, now lets wait a bit
pred.vore_selected.digest_mode = DM_DIGEST
startLifeTick = pred.life_tick
startBruteBurn = prey.getBruteLoss() + prey.getFireLoss()
return FALSE
if(pred.life_tick < (startLifeTick + 10))
return FALSE // Wait a few ticks for damage to happen
// Alright lets check it!
endBruteBurn = prey.getBruteLoss() + prey.getFireLoss()
if(startBruteBurn >= endBruteBurn)
Fail("Prey doesn't take damage in digesting belly! (Before: [startBruteBurn]; after: [endBruteBurn])")
qdel(prey)
qdel(pred)
return TRUE
-467
View File
@@ -1,467 +0,0 @@
//
// The belly object is what holds onto a mob while they're inside a predator.
// It takes care of altering the pred's decription, digesting the prey, relaying struggles etc.
//
// If you change what variables are on this, then you need to update the copy() proc.
//
// Parent type of all the various "belly" varieties.
//
/datum/belly
var/name // Name of this location
var/inside_flavor // Flavor text description of inside sight/sound/smells/feels.
var/vore_sound = 'sound/vore/pred/swallow_01.ogg' // Sound when ingesting someone
var/vore_verb = "ingest" // Verb for eating with this in messages
var/human_prey_swallow_time = 10 SECONDS // Time in deciseconds to swallow /mob/living/carbon/human
var/nonhuman_prey_swallow_time = 5 SECONDS // Time in deciseconds to swallow anything else
var/emoteTime = 30 SECONDS // How long between stomach emotes at prey
var/digest_brute = 0 // Brute damage per tick in digestion mode
var/digest_burn = 1 // Burn damage per tick in digestion mode
var/digest_tickrate = 9 // Modulus this of air controller tick number to iterate gurgles on
var/immutable = FALSE // Prevents this belly from being deleted
var/escapable = FALSE // Belly can be resisted out of at any time
var/escapetime = 60 SECONDS // Deciseconds, how long to escape this belly
var/digestchance = 0 // % Chance of stomach beginning to digest if prey struggles
// var/silenced = FALSE // Will the heartbeat/fleshy internal loop play?
var/escapechance = 0 // % Chance of prey beginning to escape if prey struggles.
var/datum/belly/transferlocation = null // Location that the prey is released if they struggle and get dropped off.
var/transferchance = 0 // % Chance of prey being transferred to transfer location when resisting
var/autotransferchance = 0 // % Chance of prey being autotransferred to transfer location
var/autotransferwait = 10 // Time between trying to transfer.
var/can_taste = FALSE // If this belly prints the flavor of prey when it eats someone.
var/tmp/digest_mode = DM_HOLD // Whether or not to digest. Default to not digest.
var/tmp/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_HEAL,DM_NOISY) // Possible digest modes
var/tmp/mob/living/owner // The mob whose belly this is.
var/tmp/list/internal_contents = list() // People/Things you've eaten into this belly!
var/tmp/is_full // Flag for if digested remeans are present. (for disposal messages)
var/tmp/emotePend = FALSE // If there's already a spawned thing counting for the next emote
var/swallow_time = 10 SECONDS // for mob transfering automation
var/vore_capacity = 1 // The capacity (in people) this person can hold
// Don't forget to watch your commas at the end of each line if you change these.
var/list/struggle_messages_outside = list(
"%pred's %belly wobbles with a squirming meal.",
"%pred's %belly jostles with movement.",
"%pred's %belly briefly swells outward as someone pushes from inside.",
"%pred's %belly fidgets with a trapped victim.",
"%pred's %belly jiggles with motion from inside.",
"%pred's %belly sloshes around.",
"%pred's %belly gushes softly.",
"%pred's %belly lets out a wet squelch.")
var/list/struggle_messages_inside = list(
"Your useless squirming only causes %pred's slimy %belly to squelch over your body.",
"Your struggles only cause %pred's %belly to gush softly around you.",
"Your movement only causes %pred's %belly to slosh around you.",
"Your motion causes %pred's %belly to jiggle.",
"You fidget around inside of %pred's %belly.",
"You shove against the walls of %pred's %belly, making it briefly swell outward.",
"You jostle %pred's %belly with movement.",
"You squirm inside of %pred's %belly, making it wobble around.")
var/list/digest_messages_owner = list(
"You feel %prey's body succumb to your digestive system, which breaks it apart into soft slurry.",
"You hear a lewd glorp as your %belly muscles grind %prey into a warm pulp.",
"Your %belly lets out a rumble as it melts %prey into sludge.",
"You feel a soft gurgle as %prey's body loses form in your %belly. They're nothing but a soft mass of churning slop now.",
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your thighs.",
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your rump.",
"Your %belly begins gushing %prey's remains through your system, adding some extra weight to your belly.",
"Your %belly groans as %prey falls apart into a thick soup. You can feel their remains soon flowing deeper into your body to be absorbed.",
"Your %belly kneads on every fiber of %prey, softening them down into mush to fuel your next hunt.",
"Your %belly churns %prey down into a hot slush. You can feel the nutrients coursing through your digestive track with a series of long, wet glorps.")
var/list/digest_messages_prey = list(
"Your body succumbs to %pred's digestive system, which breaks you apart into soft slurry.",
"%pred's %belly lets out a lewd glorp as their muscles grind you into a warm pulp.",
"%pred's %belly lets out a rumble as it melts you into sludge.",
"%pred feels a soft gurgle as your body loses form in their %belly. You're nothing but a soft mass of churning slop now.",
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's thighs.",
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's rump.",
"%pred's %belly begins gushing your remains through their system, adding some extra weight to %pred's belly.",
"%pred's %belly groans as you fall apart into a thick soup. Your remains soon flow deeper into %pred's body to be absorbed.",
"%pred's %belly kneads on every fiber of your body, softening you down into mush to fuel their next hunt.",
"%pred's %belly churns you down into a hot slush. Your nutrient-rich remains course through their digestive track with a series of long, wet glorps.")
var/list/examine_messages = list(
"They have something solid in their %belly!",
"It looks like they have something in their %belly!")
//Mostly for being overridden on precreated bellies on mobs. Could be VV'd into
//a carbon's belly if someone really wanted. No UI for carbons to adjust this.
//List has indexes that are the digestion mode strings, and keys that are lists of strings.
var/list/emote_lists = list()
// Constructor that sets the owning mob
/datum/belly/New(var/mob/living/owning_mob)
owner = owning_mob
// Toggle digestion on/off and notify user of the new setting.
// If multiple digestion modes are avaliable (i.e. unbirth) then user should be prompted.
/datum/belly/proc/toggle_digestion()
return
// Checks if any mobs are present inside the belly
// return True if the belly is empty.
/datum/belly/proc/is_empty()
return internal_contents.len == 0
// Release all contents of this belly into the owning mob's location.
// If that location is another mob, contents are transferred into whichever of its bellies the owning mob is in.
// Returns the number of mobs so released.
/datum/belly/proc/release_all_contents()
if (internal_contents.len == 0)
return 0
for (var/atom/movable/M in internal_contents)
M.forceMove(owner.loc) // Move the belly contents into the same location as belly's owner.
for(var/mob/living/W in M)
W.stop_sound_channel(CHANNEL_PREYLOOP)
internal_contents.Remove(M) // Remove from the belly contents
var/datum/belly/B = check_belly(owner) // This makes sure that the mob behaves properly if released into another mob
if(B)
B.internal_contents.Add(M)
owner.visible_message("<font color='green'><b>[owner] expels everything from their [lowertext(name)]!</b></font>")
return TRUE
// Release a specific atom from the contents of this belly into the owning mob's location.
// If that location is another mob, the atom is transferred into whichever of its bellies the owning mob is in.
// Returns the number of atoms so released.
/datum/belly/proc/release_specific_contents(var/atom/movable/M)
if (!(M in internal_contents))
return FALSE // They weren't in this belly anyway
M.forceMove(owner.loc) // Move the belly contents into the same location as belly's owner.
for(var/mob/living/W in M)
W.stop_sound_channel(CHANNEL_PREYLOOP)
src.internal_contents.Remove(M) // Remove from the belly contents
var/datum/belly/B = check_belly(owner)
if(B)
B.internal_contents.Add(M)
owner.visible_message("<font color='green'><b>[owner] expels [M] from their [lowertext(name)]!</b></font>")
// owner.regenerate_icons()
return TRUE
// Actually perform the mechanics of devouring the tasty prey.
// The purpose of this method is to avoid duplicate code, and ensure that all necessary
// steps are taken.
/datum/belly/proc/nom_mob(var/mob/prey, var/mob/user)
var/sound/preyloop = sound('sound/vore/prey/loop.ogg', repeat = TRUE)
prey.forceMove(owner)
internal_contents.Add(prey)
prey.playsound_local(get_turf(prey),preyloop,40,0, channel = CHANNEL_PREYLOOP)
// Handle prey messages
if(inside_flavor)
to_chat(prey, "<span class='warning'><B>[src.inside_flavor]</B></span>")
if(isliving(prey))
var/mob/living/M = prey
if(can_taste && M.get_taste_message(0))
to_chat(owner, "<span class='notice'>[M] tastes of [M.get_taste_message(0)].</span>")
// Setup the autotransfer checks if needed
if(transferlocation && autotransferchance > 0)
addtimer(CALLBACK(src, /datum/belly/.proc/check_autotransfer, prey), autotransferwait)
/datum/belly/proc/check_autotransfer(var/mob/prey)
// Some sanity checks
if(transferlocation && (autotransferchance > 0) && (prey in internal_contents))
if(prob(autotransferchance))
// Double check transferlocation isn't insane
if(verify_transferlocation())
transfer_contents(prey, transferlocation)
else
// Didn't transfer, so wait before retrying
addtimer(CALLBACK(src, /datum/belly/.proc/check_autotransfer, prey), autotransferwait)
/datum/belly/proc/verify_transferlocation()
for(var/I in owner.vore_organs)
var/datum/belly/B = owner.vore_organs[I]
if(B == transferlocation)
return TRUE
for(var/I in owner.vore_organs)
var/datum/belly/B = owner.vore_organs[I]
if(B.name == transferlocation.name)
transferlocation = B
return TRUE
return FALSE
// Get the line that should show up in Examine message if the owner of this belly
// is examined. By making this a proc, we not only take advantage of polymorphism,
// but can easily make the message vary based on how many people are inside, etc.
// Returns a string which shoul be appended to the Examine output.
/datum/belly/proc/get_examine_msg()
if(internal_contents.len && examine_messages.len)
var/formatted_message
var/raw_message = pick(examine_messages)
formatted_message = replacetext(raw_message,"%belly",lowertext(name))
formatted_message = replacetext(formatted_message,"%pred",owner)
formatted_message = replacetext(formatted_message,"%prey",english_list(internal_contents))
return("<span class='warning'>[formatted_message]</span><BR>")
// The next function gets the messages set on the belly, in human-readable format.
// This is useful in customization boxes and such. The delimiter right now is \n\n so
// in message boxes, this looks nice and is easily delimited.
/datum/belly/proc/get_messages(var/type, var/delim = "\n\n")
ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
var/list/raw_messages
switch(type)
if("smo")
raw_messages = struggle_messages_outside
if("smi")
raw_messages = struggle_messages_inside
if("dmo")
raw_messages = digest_messages_owner
if("dmp")
raw_messages = digest_messages_prey
if("em")
raw_messages = examine_messages
var/messages = list2text(raw_messages,delim)
return messages
// The next function sets the messages on the belly, from human-readable var
// replacement strings and linebreaks as delimiters (two \n\n by default).
// They also sanitize the messages.
/datum/belly/proc/set_messages(var/raw_text, var/type, var/delim = "\n\n")
ASSERT(type == "smo" || type == "smi" || type == "dmo" || type == "dmp" || type == "em")
var/list/raw_list = text2list(html_encode(raw_text),delim)
if(raw_list.len > 10)
raw_list.Cut(11)
for(var/i = 1, i <= raw_list.len, i++)
if(length(raw_list[i]) > 160 || length(raw_list[i]) < 10) //160 is fudged value due to htmlencoding increasing the size
raw_list.Cut(i,i)
else
raw_list[i] = readd_quotes(raw_list[i])
//Also fix % sign for var replacement
raw_list[i] = replacetext(raw_list[i],"&#37;","%")
ASSERT(raw_list.len <= 10) //Sanity
switch(type)
if("smo")
struggle_messages_outside = raw_list
if("smi")
struggle_messages_inside = raw_list
if("dmo")
digest_messages_owner = raw_list
if("dmp")
digest_messages_prey = raw_list
if("em")
examine_messages = raw_list
return
// Handle the death of a mob via digestion.
// Called from the process_Life() methods of bellies that digest prey.
// Default implementation calls M.death() and removes from internal contents.
// Indigestable items are removed, and M is deleted.
/datum/belly/proc/digestion_death(var/mob/living/M)
is_full = TRUE
internal_contents.Remove(M)
M.stop_sound_channel(CHANNEL_PREYLOOP)
// If digested prey is also a pred... anyone inside their bellies gets moved up.
if(is_vore_predator(M))
for(var/bellytype in M.vore_organs)
var/datum/belly/belly = M.vore_organs[bellytype]
for (var/obj/thing in belly.internal_contents)
thing.loc = owner
internal_contents.Add(thing)
for (var/mob/subprey in belly.internal_contents)
subprey.loc = owner
internal_contents.Add(subprey)
to_chat(subprey, "As [M] melts away around you, you find yourself in [owner]'s [name]")
//Drop all items into the belly
for(var/obj/item/W in M)
if(!M.dropItemToGround(W))
qdel(W)
message_admins("[key_name(owner)] digested [key_name(M)].")
log_attack("[key_name(owner)] digested [key_name(M)].")
// Delete the digested mob
qdel(M)
//Handle a mob struggling
// Called from /mob/living/carbon/relaymove()
/datum/belly/proc/relay_resist(var/mob/living/R)
if (!(R in internal_contents))
return // User is not in this belly, or struggle too soon.
R.setClickCooldown(50)
var/sound/prey_struggle = sound(get_sfx("prey_struggle"))
if(owner.stat) //If owner is stat (dead, KO) we can actually escape
to_chat(R, "<span class='warning'>You attempt to climb out of \the [name]. (This will take around [escapetime/10] seconds.)</span>")
to_chat(owner, "<span class='warning'>Someone is attempting to climb out of your [name]!</span>")
if(do_after(R, escapetime, owner))
if((owner.stat || escapable) && (R in internal_contents)) //Can still escape?
release_specific_contents(R)
return
else if(!(R in internal_contents)) //Aren't even in the belly. Quietly fail.
return
else //Belly became inescapable or mob revived
to_chat(R, "<span class='warning'>Your attempt to escape [name] has failed!</span>")
to_chat(owner, "<span class='notice'>The attempt to escape from your [name] has failed!</span>")
return
return
var/struggle_outer_message = pick(struggle_messages_outside)
var/struggle_user_message = pick(struggle_messages_inside)
struggle_outer_message = replacetext(struggle_outer_message,"%pred",owner)
struggle_outer_message = replacetext(struggle_outer_message,"%prey",R)
struggle_outer_message = replacetext(struggle_outer_message,"%belly",lowertext(name))
struggle_user_message = replacetext(struggle_user_message,"%pred",owner)
struggle_user_message = replacetext(struggle_user_message,"%prey",R)
struggle_user_message = replacetext(struggle_user_message,"%belly",lowertext(name))
struggle_outer_message = "<span class='alert'>" + struggle_outer_message + "</span>"
struggle_user_message = "<span class='alert'>" + struggle_user_message + "</span>"
R.visible_message( "<span class='alert'>[struggle_outer_message]</span>", "<span class='alert'>[struggle_user_message]</span>")
playsound(get_turf(owner),"struggle_sound",35,0,-6,1,channel=151,ignore_walls = FALSE)
R.stop_sound_channel(151)
R.playsound_local(get_turf(R),prey_struggle,45,0)
if(escapable && R.a_intent != "help") //If the stomach has escapable enabled and the person is actually trying to kick out
to_chat(R, "<span class='warning'>You attempt to climb out of \the [name].</span>")
to_chat(owner, "<span class='warning'>Someone is attempting to climb out of your [name]!</span>")
if(prob(escapechance)) //Let's have it check to see if the prey escapes first.
if(do_after(R, escapetime))
if((escapable) && (R in internal_contents)) //Does the owner still have escapable enabled?
release_specific_contents(R)
to_chat(R, "<span class='warning'>You climb out of \the [name].</span>")
to_chat(owner, "<span class='warning'>[R] climbs out of your [name]!</span>")
for(var/mob/M in viewers(4, owner))
M.visible_message("<span class='warning'>[R] climbs out of [owner]'s [name]!</span>", 2)
return
else if(!(R in internal_contents)) //Aren't even in the belly. Quietly fail.
return
else //Belly became inescapable.
to_chat(R, "<span class='warning'>Your attempt to escape [name] has failed!</span>")
to_chat(owner, "<span class='notice'>The attempt to escape from your [name] has failed!/span>")
return
else if(prob(transferchance) && istype(transferlocation)) //Next, let's have it see if they end up getting into an even bigger mess then when they started.
var/location_ok = verify_transferlocation()
if(!location_ok)
to_chat(owner, "<span class='warning'>Something went wrong with your belly transfer settings.</span>")
transferlocation = null
return
to_chat(R, "<span class='warning'>Your attempt to escape [name] has failed and your struggles only results in you sliding into [owner]'s [transferlocation]!</span>")
to_chat(owner, "<span class='warning'>Someone slid into your [transferlocation] due to their struggling inside your [name]!</span>")
transfer_contents(R, transferlocation)
return
else if(prob(digestchance)) //Finally, let's see if it should run the digest chance.)
to_chat(R, "<span class='warning'>In response to your struggling, \the [name] begins to get more active...</span>")
to_chat(owner, "<span class='warning'>You feel your [name] beginning to become active!</span>")
digest_mode = DM_DIGEST
return
else //Nothing interesting happened.
to_chat(R, "<span class='warning'>But make no progress in escaping [owner]'s [name].</span>")
to_chat(owner, "<span class='warning'>But appears to be unable to make any progress in escaping your [name].</span>")
return
//Transfers contents from one belly to another
/datum/belly/proc/transfer_contents(var/atom/movable/content, var/datum/belly/target, silent = 0)
if(!(content in internal_contents))
return
internal_contents.Remove(content)
// Re-use nom_mob
target.nom_mob(content, target.owner)
if(!silent)
playsound(get_turf(owner),"[target].vore_sound",35,0,-6,1,ignore_walls = FALSE)
/*
//Handles creation of temporary 'vore chest' upon digestion
/datum/belly/proc/slimy_mass(var/obj/item/content, var/mob/living/M)
if(!content in internal_contents)
return
internal_contents += new /obj/structure/closet/crate/vore(src)
internal_contents.Remove(content)
M.transferItemToLoc(content, /obj/structure/closet/crate/vore)
if(!M.transferItemToLoc(W))
qdel(W)
/datum/belly/proc/regurgitate_items(var/obj/structure/closet/crate/vore/C)
*/
// Belly copies and then returns the copy
// Needs to be updated for any var changes
/datum/belly/proc/copy(mob/new_owner)
var/datum/belly/dupe = new /datum/belly(new_owner)
//// Non-object variables
dupe.name = name
dupe.inside_flavor = inside_flavor
dupe.vore_sound = vore_sound
dupe.vore_verb = vore_verb
dupe.human_prey_swallow_time = human_prey_swallow_time
dupe.nonhuman_prey_swallow_time = nonhuman_prey_swallow_time
dupe.emoteTime = emoteTime
dupe.digest_brute = digest_brute
dupe.digest_burn = digest_burn
dupe.digest_tickrate = digest_tickrate
dupe.immutable = immutable
dupe.can_taste = can_taste
dupe.escapable = escapable
dupe.escapetime = escapetime
dupe.digestchance = digestchance
dupe.escapechance = escapechance
dupe.transferchance = transferchance
dupe.transferlocation = transferlocation
dupe.autotransferchance = autotransferchance
dupe.autotransferwait = autotransferwait
//// Object-holding variables
//struggle_messages_outside - strings
dupe.struggle_messages_outside.Cut()
for(var/I in struggle_messages_outside)
dupe.struggle_messages_outside += I
//struggle_messages_inside - strings
dupe.struggle_messages_inside.Cut()
for(var/I in struggle_messages_inside)
dupe.struggle_messages_inside += I
//digest_messages_owner - strings
dupe.digest_messages_owner.Cut()
for(var/I in digest_messages_owner)
dupe.digest_messages_owner += I
//digest_messages_prey - strings
dupe.digest_messages_prey.Cut()
for(var/I in digest_messages_prey)
dupe.digest_messages_prey += I
//examine_messages - strings
dupe.examine_messages.Cut()
for(var/I in examine_messages)
dupe.examine_messages += I
//emote_lists - index: digest mode, key: list of strings
dupe.emote_lists.Cut()
for(var/K in emote_lists)
dupe.emote_lists[K] = list()
for(var/I in emote_lists[K])
dupe.emote_lists[K] += I
return dupe
-143
View File
@@ -1,143 +0,0 @@
// Process the predator's effects upon the contents of its belly (i.e digestion/transformation etc)
// Called from /mob/living/Life() proc.
/datum/belly/proc/process_Life()
var/sound/prey_gurgle = sound(get_sfx("digest_prey"))
var/sound/prey_digest = sound(get_sfx("death_prey"))
/////////////////////////// Auto-Emotes ///////////////////////////
if((digest_mode in emote_lists) && !emotePend)
emotePend = TRUE
spawn(emoteTime)
var/list/EL = emote_lists[digest_mode]
for(var/mob/living/M in internal_contents)
M << "<span class='notice'>[pick(EL)]</span>"
src.emotePend = FALSE
///////////////////////////// DM_HOLD /////////////////////////////
if(digest_mode == DM_HOLD)
return //Pretty boring, huh
//////////////////////////// DM_DIGEST ////////////////////////////
if(digest_mode == DM_DIGEST)
for (var/mob/living/M in internal_contents)
if(prob(25))
M.stop_sound_channel(CHANNEL_PRED)
playsound(get_turf(owner),"digest_pred",50,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
M.stop_sound_channel(CHANNEL_PRED)
M.playsound_local(get_turf(M), null, 45, S = prey_gurgle)
//Pref protection!
if (!M.digestable)
continue
//Person just died in guts!
if(M.stat == DEAD)
var/digest_alert_owner = pick(digest_messages_owner)
var/digest_alert_prey = pick(digest_messages_prey)
//Replace placeholder vars
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
//Send messages
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
M.visible_message("<span class='notice'>You watch as [owner]'s form loses its additions.</span>")
owner.nutrition += 400 // so eating dead mobs gives you *something*.
M.stop_sound_channel(CHANNEL_PRED)
playsound(get_turf(owner),"death_pred",45,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
M.stop_sound_channel(CHANNEL_PRED)
M.playsound_local(get_turf(M), null, 45, S = prey_digest)
digestion_death(M)
owner.update_icons()
continue
// Deal digestion damage (and feed the pred)
if(!(M.status_flags & GODMODE))
M.adjustFireLoss(digest_burn)
owner.nutrition += 1
return
///////////////////////////// DM_HEAL /////////////////////////////
if(digest_mode == DM_HEAL)
for (var/mob/living/M in internal_contents)
if(prob(25))
M.stop_sound_channel(CHANNEL_PRED)
playsound(get_turf(owner),"digest_pred",35,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
M.stop_sound_channel(CHANNEL_PRED)
M.playsound_local(get_turf(M), null, 45, S = prey_gurgle)
if(M.stat != DEAD)
if(owner.nutrition >= NUTRITION_LEVEL_STARVING && (M.health < M.maxHealth))
M.adjustBruteLoss(-1)
M.adjustFireLoss(-1)
owner.nutrition -= 10
return
////////////////////////// DM_NOISY /////////////////////////////////
//for when you just want people to squelch around
if(digest_mode == DM_NOISY)
for (var/mob/living/M in internal_contents)
if(prob(35))
M.stop_sound_channel(CHANNEL_PRED)
playsound(get_turf(owner),"digest_pred",35,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
M.stop_sound_channel(CHANNEL_PRED)
M.playsound_local(get_turf(M), null, 45, S = prey_gurgle)
//////////////////////////DM_DRAGON /////////////////////////////////////
//because dragons need snowflake guts
if(digest_mode == DM_DRAGON)
for (var/mob/living/M in internal_contents)
if(prob(25))
M.stop_sound_channel(CHANNEL_PRED)
playsound(get_turf(owner),"digest_pred",50,0,-6,0,channel=CHANNEL_PRED,ignore_walls = FALSE)
M.stop_sound_channel(CHANNEL_PRED)
M.playsound_local(get_turf(M), null, 45, S = prey_gurgle)
//No digestion protection for megafauna.
//Person just died in guts!
if(M.stat == DEAD)
var/digest_alert_owner = pick(digest_messages_owner)
var/digest_alert_prey = pick(digest_messages_prey)
//Replace placeholder vars
digest_alert_owner = replacetext(digest_alert_owner,"%pred",owner)
digest_alert_owner = replacetext(digest_alert_owner,"%prey",M)
digest_alert_owner = replacetext(digest_alert_owner,"%belly",lowertext(name))
digest_alert_prey = replacetext(digest_alert_prey,"%pred",owner)
digest_alert_prey = replacetext(digest_alert_prey,"%prey",M)
digest_alert_prey = replacetext(digest_alert_prey,"%belly",lowertext(name))
//Send messages
to_chat(owner, "<span class='warning'>[digest_alert_owner]</span>")
to_chat(M, "<span class='warning'>[digest_alert_prey]</span>")
M.visible_message("<span class='notice'>You watch as [owner]'s guts loudly rumble as it finishes off a meal.</span>")
M.stop_sound_channel(CHANNEL_PRED)
playsound(get_turf(owner),"death_pred",45,0,-6,0,channel=CHANNEL_PRED)
M.stop_sound_channel(CHANNEL_PRED)
M.playsound_local(get_turf(M), null, 45, S = prey_digest)
M.spill_organs(FALSE,TRUE,TRUE)
M << sound(null, repeat = 0, wait = 0, volume = 80, channel = CHANNEL_PREYLOOP)
digestion_death(M)
owner.update_icons()
continue
// Deal digestion damage (and feed the pred)
if(!(M.status_flags & GODMODE))
M.adjustFireLoss(digest_burn)
M.adjustToxLoss(4) // something something plasma based acids
M.adjustCloneLoss(3) // eventually this'll kill you if you're healing everything else, you nerds.
return
@@ -0,0 +1,6 @@
author: "Poojawa"
delete-after: True
changes:
- rscadd: "Hypospray mk IIs are being deployed to stations, these should provide an easier time for medical staff! They come with both inject and spray modes! Spray mode acts like a patch for applying meds"
- soundadd: "Hyposprays are fancy, you'll know when they're being used."
- server: "Due to fucky-ness, you'll need to unload, then reload the hypos at least once. just how it be."
@@ -0,0 +1,6 @@
author: "Poojawa"
delete-after: True
changes:
- rscadd: "Tesla Engines are now standard on all but Omega."
- bugfix: "fixed a pipe in Meta station that wasn't connected properly."
- bugfix: "fixed an exploit related to Tesla wires."
+12
View File
@@ -0,0 +1,12 @@
author: "Poojawa"
delete-after: True
changes:
- rscadd: "Added release sound effects for choosing. If having a non-belly, belly."
- rscadd: "Added a 'silent' modifier to bellies."
- rscadd: "Added a vore subsystem to handle belly processing, should be less clunky"
- balance: "rebalanced heal mode and dragon digestion."
- soundadd: "added client preference based sound toggles to both eating/release/struggle and digestion noises seperately."
- refactor: "vore prefs save to JSON now instead of .sav. much easier really.
refractor: dragon vore is working, though with this game who knows."
- server: "your prefs should automatically transfer, but it's likely you'll lose pre-loaded bellies, BACK UP EVERYTHING. (you should be doing this anyway too)"
- server: "Creating new characters will import the previous' bellies. but once you click 'save' they'll make the new JSON file will all the info. This is per slot, so if you change your character, you'll have to change belly stuff."
@@ -0,0 +1,6 @@
author: "Denton"
delete-after: True
changes:
- bugfix: "Pubbystation: Added a missing APC to the cargo sorting room, a light fixture to the RnD security checkpoint and removed an overlooked firelock east of the bridge."
- rscadd: "Pubbystation: Added a spare RPD to the Atmospherics department. Replaced Engineering's outdated meson goggles with modern engineering scanners. Added a GPS device to the secure storage crate."
- tweak: "Moved Pubbystation's drone shell dispenser from the experimentation lab to Robotics maint."
@@ -0,0 +1,4 @@
author: "Jittai / ChuckTheSheep"
delete-after: True
changes:
- tweak: "Adjusted the space parallax's contrast to be less vibrant."
@@ -0,0 +1,4 @@
author: "Naksu"
delete-after: True
changes:
- admin: "Admins can now easily spawn mobs that look like objects. Googly eyes optional!"
@@ -0,0 +1,8 @@
author: "Poojawa"
delete-after: True
changes:
- rscdel: "Removed old things in .dms we weren't using anymore"
- tweak: "subtle messages are now italic'd, so there's better context on whispering"
- tweak: "broke apart the cit_gun.dm file, they're decently spaced out now"
- tweak: "dogborg_sleeper is now standalone from dogborg_equipment because too lazy to debug why it was breaking backpacks."
- tweak: "does that thing I've been meaning to do with Xenobio. additional tools have been provided."
Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Before

Width:  |  Height:  |  Size: 559 B

After

Width:  |  Height:  |  Size: 559 B

@@ -1,6 +1,6 @@
/area/maintenance/bar
name = "Maintenance Bar"
icon = 'code/citadel/icons/areas.dmi'
icon = 'modular_citadel/code/game/area/areas.dmi'
icon_state = "maintbar"
/area/maintenance/bar/cafe
@@ -14,5 +14,5 @@
/area/crew_quarters/cryopod
name = "Cryogenics"
icon = 'code/citadel/icons/areas.dmi'
icon = 'modular_citadel/code/game/area/areas.dmi'
icon_state = "cryo"
+104 -1
View File
@@ -1,3 +1,106 @@
/obj/machinery/vending/security
contraband = list(/obj/item/clothing/glasses/sunglasses = 2, /obj/item/storage/fancy/donut_box = 2, /obj/item/device/ssword_kit = 1)
premium = list(/obj/item/coin/antagtoken = 1, /obj/item/device/ssword_kit = 1)
premium = list(/obj/item/coin/antagtoken = 1, /obj/item/device/ssword_kit = 1)
#define STANDARD_CHARGE 1
#define CONTRABAND_CHARGE 2
#define COIN_CHARGE 3
/obj/machinery/vending/kink
name = "KinkMate"
desc = "A vending machine for all your unmentionable desires."
icon = 'icons/obj/citvending.dmi'
icon_state = "kink"
product_slogans = "Kinky!;Sexy!;Check me out, big boy!"
vend_reply = "Have fun, you shameless pervert!"
products = list(
/obj/item/clothing/under/maid = 5,
/obj/item/clothing/under/stripper_pink = 5,
/obj/item/clothing/under/stripper_green = 5,
/obj/item/dildo/custom = 5
)
contraband = list(/obj/item/restraints/handcuffs/fake/kinky = 5,
/obj/item/clothing/neck/petcollar = 5,
/obj/item/clothing/under/mankini = 1,
/obj/item/dildo/flared/huge = 1
)
premium = list(/obj/item/device/electropack/shockcollar = 1)
refill_canister = /obj/item/vending_refill/kink
/*
/obj/machinery/vending/nazivend
name = "Nazivend"
desc = "A vending machine containing Nazi German supplies. A label reads: \"Remember the gorrilions lost.\""
icon = 'icons/obj/citvending.dmi'
icon_state = "nazi"
vend_reply = "SIEG HEIL!"
product_slogans = "Das Vierte Reich wird zuruckkehren!;ENTFERNEN JUDEN!;Billiger als die Juden jemals geben!;Rader auf dem adminbus geht rund und rund.;Warten Sie, warum wir wieder hassen Juden?- *BZZT*"
products = list(
/obj/item/clothing/head/stalhelm = 20,
/obj/item/clothing/head/panzer = 20,
/obj/item/clothing/suit/soldiercoat = 20,
// /obj/item/clothing/under/soldieruniform = 20,
/obj/item/clothing/shoes/jackboots = 20
)
contraband = list(
/obj/item/clothing/head/naziofficer = 10,
// /obj/item/clothing/suit/officercoat = 10,
// /obj/item/clothing/under/officeruniform = 10,
/obj/item/clothing/suit/space/hardsuit/nazi = 3,
/obj/item/gun/energy/plasma/MP40k = 4
)
premium = list()
refill_canister = /obj/item/vending_refill/nazi
*/
/obj/machinery/vending/sovietvend
name = "KomradeVendtink"
desc = "Rodina-mat' zovyot!"
icon = 'icons/obj/citvending.dmi'
icon_state = "soviet"
vend_reply = "The fascist and capitalist svin'ya shall fall, komrade!"
product_slogans = "Quality worth waiting in line for!; Get Hammer and Sickled!; Sosvietsky soyuz above all!; With capitalist pigsky, you would have paid a fortunetink! ; Craftink in Motherland herself!"
products = list(
/obj/item/clothing/under/soviet = 20,
/obj/item/clothing/head/ushanka = 20,
/obj/item/clothing/shoes/jackboots = 20,
/obj/item/clothing/head/squatter_hat = 20,
/obj/item/clothing/under/squatter_outfit = 20,
/obj/item/clothing/under/russobluecamooutfit = 20,
/obj/item/clothing/head/russobluecamohat = 20
)
contraband = list(
/obj/item/clothing/under/syndicate/tacticool = 4,
/obj/item/clothing/mask/balaclava = 4,
/obj/item/clothing/suit/russofurcoat = 4,
/obj/item/clothing/head/russofurhat = 4,
/obj/item/clothing/suit/space/hardsuit/soviet = 3,
/obj/item/gun/energy/laser/LaserAK = 4
)
premium = list()
refill_canister = /obj/item/vending_refill/soviet
#undef STANDARD_CHARGE
#undef CONTRABAND_CHARGE
#undef COIN_CHARGE
/obj/item/vending_refill/kink
machine_name = "KinkMate"
icon = 'modular_citadel/icons/vending_restock.dmi'
icon_state = "refill_kink"
charges = list(8, 5, 0)// of 20 standard, 12 contraband, 0 premium
init_charges = list(8, 5, 0)
/obj/item/vending_refill/nazi
machine_name = "nazivend"
icon_state = "refill_nazi"
charges = list(33, 13, 0)
init_charges = list(33, 13, 0)
/obj/item/vending_refill/soviet
machine_name = "sovietvend"
icon_state = "refill_soviet"
charges = list(47, 7, 0)
init_charges = list(47, 7, 0)

Some files were not shown because too many files have changed in this diff Show More