mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2026-01-09 08:33:01 +00:00
Merge branch 'master' into upstream-merge-29747
This commit is contained in:
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,6 +1,3 @@
|
||||
[Feature Freeze!]: # We are currently not considering any balance or antagonist oriented pull requests. Full details, as well as ways to bypass this freeze, are available here https://github.com/tgstation/tgstation/pull/28223
|
||||
|
||||
|
||||
[Changelogs]: # (Please make a changelog if you're adding, removing or changing content that'll affect players. This includes, but is not limited to, new features, sprites, sounds; balance changes; map edits and important fixes)
|
||||
[]: # (See here for how to easily make a changelog: https://github.com/tgstation/tgstation/wiki/Changelogs. An example changelog has been provided below. Please edit or remove)
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
language: generic
|
||||
sudo: false
|
||||
dist: precise
|
||||
|
||||
env:
|
||||
global:
|
||||
|
||||
15
SQL/database_changelog.txt.rej
Normal file
15
SQL/database_changelog.txt.rej
Normal file
@@ -0,0 +1,15 @@
|
||||
diff a/SQL/database_changelog.txt b/SQL/database_changelog.txt (rejected hunks)
|
||||
@@ -1,10 +1,10 @@
|
||||
Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255.
|
||||
|
||||
-The latest database version is 3.1; The query to update the schema revision table is:
|
||||
+The latest database version is 3.0; The query to update the schema revision table is:
|
||||
|
||||
-UPDATE `schema_revision` SET major = 3, minor = 1 LIMIT 1;
|
||||
+INSERT INTO `schema_revision` (`major`, `minor`) VALUES (3, 0);
|
||||
or
|
||||
-UPDATE `SS13_schema_revision` SET major = 3, minor = 1 LIMIT 1;
|
||||
+INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (3, 0);
|
||||
|
||||
----------------------------------------------------
|
||||
|
||||
@@ -460,7 +460,7 @@
|
||||
/area/ruin/powered/beach)
|
||||
"cz" = (
|
||||
/obj/effect/turf_decal/sand,
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plating/beach/sand,
|
||||
/area/ruin/powered/beach)
|
||||
"cR" = (
|
||||
|
||||
@@ -896,7 +896,7 @@
|
||||
/area/ruin/powered/clownplanet)
|
||||
"dR" = (
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/indestructible/sound{
|
||||
icon_state = "bananium";
|
||||
name = "bananium floor";
|
||||
|
||||
@@ -809,7 +809,7 @@
|
||||
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/lavaland/surface/outdoors)
|
||||
"cF" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/closed/wall/mineral/titanium/nodiagonal,
|
||||
/area/ruin/powered/animal_hospital)
|
||||
|
||||
|
||||
@@ -1071,7 +1071,7 @@
|
||||
/area/ruin/unpowered/ash_walkers)
|
||||
"cE" = (
|
||||
/obj/structure/stone_tile/surrounding/cracked,
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/ruin/unpowered/ash_walkers)
|
||||
"cF" = (
|
||||
|
||||
@@ -275,7 +275,7 @@
|
||||
},
|
||||
/area/ruin/powered/snow_biodome)
|
||||
"bS" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plating/asteroid/snow{
|
||||
initial_gas_mix = "o2=22;n2=82;TEMP=180"
|
||||
},
|
||||
|
||||
@@ -163,7 +163,7 @@
|
||||
/turf/open/floor/plasteel/cult{
|
||||
initial_gas_mix = "o2=14;n2=23;TEMP=300"
|
||||
},
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/closed/wall/mineral/cult,
|
||||
/area/ruin/unpowered)
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
/turf/open/floor/plating,
|
||||
/area/ruin/unpowered)
|
||||
"r" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/closed/wall/rust,
|
||||
/area/ruin/unpowered)
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
/turf/open/floor/engine/cult,
|
||||
/area/ruin/unpowered)
|
||||
"i" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/engine/cult,
|
||||
/area/ruin/unpowered)
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
/turf/open/floor/plasteel/freezer,
|
||||
/area/ruin/powered/gluttony)
|
||||
"D" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plasteel/freezer,
|
||||
/area/ruin/powered/gluttony)
|
||||
"R" = (
|
||||
|
||||
@@ -285,7 +285,7 @@
|
||||
/turf/open/floor/plating,
|
||||
/area/ruin/powered/golem_ship)
|
||||
"Y" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/mineral/titanium/purple,
|
||||
/area/ruin/powered/golem_ship)
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
/turf/open/floor/engine/cult,
|
||||
/area/ruin/powered/greed)
|
||||
"z" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/engine/cult,
|
||||
/area/ruin/powered/greed)
|
||||
"J" = (
|
||||
|
||||
@@ -180,7 +180,7 @@
|
||||
},
|
||||
/area/ruin/powered)
|
||||
"L" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plating/asteroid/basalt,
|
||||
/area/ruin/powered)
|
||||
|
||||
|
||||
@@ -342,7 +342,7 @@
|
||||
/area/ruin/unpowered)
|
||||
"S" = (
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/wood{
|
||||
baseturf = /turf/open/floor/plating/asteroid/basalt/lava_land_surface;
|
||||
initial_gas_mix = "o2=14;n2=23;TEMP=300"
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
/turf/open/floor/mineral/silver,
|
||||
/area/ruin/powered/pride)
|
||||
"u" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/mineral/silver,
|
||||
/area/ruin/powered/pride)
|
||||
"G" = (
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
/turf/open/floor/plasteel/freezer,
|
||||
/area/ruin/powered/seedvault)
|
||||
"Z" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/closed/wall/r_wall,
|
||||
/area/ruin/powered/seedvault)
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
},
|
||||
/area/ruin/unpowered)
|
||||
"h" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/sepia{
|
||||
blocks_air = 0;
|
||||
slowdown = 10
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/lavaland/surface/outdoors)
|
||||
"B" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/closed/wall/mineral/titanium/survival/pod,
|
||||
/area/ruin/powered)
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
/turf/open/floor/mineral/plastitanium,
|
||||
/area/ruin/unpowered)
|
||||
"g" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/closed/wall/mineral/plastitanium,
|
||||
/area/ruin/unpowered)
|
||||
|
||||
|
||||
@@ -1285,7 +1285,7 @@
|
||||
},
|
||||
/area/ruin/powered/syndicate_lava_base)
|
||||
"dd" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plasteel/vault{
|
||||
dir = 5
|
||||
},
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
"s" = (
|
||||
/obj/structure/table/optable/abductor,
|
||||
/obj/item/weapon/cautery/alien,
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plating/abductor{
|
||||
initial_gas_mix = "o2=16;n2=23;TEMP=300"
|
||||
},
|
||||
|
||||
@@ -269,7 +269,7 @@
|
||||
"W" = (
|
||||
/obj/structure/alien/weeds,
|
||||
/obj/structure/alien/resin/wall,
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/ruin/xenonest)
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
diff a/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_xeno_nest.dmm (rejected hunks)
|
||||
@@ -269,7 +269,7 @@
|
||||
"W" = (
|
||||
/obj/structure/alien/weeds,
|
||||
/obj/structure/alien/resin/wall,
|
||||
-/obj/effect/baseturf_helper,
|
||||
+/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/ruin/unpowered/xenonest)
|
||||
|
||||
@@ -60788,9 +60788,6 @@
|
||||
/turf/open/floor/plasteel,
|
||||
/area/science/robotics/lab)
|
||||
"cHY" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
|
||||
dir = 4
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
|
||||
dir = 4
|
||||
},
|
||||
|
||||
@@ -7457,9 +7457,6 @@
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/port/fore)
|
||||
"aqr" = (
|
||||
/turf/open/floor/plating{
|
||||
icon_state = "panelscorched"
|
||||
},
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
|
||||
dir = 4
|
||||
@@ -25015,6 +25012,10 @@
|
||||
dir = 1;
|
||||
icon_state = "pipe-c"
|
||||
},
|
||||
/obj/structure/fireaxecabinet{
|
||||
pixel_x = -32;
|
||||
pixel_y = 0
|
||||
},
|
||||
/turf/open/floor/plasteel/caution{
|
||||
icon_state = "caution";
|
||||
dir = 8
|
||||
@@ -29570,10 +29571,10 @@
|
||||
"bgT" = (
|
||||
/obj/machinery/computer/atmos_control/tank{
|
||||
frequency = 1441;
|
||||
input_tag = "co2_in";
|
||||
name = "Carbon Dioxide Supply Control";
|
||||
output_tag = "co2_out";
|
||||
sensors = list("co2_sensor" = "Tank")
|
||||
input_tag = "n2o_in";
|
||||
name = "Nitrous Oxide Supply Control";
|
||||
output_tag = "n2o_out";
|
||||
sensors = list("n2o_sensor" = "Tank")
|
||||
},
|
||||
/obj/structure/window/reinforced{
|
||||
dir = 8
|
||||
@@ -112682,9 +112683,6 @@
|
||||
/turf/open/floor/plating,
|
||||
/area/engine/atmospherics_engine)
|
||||
"ept" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden{
|
||||
dir = 4
|
||||
},
|
||||
/obj/effect/turf_decal/stripes/line{
|
||||
dir = 9
|
||||
},
|
||||
@@ -138464,7 +138462,7 @@ aRf
|
||||
aSV
|
||||
aUs
|
||||
aIU
|
||||
aIU
|
||||
aSV
|
||||
aIU
|
||||
aSV
|
||||
aSV
|
||||
|
||||
@@ -1241,6 +1241,7 @@
|
||||
d2 = 4;
|
||||
icon_state = "1-4"
|
||||
},
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/circuit,
|
||||
/area/mine/maintenance)
|
||||
"dy" = (
|
||||
@@ -3399,17 +3400,27 @@
|
||||
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
|
||||
/area/lavaland/surface/outdoors)
|
||||
"Wt" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/closed/wall,
|
||||
/area/mine/laborcamp/security)
|
||||
"Wu" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/closed/wall,
|
||||
/area/mine/laborcamp)
|
||||
"Ww" = (
|
||||
/obj/effect/baseturf_helper,
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/mine/living_quarters)
|
||||
"Wx" = (
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plasteel/brown{
|
||||
dir = 4
|
||||
},
|
||||
/area/mine/eva)
|
||||
"Wy" = (
|
||||
/obj/effect/baseturf_helper/lava_land/surface,
|
||||
/turf/open/floor/plasteel,
|
||||
/area/mine/production)
|
||||
|
||||
(1,1,1) = {"
|
||||
aa
|
||||
@@ -19057,7 +19068,7 @@ cI
|
||||
cP
|
||||
cn
|
||||
bP
|
||||
bP
|
||||
Wy
|
||||
bP
|
||||
bP
|
||||
eD
|
||||
@@ -19570,7 +19581,7 @@ bf
|
||||
cK
|
||||
bq
|
||||
bq
|
||||
dt
|
||||
br
|
||||
bq
|
||||
dV
|
||||
el
|
||||
@@ -20335,7 +20346,7 @@ bf
|
||||
bp
|
||||
bu
|
||||
bI
|
||||
bW
|
||||
Wx
|
||||
cr
|
||||
bf
|
||||
ad
|
||||
|
||||
@@ -5039,7 +5039,6 @@
|
||||
name = "Detective Privacy Blast door"
|
||||
},
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
|
||||
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
|
||||
/turf/open/floor/plating,
|
||||
/area/security/detectives_office)
|
||||
"aix" = (
|
||||
@@ -32004,7 +32003,6 @@
|
||||
"bcM" = (
|
||||
/obj/effect/decal/cleanable/dirt,
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden,
|
||||
/turf/open/floor/plasteel/vault{
|
||||
dir = 5
|
||||
},
|
||||
|
||||
@@ -49675,7 +49675,7 @@
|
||||
/turf/open/floor/plating,
|
||||
/area/maintenance/department/engine)
|
||||
"cdF" = (
|
||||
/obj/structure/closet/secure_closet/miner,
|
||||
/obj/structure/closet/secure_closet/miner/unlocked,
|
||||
/turf/open/floor/plating,
|
||||
/area/shuttle/auxillary_base)
|
||||
"cdG" = (
|
||||
|
||||
BIN
apc_repair.dmi
Normal file
BIN
apc_repair.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 627 B |
@@ -10,6 +10,7 @@
|
||||
#define INVESTIGATE_TELESCI "telesci"
|
||||
#define INVESTIGATE_WIRES "wires"
|
||||
#define INVESTIGATE_PORTAL "portals"
|
||||
#define INVESTIGATE_HALLUCINATIONS "hallucinations"
|
||||
|
||||
//Individual logging defines
|
||||
#define INDIVIDUAL_ATTACK_LOG "Attack log"
|
||||
|
||||
9
code/__DEFINES/logging.dm.rej
Normal file
9
code/__DEFINES/logging.dm.rej
Normal file
@@ -0,0 +1,9 @@
|
||||
diff a/code/__DEFINES/logging.dm b/code/__DEFINES/logging.dm (rejected hunks)
|
||||
@@ -9,6 +9,7 @@
|
||||
#define INVESTIGATE_SUPERMATTER "supermatter"
|
||||
#define INVESTIGATE_TELESCI "telesci"
|
||||
#define INVESTIGATE_WIRES "wires"
|
||||
+#define INVESTIGATE_HALLUCINATIONS "hallucinations"
|
||||
|
||||
//Individual logging defines
|
||||
#define INDIVIDUAL_ATTACK_LOG "Attack log"
|
||||
@@ -8,7 +8,7 @@
|
||||
//You can use these defines to get the typepath of the currently running proc/verb (yes procs + verbs are objects)
|
||||
/* eg:
|
||||
/mob/living/carbon/human/death()
|
||||
world << THIS_PROC_TYPE_STR //You can only output the string versions
|
||||
to_chat(world, THIS_PROC_TYPE_STR) //You can only output the string versions
|
||||
Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a string with () (eg: the _WITH_ARGS defines) to make it look nicer)
|
||||
*/
|
||||
#define THIS_PROC_TYPE .....
|
||||
@@ -46,8 +46,8 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s
|
||||
//Human Overlays Indexes/////////
|
||||
//citadel code
|
||||
#define MUTATIONS_LAYER 30 //mutations. Tk headglows, cold resistance glow, etc
|
||||
#define BODY_BEHIND_LAYER 29 //certain mutantrace features (tail when looking south) that must appear behind the body parts
|
||||
#define GENITALS_BEHIND_LAYER 28
|
||||
#define GENITALS_BEHIND_LAYER 29 //Some genitalia needs to be behind everything, such as with taurs (Taurs use body_behind_layer
|
||||
#define BODY_BEHIND_LAYER 28 //certain mutantrace features (tail when looking south) that must appear behind the body parts
|
||||
#define BODYPARTS_LAYER 27 //Initially "AUGMENTS", this was repurposed to be a catch-all bodyparts flag
|
||||
#define BODY_ADJ_LAYER 26 //certain mutantrace features (snout, body markings) that must appear above the body parts
|
||||
#define GENITALS_ADJ_LAYER 25
|
||||
@@ -350,6 +350,7 @@ GLOBAL_LIST_INIT(ghost_others_options, list(GHOST_OTHERS_SIMPLE, GHOST_OTHERS_DE
|
||||
|
||||
//debug printing macros
|
||||
#define debug_world(msg) if (GLOB.Debug2) to_chat(world, "DEBUG: [msg]")
|
||||
#define debug_usr(msg) if (GLOB.Debug2&&usr) to_chat(usr, "DEBUG: [msg]")
|
||||
#define debug_admins(msg) if (GLOB.Debug2) to_chat(GLOB.admins, "DEBUG: [msg]")
|
||||
#define debug_world_log(msg) if (GLOB.Debug2) log_world("DEBUG: [msg]")
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
#define IRC_STATUS_THROTTLE 5
|
||||
|
||||
#define PR_ANNOUNCEMENTS_PER_ROUND 5 //The number of unique PR announcements allowed per round
|
||||
//This makes sure that a single person can only spam 3 reopens and 3 closes before being ignored
|
||||
|
||||
//keep these in sync with TGS3
|
||||
#define SERVICE_WORLD_PARAM "server_service"
|
||||
#define SERVICE_PR_TEST_JSON "..\\..\\prtestjob.json"
|
||||
@@ -17,7 +20,7 @@
|
||||
#define SERVICE_CMD_NAME_CHECK "namecheck"
|
||||
#define SERVICE_CMD_ADMIN_WHO "adminwho"
|
||||
|
||||
//#define SERVICE_CMD_PARAM_KEY //defined in __compile_options.dm
|
||||
#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
|
||||
#define SERVICE_CMD_PARAM_COMMAND "command"
|
||||
#define SERVICE_CMD_PARAM_MESSAGE "message"
|
||||
#define SERVICE_CMD_PARAM_TARGET "target"
|
||||
|
||||
@@ -320,7 +320,7 @@
|
||||
return r
|
||||
|
||||
// Returns the key based on the index
|
||||
#define KEYBYINDEX(L, index) (((index <= L:len) && (index > 0)) ? L[index] : null)
|
||||
#define KEYBYINDEX(L, index) (((index <= length(L)) && (index > 0)) ? L[index] : null)
|
||||
|
||||
/proc/count_by_type(list/L, type)
|
||||
var/i = 0
|
||||
@@ -468,7 +468,7 @@
|
||||
. |= key_list[key]
|
||||
|
||||
//Picks from the list, with some safeties, and returns the "default" arg if it fails
|
||||
#define DEFAULTPICK(L, default) ((islist(L) && L:len) ? pick(L) : default)
|
||||
#define DEFAULTPICK(L, default) ((islist(L) && length(L)) ? pick(L) : default)
|
||||
#define LAZYINITLIST(L) if (!L) L = list()
|
||||
#define UNSETEMPTY(L) if (L && !L.len) L = null
|
||||
#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } }
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
//wrapper macros for easier grepping
|
||||
#define DIRECT_OUTPUT(A, B) A << B
|
||||
#define SEND_IMAGE(target, image) DIRECT_OUTPUT(target, image)
|
||||
#define SEND_SOUND(target, sound) DIRECT_OUTPUT(target, sound)
|
||||
#define SEND_TEXT(target, text) DIRECT_OUTPUT(target, text)
|
||||
#define WRITE_FILE(file, text) DIRECT_OUTPUT(file, text)
|
||||
|
||||
//print a warning message to world.log
|
||||
#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].")
|
||||
/proc/warning(msg)
|
||||
@@ -20,13 +27,13 @@
|
||||
/proc/log_admin(text)
|
||||
GLOB.admin_log.Add(text)
|
||||
if (config.log_admin)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ADMIN: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMIN: [text]")
|
||||
|
||||
//Items using this proc are stripped from public logs - use with caution
|
||||
/proc/log_admin_private(text)
|
||||
GLOB.admin_log.Add(text)
|
||||
if (config.log_admin)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ADMINPRIVATE: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ADMINPRIVATE: [text]")
|
||||
|
||||
/proc/log_adminsay(text)
|
||||
if (config.log_adminchat)
|
||||
@@ -38,65 +45,65 @@
|
||||
|
||||
/proc/log_game(text)
|
||||
if (config.log_game)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]GAME: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]GAME: [text]")
|
||||
|
||||
/proc/log_vote(text)
|
||||
if (config.log_vote)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]VOTE: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]VOTE: [text]")
|
||||
|
||||
/proc/log_access(text)
|
||||
if (config.log_access)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]ACCESS: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]ACCESS: [text]")
|
||||
|
||||
/proc/log_say(text)
|
||||
if (config.log_say)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]SAY: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]SAY: [text]")
|
||||
|
||||
/proc/log_prayer(text)
|
||||
if (config.log_prayer)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]PRAY: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]PRAY: [text]")
|
||||
|
||||
/proc/log_law(text)
|
||||
if (config.log_law)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]LAW: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]LAW: [text]")
|
||||
|
||||
/proc/log_ooc(text)
|
||||
if (config.log_ooc)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]OOC: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]OOC: [text]")
|
||||
|
||||
/proc/log_whisper(text)
|
||||
if (config.log_whisper)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]WHISPER: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]WHISPER: [text]")
|
||||
|
||||
/proc/log_emote(text)
|
||||
if (config.log_emote)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]EMOTE: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]EMOTE: [text]")
|
||||
|
||||
/proc/log_attack(text)
|
||||
if (config.log_attack)
|
||||
GLOB.world_attack_log << "\[[time_stamp()]]ATTACK: [text]"
|
||||
WRITE_FILE(GLOB.world_attack_log, "\[[time_stamp()]]ATTACK: [text]")
|
||||
|
||||
/proc/log_pda(text)
|
||||
if (config.log_pda)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]PDA: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]PDA: [text]")
|
||||
|
||||
/proc/log_comment(text)
|
||||
if (config.log_pda)
|
||||
//reusing the PDA option because I really don't think news comments are worth a config option
|
||||
GLOB.world_game_log << "\[[time_stamp()]]COMMENT: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]COMMENT: [text]")
|
||||
|
||||
/proc/log_chat(text)
|
||||
if (config.log_pda)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]CHAT: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]CHAT: [text]")
|
||||
|
||||
/proc/log_sql(text)
|
||||
if(config.sql_enabled)
|
||||
GLOB.world_game_log << "\[[time_stamp()]]SQL: [text]"
|
||||
WRITE_FILE(GLOB.world_game_log, "\[[time_stamp()]]SQL: [text]")
|
||||
|
||||
//This replaces world.log so it displays both in DD and the file
|
||||
/proc/log_world(text)
|
||||
GLOB.world_runtime_log << text
|
||||
world.log << text
|
||||
WRITE_FILE(GLOB.world_runtime_log, text)
|
||||
SEND_TEXT(world.log, text)
|
||||
|
||||
// Helper procs for building detailed log lines
|
||||
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
/proc/showCandidatePollWindow(mob/M, poll_time, Question, list/candidates, ignore_category, time_passed, flashwindow = TRUE)
|
||||
set waitfor = 0
|
||||
|
||||
M << 'sound/misc/notice2.ogg' //Alerting them to their consideration
|
||||
SEND_SOUND(M, 'sound/misc/notice2.ogg') //Alerting them to their consideration
|
||||
if(flashwindow)
|
||||
window_flash(M.client)
|
||||
switch(ignore_category ? askuser(M,Question,"Please answer in [poll_time/10] seconds!","Yes","No","Never for this round", StealFocus=0, Timeout=poll_time) : askuser(M,Question,"Please answer in [poll_time/10] seconds!","Yes","No", StealFocus=0, Timeout=poll_time))
|
||||
@@ -426,7 +426,7 @@
|
||||
to_chat(M, "<span class='notice'>Choice registered: Yes.</span>")
|
||||
if(time_passed + poll_time <= world.time)
|
||||
to_chat(M, "<span class='danger'>Sorry, you answered too late to be considered!</span>")
|
||||
M << 'sound/machines/buzz-sigh.ogg'
|
||||
SEND_SOUND(M, 'sound/machines/buzz-sigh.ogg')
|
||||
candidates -= M
|
||||
else
|
||||
candidates += M
|
||||
|
||||
@@ -48,6 +48,11 @@
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/xeno_dorsal, GLOB.xeno_dorsal_list)
|
||||
//genitals
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list)
|
||||
|
||||
for(var/K in GLOB.cock_shapes_list)
|
||||
var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K]
|
||||
GLOB.cock_shapes_icons[K] = value.icon_state
|
||||
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list)
|
||||
init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list)
|
||||
GLOB.breasts_size_list = list("a","b","c","d","e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing.
|
||||
|
||||
@@ -167,7 +167,7 @@ mob
|
||||
|
||||
Output_Icon()
|
||||
set name = "2. Output Icon"
|
||||
to_chat(src, "Icon is: [bicon(getFlatIcon(src))]")
|
||||
to_chat(src, "Icon is: [icon2base64html(getFlatIcon(src))]")
|
||||
|
||||
Label_Icon()
|
||||
set name = "3. Label Icon"
|
||||
@@ -712,7 +712,8 @@ The _flatIcons list is a cache for generated icon files.
|
||||
if(!current)
|
||||
curIndex++ //Try the next layer
|
||||
continue
|
||||
currentLayer = current:layer
|
||||
var/image/I = current
|
||||
currentLayer = I.layer
|
||||
if(currentLayer<0) // Special case for FLY_LAYER
|
||||
if(currentLayer <= -1000) return flat
|
||||
if(pSet == 0) // Underlay
|
||||
@@ -747,22 +748,22 @@ The _flatIcons list is a cache for generated icon files.
|
||||
// Dimensions of overlay being added
|
||||
var/{addX1;addX2;addY1;addY2}
|
||||
|
||||
for(var/I in layers)
|
||||
|
||||
if(I:alpha == 0)
|
||||
for(var/V in layers)
|
||||
var/image/I = V
|
||||
if(I.alpha == 0)
|
||||
continue
|
||||
|
||||
if(I == copy) // 'I' is an /image based on the object being flattened.
|
||||
curblend = BLEND_OVERLAY
|
||||
add = icon(I:icon, I:icon_state, I:dir)
|
||||
add = icon(I.icon, I.icon_state, I.dir)
|
||||
else // 'I' is an appearance object.
|
||||
add = getFlatIcon(new/image(I), curdir, curicon, curstate, curblend)
|
||||
|
||||
// Find the new dimensions of the flat icon to fit the added overlay
|
||||
addX1 = min(flatX1, I:pixel_x+1)
|
||||
addX2 = max(flatX2, I:pixel_x+add.Width())
|
||||
addY1 = min(flatY1, I:pixel_y+1)
|
||||
addY2 = max(flatY2, I:pixel_y+add.Height())
|
||||
addX1 = min(flatX1, I.pixel_x+1)
|
||||
addX2 = max(flatX2, I.pixel_x+add.Width())
|
||||
addY1 = min(flatY1, I.pixel_y+1)
|
||||
addY2 = max(flatY2, I.pixel_y+add.Height())
|
||||
|
||||
if(addX1!=flatX1 || addX2!=flatX2 || addY1!=flatY1 || addY2!=flatY2)
|
||||
// Resize the flattened icon so the new icon fits
|
||||
@@ -771,7 +772,7 @@ The _flatIcons list is a cache for generated icon files.
|
||||
flatY1=addY1;flatY2=addY2
|
||||
|
||||
// Blend the overlay into the flattened icon
|
||||
flat.Blend(add, blendMode2iconMode(curblend), I:pixel_x + 2 - flatX1, I:pixel_y + 2 - flatY1)
|
||||
flat.Blend(add, blendMode2iconMode(curblend), I.pixel_x + 2 - flatX1, I.pixel_y + 2 - flatY1)
|
||||
|
||||
if(A.color)
|
||||
flat.Blend(A.color, ICON_MULTIPLY)
|
||||
@@ -782,10 +783,11 @@ The _flatIcons list is a cache for generated icon files.
|
||||
|
||||
/proc/getIconMask(atom/A)//By yours truly. Creates a dynamic mask for a mob/whatever. /N
|
||||
var/icon/alpha_mask = new(A.icon,A.icon_state)//So we want the default icon and icon state of A.
|
||||
for(var/I in A.overlays)//For every image in overlays. var/image/I will not work, don't try it.
|
||||
if(I:layer>A.layer)
|
||||
for(var/V in A.overlays)//For every image in overlays. var/image/I will not work, don't try it.
|
||||
var/image/I = V
|
||||
if(I.layer>A.layer)
|
||||
continue//If layer is greater than what we need, skip it.
|
||||
var/icon/image_overlay = new(I:icon,I:icon_state)//Blend only works with icon objects.
|
||||
var/icon/image_overlay = new(I.icon,I.icon_state)//Blend only works with icon objects.
|
||||
//Also, icons cannot directly set icon_state. Slower than changing variables but whatever.
|
||||
alpha_mask.Blend(image_overlay,ICON_OR)//OR so they are lumped together in a nice overlay.
|
||||
return alpha_mask//And now return the mask.
|
||||
@@ -993,3 +995,110 @@ GLOBAL_LIST_EMPTY(friendly_animal_types)
|
||||
#undef FROZEN_RED_COLOR
|
||||
#undef FROZEN_GREEN_COLOR
|
||||
#undef FROZEN_BLUE_COLOR
|
||||
|
||||
|
||||
//Converts an icon to base64. Operates by putting the icon in the iconCache savefile,
|
||||
// exporting it as text, and then parsing the base64 from that.
|
||||
// (This relies on byond automatically storing icons in savefiles as base64)
|
||||
/proc/icon2base64(icon/icon, iconKey = "misc")
|
||||
if (!isicon(icon))
|
||||
return FALSE
|
||||
WRITE_FILE(GLOB.iconCache[iconKey], icon)
|
||||
var/iconData = GLOB.iconCache.ExportText(iconKey)
|
||||
var/list/partial = splittext(iconData, "{")
|
||||
return replacetext(copytext(partial[2], 3, -5), "\n", "")
|
||||
|
||||
/proc/icon2html(thing, target, icon_state, dir, frame = 1, moving = FALSE)
|
||||
if (!thing)
|
||||
return
|
||||
|
||||
var/key
|
||||
var/icon/I = thing
|
||||
if (!target)
|
||||
return
|
||||
if (target == world)
|
||||
target = GLOB.clients
|
||||
|
||||
var/list/targets
|
||||
if (!islist(target))
|
||||
targets = list(target)
|
||||
else
|
||||
targets = target
|
||||
if (!targets.len)
|
||||
return
|
||||
if (!isicon(I))
|
||||
if (isfile(thing)) //special snowflake
|
||||
var/name = sanitize_filename("[generate_asset_name(thing)].png")
|
||||
register_asset(name, thing)
|
||||
for (var/thing2 in targets)
|
||||
send_asset(thing2, key, FALSE)
|
||||
return "<img class='icon icon-misc' src=\"[url_encode(name)]\">"
|
||||
var/atom/A = thing
|
||||
if (isnull(dir))
|
||||
dir = A.dir
|
||||
if (isnull(icon_state))
|
||||
icon_state = A.icon_state
|
||||
I = A.icon
|
||||
if (ishuman(thing)) // Shitty workaround for a BYOND issue.
|
||||
var/icon/temp = I
|
||||
I = icon()
|
||||
I.Insert(temp, dir = SOUTH)
|
||||
dir = SOUTH
|
||||
else
|
||||
if (isnull(dir))
|
||||
dir = SOUTH
|
||||
if (isnull(icon_state))
|
||||
icon_state = ""
|
||||
|
||||
I = icon(I, icon_state, dir, frame, moving)
|
||||
|
||||
key = "[generate_asset_name(I)].png"
|
||||
register_asset(key, I)
|
||||
for (var/thing2 in targets)
|
||||
send_asset(thing2, key, FALSE)
|
||||
|
||||
return "<img class='icon icon-[icon_state]' src=\"[url_encode(key)]\">"
|
||||
|
||||
/proc/icon2base64html(thing)
|
||||
if (!thing)
|
||||
return
|
||||
var/static/list/bicon_cache = list()
|
||||
if (isicon(thing))
|
||||
var/icon/I = thing
|
||||
var/icon_base64 = icon2base64(I)
|
||||
|
||||
if (I.Height() > world.icon_size || I.Width() > world.icon_size)
|
||||
var/icon_md5 = md5(icon_base64)
|
||||
icon_base64 = bicon_cache[icon_md5]
|
||||
if (!icon_base64) // Doesn't exist yet, make it.
|
||||
bicon_cache[icon_md5] = icon_base64 = icon2base64(I)
|
||||
|
||||
|
||||
return "<img class='icon icon-misc' src='data:image/png;base64,[icon_base64]'>"
|
||||
|
||||
// Either an atom or somebody fucked up and is gonna get a runtime, which I'm fine with.
|
||||
var/atom/A = thing
|
||||
var/key = "[istype(A.icon, /icon) ? "\ref[A.icon]" : A.icon]:[A.icon_state]"
|
||||
|
||||
|
||||
if (!bicon_cache[key]) // Doesn't exist, make it.
|
||||
var/icon/I = icon(A.icon, A.icon_state, SOUTH, 1)
|
||||
if (ishuman(thing)) // Shitty workaround for a BYOND issue.
|
||||
var/icon/temp = I
|
||||
I = icon()
|
||||
I.Insert(temp, dir = SOUTH)
|
||||
|
||||
bicon_cache[key] = icon2base64(I, key)
|
||||
|
||||
return "<img class='icon icon-[A.icon_state]' src='data:image/png;base64,[bicon_cache[key]]'>"
|
||||
|
||||
//Costlier version of icon2html() that uses getFlatIcon() to account for overlays, underlays, etc. Use with extreme moderation, ESPECIALLY on mobs.
|
||||
/proc/costly_icon2html(thing, target)
|
||||
if (!thing)
|
||||
return
|
||||
|
||||
if (isicon(thing))
|
||||
return icon2html(thing, target)
|
||||
|
||||
var/icon/I = getFlatIcon(thing)
|
||||
return icon2html(I, target)
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
//wrapper macro for sending images that makes grepping easy
|
||||
#define SEND_IMAGE(target, image) target << image
|
||||
|
||||
/proc/random_blood_type()
|
||||
return pick(4;"O-", 36;"O+", 3;"A-", 28;"A+", 1;"B-", 20;"B+", 1;"AB-", 5;"AB+")
|
||||
|
||||
@@ -116,6 +113,7 @@
|
||||
"xenohead" = "None",
|
||||
"xenotail" = "None",
|
||||
"exhibitionist" = FALSE,
|
||||
"genitals_use_skintone" = FALSE,
|
||||
"has_cock" = FALSE,
|
||||
"cock_shape" = pick(GLOB.cock_shapes_list),
|
||||
"cock_length" = 6,
|
||||
@@ -158,7 +156,8 @@
|
||||
"womb_cum_rate" = CUM_RATE,
|
||||
"womb_cum_mult" = CUM_RATE_MULT,
|
||||
"womb_efficiency" = CUM_EFFICIENCY,
|
||||
"womb_fluid" = "femcum"))
|
||||
"womb_fluid" = "femcum",
|
||||
"flavor_text" = ""))
|
||||
|
||||
/proc/random_hair_style(gender)
|
||||
switch(gender)
|
||||
|
||||
@@ -24,11 +24,12 @@
|
||||
announcement += "<br><span class='alert'>[html_encode(text)]</span><br>"
|
||||
announcement += "<br>"
|
||||
|
||||
var/s = sound(sound)
|
||||
for(var/mob/M in GLOB.player_list)
|
||||
if(!isnewplayer(M) && M.can_hear())
|
||||
to_chat(M, announcement)
|
||||
if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS)
|
||||
M << sound(sound)
|
||||
SEND_SOUND(M, s)
|
||||
|
||||
/proc/print_command_report(text = "", title = null, announce=TRUE)
|
||||
if(!title)
|
||||
@@ -55,6 +56,6 @@
|
||||
to_chat(M, "<b><font size = 3><font color = red>[title]</font color><BR>[message]</font size></b><BR>")
|
||||
if(M.client.prefs.toggles & SOUND_ANNOUNCEMENTS)
|
||||
if(alert)
|
||||
M << sound('sound/misc/notice1.ogg')
|
||||
SEND_SOUND(M, sound('sound/misc/notice1.ogg'))
|
||||
else
|
||||
M << sound('sound/misc/notice2.ogg')
|
||||
SEND_SOUND(M, sound('sound/misc/notice2.ogg'))
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
index = findtext(t, char, index+1)
|
||||
return t
|
||||
|
||||
/proc/sanitize_filename(t)
|
||||
return sanitize_simple(t, list("\n"="", "\t"="", "/"="", "\\"="", "?"="", "%"="", "*"="", ":"="", "|"="", "\""="", "<"="", ">"=""))
|
||||
|
||||
//Runs byond's sanitization proc along-side sanitize_simple
|
||||
/proc/sanitize(t,list/repl_chars = null)
|
||||
return html_encode(sanitize_simple(t,repl_chars))
|
||||
@@ -553,7 +556,7 @@ GLOBAL_LIST_INIT(binary, list("0","1"))
|
||||
|
||||
var/list/tosend = list()
|
||||
tosend["data"] = finalized
|
||||
log << json_encode(tosend)
|
||||
WRITE_FILE(log, json_encode(tosend))
|
||||
|
||||
//Used for applying byonds text macros to strings that are loaded at runtime
|
||||
/proc/apply_text_macros(string)
|
||||
|
||||
@@ -537,3 +537,18 @@
|
||||
if(!istype(the_matrix) || the_matrix.len != 20)
|
||||
return "#ffffffff"
|
||||
return rgb(the_matrix[1]*255, the_matrix[6]*255, the_matrix[11]*255, the_matrix[16]*255)
|
||||
|
||||
/proc/type2parent(child)
|
||||
var/string_type = "[child]"
|
||||
var/last_slash = findlasttext(string_type, "/")
|
||||
if(last_slash == 1)
|
||||
switch(child)
|
||||
if(/datum)
|
||||
return null
|
||||
if(/obj || /mob)
|
||||
return /atom/movable
|
||||
if(/area || /turf)
|
||||
return /atom
|
||||
else
|
||||
return /datum
|
||||
return text2path(copytext(string_type, 1, last_slash))
|
||||
@@ -289,7 +289,7 @@ Turf and target are separate in case you want to teleport some distance from a t
|
||||
var/list/pois = list()
|
||||
for(var/mob/M in mobs)
|
||||
if(skip_mindless && (!M.mind && !M.ckey))
|
||||
if(!isbot(M) && !istype(M, /mob/camera/))
|
||||
if(!isbot(M) && !istype(M, /mob/camera) && !ismegafauna(M))
|
||||
continue
|
||||
if(M.client && M.client.holder && M.client.holder.fakekey) //stealthmins
|
||||
continue
|
||||
@@ -845,11 +845,11 @@ GLOBAL_LIST_INIT(WALLITEMS_INVERSE, typecacheof(list(
|
||||
|
||||
/obj/proc/atmosanalyzer_scan(datum/gas_mixture/air_contents, mob/user, obj/target = src)
|
||||
var/obj/icon = target
|
||||
user.visible_message("[user] has used the analyzer on [bicon(icon)] [target].", "<span class='notice'>You use the analyzer on [bicon(icon)] [target].</span>")
|
||||
user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(src))] [target].", "<span class='notice'>You use the analyzer on [icon2html(icon, user)] [target].</span>")
|
||||
var/pressure = air_contents.return_pressure()
|
||||
var/total_moles = air_contents.total_moles()
|
||||
|
||||
to_chat(user, "<span class='notice'>Results of analysis of [bicon(icon)] [target].</span>")
|
||||
to_chat(user, "<span class='notice'>Results of analysis of [icon2html(icon, user)] [target].</span>")
|
||||
if(total_moles>0)
|
||||
to_chat(user, "<span class='notice'>Pressure: [round(pressure,0.1)] kPa</span>")
|
||||
|
||||
|
||||
@@ -69,8 +69,6 @@
|
||||
#error You need version 511 or higher
|
||||
#endif
|
||||
|
||||
#define SERVICE_CMD_PARAM_KEY "serviceCommsKey"
|
||||
|
||||
//Update this whenever the db schema changes
|
||||
//make sure you add an update to the schema_version stable in the db changelog
|
||||
#define DB_MAJOR_VERSION 3
|
||||
|
||||
@@ -205,7 +205,7 @@ or something covering your eyes."
|
||||
/obj/screen/alert/embeddedobject
|
||||
name = "Embedded Object"
|
||||
desc = "Something got lodged into your flesh and is causing major bleeding. It might fall out with time, but surgery is the safest way. \
|
||||
If you're feeling frisky, click yourself in help intent to pull the object out."
|
||||
If you're feeling frisky, examine yourself and click the underlined item to pull the object out."
|
||||
icon_state = "embeddedobject"
|
||||
|
||||
/obj/screen/alert/embeddedobject/Click()
|
||||
|
||||
@@ -53,6 +53,7 @@ GLOBAL_LIST_EMPTY(xeno_dorsal_list)
|
||||
|
||||
//Genitals and Arousal Lists
|
||||
GLOBAL_LIST_EMPTY(cock_shapes_list)//global_lists.dm for the list initializations //Now also _DATASTRUCTURES globals.dm
|
||||
GLOBAL_LIST_EMPTY(cock_shapes_icons) //Associated list for names->icon_states for cockshapes.
|
||||
GLOBAL_LIST_EMPTY(breasts_size_list)
|
||||
GLOBAL_LIST_EMPTY(breasts_shapes_list)
|
||||
GLOBAL_LIST_EMPTY(vagina_shapes_list)
|
||||
|
||||
@@ -181,83 +181,272 @@
|
||||
else
|
||||
to_chat(src, "<span class='notice'>You aren't aroused enough for that.</span>")
|
||||
|
||||
/mob/living/carbon/human/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints
|
||||
if(mb_cd_timer > world.time)
|
||||
if(!forced_climax) //Don't spam the message to the victim if forced to come too fast
|
||||
to_chat(src, "<span class='warning'>You need to wait [round((mb_cd_timer - world.time)/(20))] seconds before you can do that again!</span>")
|
||||
return
|
||||
mb_cd_timer = (world.time + mb_cd_length)
|
||||
var/list/genitals_list = list()
|
||||
var/obj/item/organ/genital/SG = null//originally selected_genital
|
||||
var/list/containers_list = list()
|
||||
var/obj/item/weapon/reagent_containers/SC = null
|
||||
|
||||
//These are various procs that we'll use later, split up for readability instead of having one, huge proc.
|
||||
//For all of these, we assume the arguments given are proper and have been checked beforehand.
|
||||
/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/G, mb_time = 30) //Masturbation, keep it gender-neutral
|
||||
var/total_fluids = 0
|
||||
var/datum/reagents/fluid_source = null
|
||||
var/into_container = 0
|
||||
var/free_hands = get_num_arms() //arms was only used to know if we had ANY at all
|
||||
var/total_cum = 0
|
||||
var/finished = 0
|
||||
var/mb_time = 30
|
||||
if(canbearoused && has_dna())
|
||||
if(stat==2)
|
||||
to_chat(src, "<span class='warning'>You can't do that while dead!</span>")
|
||||
|
||||
if(G.producing) //Can it produce its own fluids, such as breasts?
|
||||
fluid_source = G.reagents
|
||||
else
|
||||
if(!G.linked_organ)
|
||||
to_chat(src, "<span class='warning'>Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.</span>")
|
||||
return
|
||||
if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks
|
||||
for(var/obj/item/organ/genital/G in internal_organs)
|
||||
if(G.can_masturbate_with) //All capable genitals will orgasm with this
|
||||
fluid_source = G.linked_organ.reagents
|
||||
total_fluids = fluid_source.total_volume
|
||||
if(mb_time)
|
||||
src.visible_message("<span class='danger'>[src] starts to [G.masturbation_verb] [p_their()] [G.name].</span>", \
|
||||
"<span class='green'>You start to [G.masturbation_verb] your [G.name].</span>", \
|
||||
"<span class='green'>You start to [G.masturbation_verb] your [G.name].</span>")
|
||||
|
||||
if(do_after(src, mb_time, target = src))
|
||||
if(total_fluids > 5)
|
||||
fluid_source.reaction(src.loc, TOUCH, 1, 0)
|
||||
fluid_source.clear_reagents()
|
||||
src.visible_message("<span class='danger'>[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!</span>", \
|
||||
"<span class='green'>You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
if(G.can_climax)
|
||||
setArousalLoss(min_arousal)
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes
|
||||
var/total_fluids = 0
|
||||
var/datum/reagents/fluid_source = null
|
||||
var/unable_to_come = FALSE
|
||||
switch(G.type)
|
||||
if(/obj/item/organ/genital/penis)
|
||||
var/obj/item/organ/genital/penis/P = G
|
||||
if(!P.linked_balls)
|
||||
|
||||
if(G.producing) //Can it produce its own fluids, such as breasts?
|
||||
fluid_source = G.reagents
|
||||
total_fluids = fluid_source.total_volume
|
||||
else
|
||||
if(!G.linked_organ)
|
||||
unable_to_come = TRUE
|
||||
else
|
||||
fluid_source = P.linked_balls.reagents
|
||||
|
||||
|
||||
if(/obj/item/organ/genital/vagina)
|
||||
var/obj/item/organ/genital/vagina/V = G
|
||||
if(!V.linked_womb)
|
||||
unable_to_come = TRUE
|
||||
else
|
||||
fluid_source = V.linked_womb.reagents
|
||||
else //Weird, undefined genitalia behaviour
|
||||
unable_to_come = TRUE
|
||||
fluid_source = G.linked_organ.reagents
|
||||
total_fluids = fluid_source.total_volume
|
||||
|
||||
if(unable_to_come)
|
||||
src.visible_message("<span class='danger'>[src] shudders, their [G.name] unable to cum.</span>", \
|
||||
"<span class='userdanger'>Your [G.name] cannot cum, giving no relief.</span>", \
|
||||
"<span class='userdanger'>Your [G.name] cannot cum, giving no relief.</span>")
|
||||
else
|
||||
if(fluid_source)
|
||||
total_cum = fluid_source.total_volume
|
||||
total_fluids = fluid_source.total_volume
|
||||
if(mb_time) //as long as it's not instant, give a warning
|
||||
src.visible_message("<span class='danger'>[src] looks like they're about to cum.</span>", \
|
||||
"<span class='green'>You feel yourself about to orgasm.</span>", \
|
||||
"<span class='green'>You feel yourself about to orgasm.</span>")
|
||||
if(do_after(src, mb_time, target = src))
|
||||
if(total_cum > 5)
|
||||
if(total_fluids > 5)
|
||||
fluid_source.reaction(src.loc, TOUCH, 1, 0)
|
||||
fluid_source.clear_reagents()
|
||||
fluid_source = null //cleanup so this can be used for the next genitalia
|
||||
|
||||
src.visible_message("<span class='danger'>[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!</span>", \
|
||||
"<span class='green'>You're forced to cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""] with your [G].</span>", \
|
||||
"<span class='green'>Your [G] have been forced to climax.</span>")
|
||||
finished = 1
|
||||
if(finished)
|
||||
src.visible_message("<span class='danger'>[src] orgasms[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""], using [p_their()] [G.name]!</span>", \
|
||||
"<span class='green'>You climax[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""] with your [G.name].</span>", \
|
||||
"<span class='green'>You climax using your [G.name].</span>")
|
||||
if(G.can_climax)
|
||||
setArousalLoss(min_arousal)
|
||||
return //Do not proceed to masturbating if all genitals have been forced to orgasm.
|
||||
if(stat==1) //Sleeping people can be forced chemically or with electrical stimulants, for example.
|
||||
to_chat(src, "<span class='warning'>You must be conscious to do that!</span>")
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, mb_time = 30) //Used for climaxing with any living thing
|
||||
var/total_fluids = 0
|
||||
var/datum/reagents/fluid_source = null
|
||||
|
||||
if(G.producing) //Can it produce its own fluids, such as breasts?
|
||||
fluid_source = G.reagents
|
||||
else
|
||||
if(!G.linked_organ)
|
||||
to_chat(src, "<span class='warning'>Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.</span>")
|
||||
return
|
||||
if(restrained())
|
||||
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
|
||||
fluid_source = G.linked_organ.reagents
|
||||
total_fluids = fluid_source.total_volume
|
||||
if(mb_time) //Skip warning if this is an instant climax.
|
||||
src.visible_message("[src] is about to climax with [L]!", \
|
||||
"You're about to climax with [L]!", \
|
||||
"<span class='danger'>You're preparing to climax with someone!</span>")
|
||||
if(spillage)
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, L))
|
||||
fluid_source.trans_to(L, total_fluids*G.fluid_transfer_factor)
|
||||
total_fluids -= total_fluids*G.fluid_transfer_factor
|
||||
if(total_fluids > 5)
|
||||
fluid_source.reaction(L.loc, TOUCH, 1, 0)
|
||||
fluid_source.clear_reagents()
|
||||
src.visible_message("<span class='danger'>[src] climaxes with [L][spillage ? ", overflowing and spilling":""], using [p_their()] [G.name]!</span>", \
|
||||
"<span class='green'>You orgasm with [L][spillage ? ", spilling out of them":""], using your [G.name].</span>", \
|
||||
"<span class='green'>You have climaxed with someone[spillage ? ", spilling out of them":""], using your [G.name].</span>")
|
||||
if(G.can_climax)
|
||||
setArousalLoss(min_arousal)
|
||||
else //knots and other non-spilling orgasms
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, L))
|
||||
fluid_source.trans_to(L, total_fluids)
|
||||
total_fluids = 0
|
||||
src.visible_message("<span class='danger'>[src] climaxes with [L], [p_their()] [G.name] spilling nothing!</span>", \
|
||||
"<span class='green'>You ejaculate with [L], your [G.name] spilling nothing.</span>", \
|
||||
"<span class='green'>You have climaxed inside someone, your [G.name] spilling nothing.</span>")
|
||||
if(G.can_climax)
|
||||
setArousalLoss(min_arousal)
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/G, obj/item/weapon/reagent_containers/container, mb_time = 30) //For beaker-filling, beware the bartender
|
||||
var/total_fluids = 0
|
||||
var/datum/reagents/fluid_source = null
|
||||
|
||||
if(G.producing) //Can it produce its own fluids, such as breasts?
|
||||
fluid_source = G.reagents
|
||||
else
|
||||
if(!G.linked_organ)
|
||||
to_chat(src, "<span class='warning'>Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.</span>")
|
||||
return
|
||||
fluid_source = G.linked_organ.reagents
|
||||
total_fluids = fluid_source.total_volume
|
||||
|
||||
//if(!container) //Something weird happened
|
||||
// to_chat(src, "<span class='warning'>You need a container to do this!</span>")
|
||||
// return
|
||||
|
||||
src.visible_message("<span class='danger'>[src] starts to [G.masturbation_verb] their [G.name] over [container].</span>", \
|
||||
"<span class='userdanger'>You start to [G.masturbation_verb] your [G.name] over [container].</span>", \
|
||||
"<span class='userdanger'>You start to [G.masturbation_verb] your [G.name] over something.</span>")
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, container))
|
||||
fluid_source.trans_to(container, total_fluids)
|
||||
src.visible_message("<span class='danger'>[src] uses [p_their()] [G.name] to fill [container]!</span>", \
|
||||
"<span class='green'>You used your [G.name] to fill [container].</span>", \
|
||||
"<span class='green'>You have relieved some pressure.</span>")
|
||||
if(G.can_climax)
|
||||
setArousalLoss(min_arousal)
|
||||
|
||||
/mob/living/carbon/human/proc/pick_masturbate_genitals()
|
||||
var/obj/item/organ/genital/ret_organ
|
||||
var/list/genitals_list = list()
|
||||
var/list/worn_stuff = get_equipped_items()
|
||||
|
||||
for(var/obj/item/organ/genital/G in internal_organs)
|
||||
if(G.can_masturbate_with) //filter out what you can't masturbate with
|
||||
if(G.is_exposed(worn_stuff)) //Nude or through_clothing
|
||||
genitals_list += G
|
||||
if(genitals_list.len)
|
||||
ret_organ = input(src, "with what?", "Masturbate", null) as null|obj in genitals_list
|
||||
return ret_organ
|
||||
return null //error stuff
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/pick_climax_genitals()
|
||||
var/obj/item/organ/genital/ret_organ
|
||||
var/list/genitals_list = list()
|
||||
var/list/worn_stuff = get_equipped_items()
|
||||
|
||||
for(var/obj/item/organ/genital/G in internal_organs)
|
||||
if(G.can_climax) //filter out what you can't masturbate with
|
||||
if(G.is_exposed(worn_stuff)) //Nude or through_clothing
|
||||
genitals_list += G
|
||||
if(genitals_list.len)
|
||||
ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list
|
||||
return ret_organ
|
||||
return null //error stuff
|
||||
|
||||
|
||||
/mob/living/carbon/human/proc/pick_partner()
|
||||
var/list/partners = list()
|
||||
if(src.pulling)
|
||||
partners += src.pulling //Yes, even objects for now
|
||||
if(src.pulledby)
|
||||
partners += src.pulledby
|
||||
//Now we got both of them, let's check if they're proper
|
||||
for(var/I in partners)
|
||||
if(isliving(I))
|
||||
if(iscarbon(I))
|
||||
var/mob/living/carbon/C = I
|
||||
if(!C.exposed_genitals.len) //Nothing through_clothing
|
||||
if(!C.is_groin_exposed()) //No pants undone
|
||||
if(!C.is_chest_exposed()) //No chest exposed
|
||||
partners -= I //Then not proper, remove them
|
||||
else
|
||||
partners -= I //No fucking objects
|
||||
//NOW the list should only contain correct partners
|
||||
if(!partners.len)
|
||||
return null //No one left.
|
||||
return input(src, "With whom?", "Sexual partner", null) in partners //pick one, default to null
|
||||
|
||||
/mob/living/carbon/human/proc/pick_climax_container()
|
||||
var/obj/item/weapon/reagent_containers/SC = null
|
||||
var/list/containers_list = list()
|
||||
|
||||
for(var/obj/item/weapon/reagent_containers/container in held_items)
|
||||
if(container.is_open_container() || istype(container, /obj/item/weapon/reagent_containers/food/snacks))
|
||||
containers_list += container
|
||||
|
||||
if(containers_list.len)
|
||||
SC = input(src, "Into or onto what?(Cancel for nowhere)", null) as null|obj in containers_list
|
||||
if(SC)
|
||||
if(in_range(src, SC))
|
||||
return SC
|
||||
return null //If nothing correct, give null.
|
||||
|
||||
|
||||
//Here's the main proc itself
|
||||
/mob/living/carbon/human/mob_climax(forced_climax=FALSE) //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints
|
||||
if(mb_cd_timer > world.time)
|
||||
if(!forced_climax) //Don't spam the message to the victim if forced to come too fast
|
||||
to_chat(src, "<span class='warning'>You need to wait [round((mb_cd_timer - world.time)/(20))] seconds before you can do that again!</span>")
|
||||
return
|
||||
mb_cd_timer = (world.time + mb_cd_length)
|
||||
|
||||
|
||||
if(canbearoused && has_dna())
|
||||
if(stat==2)
|
||||
to_chat(src, "<span class='warning'>You can't do that while dead!</span>")
|
||||
return
|
||||
if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks
|
||||
for(var/obj/item/organ/O in internal_organs)
|
||||
if(istype(O, /obj/item/organ/genital))
|
||||
var/obj/item/organ/genital/G = O
|
||||
if(!G.can_climax) //Skip things like wombs and testicles
|
||||
continue
|
||||
var/mob/living/partner
|
||||
var/check_target
|
||||
var/list/worn_stuff = get_equipped_items()
|
||||
|
||||
if(G.is_exposed(worn_stuff))
|
||||
if(src.pulling) //Are we pulling someone? Priority target, we can't be making option menus for this, has to be quick
|
||||
if(isliving(src.pulling)) //Don't fuck objects
|
||||
check_target = src.pulling
|
||||
if(src.pulledby && !check_target) //prioritise pulled over pulledby
|
||||
if(isliving(src.pulledby))
|
||||
check_target = src.pulledby
|
||||
//Now we should have a partner, or else we have to come alone
|
||||
if(check_target)
|
||||
if(iscarbon(check_target)) //carbons can have clothes
|
||||
var/mob/living/carbon/C = check_target
|
||||
if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) //Are they naked enough?
|
||||
partner = C
|
||||
else //A cat is fine too
|
||||
partner = check_target
|
||||
if(partner) //Did they pass the clothing checks?
|
||||
mob_climax_partner(G, partner, mb_time = 0) //Instant climax due to forced
|
||||
continue //You've climaxed once with this organ, continue on
|
||||
//not exposed OR if no partner was found while exposed, climax alone
|
||||
mob_climax_outside(G, mb_time = 0) //removed climax timer for sudden, forced orgasms
|
||||
//Now all genitals that could climax, have.
|
||||
//Since this was a forced climax, we do not need to continue with the other stuff
|
||||
return
|
||||
//If we get here, then this is not a forced climax and we gotta check a few things.
|
||||
|
||||
if(stat==1) //No sleep-masturbation, you're unconscious.
|
||||
to_chat(src, "<span class='warning'>You must be conscious to do that!</span>")
|
||||
return
|
||||
if(getArousalLoss() < 33) //flat number instead of percentage
|
||||
to_chat(src, "<span class='warning'>You aren't aroused enough for that!</span>")
|
||||
return
|
||||
if(!is_groin_exposed())
|
||||
to_chat(src, "<span class='warning'>You need to undress, first!</span>")
|
||||
|
||||
//Ok, now we check what they want to do.
|
||||
var/choice = input(src, "Select sexual activity", "Sexual activity:") in list("Masturbate", "Climax alone", "Climax with partner", "Fill container")
|
||||
|
||||
switch(choice)
|
||||
if("Masturbate")
|
||||
if(restrained(TRUE)) //TRUE ignores grabs
|
||||
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
|
||||
return
|
||||
var/free_hands = get_num_arms()
|
||||
if(!free_hands)
|
||||
to_chat(src, "<span class='warning'>You need at least one free arm.</span>")
|
||||
return
|
||||
@@ -265,140 +454,91 @@
|
||||
if(isobj(helditem))
|
||||
free_hands--
|
||||
if(free_hands <= 0)
|
||||
to_chat(src, "<span class='warning'>You need at least one free hand.</span>")
|
||||
to_chat(src, "<span class='warning'>You're holding too many things.</span>")
|
||||
return
|
||||
for(var/obj/item/organ/genital/G in internal_organs)
|
||||
if(G.can_masturbate_with)//filter out what you can't masturbate with
|
||||
genitals_list += G
|
||||
if(genitals_list.len)
|
||||
SG = input(src, "with what?", "Masturbate") as null|obj in genitals_list
|
||||
if(SG)
|
||||
for(var/obj/item/weapon/reagent_containers/container in held_items)
|
||||
if(container.is_open_container() || istype(container, /obj/item/weapon/reagent_containers/food/snacks/pie))
|
||||
containers_list += container
|
||||
if(containers_list.len)
|
||||
SC = input(src, "Into or onto what?(Cancel for nowhere)", "Masturbate") as null|obj in containers_list
|
||||
if(SC)
|
||||
if(in_range(src, SC))
|
||||
into_container = 1
|
||||
SG.update()
|
||||
switch(SG.type)
|
||||
|
||||
//Penis
|
||||
if(/obj/item/organ/genital/penis)
|
||||
var/obj/item/organ/genital/penis/P = SG
|
||||
if(!P.linked_balls)
|
||||
to_chat(src, "<span class='warning'>You need a pair of testicles to do this.</span>")
|
||||
//We got hands, let's pick an organ
|
||||
var/obj/item/organ/genital/picked_organ
|
||||
picked_organ = pick_masturbate_genitals()
|
||||
if(picked_organ)
|
||||
mob_masturbate(picked_organ)
|
||||
return
|
||||
fluid_source = P.linked_balls.reagents
|
||||
total_cum = fluid_source.total_volume
|
||||
if(into_container)//into a glass or beaker or whatever
|
||||
src.visible_message("<span class='danger'>[src] starts [pick("jerking off","stroking")] their [SG.name] over [SC].</span>", \
|
||||
"<span class='userdanger'>You start jerking off over [SC.name].</span>", \
|
||||
"<span class='userdanger'>You start masturbating.</span>")
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, SC))
|
||||
fluid_source.trans_to(SC, total_cum)
|
||||
src.visible_message("<span class='danger'>[src] orgasms, [pick("cumming into", "emptying themself into")] [SC]!</span>", \
|
||||
"<span class='green'>You cum into [SC].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
else //Not in a container
|
||||
if(src.pulling)
|
||||
if(iscarbon(src.pulling))
|
||||
var/mob/living/carbon/C = src.pulling
|
||||
if(!C.is_groin_exposed())
|
||||
to_chat(src, "<span class='warning'>You must undress someone to climax inside them.</span>")
|
||||
else //They either lack organs that can masturbate, or they didn't pick one.
|
||||
to_chat(src, "<span class='warning'>You cannot masturbate without choosing genitals.</span>")
|
||||
return
|
||||
if(isliving(src.pulling)) //Gotta be alive to fuck it, don't wanna have to code fucking objects that ain't containers...
|
||||
var/mob/living/partner = src.pulling
|
||||
src.visible_message("[src] is about to climax inside [partner]!", \
|
||||
"You're about to climax inside [partner]!", \
|
||||
"<span class='danger'>You're preparing to climax inside someone!</span>")
|
||||
switch(grab_state)
|
||||
if(GRAB_PASSIVE)
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, partner))
|
||||
var/spillage = 0.5 //Leaks a bit on passive grab
|
||||
var/did_spill = FALSE
|
||||
fluid_source.trans_to(partner, total_cum*(1-spillage))
|
||||
total_cum = total_cum*spillage
|
||||
if(total_cum > 5)
|
||||
fluid_source.reaction(partner.loc, TOUCH, 1, 0)
|
||||
did_spill = TRUE
|
||||
fluid_source.clear_reagents()
|
||||
|
||||
src.visible_message("<span class='danger'>[src] ejaculates inside [partner][did_spill ? ", overflowing and spilling":""]!</span>", \
|
||||
"<span class='green'>You ejaculate inside [partner][did_spill ? ", spilling out of them":""].</span>", \
|
||||
"<span class='green'>You have climaxed inside someone[did_spill ? ", spilling out of them":""].</span>")
|
||||
finished = 1
|
||||
else //Aggressive or higher
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, partner))
|
||||
var/spillage = 0.0 //Leakproofing seals
|
||||
fluid_source.trans_to(partner, total_cum*(1-spillage))
|
||||
total_cum = total_cum*spillage
|
||||
if(total_cum > 5)
|
||||
fluid_source.reaction(partner.loc, TOUCH, 1, 0)
|
||||
fluid_source.clear_reagents()
|
||||
|
||||
src.visible_message("<span class='danger'>[src] ejaculates inside [partner], spilling nothing!</span>", \
|
||||
"<span class='green'>You ejaculate inside [partner], spilling nothing.</span>", \
|
||||
"<span class='green'>You have climaxed inside someone, spilling nothing.</span>")
|
||||
finished = 1
|
||||
//Don't care, not coding you fucking a unanchored girder
|
||||
else //No pulling, or pulling non-living things
|
||||
src.visible_message("<span class='danger'>[src] starts [pick("jerking off","stroking")] their [SG].</span>", \
|
||||
"<span class='green'>You start masturbating.</span>", \
|
||||
"<span class='green'>You start masturbating.</span>")
|
||||
if(do_after(src, mb_time, target = src))
|
||||
if(total_cum > 5)
|
||||
fluid_source.reaction(src.loc, TOUCH, 1, 0)
|
||||
fluid_source.clear_reagents()
|
||||
|
||||
src.visible_message("<span class='danger'>[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!</span>", \
|
||||
"<span class='green'>You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
|
||||
if(/obj/item/organ/genital/vagina)
|
||||
var/obj/item/organ/genital/vagina/V = SG
|
||||
if(!V.linked_womb)
|
||||
to_chat(src, "<span class='warning'>You need a womb to do this.</span>")
|
||||
if("Climax alone")
|
||||
if(restrained(TRUE)) //TRUE ignores grabs
|
||||
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
|
||||
return
|
||||
var/free_hands = get_num_arms()
|
||||
if(!free_hands)
|
||||
to_chat(src, "<span class='warning'>You need at least one free arm.</span>")
|
||||
return
|
||||
for(var/helditem in held_items)//how many hands are free
|
||||
if(isobj(helditem))
|
||||
free_hands--
|
||||
if(free_hands <= 0)
|
||||
to_chat(src, "<span class='warning'>You're holding too many things.</span>")
|
||||
return
|
||||
//We got hands, let's pick an organ
|
||||
var/obj/item/organ/genital/picked_organ
|
||||
picked_organ = pick_climax_genitals()
|
||||
if(picked_organ)
|
||||
mob_climax_outside(picked_organ)
|
||||
return
|
||||
else //They either lack organs that can masturbate, or they didn't pick one.
|
||||
to_chat(src, "<span class='warning'>You cannot climax without choosing genitals.</span>")
|
||||
return
|
||||
fluid_source = V.linked_womb.reagents
|
||||
total_cum = fluid_source.total_volume
|
||||
if(into_container)//into a glass or beaker or whatever
|
||||
src.visible_message("<span class='danger'>[src] starts fingering their [SG.name] over [SC].</span>", \
|
||||
"<span class='userdanger'>You start fingering over [SC.name].</span>", \
|
||||
"<span class='userdanger'>You start masturbating.</span>")
|
||||
if(do_after(src, mb_time, target = src) && in_range(src, SC))
|
||||
fluid_source.trans_to(SC, total_cum)
|
||||
src.visible_message("<span class='danger'>[src] orgasms, [pick("cumming into", "emptying themself into")] [SC]!</span>", \
|
||||
"<span class='green'>You cum into [SC].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
|
||||
else//not into a container
|
||||
src.visible_message("<span class='danger'>[src] starts fingering their vagina.</span>", \
|
||||
"<span class='userdanger'>You start fingering your vagina.</span>", \
|
||||
"<span class='userdanger'>You start masturbating.</span>")
|
||||
if(do_after(src, mb_time, target = src))
|
||||
if(total_cum > 5)
|
||||
fluid_source.reaction(src.loc, TOUCH, 1, 0)
|
||||
fluid_source.clear_reagents()
|
||||
src.visible_message("<span class='danger'>[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!</span>", \
|
||||
"<span class='green'>You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].</span>", \
|
||||
"<span class='green'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
|
||||
else//backup message, just in case
|
||||
src.visible_message("<span class='danger'>[src] starts masturbating!</span>", \
|
||||
"<span class='userdanger'>You start masturbating.</span>")
|
||||
if(do_after(src, mb_time, target = src))
|
||||
src.visible_message("<span class='danger'>[src] [pick("relieves themself!", "shudders and moans in orgasm!")]</span>", \
|
||||
"<span class='userdanger'>You have relieved yourself.</span>")
|
||||
finished = 1
|
||||
if(finished)
|
||||
setArousalLoss(min_arousal)
|
||||
|
||||
if("Climax with partner")
|
||||
//We need no hands, we can be restrained and so on, so let's pick an organ
|
||||
var/obj/item/organ/genital/picked_organ
|
||||
picked_organ = pick_climax_genitals()
|
||||
if(picked_organ)
|
||||
var/mob/living/partner = pick_partner() //Get someone
|
||||
if(partner)
|
||||
var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No")
|
||||
if(spillage == "Yes")
|
||||
mob_climax_partner(picked_organ, partner, TRUE)
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You have no genitals!</span>")
|
||||
mob_climax_partner(picked_organ, partner, FALSE)
|
||||
return
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You cannot do this alone.</span>")
|
||||
return
|
||||
else //They either lack organs that can masturbate, or they didn't pick one.
|
||||
to_chat(src, "<span class='warning'>You cannot climax without choosing genitals.</span>")
|
||||
return
|
||||
|
||||
if("Fill container")
|
||||
//We'll need hands and no restraints.
|
||||
if(restrained(TRUE)) //TRUE ignores grabs
|
||||
to_chat(src, "<span class='warning'>You can't do that while restrained!</span>")
|
||||
return
|
||||
var/free_hands = get_num_arms()
|
||||
if(!free_hands)
|
||||
to_chat(src, "<span class='warning'>You need at least one free arm.</span>")
|
||||
return
|
||||
for(var/helditem in held_items)//how many hands are free
|
||||
if(isobj(helditem))
|
||||
free_hands--
|
||||
if(free_hands <= 0)
|
||||
to_chat(src, "<span class='warning'>You're holding too many things.</span>")
|
||||
return
|
||||
//We got hands, let's pick an organ
|
||||
var/obj/item/organ/genital/picked_organ
|
||||
picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids.
|
||||
if(picked_organ)
|
||||
//Good, got an organ, time to pick a container
|
||||
var/obj/item/weapon/reagent_containers/fluid_container = pick_climax_container()
|
||||
if(fluid_container)
|
||||
mob_fill_container(picked_organ, fluid_container)
|
||||
return
|
||||
else
|
||||
to_chat(src, "<span class='warning'>You cannot do this without anything to fill.</span>")
|
||||
return
|
||||
else //They either lack organs that can climax, or they didn't pick one.
|
||||
to_chat(src, "<span class='warning'>You cannot fill anything without choosing genitals.</span>")
|
||||
return
|
||||
else //Somehow another option was taken, maybe something interrupted the selection or it was cancelled
|
||||
return //Just end it in that case.
|
||||
|
||||
@@ -153,14 +153,13 @@
|
||||
if(prob(33))
|
||||
if(M.getArousalLoss() >= 100 && ishuman(M) && M.has_dna())
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(prob(50)) //Less spam
|
||||
to_chat(H, "<span class='love'>Your libido is going haywire!</span>")
|
||||
H.mob_climax(forced_climax=TRUE)
|
||||
if(M.min_arousal < 50)
|
||||
M.min_arousal += 1
|
||||
to_chat(M, "<span class='love'>You're having a hard time thinkin about things other than sex!</span>")
|
||||
if(M.min_arousal < M.max_arousal)
|
||||
M.min_arousal += 1
|
||||
to_chat(M, "<span class='love'>You feel your libido permanently increasing.</span>")
|
||||
M.adjustArousalLoss(2)
|
||||
..()
|
||||
|
||||
@@ -197,10 +196,8 @@
|
||||
if(prob(33))
|
||||
if(M.min_arousal > 0)
|
||||
M.min_arousal -= 1
|
||||
to_chat(M, "<span class='notice'>You feel your libido returning to more normal levels.</span>")
|
||||
if(M.min_arousal > 50)
|
||||
M.min_arousal -= 1
|
||||
to_chat(M, "<span class='notice'>You feel like your overactive libido is calming down.</span>")
|
||||
M.adjustArousalLoss(-2)
|
||||
..()
|
||||
|
||||
|
||||
BIN
code/citadel/icons/taur_penis_onmob.dmi
Normal file
BIN
code/citadel/icons/taur_penis_onmob.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 704 B |
@@ -1,5 +1,5 @@
|
||||
/obj/item/organ/genital/breasts
|
||||
name = "Breasts"
|
||||
name = "breasts"
|
||||
desc = "Female milk producing organs."
|
||||
icon_state = "breasts"
|
||||
icon = 'code/citadel/icons/breasts.dmi'
|
||||
@@ -11,6 +11,10 @@
|
||||
var/amount = 2
|
||||
producing = TRUE
|
||||
shape = "pair"
|
||||
can_masturbate_with = TRUE
|
||||
masturbation_verb = "massage"
|
||||
can_climax = TRUE
|
||||
fluid_transfer_factor =0.5
|
||||
|
||||
/obj/item/organ/genital/breasts/Initialize()
|
||||
. = ..()
|
||||
@@ -55,3 +59,9 @@
|
||||
color = "#[skintone2hex(H.skin_tone)]"
|
||||
else
|
||||
color = "#[owner.dna.features["breasts_color"]]"
|
||||
|
||||
/obj/item/organ/genital/breasts/is_exposed()
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
return owner.is_chest_exposed()
|
||||
@@ -7,7 +7,7 @@
|
||||
slot = "testicles"
|
||||
color = null //don't use the /genital color since it already is colored
|
||||
w_class = 3
|
||||
var/internal = TRUE
|
||||
internal = TRUE
|
||||
var/egg_girth = EGG_GIRTH_DEF
|
||||
var/cum_mult = CUM_RATE_MULT
|
||||
var/cum_rate = CUM_RATE
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
var/shape = "human"
|
||||
var/sensitivity = 1
|
||||
var/list/genital_flags = list()
|
||||
var/can_masturbate_with = 0
|
||||
var/can_masturbate_with = FALSE
|
||||
var/masturbation_verb = "masturbate"
|
||||
var/can_climax = FALSE
|
||||
var/fluid_transfer_factor = 0.0 //How much would a partner get in them if they climax using this?
|
||||
var/size = 2 //can vary between num or text, just used in icon_state strings
|
||||
var/fluid_id = null
|
||||
var/fluid_max_volume = 50
|
||||
@@ -13,6 +16,9 @@
|
||||
var/producing = FALSE
|
||||
var/aroused_state = FALSE //Boolean used in icon_state strings
|
||||
var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons.
|
||||
var/obj/item/organ/genital/linked_organ
|
||||
var/through_clothes = FALSE
|
||||
var/internal = FALSE
|
||||
|
||||
/obj/item/organ/genital/Initialize()
|
||||
. = ..()
|
||||
@@ -34,6 +40,52 @@
|
||||
update_appearance()
|
||||
update_link()
|
||||
|
||||
//exposure and through-clothing code
|
||||
/mob/living/carbon
|
||||
var/list/exposed_genitals = list() //Keeping track of them so we don't have to iterate through every genitalia and see if exposed
|
||||
|
||||
/obj/item/organ/genital/proc/is_exposed()
|
||||
if(!owner)
|
||||
return FALSE
|
||||
if(internal)
|
||||
return FALSE
|
||||
if(through_clothes)
|
||||
return TRUE
|
||||
|
||||
/obj/item/organ/genital/proc/toggle_through_clothes()
|
||||
if(through_clothes)
|
||||
through_clothes = FALSE
|
||||
owner.exposed_genitals -= src
|
||||
else
|
||||
through_clothes = TRUE
|
||||
owner.exposed_genitals += src
|
||||
if(ishuman(owner)) //recast to use update genitals proc
|
||||
var/mob/living/carbon/human/H = owner
|
||||
H.update_genitals()
|
||||
|
||||
/mob/living/carbon/verb/toggle_genitals()
|
||||
set category = "IC"
|
||||
set name = "Expose/Hide genitals"
|
||||
set desc = "Allows you to toggle which genitals should show through clothes or not."
|
||||
|
||||
var/list/genital_list = list()
|
||||
for(var/obj/item/organ/O in internal_organs)
|
||||
if(istype(O, /obj/item/organ/genital))
|
||||
var/obj/item/organ/genital/G = O
|
||||
if(!G.internal)
|
||||
genital_list += G
|
||||
if(!genital_list.len) //There is nothing to expose
|
||||
return
|
||||
//Full list of exposable genitals created
|
||||
var/obj/item/organ/genital/picked_organ
|
||||
picked_organ = input(src, "Expose/Hide genitals", "Choose which genitalia to expose/hide", null) in genital_list
|
||||
if(picked_organ)
|
||||
picked_organ.toggle_through_clothes()
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
/obj/item/organ/genital/proc/update_size()
|
||||
|
||||
/obj/item/organ/genital/proc/update_appearance()
|
||||
@@ -41,6 +93,9 @@
|
||||
/obj/item/organ/genital/proc/update_link()
|
||||
|
||||
/obj/item/organ/genital/proc/remove_ref()
|
||||
if(linked_organ)
|
||||
linked_organ.linked_organ = null
|
||||
linked_organ = null
|
||||
|
||||
/obj/item/organ/genital/Insert(mob/living/carbon/M, special = 0)
|
||||
..()
|
||||
@@ -58,21 +113,21 @@
|
||||
var/obj/item/organ/genital/GtoClean
|
||||
for(GtoClean in internal_organs)
|
||||
qdel(GtoClean)
|
||||
|
||||
if(dna.features["has_cock"])
|
||||
give_penis()
|
||||
if(dna.features["has_balls"])
|
||||
give_balls()
|
||||
else if(dna.features["has_ovi"])
|
||||
give_ovipositor()
|
||||
if(dna.features["has_eggsack"])
|
||||
give_eggsack()
|
||||
//Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in.
|
||||
if(dna.features["has_breasts"])
|
||||
give_breasts()
|
||||
if(dna.features["has_vag"])
|
||||
give_vagina()
|
||||
if(dna.features["has_womb"])
|
||||
give_womb()
|
||||
if(dna.features["has_balls"])
|
||||
give_balls()
|
||||
if(dna.features["has_cock"])
|
||||
give_penis()
|
||||
if(dna.features["has_ovi"])
|
||||
give_ovipositor()
|
||||
if(dna.features["has_eggsack"])
|
||||
give_eggsack()
|
||||
|
||||
/mob/living/carbon/human/proc/give_penis()
|
||||
if(!dna)
|
||||
@@ -208,17 +263,15 @@
|
||||
if(H.disabilities & HUSK)
|
||||
return
|
||||
//start scanning for genitals
|
||||
var/list/worn_stuff = H.get_equipped_items()//cache this list so it's not built again
|
||||
if(H.is_groin_exposed(worn_stuff))
|
||||
//ORDER is important here. Vaginas first, theoretical testes after, and penis LAST.
|
||||
//The latter is always drawn on top of the former.
|
||||
if(H.has_vagina())
|
||||
genitals_to_add += H.getorganslot("vagina")
|
||||
if(H.has_penis())
|
||||
genitals_to_add += H.getorganslot("penis")
|
||||
if(H.is_chest_exposed(worn_stuff))
|
||||
if(H.has_breasts())
|
||||
genitals_to_add += H.getorganslot("breasts")
|
||||
//var/list/worn_stuff = H.get_equipped_items()//cache this list so it's not built again
|
||||
|
||||
for(var/obj/item/organ/O in H.internal_organs)
|
||||
if(istype(O, /obj/item/organ/genital))
|
||||
var/obj/item/organ/genital/G = O
|
||||
if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes
|
||||
genitals_to_add += H.getorganslot(G.slot)
|
||||
//Now we added all genitals that aren't internal and should be rendered
|
||||
|
||||
var/image/I
|
||||
//start applying overlays
|
||||
for(var/layer in relevant_layers)
|
||||
@@ -243,8 +296,10 @@
|
||||
G.aroused_state = FALSE
|
||||
icon_string = "[G.slot]_[S.icon_state]_[size]_[G.aroused_state]_[layertext]"
|
||||
I = image("icon" = S.icon, "icon_state" = icon_string, "layer" =- layer)
|
||||
|
||||
if(S.center)
|
||||
I = center_image(I,S.dimension_x,S.dimension_y)
|
||||
|
||||
if(use_skintones && H.dna.features["genitals_use_skintone"])
|
||||
I.color = "#[skintone2hex(H.skin_tone)]"
|
||||
else
|
||||
|
||||
@@ -31,6 +31,33 @@
|
||||
icon_state = "tapered"
|
||||
name = "Tapered"
|
||||
|
||||
////////////////////////
|
||||
// Taur cocks go here //
|
||||
////////////////////////
|
||||
/datum/sprite_accessory/penis/taur_flared
|
||||
icon = 'code/citadel/icons/taur_penis_onmob.dmi' //Needed larger width
|
||||
icon_state = "flared"
|
||||
name = "Taur, Flared"
|
||||
center = TRUE //Center the image 'cause 2-tile wide.
|
||||
dimension_x = 64
|
||||
|
||||
/datum/sprite_accessory/penis/taur_knotted
|
||||
icon = 'code/citadel/icons/taur_penis_onmob.dmi' //Needed larger width
|
||||
icon_state = "knotted"
|
||||
name = "Taur, Knotted"
|
||||
center = TRUE //Center the image 'cause 2-tile wide.
|
||||
dimension_x = 64
|
||||
|
||||
/datum/sprite_accessory/penis/taur_tapered
|
||||
icon = 'code/citadel/icons/taur_penis_onmob.dmi' //Needed larger width
|
||||
icon_state = "tapered"
|
||||
name = "Taur, Tapered"
|
||||
center = TRUE //Center the image 'cause 2-tile wide.
|
||||
dimension_x = 64
|
||||
|
||||
|
||||
|
||||
|
||||
//Vaginas
|
||||
/datum/sprite_accessory/vagina
|
||||
icon = 'code/citadel/icons/vagina_onmob.dmi'
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
/obj/item/organ/genital/penis
|
||||
name = "Penis"
|
||||
name = "penis"
|
||||
desc = "A male reproductive organ."
|
||||
icon_state = "penis"
|
||||
icon = 'code/citadel/icons/penis.dmi'
|
||||
zone = "groin"
|
||||
slot = "penis"
|
||||
w_class = 3
|
||||
can_masturbate_with = 1
|
||||
can_masturbate_with = TRUE
|
||||
masturbation_verb = "stroke"
|
||||
can_climax = TRUE
|
||||
fluid_transfer_factor = 0.5
|
||||
size = 2 //arbitrary value derived from length and girth for sprites.
|
||||
var/length = 6 //inches
|
||||
var/cached_length //used to detect a change in length
|
||||
@@ -15,7 +18,6 @@
|
||||
var/knot_girth_ratio = KNOT_GIRTH_RATIO_DEF
|
||||
var/list/dickflags = list()
|
||||
var/list/knotted_types = list("knotted", "barbknot")
|
||||
var/obj/item/organ/genital/testicles/linked_balls
|
||||
|
||||
/obj/item/organ/genital/penis/update_size()
|
||||
if(length == cached_length)
|
||||
@@ -35,7 +37,7 @@
|
||||
cached_length = length
|
||||
|
||||
/obj/item/organ/genital/penis/update_appearance()
|
||||
var/string = "penis_[lowertext(shape)]_[size]"
|
||||
var/string = "penis_[GLOB.cock_shapes_icons[shape]]_[size]"
|
||||
icon_state = sanitize_text(string)
|
||||
var/lowershape = lowertext(shape)
|
||||
if(lowershape in knotted_types)
|
||||
@@ -55,15 +57,16 @@
|
||||
|
||||
/obj/item/organ/genital/penis/update_link()
|
||||
if(owner)
|
||||
linked_balls = (owner.getorganslot("testicles"))
|
||||
if(linked_balls)
|
||||
linked_balls.linked_penis = src
|
||||
linked_organ = (owner.getorganslot("testicles"))
|
||||
if(linked_organ)
|
||||
linked_organ.linked_organ = src
|
||||
else
|
||||
if(linked_balls)
|
||||
linked_balls.linked_penis = null
|
||||
linked_balls = null
|
||||
if(linked_organ)
|
||||
linked_organ.linked_organ = null
|
||||
linked_organ = null
|
||||
|
||||
/obj/item/organ/genital/penis/remove_ref()
|
||||
if(linked_balls)
|
||||
linked_balls.linked_penis = null
|
||||
linked_balls = null
|
||||
/obj/item/organ/genital/penis/is_exposed()
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
return owner.is_groin_exposed()
|
||||
@@ -1,18 +1,17 @@
|
||||
/obj/item/organ/genital/testicles
|
||||
name = "Testicles"
|
||||
name = "testicles"
|
||||
desc = "A male reproductive organ."
|
||||
icon_state = "testicles"
|
||||
icon = 'code/citadel/icons/penis.dmi'
|
||||
zone = "groin"
|
||||
slot = "testicles"
|
||||
w_class = 3
|
||||
var/internal = FALSE
|
||||
internal = TRUE
|
||||
size = BALLS_SIZE_DEF
|
||||
var/sack_size = BALLS_SACK_SIZE_DEF
|
||||
fluid_id = "semen"
|
||||
producing = TRUE
|
||||
var/sent_full_message = 1 //defaults to 1 since they're full to start
|
||||
var/obj/item/organ/genital/penis/linked_penis
|
||||
|
||||
/obj/item/organ/genital/testicles/Initialize()
|
||||
. = ..()
|
||||
@@ -33,20 +32,20 @@
|
||||
return FALSE
|
||||
sent_full_message = 0
|
||||
update_link()
|
||||
if(!linked_penis)
|
||||
if(!linked_organ)
|
||||
return FALSE
|
||||
reagents.isolate_reagent(fluid_id)//remove old reagents if it changed and just clean up generally
|
||||
reagents.add_reagent(fluid_id, (fluid_mult * fluid_rate))//generate the cum
|
||||
|
||||
/obj/item/organ/genital/testicles/update_link()
|
||||
if(owner && !QDELETED(src))
|
||||
linked_penis = (owner.getorganslot("penis"))
|
||||
if(linked_penis)
|
||||
linked_penis.linked_balls = src
|
||||
linked_organ = (owner.getorganslot("penis"))
|
||||
if(linked_organ)
|
||||
linked_organ.linked_organ = src
|
||||
else
|
||||
if(linked_penis)
|
||||
linked_penis.linked_balls = null
|
||||
linked_penis = null
|
||||
if(linked_organ)
|
||||
linked_organ.linked_organ = null
|
||||
linked_organ = null
|
||||
|
||||
/obj/item/organ/genital/testicles/proc/send_full_message(msg = "Your balls finally feel full, again.")
|
||||
if(owner && istext(msg))
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
/obj/item/organ/genital/vagina
|
||||
name = "Vagina"
|
||||
name = "vagina"
|
||||
desc = "A female reproductive organ."
|
||||
icon = 'code/citadel/icons/vagina.dmi'
|
||||
icon_state = "vagina"
|
||||
zone = "groin"
|
||||
slot = "vagina"
|
||||
size = 1 //There is only 1 size right now
|
||||
can_masturbate_with = 1
|
||||
can_masturbate_with = TRUE
|
||||
masturbation_verb = "finger"
|
||||
can_climax = TRUE
|
||||
fluid_transfer_factor = 0.1 //Yes, some amount is exposed to you, go get your AIDS
|
||||
w_class = 3
|
||||
var/cap_length = 8//D E P T H (cap = capacity)
|
||||
var/cap_girth = 12
|
||||
@@ -15,7 +18,6 @@
|
||||
var/clit_diam = 0.25
|
||||
var/clit_len = 0.25
|
||||
var/list/vag_types = list("tentacle", "dentata", "hairy")
|
||||
var/obj/item/organ/genital/womb/linked_womb
|
||||
|
||||
|
||||
/obj/item/organ/genital/vagina/update_appearance()
|
||||
@@ -56,15 +58,16 @@
|
||||
|
||||
/obj/item/organ/genital/vagina/update_link()
|
||||
if(owner)
|
||||
linked_womb = (owner.getorganslot("womb"))
|
||||
if(linked_womb)
|
||||
linked_womb.linked_vag = src
|
||||
linked_organ = (owner.getorganslot("womb"))
|
||||
if(linked_organ)
|
||||
linked_organ.linked_organ = src
|
||||
else
|
||||
if(linked_womb)
|
||||
linked_womb.linked_vag = null
|
||||
linked_womb = null
|
||||
if(linked_organ)
|
||||
linked_organ.linked_organ = null
|
||||
linked_organ = null
|
||||
|
||||
/obj/item/organ/genital/vagina/remove_ref()
|
||||
if(linked_womb)
|
||||
linked_womb.linked_vag = null
|
||||
linked_womb = null
|
||||
/obj/item/organ/genital/vagina/is_exposed()
|
||||
. = ..()
|
||||
if(.)
|
||||
return TRUE
|
||||
return owner.is_groin_exposed()
|
||||
@@ -1,15 +1,15 @@
|
||||
/obj/item/organ/genital/womb
|
||||
name = "Womb"
|
||||
name = "womb"
|
||||
desc = "A female reproductive organ."
|
||||
icon = 'code/citadel/icons/vagina.dmi'
|
||||
icon_state = "womb"
|
||||
zone = "groin"
|
||||
slot = "womb"
|
||||
w_class = 3
|
||||
var/internal = FALSE
|
||||
internal = TRUE
|
||||
fluid_id = "femcum"
|
||||
producing = TRUE
|
||||
var/obj/item/organ/genital/vagina/linked_vag
|
||||
|
||||
|
||||
/obj/item/organ/genital/womb/Initialize()
|
||||
. = ..()
|
||||
@@ -24,25 +24,20 @@
|
||||
/obj/item/organ/genital/womb/proc/generate_femcum()
|
||||
reagents.maximum_volume = fluid_max_volume
|
||||
update_link()
|
||||
if(!linked_vag)
|
||||
if(!linked_organ)
|
||||
return FALSE
|
||||
reagents.isolate_reagent(fluid_id)//remove old reagents if it changed and just clean up generally
|
||||
reagents.add_reagent(fluid_id, (fluid_mult * fluid_rate))//generate the cum
|
||||
|
||||
/obj/item/organ/genital/womb/update_link()
|
||||
if(owner)
|
||||
linked_vag = (owner.getorganslot("vagina"))
|
||||
if(linked_vag)
|
||||
linked_vag.linked_womb = src
|
||||
linked_organ = (owner.getorganslot("vagina"))
|
||||
if(linked_organ)
|
||||
linked_organ.linked_organ = src
|
||||
else
|
||||
if(linked_vag)
|
||||
linked_vag.linked_womb = null
|
||||
linked_vag = null
|
||||
|
||||
/obj/item/organ/genital/womb/remove_ref()
|
||||
if(linked_vag)
|
||||
linked_vag.linked_womb = null
|
||||
linked_vag = null
|
||||
if(linked_organ)
|
||||
linked_organ.linked_organ = null
|
||||
linked_organ = null
|
||||
|
||||
/obj/item/organ/genital/womb/Destroy()
|
||||
return ..()
|
||||
|
||||
@@ -275,7 +275,7 @@
|
||||
|
||||
if(M.config_tag)
|
||||
if(!(M.config_tag in modes)) // ensure each mode is added only once
|
||||
GLOB.config_error_log << "Adding game mode [M.name] ([M.config_tag]) to configuration."
|
||||
WRITE_FILE(GLOB.config_error_log, "Adding game mode [M.name] ([M.config_tag]) to configuration.")
|
||||
modes += M.config_tag
|
||||
mode_names[M.config_tag] = M.name
|
||||
probabilities[M.config_tag] = M.probability
|
||||
@@ -548,7 +548,7 @@
|
||||
if("irc_announce_new_game")
|
||||
irc_announce_new_game = TRUE
|
||||
else
|
||||
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'")
|
||||
|
||||
else if(type == "game_options")
|
||||
switch(name)
|
||||
@@ -611,13 +611,13 @@
|
||||
if(mode_name in modes)
|
||||
continuous[mode_name] = 1
|
||||
else
|
||||
GLOB.config_error_log << "Unknown continuous configuration definition: [mode_name]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown continuous configuration definition: [mode_name].")
|
||||
if("midround_antag")
|
||||
var/mode_name = lowertext(value)
|
||||
if(mode_name in modes)
|
||||
midround_antag[mode_name] = 1
|
||||
else
|
||||
GLOB.config_error_log << "Unknown midround antagonist configuration definition: [mode_name]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown midround antagonist configuration definition: [mode_name].")
|
||||
if("midround_antag_time_check")
|
||||
midround_antag_time_check = text2num(value)
|
||||
if("midround_antag_life_check")
|
||||
@@ -633,9 +633,9 @@
|
||||
if(mode_name in modes)
|
||||
min_pop[mode_name] = text2num(mode_value)
|
||||
else
|
||||
GLOB.config_error_log << "Unknown minimum population configuration definition: [mode_name]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown minimum population configuration definition: [mode_name].")
|
||||
else
|
||||
GLOB.config_error_log << "Incorrect minimum population configuration definition: [mode_name] [mode_value]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Incorrect minimum population configuration definition: [mode_name] [mode_value].")
|
||||
if("max_pop")
|
||||
var/pop_pos = findtext(value, " ")
|
||||
var/mode_name = null
|
||||
@@ -647,9 +647,9 @@
|
||||
if(mode_name in modes)
|
||||
max_pop[mode_name] = text2num(mode_value)
|
||||
else
|
||||
GLOB.config_error_log << "Unknown maximum population configuration definition: [mode_name]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown maximum population configuration definition: [mode_name].")
|
||||
else
|
||||
GLOB.config_error_log << "Incorrect maximum population configuration definition: [mode_name] [mode_value]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Incorrect maximum population configuration definition: [mode_name] [mode_value].")
|
||||
if("shuttle_refuel_delay")
|
||||
shuttle_refuel_delay = text2num(value)
|
||||
if("show_game_type_odds")
|
||||
@@ -677,9 +677,9 @@
|
||||
if(prob_name in modes)
|
||||
probabilities[prob_name] = text2num(prob_value)
|
||||
else
|
||||
GLOB.config_error_log << "Unknown game mode probability configuration definition: [prob_name]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown game mode probability configuration definition: [prob_name].")
|
||||
else
|
||||
GLOB.config_error_log << "Incorrect probability configuration definition: [prob_name] [prob_value]."
|
||||
WRITE_FILE(GLOB.config_error_log, "Incorrect probability configuration definition: [prob_name] [prob_value].")
|
||||
|
||||
if("protect_roles_from_antagonist")
|
||||
protect_roles_from_antagonist = 1
|
||||
@@ -726,7 +726,7 @@
|
||||
// Value is in the form "LAWID,NUMBER"
|
||||
var/list/L = splittext(value, ",")
|
||||
if(L.len != 2)
|
||||
GLOB.config_error_log << "Invalid LAW_WEIGHT: " + t
|
||||
WRITE_FILE(GLOB.config_error_log, "Invalid LAW_WEIGHT: " + t)
|
||||
continue
|
||||
var/lawid = L[1]
|
||||
var/weight = text2num(L[2])
|
||||
@@ -781,7 +781,7 @@
|
||||
if("mice_roundstart")
|
||||
mice_roundstart = text2num(value)
|
||||
else
|
||||
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'")
|
||||
else if(type == "policies")
|
||||
policies[name] = value
|
||||
|
||||
@@ -839,7 +839,7 @@
|
||||
if ("disabled")
|
||||
currentmap = null
|
||||
else
|
||||
GLOB.config_error_log << "Unknown command in map vote config: '[command]'"
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown command in map vote config: '[command]'")
|
||||
|
||||
|
||||
/datum/configuration/proc/loadsql(filename)
|
||||
@@ -883,7 +883,7 @@
|
||||
if("feedback_tableprefix")
|
||||
global.sqlfdbktableprefix = value
|
||||
else
|
||||
GLOB.config_error_log << "Unknown setting in configuration: '[name]'"
|
||||
WRITE_FILE(GLOB.config_error_log, "Unknown setting in configuration: '[name]'")
|
||||
|
||||
/datum/configuration/proc/pick_mode(mode_name)
|
||||
// I wish I didn't have to instance the game modes in order to look up
|
||||
|
||||
@@ -3,12 +3,15 @@ SUBSYSTEM_DEF(assets)
|
||||
init_order = INIT_ORDER_ASSETS
|
||||
flags = SS_NO_FIRE
|
||||
var/list/cache = list()
|
||||
var/list/preload = list()
|
||||
|
||||
/datum/controller/subsystem/assets/Initialize(timeofday)
|
||||
for(var/type in typesof(/datum/asset) - list(/datum/asset, /datum/asset/simple))
|
||||
var/datum/asset/A = new type()
|
||||
A.register()
|
||||
|
||||
preload = cache.Copy() //don't preload assets generated during the round
|
||||
|
||||
for(var/client/C in GLOB.clients)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, cache, FALSE), 10)
|
||||
addtimer(CALLBACK(GLOBAL_PROC, .proc/getFilesSlow, C, preload, FALSE), 10)
|
||||
..()
|
||||
|
||||
@@ -260,9 +260,9 @@ SUBSYSTEM_DEF(blackbox)
|
||||
/datum/feedback_variable/proc/add_details(text)
|
||||
if (istext(text))
|
||||
if (!details)
|
||||
details = text
|
||||
details = "\"[text]\""
|
||||
else
|
||||
details += " [text]"
|
||||
details += " | \"[text]\""
|
||||
|
||||
/datum/feedback_variable/proc/get_details()
|
||||
return details
|
||||
|
||||
@@ -149,7 +149,6 @@ SUBSYSTEM_DEF(pai)
|
||||
continue
|
||||
if(!(ROLE_PAI in G.client.prefs.be_special))
|
||||
continue
|
||||
//G << 'sound/misc/server-ready.ogg' //Alerting them to their consideration
|
||||
to_chat(G, "<span class='ghostalert'>[user] is requesting a pAI personality! Use the pAI button to submit yourself as one.</span>")
|
||||
addtimer(CALLBACK(src, .proc/spam_again), spam_delay)
|
||||
var/list/available = list()
|
||||
|
||||
@@ -49,7 +49,7 @@ SUBSYSTEM_DEF(persistence)
|
||||
satchel_string = pick_n_take(expanded_old_satchels)
|
||||
|
||||
old_secret_satchels = jointext(expanded_old_satchels,"#")
|
||||
secret_satchels[SSmapping.config.map_name] << old_secret_satchels
|
||||
WRITE_FILE(secret_satchels[SSmapping.config.map_name], old_secret_satchels)
|
||||
|
||||
var/list/chosen_satchel = splittext(satchel_string,"|")
|
||||
if(!chosen_satchel || isemptylist(chosen_satchel) || chosen_satchel.len != 3) //Malformed
|
||||
@@ -171,7 +171,7 @@ SUBSYSTEM_DEF(persistence)
|
||||
if(isemptylist(savable_obj))
|
||||
continue
|
||||
old_secret_satchels += "[F.x]|[F.y]|[pick(savable_obj)]#"
|
||||
secret_satchels[SSmapping.config.map_name] << old_secret_satchels
|
||||
WRITE_FILE(secret_satchels[SSmapping.config.map_name], old_secret_satchels)
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectChiselMessages()
|
||||
var/savefile/chisel_messages_sav = new /savefile("data/npc_saves/ChiselMessages.sav")
|
||||
@@ -181,14 +181,14 @@ SUBSYSTEM_DEF(persistence)
|
||||
|
||||
log_world("Saved [saved_messages.len] engraved messages on map [SSmapping.config.map_name]")
|
||||
|
||||
chisel_messages_sav[SSmapping.config.map_name] << json_encode(saved_messages)
|
||||
WRITE_FILE(chisel_messages_sav[SSmapping.config.map_name], json_encode(saved_messages))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveChiselMessage(obj/structure/chisel_message/M)
|
||||
saved_messages += list(M.pack()) // dm eats one list
|
||||
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/CollectTrophies()
|
||||
trophy_sav << json_encode(saved_trophies)
|
||||
WRITE_FILE(trophy_sav, json_encode(saved_trophies))
|
||||
|
||||
/datum/controller/subsystem/persistence/proc/SaveTrophy(obj/structure/displaycase/trophy/T)
|
||||
if(!T.added_roundstart && T.showpiece)
|
||||
|
||||
@@ -101,8 +101,6 @@ SUBSYSTEM_DEF(shuttle)
|
||||
T.color = "#00ffff"
|
||||
#endif
|
||||
|
||||
//world.log << "[transit_turfs.len] transit turfs registered"
|
||||
|
||||
/datum/controller/subsystem/shuttle/fire()
|
||||
for(var/thing in mobile)
|
||||
if(!thing)
|
||||
|
||||
@@ -225,7 +225,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
round_start_time = world.time
|
||||
|
||||
to_chat(world, "<FONT color='blue'><B>Welcome to [station_name()], enjoy your stay!</B></FONT>")
|
||||
world << sound('sound/ai/welcome.ogg')
|
||||
SEND_SOUND(world, sound('sound/ai/welcome.ogg'))
|
||||
|
||||
current_state = GAME_STATE_PLAYING
|
||||
Master.SetRunLevel(RUNLEVEL_GAME)
|
||||
@@ -300,7 +300,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
if("nuclear emergency") //Nuke wasn't on station when it blew up
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
flick("station_intact_fade_red",cinematic)
|
||||
cinematic.icon_state = "summary_nukefail"
|
||||
@@ -308,12 +308,12 @@ SUBSYSTEM_DEF(ticker)
|
||||
cinematic.icon_state = null
|
||||
flick("intro_cult",cinematic)
|
||||
sleep(25)
|
||||
world << sound('sound/magic/enter_blood.ogg')
|
||||
SEND_SOUND(world, sound('sound/magic/enter_blood.ogg'))
|
||||
sleep(28)
|
||||
world << sound('sound/machines/terminal_off.ogg')
|
||||
SEND_SOUND(world, sound('sound/machines/terminal_off.ogg'))
|
||||
sleep(20)
|
||||
flick("station_corrupted",cinematic)
|
||||
world << sound('sound/effects/ghost.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/ghost.ogg'))
|
||||
actually_blew_up = FALSE
|
||||
if("gang war") //Gang Domination (just show the override screen)
|
||||
cinematic.icon_state = "intro_malf_still"
|
||||
@@ -323,19 +323,19 @@ SUBSYSTEM_DEF(ticker)
|
||||
if("fake") //The round isn't over, we're just freaking people out for fun
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/items/bikehorn.ogg')
|
||||
SEND_SOUND(world, sound('sound/items/bikehorn.ogg'))
|
||||
flick("summary_selfdes",cinematic)
|
||||
actually_blew_up = FALSE
|
||||
else
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
|
||||
|
||||
if(NUKE_MISS_STATION || NUKE_SYNDICATE_BASE) //nuke was nowhere nearby //TODO: a really distant explosion animation
|
||||
sleep(50)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
actually_blew_up = station_missed == NUKE_SYNDICATE_BASE //don't kill everyone on station if it detonated off station
|
||||
else //station was destroyed
|
||||
@@ -346,42 +346,42 @@ SUBSYSTEM_DEF(ticker)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
cinematic.icon_state = "summary_nukewin"
|
||||
if("AI malfunction") //Malf (screen,explosion,summary)
|
||||
flick("intro_malf",cinematic)
|
||||
sleep(76)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb) //TODO: If we ever decide to actually detonate the vault bomb
|
||||
cinematic.icon_state = "summary_malf"
|
||||
if("blob") //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb) //TODO: no idea what this case could be
|
||||
cinematic.icon_state = "summary_selfdes"
|
||||
if("cult") //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red",cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb) //TODO: no idea what this case could be
|
||||
cinematic.icon_state = "summary_cult"
|
||||
if("no_core") //Nuke failed to detonate as it had no core
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_intact",cinematic)
|
||||
world << sound('sound/ambience/signal.ogg')
|
||||
SEND_SOUND(world, sound('sound/ambience/signal.ogg'))
|
||||
addtimer(CALLBACK(src, .proc/finish_cinematic, null, FALSE), 100)
|
||||
return //Faster exit, since nothing happened
|
||||
else //Station nuked (nuke,explosion,summary)
|
||||
flick("intro_nuke",cinematic)
|
||||
sleep(35)
|
||||
flick("station_explode_fade_red", cinematic)
|
||||
world << sound('sound/effects/explosionfar.ogg')
|
||||
SEND_SOUND(world, sound('sound/effects/explosion_distant.ogg'))
|
||||
station_explosion_detonation(bomb)
|
||||
cinematic.icon_state = "summary_selfdes"
|
||||
//If its actually the end of the round, wait for it to end.
|
||||
@@ -636,7 +636,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
if(living_player_count() < config.hard_popcap)
|
||||
if(next_in_line && next_in_line.client)
|
||||
to_chat(next_in_line, "<span class='userdanger'>A slot has opened! You have approximately 20 seconds to join. <a href='?src=\ref[next_in_line];late_join=override'>\>\>Join Game\<\<</a></span>")
|
||||
next_in_line << sound('sound/misc/notice1.ogg')
|
||||
SEND_SOUND(next_in_line, sound('sound/misc/notice1.ogg'))
|
||||
next_in_line.LateChoices()
|
||||
return
|
||||
queued_players -= next_in_line //Client disconnected, remove he
|
||||
@@ -804,7 +804,7 @@ SUBSYSTEM_DEF(ticker)
|
||||
/datum/controller/subsystem/ticker/proc/save_mode(the_mode)
|
||||
var/F = file("data/mode.txt")
|
||||
fdel(F)
|
||||
F << the_mode
|
||||
WRITE_FILE(F, the_mode)
|
||||
|
||||
/datum/controller/subsystem/ticker/proc/SetRoundEndSound(the_sound)
|
||||
set waitfor = FALSE
|
||||
@@ -858,4 +858,4 @@ SUBSYSTEM_DEF(ticker)
|
||||
'sound/roundend/disappointed.ogg'\
|
||||
)
|
||||
|
||||
world << sound(round_end_sound)
|
||||
SEND_SOUND(world, sound(round_end_sound))
|
||||
|
||||
@@ -53,7 +53,7 @@ SUBSYSTEM_DEF(title)
|
||||
/datum/controller/subsystem/title/Shutdown()
|
||||
if(file_path)
|
||||
var/F = file("data/previous_title.dat")
|
||||
F << file_path
|
||||
WRITE_FILE(F, file_path)
|
||||
|
||||
for(var/thing in GLOB.clients)
|
||||
if(!thing)
|
||||
|
||||
@@ -490,7 +490,8 @@
|
||||
var/obj/effect/proc_holder/spell/S = target
|
||||
S.action = src
|
||||
name = S.name
|
||||
icon_icon = S.action_icon
|
||||
desc = S.desc
|
||||
button_icon = S.action_icon
|
||||
button_icon_state = S.action_icon_state
|
||||
background_icon_state = S.action_background_icon_state
|
||||
button.name = name
|
||||
|
||||
@@ -280,7 +280,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
|
||||
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>")
|
||||
world << 'sound/hallucinations/veryfar_noise.ogg'
|
||||
SEND_SOUND(world, sound('sound/hallucinations/veryfar_noise.ogg'))
|
||||
give_appropriate_spells()
|
||||
D.convert_to_archdevil()
|
||||
if(istype(D.loc, /obj/effect/dummy/slaughter/))
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
|
||||
|
||||
/datum/antagonist/ninja/greet()
|
||||
owner.current << sound('sound/effects/ninja_greeting.ogg')
|
||||
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.")
|
||||
|
||||
@@ -100,3 +100,57 @@
|
||||
if (object == GLOBAL_PROC)
|
||||
return call(delegate)(arglist(calling_arguments))
|
||||
return call(object, delegate)(arglist(calling_arguments))
|
||||
|
||||
|
||||
/datum/callback_select
|
||||
var/list/finished
|
||||
var/pendingcount
|
||||
var/total
|
||||
|
||||
/datum/callback_select/New(count, savereturns)
|
||||
total = count
|
||||
if (savereturns)
|
||||
finished = new(count)
|
||||
|
||||
|
||||
/datum/callback_select/proc/invoke_callback(index, datum/callback/callback, list/callback_args, savereturn = TRUE)
|
||||
set waitfor = FALSE
|
||||
if (!callback || !istype(callback))
|
||||
//This check only exists because the alternative is callback_select would block forever if given invalid data
|
||||
CRASH("invalid callback passed to invoke_callback")
|
||||
if (!length(callback_args))
|
||||
callback_args = list()
|
||||
pendingcount++
|
||||
var/rtn = callback.Invoke(arglist(callback_args))
|
||||
pendingcount--
|
||||
if (savereturn)
|
||||
finished[index] = rtn
|
||||
|
||||
|
||||
|
||||
|
||||
//runs a list of callbacks asynchronously, returning once all of them return.
|
||||
//callbacks can be repeated.
|
||||
//callbacks-args is a optional list of argument lists, in the same order as the callbacks,
|
||||
// the inner lists will be sent to the callbacks when invoked() as additional args.
|
||||
//can optionly save and return a list of return values, in the same order as the original list of callbacks
|
||||
//resolution is the number of byond ticks between checks.
|
||||
/proc/callback_select(list/callbacks, list/callback_args, savereturns = TRUE, resolution = 1)
|
||||
if (!callbacks)
|
||||
return
|
||||
var/count = length(callbacks)
|
||||
if (!count)
|
||||
return
|
||||
if (!callback_args)
|
||||
callback_args = list()
|
||||
|
||||
callback_args.len = count
|
||||
|
||||
var/datum/callback_select/CS = new(count, savereturns)
|
||||
for (var/i in 1 to count)
|
||||
CS.invoke_callback(i, callbacks[i], callback_args[i], savereturns)
|
||||
|
||||
while(CS.pendingcount)
|
||||
sleep(resolution*world.tick_lag)
|
||||
return CS.finished
|
||||
|
||||
|
||||
62
code/datums/callback.dm.rej
Normal file
62
code/datums/callback.dm.rej
Normal file
@@ -0,0 +1,62 @@
|
||||
diff a/code/datums/callback.dm b/code/datums/callback.dm (rejected hunks)
|
||||
@@ -100,60 +100,3 @@
|
||||
if (object == GLOBAL_PROC)
|
||||
return call(delegate)(arglist(calling_arguments))
|
||||
return call(object, delegate)(arglist(calling_arguments))
|
||||
-
|
||||
-
|
||||
-/datum/callback_select
|
||||
- var/list/finished
|
||||
- var/pendingcount
|
||||
- var/total
|
||||
-
|
||||
-/datum/callback_select/New(count, savereturns)
|
||||
- total = count
|
||||
- if (savereturns)
|
||||
- finished = new(count)
|
||||
-
|
||||
-
|
||||
-/datum/callback_select/proc/invoke_callback(index, datum/callback/callback, list/callback_args, savereturn = TRUE)
|
||||
- set waitfor = FALSE
|
||||
- if (!callback || !istype(callback))
|
||||
- //This check only exists because the alternative is callback_select would block forever if given invalid data
|
||||
- CRASH("invalid callback passed to invoke_callback")
|
||||
- if (!length(callback_args))
|
||||
- callback_args = list()
|
||||
- pendingcount++
|
||||
- debug_usr("calling callback")
|
||||
- var/rtn = callback.Invoke(arglist(callback_args))
|
||||
- debug_usr("callback returned")
|
||||
- pendingcount--
|
||||
- if (savereturn)
|
||||
- finished[index] = rtn
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-//runs a list of callbacks asynchronously, returning once all of them return.
|
||||
-//callbacks can be repeated.
|
||||
-//callbacks-args is a optional list of argument lists, in the same order as the callbacks,
|
||||
-// the inner lists will be sent to the callbacks when invoked() as additional args.
|
||||
-//can optionly save and return a list of return values, in the same order as the original list of callbacks
|
||||
-//resolution is the number of byond ticks between checks.
|
||||
-/proc/callback_select(list/callbacks, list/callback_args, savereturns = TRUE, resolution = 1)
|
||||
- if (!callbacks)
|
||||
- return
|
||||
- var/count = length(callbacks)
|
||||
- if (!count)
|
||||
- return
|
||||
- if (!callback_args)
|
||||
- callback_args = list()
|
||||
-
|
||||
- callback_args.len = count
|
||||
-
|
||||
- var/datum/callback_select/CS = new(count, savereturns)
|
||||
- for (var/i in 1 to count)
|
||||
- CS.invoke_callback(i, callbacks[i], callback_args[i], savereturns)
|
||||
- debug_usr("starting callbacks: [CS.pendingcount]")
|
||||
- while(CS.pendingcount)
|
||||
- debug_usr("callbacks: [CS.pendingcount]")
|
||||
- sleep(resolution*world.tick_lag)
|
||||
- return CS.finished
|
||||
-
|
||||
@@ -18,7 +18,38 @@
|
||||
qdel(src)
|
||||
return
|
||||
P.SendSignal(COMSIG_COMPONENT_ADDED, src)
|
||||
LAZYADD(P.datum_components, src)
|
||||
|
||||
//lazy init the parent's dc list
|
||||
var/list/dc = P.datum_components
|
||||
if(!dc)
|
||||
P.datum_components = dc = list()
|
||||
|
||||
//set up the typecache
|
||||
var/our_type = type
|
||||
for(var/I in _GetInverseTypeListExceptRoot(our_type))
|
||||
var/test = dc[I]
|
||||
if(test) //already another component of this type here
|
||||
var/list/components_of_type
|
||||
if(!islist(test))
|
||||
components_of_type = list(test)
|
||||
dc[I] = components_of_type
|
||||
else
|
||||
components_of_type = test
|
||||
if(I == our_type) //exact match, take priority
|
||||
var/inserted = FALSE
|
||||
for(var/J in 1 to components_of_type.len)
|
||||
var/datum/component/C = components_of_type[J]
|
||||
if(C.type != our_type) //but not over other exact matches
|
||||
components_of_type.Insert(J, I)
|
||||
inserted = TRUE
|
||||
break
|
||||
if(!inserted)
|
||||
components_of_type += src
|
||||
else //indirect match, back of the line with ya
|
||||
components_of_type += src
|
||||
else //only component of this type, no list
|
||||
dc[I] = src
|
||||
|
||||
parent = P
|
||||
|
||||
/datum/component/Destroy()
|
||||
@@ -33,7 +64,20 @@
|
||||
/datum/component/proc/_RemoveNoSignal()
|
||||
var/datum/P = parent
|
||||
if(P)
|
||||
LAZYREMOVE(P.datum_components, src)
|
||||
var/list/dc = P.datum_components
|
||||
var/our_type = type
|
||||
for(var/I in _GetInverseTypeListExceptRoot(our_type))
|
||||
var/list/components_of_type = dc[I]
|
||||
if(islist(components_of_type)) //
|
||||
var/list/subtracted = components_of_type - src
|
||||
if(subtracted.len == 1) //only 1 guy left
|
||||
dc[I] = subtracted[1] //make him special
|
||||
else
|
||||
dc[I] = subtracted
|
||||
else //just us
|
||||
dc -= I
|
||||
if(!dc.len)
|
||||
P.datum_components = null
|
||||
parent = null
|
||||
|
||||
/datum/component/proc/RegisterSignal(sig_type, proc_on_self, override = FALSE)
|
||||
@@ -66,6 +110,13 @@
|
||||
/datum/component/proc/OnTransfer(datum/new_parent)
|
||||
return
|
||||
|
||||
/datum/component/proc/_GetInverseTypeListExceptRoot(our_type_cached)
|
||||
var/datum/component/current_type = our_type_cached
|
||||
. = list()
|
||||
while (current_type != /datum/component)
|
||||
. += current_type
|
||||
current_type = type2parent(current_type)
|
||||
|
||||
/datum/proc/SendSignal(sigtype, ...)
|
||||
var/list/comps = datum_components
|
||||
. = FALSE
|
||||
@@ -81,21 +132,32 @@
|
||||
return
|
||||
|
||||
/datum/proc/GetComponent(c_type)
|
||||
for(var/I in datum_components)
|
||||
if(istype(I, c_type))
|
||||
return I
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
return null
|
||||
. = dc[c_type]
|
||||
if(islist(.))
|
||||
return .[1]
|
||||
|
||||
/datum/proc/GetExactComponent(c_type)
|
||||
for(var/I in datum_components)
|
||||
var/datum/component/C = I
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
return null
|
||||
var/datum/component/C = dc[c_type]
|
||||
if(C)
|
||||
if(islist(C))
|
||||
C = C[1]
|
||||
if(C.type == c_type)
|
||||
return I
|
||||
return C
|
||||
return null
|
||||
|
||||
/datum/proc/GetComponents(c_type)
|
||||
. = list()
|
||||
for(var/I in datum_components)
|
||||
if(istype(I, c_type))
|
||||
. += I
|
||||
var/list/dc = datum_components
|
||||
if(!dc)
|
||||
return null
|
||||
. = dc[c_type]
|
||||
if(!islist(.))
|
||||
return list(.)
|
||||
|
||||
/datum/proc/AddComponent(new_type, ...)
|
||||
var/nt = new_type
|
||||
|
||||
18
code/datums/components/component.dm.rej
Normal file
18
code/datums/components/component.dm.rej
Normal file
@@ -0,0 +1,18 @@
|
||||
diff a/code/datums/components/component.dm b/code/datums/components/component.dm (rejected hunks)
|
||||
@@ -22,8 +22,7 @@
|
||||
//lazy init the parent's dc list
|
||||
var/list/dc = P.datum_components
|
||||
if(!dc)
|
||||
- dc = list()
|
||||
- P.datum_components = dc
|
||||
+ P.datum_components = dc = list()
|
||||
|
||||
//set up the typecache
|
||||
var/our_type = type
|
||||
@@ -179,4 +178,4 @@
|
||||
helicopter.SendSignal(COMSIG_COMPONENT_REMOVING, C)
|
||||
C.OnTransfer(src)
|
||||
C.parent = src
|
||||
- SendSignal(COMSIG_COMPONENT_ADDED, C)
|
||||
\ No newline at end of file
|
||||
+ SendSignal(COMSIG_COMPONENT_ADDED, C)
|
||||
@@ -929,6 +929,26 @@
|
||||
manipulate_organs(C)
|
||||
href_list["datumrefresh"] = href_list["editorgans"]
|
||||
|
||||
else if(href_list["hallucinate"])
|
||||
if(!check_rights(0))
|
||||
return
|
||||
|
||||
var/mob/living/carbon/C = locate(href_list["hallucinate"]) in GLOB.mob_list
|
||||
if(!istype(C))
|
||||
to_chat(usr, "This can only be done to instances of type /mob/living/carbon")
|
||||
return
|
||||
|
||||
var/list/hallucinations = subtypesof(/datum/hallucination)
|
||||
var/result = input(usr, "Choose the hallucination to apply","Send Hallucination") as null|anything in hallucinations
|
||||
if(!usr)
|
||||
return
|
||||
if(QDELETED(C))
|
||||
to_chat(usr, "Mob doesn't exist anymore")
|
||||
return
|
||||
|
||||
if(result)
|
||||
new result(C, TRUE)
|
||||
|
||||
else if(href_list["makehuman"])
|
||||
if(!check_rights(R_SPAWN))
|
||||
return
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
SSdisease.active_diseases += DD //Add it to the active diseases list, now that it's actually in a mob and being processed.
|
||||
|
||||
//Copy properties over. This is so edited diseases persist.
|
||||
var/list/skipped = list("affected_mob","holder","carrier","stage","type","parent_type","vars","transformed")
|
||||
var/list/skipped = list("affected_mob","holder","carrier","stage","type","parent_type","vars","transformed","symptoms")
|
||||
for(var/V in DD.vars)
|
||||
if(V in skipped)
|
||||
continue
|
||||
|
||||
@@ -57,9 +57,7 @@
|
||||
symptoms = GenerateSymptoms(0, 2)
|
||||
else
|
||||
for(var/datum/symptom/S in D.symptoms)
|
||||
var/datum/symptom/new_symp = new S.type
|
||||
new_symp.name = S.name
|
||||
new_symp.neutered = S.neutered
|
||||
var/datum/symptom/new_symp = S.Copy()
|
||||
symptoms += new_symp
|
||||
|
||||
Refresh()
|
||||
|
||||
@@ -59,4 +59,4 @@ Bonus
|
||||
else
|
||||
if(prob(base_message_chance))
|
||||
to_chat(M, "<span class='userdanger'>[pick("Oh, your head...", "Your head pounds.", "They're everywhere! Run!", "Something in the shadows...")]</span>")
|
||||
M.hallucination += (15 * power)
|
||||
M.hallucination += (45 * power)
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
if(ishuman(destination))
|
||||
var/mob/living/carbon/human/H = destination
|
||||
H.give_genitals(TRUE)//This gives the body the genitals of this DNA. Used for any transformations based on DNA
|
||||
destination.flavor_text = destination.dna.features["flavor_text"] //Update the flavor_text to use new dna text
|
||||
|
||||
/datum/dna/proc/copy_dna(datum/dna/new_dna)
|
||||
new_dna.unique_enzymes = unique_enzymes
|
||||
@@ -231,6 +232,7 @@
|
||||
|
||||
if(newfeatures)
|
||||
dna.features = newfeatures
|
||||
flavor_text = dna.features["flavor_text"] //Update the flavor_text to use new dna text
|
||||
|
||||
if(mrace)
|
||||
set_species(mrace, icon_update=0)
|
||||
|
||||
@@ -400,7 +400,15 @@
|
||||
if (assigned_role in GLOB.command_positions)
|
||||
text += "<b>HEAD</b>|loyal|employee|headrev|rev"
|
||||
else if (src in SSticker.mode.head_revolutionaries)
|
||||
text += "head|loyal|<a href='?src=\ref[src];revolution=clear'>employee</a>|<b>HEADREV</b>|<a href='?src=\ref[src];revolution=rev'>rev</a>"
|
||||
var/last_healthy_headrev = TRUE
|
||||
for(var/I in SSticker.mode.head_revolutionaries)
|
||||
if(I == src)
|
||||
continue
|
||||
var/mob/M = I
|
||||
if(M.z == ZLEVEL_STATION && !M.stat)
|
||||
last_healthy_headrev = FALSE
|
||||
break
|
||||
text += "head|loyal|<a href='?src=\ref[src];revolution=clear'>employee</a>|<b>[last_healthy_headrev ? "<font color='red'>LAST </font> " : ""]HEADREV</b>|<a href='?src=\ref[src];revolution=rev'>rev</a>"
|
||||
text += "<br>Flash: <a href='?src=\ref[src];revolution=flash'>give</a>"
|
||||
|
||||
var/list/L = current.get_contents()
|
||||
@@ -805,11 +813,11 @@
|
||||
possible_targets += possible_target.current
|
||||
|
||||
var/mob/def_target = null
|
||||
var/objective_list[] = list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain, /datum/objective/maroon)
|
||||
if (objective&&(objective.type in objective_list) && objective:target)
|
||||
def_target = objective:target.current
|
||||
var/list/objective_list = typecacheof(list(/datum/objective/assassinate, /datum/objective/protect, /datum/objective/debrain, /datum/objective/maroon))
|
||||
if (is_type_in_typecache(objective, objective_list) && objective.target)
|
||||
def_target = objective.target.current
|
||||
|
||||
var/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets
|
||||
var/mob/new_target = input("Select target:", "Objective target", def_target) as null|anything in possible_targets
|
||||
if (!new_target)
|
||||
return
|
||||
|
||||
@@ -817,12 +825,12 @@
|
||||
if (new_target == "Free objective")
|
||||
new_objective = new objective_path
|
||||
new_objective.owner = src
|
||||
new_objective:target = null
|
||||
new_objective.target = null
|
||||
new_objective.explanation_text = "Free objective"
|
||||
else
|
||||
new_objective = new objective_path
|
||||
new_objective.owner = src
|
||||
new_objective:target = new_target:mind
|
||||
new_objective.target = new_target.mind
|
||||
//Will display as special role if the target is set as MODE. Ninjas/commandos/nuke ops.
|
||||
new_objective.update_explanation_text()
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
icon_state = "shadow_mend"
|
||||
|
||||
/datum/status_effect/void_price/tick()
|
||||
owner << sound('sound/magic/summon_karp.ogg', volume = 25)
|
||||
SEND_SOUND(owner, sound('sound/magic/summon_karp.ogg', volume = 25))
|
||||
owner.adjustBruteLoss(3)
|
||||
|
||||
|
||||
@@ -247,7 +247,7 @@
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(isliving(B.current))
|
||||
var/mob/living/M = B.current
|
||||
M << 'sound/hallucinations/veryfar_noise.ogg'
|
||||
SEND_SOUND(M, sound('sound/hallucinations/veryfar_noise.ogg'))
|
||||
to_chat(M, "<span class='cultlarge'>The Cult's Master, [owner], has fallen in \the [A]!</span>")
|
||||
|
||||
/datum/status_effect/cult_master/tick()
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
if(telegraph_message)
|
||||
to_chat(M, telegraph_message)
|
||||
if(telegraph_sound)
|
||||
M << sound(telegraph_sound)
|
||||
SEND_SOUND(M, sound(telegraph_sound))
|
||||
addtimer(CALLBACK(src, .proc/start), telegraph_duration)
|
||||
|
||||
/datum/weather/proc/start()
|
||||
@@ -83,7 +83,7 @@
|
||||
if(weather_message)
|
||||
to_chat(M, weather_message)
|
||||
if(weather_sound)
|
||||
M << sound(weather_sound)
|
||||
SEND_SOUND(M, sound(weather_sound))
|
||||
START_PROCESSING(SSweather, src)
|
||||
addtimer(CALLBACK(src, .proc/wind_down), weather_duration)
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
if(end_message)
|
||||
to_chat(M, end_message)
|
||||
if(end_sound)
|
||||
M << sound(end_sound)
|
||||
SEND_SOUND(M, sound(end_sound))
|
||||
STOP_PROCESSING(SSweather, src)
|
||||
addtimer(CALLBACK(src, .proc/end), end_duration)
|
||||
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
var/mob/living/simple_animal/bot/mulebot/M = holder
|
||||
switch(wire)
|
||||
if(WIRE_POWER1, WIRE_POWER2)
|
||||
holder.visible_message("<span class='notice'>[bicon(M)] The charge light flickers.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The charge light flickers.</span>")
|
||||
if(WIRE_AVOIDANCE)
|
||||
holder.visible_message("<span class='notice'>[bicon(M)] The external warning lights flash briefly.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The external warning lights flash briefly.</span>")
|
||||
if(WIRE_LOADCHECK)
|
||||
holder.visible_message("<span class='notice'>[bicon(M)] The load platform clunks.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The load platform clunks.</span>")
|
||||
if(WIRE_MOTOR1, WIRE_MOTOR2)
|
||||
holder.visible_message("<span class='notice'>[bicon(M)] The drive motor whines briefly.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] The drive motor whines briefly.</span>")
|
||||
else
|
||||
holder.visible_message("<span class='notice'>[bicon(M)] You hear a radio crackle.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(M, viewers(holder))] You hear a radio crackle.</span>")
|
||||
@@ -25,7 +25,7 @@
|
||||
if(WIRE_INTERFACE)
|
||||
C.interface_control = !C.interface_control
|
||||
if(WIRE_LIMIT)
|
||||
C.visible_message("[bicon(C)]<b>[C]</b> makes a large whirring noise.")
|
||||
C.visible_message("[icon2html(C, viewers(holder))]<b>[C]</b> makes a large whirring noise.")
|
||||
|
||||
/datum/wires/particle_accelerator/control_box/on_cut(wire, mend)
|
||||
var/obj/machinery/particle_accelerator/control_box/C = holder
|
||||
|
||||
@@ -19,21 +19,21 @@
|
||||
switch(wire)
|
||||
if(WIRE_BOOM)
|
||||
if(B.active)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
|
||||
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] An alarm sounds! It's go-</span>")
|
||||
B.explode_now = TRUE
|
||||
tell_admins(B)
|
||||
if(WIRE_UNBOLT)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bolts spin in place for a moment.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bolts spin in place for a moment.</span>")
|
||||
if(WIRE_DELAY)
|
||||
if(B.delayedbig)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bomb has already been delayed.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bomb has already been delayed.</span>")
|
||||
else
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bomb chirps.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bomb chirps.</span>")
|
||||
playsound(B, 'sound/machines/chime.ogg', 30, 1)
|
||||
B.detonation_timer += 300
|
||||
B.delayedbig = TRUE
|
||||
if(WIRE_PROCEED)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] The bomb buzzes ominously!</span>")
|
||||
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] The bomb buzzes ominously!</span>")
|
||||
playsound(B, 'sound/machines/buzz-sigh.ogg', 30, 1)
|
||||
var/seconds = B.seconds_remaining()
|
||||
if(seconds >= 61) // Long fuse bombs can suddenly become more dangerous if you tinker with them.
|
||||
@@ -44,13 +44,13 @@
|
||||
B.detonation_timer = world.time + 100
|
||||
if(WIRE_ACTIVATE)
|
||||
if(!B.active && !B.defused)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] You hear the bomb start ticking!</span>")
|
||||
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] You hear the bomb start ticking!</span>")
|
||||
B.activate()
|
||||
B.update_icon()
|
||||
else if(B.delayedlittle)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] Nothing happens.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] Nothing happens.</span>")
|
||||
else
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bomb seems to hesitate for a moment.</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bomb seems to hesitate for a moment.</span>")
|
||||
B.detonation_timer += 100
|
||||
B.delayedlittle = TRUE
|
||||
|
||||
@@ -62,24 +62,24 @@
|
||||
B.defused = FALSE // Cutting and mending all the wires of an inactive bomb will thus cure any sabotage.
|
||||
else
|
||||
if(B.active)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
|
||||
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] An alarm sounds! It's go-</span>")
|
||||
B.explode_now = TRUE
|
||||
tell_admins(B)
|
||||
else
|
||||
B.defused = TRUE
|
||||
if(WIRE_UNBOLT)
|
||||
if(!mend && B.anchored)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The bolts lift out of the ground!</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The bolts lift out of the ground!</span>")
|
||||
playsound(B, 'sound/effects/stealthoff.ogg', 30, 1)
|
||||
B.anchored = FALSE
|
||||
if(WIRE_PROCEED)
|
||||
if(!mend && B.active)
|
||||
holder.visible_message("<span class='danger'>[bicon(B)] An alarm sounds! It's go-</span>")
|
||||
holder.visible_message("<span class='danger'>[icon2html(B, viewers(holder))] An alarm sounds! It's go-</span>")
|
||||
B.explode_now = TRUE
|
||||
tell_admins(B)
|
||||
if(WIRE_ACTIVATE)
|
||||
if(!mend && B.active)
|
||||
holder.visible_message("<span class='notice'>[bicon(B)] The timer stops! The bomb has been defused!</span>")
|
||||
holder.visible_message("<span class='notice'>[icon2html(B, viewers(holder))] The timer stops! The bomb has been defused!</span>")
|
||||
B.active = FALSE
|
||||
B.defused = TRUE
|
||||
B.update_icon()
|
||||
|
||||
@@ -439,7 +439,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
// Ambience goes down here -- make sure to list each area separately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
|
||||
if(L.client && !L.client.ambience_playing && L.client.prefs.toggles & SOUND_SHIP_AMBIENCE)
|
||||
L.client.ambience_playing = 1
|
||||
L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ)
|
||||
SEND_SOUND(L, sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ))
|
||||
|
||||
if(!(L.client && (L.client.prefs.toggles & SOUND_AMBIENCE)))
|
||||
return //General ambience check is below the ship ambience so one can play without the other
|
||||
@@ -448,7 +448,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
var/sound = pick(ambientsounds)
|
||||
|
||||
if(!L.client.played)
|
||||
L << sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE)
|
||||
SEND_SOUND(L, sound(sound, repeat = 0, wait = 0, volume = 25, channel = CHANNEL_AMBIENCE))
|
||||
L.client.played = 1
|
||||
sleep(600) //ewww - this is very very bad
|
||||
if(L.&& L.client)
|
||||
|
||||
10
code/game/area/areas.dm.rej
Normal file
10
code/game/area/areas.dm.rej
Normal file
@@ -0,0 +1,10 @@
|
||||
diff a/code/game/area/areas.dm b/code/game/area/areas.dm (rejected hunks)
|
||||
@@ -432,7 +432,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
|
||||
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
|
||||
if(L.client && !L.client.ambience_playing && L.client.prefs.toggles & SOUND_SHIP_AMBIENCE)
|
||||
L.client.ambience_playing = 1
|
||||
- L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ)
|
||||
+ SEND_SOUND(L, sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = CHANNEL_BUZZ))
|
||||
|
||||
if(!(L.client && (L.client.prefs.toggles & SOUND_AMBIENCE)))
|
||||
return //General ambience check is below the ship ambience so one can play without the other
|
||||
@@ -270,7 +270,7 @@
|
||||
f_name = "a "
|
||||
f_name += "<span class='danger'>blood-stained</span> [name]!"
|
||||
|
||||
to_chat(user, "[bicon(src)] That's [f_name]")
|
||||
to_chat(user, "[icon2html(src, user)] That's [f_name]")
|
||||
|
||||
if(desc)
|
||||
to_chat(user, desc)
|
||||
|
||||
@@ -292,7 +292,7 @@ GLOBAL_VAR_INIT(RADIO_MAGNETS, "9")
|
||||
|
||||
/datum/signal/proc/debug_print()
|
||||
if (source)
|
||||
. = "signal = {source = '[source]' ([source:x],[source:y],[source:z])\n"
|
||||
. = "signal = {source = '[source]' [COORD(source)]\n"
|
||||
else
|
||||
. = "signal = {source = '[source]' ()\n"
|
||||
for (var/i in data)
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
SSticker.mode.apprentices += M.mind
|
||||
M.mind.special_role = "apprentice"
|
||||
SSticker.mode.update_wiz_icons_added(M.mind)
|
||||
M << sound('sound/effects/magic.ogg')
|
||||
SEND_SOUND(M, sound('sound/effects/magic.ogg'))
|
||||
var/newname = copytext(sanitize(input(M, "You are [wizard_name]'s apprentice. Would you like to change your name to something else?", "Name change", randomname) as null|text),1,MAX_NAME_LEN)
|
||||
if (!newname)
|
||||
newname = randomname
|
||||
|
||||
@@ -171,11 +171,11 @@
|
||||
if(candidates.len) //if we got at least one candidate, they're a blobbernaut now.
|
||||
var/client/C = pick(candidates)
|
||||
blobber.key = C.key
|
||||
blobber << 'sound/effects/blobattack.ogg'
|
||||
blobber << 'sound/effects/attackblob.ogg'
|
||||
SEND_SOUND(blobber, sound('sound/effects/blobattack.ogg'))
|
||||
SEND_SOUND(blobber, sound('sound/effects/attackblob.ogg'))
|
||||
to_chat(blobber, "<b>You are a blobbernaut!</b>")
|
||||
to_chat(blobber, "You are powerful, hard to kill, and slowly regenerate near nodes and cores, but will slowly die if not near the blob or if the factory that made you is killed.")
|
||||
to_chat(blobber, "You can communicate with other blobbernauts and GLOB.overminds via <b>:b</b>")
|
||||
to_chat(blobber, "You can communicate with other blobbernauts and overminds via <b>:b</b>")
|
||||
to_chat(blobber, "Your overmind's blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
|
||||
to_chat(blobber, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]")
|
||||
if(blobber)
|
||||
|
||||
10
code/game/gamemodes/blob/powers.dm.rej
Normal file
10
code/game/gamemodes/blob/powers.dm.rej
Normal file
@@ -0,0 +1,10 @@
|
||||
diff a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm (rejected hunks)
|
||||
@@ -175,7 +175,7 @@
|
||||
SEND_SOUND(blobber, sound('sound/effects/attackblob.ogg'))
|
||||
to_chat(blobber, "<b>You are a blobbernaut!</b>")
|
||||
to_chat(blobber, "You are powerful, hard to kill, and slowly regenerate near nodes and cores, but will slowly die if not near the blob or if the factory that made you is killed.")
|
||||
- to_chat(blobber, "You can communicate with other blobbernauts and GLOB.overminds via <b>:b</b>")
|
||||
+ to_chat(blobber, "You can communicate with other blobbernauts and overminds via <b>:b</b>")
|
||||
to_chat(blobber, "Your overmind's blob reagent is: <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font>!")
|
||||
to_chat(blobber, "The <b><font color=\"[blob_reagent_datum.color]\">[blob_reagent_datum.name]</b></font> reagent [blob_reagent_datum.shortdesc ? "[blob_reagent_datum.shortdesc]" : "[blob_reagent_datum.description]"]")
|
||||
if(blobber)
|
||||
@@ -24,6 +24,7 @@
|
||||
M.changeNext_move(CLICK_CD_MELEE)
|
||||
var/a = pick("gently stroke", "nuzzle", "affectionatly pet", "cuddle")
|
||||
M.visible_message("<span class='notice'>[M] [a]s [src]!</span>", "<span class='notice'>You [a] [src]!</span>")
|
||||
to_chat(overmind, "<span class='notice'>[M] [a]s you!</span>")
|
||||
playsound(src, 'sound/effects/blobattack.ogg', 50, 1) //SQUISH SQUISH
|
||||
|
||||
|
||||
@@ -235,7 +236,7 @@
|
||||
if(istype(I, /obj/item/device/analyzer))
|
||||
user.changeNext_move(CLICK_CD_MELEE)
|
||||
to_chat(user, "<b>The analyzer beeps once, then reports:</b><br>")
|
||||
user << 'sound/machines/ping.ogg'
|
||||
SEND_SOUND(user, sound('sound/machines/ping.ogg'))
|
||||
chemeffectreport(user)
|
||||
typereport(user)
|
||||
else
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
C.confused += 25
|
||||
C.Jitter(50)
|
||||
else
|
||||
C << sound('sound/effects/screech.ogg')
|
||||
SEND_SOUND(C, sound('sound/effects/screech.ogg'))
|
||||
|
||||
if(issilicon(M))
|
||||
M << sound('sound/weapons/flash.ogg')
|
||||
SEND_SOUND(M, sound('sound/weapons/flash.ogg'))
|
||||
M.Knockdown(rand(100,200))
|
||||
|
||||
for(var/obj/machinery/light/L in range(4, user))
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
/mob/living/simple_animal/hostile/clockwork/examine(mob/user)
|
||||
var/t_He = p_they(TRUE)
|
||||
var/t_s = p_s()
|
||||
var/msg = "<span class='brass'>*---------*\nThis is [bicon(src)] \a <b>[src]</b>!\n"
|
||||
var/msg = "<span class='brass'>*---------*\nThis is [icon2html(src, user)] \a <b>[src]</b>!\n"
|
||||
msg += "[desc]\n"
|
||||
if(health < maxHealth)
|
||||
msg += "<span class='warning'>"
|
||||
|
||||
@@ -150,7 +150,7 @@ Judgement: 12 servants, 5 caches, 300 CV, and any existing AIs are converted or
|
||||
if(prob(ratvarian_prob))
|
||||
message = text2ratvar(message)
|
||||
to_chat(invoker, "<span class='[get_component_span(primary_component)]_large'>\"[message]\"</span>")
|
||||
invoker << 'sound/magic/clockwork/invoke_general.ogg'
|
||||
SEND_SOUND(invoker, sound('sound/magic/clockwork/invoke_general.ogg'))
|
||||
return TRUE
|
||||
|
||||
/datum/clockwork_scripture/proc/check_offstation_penalty()
|
||||
|
||||
@@ -103,13 +103,13 @@
|
||||
if(B.current)
|
||||
B.current.update_action_buttons_icon()
|
||||
if(!B.current.incapacitated())
|
||||
B.current << 'sound/hallucinations/im_here1.ogg'
|
||||
SEND_SOUND(B.current, 'sound/hallucinations/im_here1.ogg')
|
||||
to_chat(B.current, "<span class='cultlarge'>Acolyte [Nominee] has asserted that they are worthy of leading the cult. A vote will be called shortly.</span>")
|
||||
sleep(100)
|
||||
var/list/asked_cultists = list()
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current && B.current != Nominee && !B.current.incapacitated())
|
||||
B.current << 'sound/magic/exit_blood.ogg'
|
||||
SEND_SOUND(B.current, 'sound/magic/exit_blood.ogg')
|
||||
asked_cultists += B.current
|
||||
var/list/yes_voters = pollCandidates("[Nominee] seeks to lead your cult, do you support [Nominee.p_them()]?", poll_time = 300, group = asked_cultists)
|
||||
if(QDELETED(Nominee) || Nominee.incapacitated())
|
||||
@@ -280,7 +280,7 @@
|
||||
for(var/datum/mind/B in SSticker.mode.cult)
|
||||
if(B.current && B.current.stat != DEAD && B.current.client)
|
||||
to_chat(B.current, "<span class='cultlarge'><b>Master [ranged_ability_user] has marked [GLOB.blood_target] in the [A.name] as the cult's top priority, get there immediately!</b></span>")
|
||||
B.current << pick(sound('sound/hallucinations/over_here2.ogg',0,1,75), sound('sound/hallucinations/over_here3.ogg',0,1,75))
|
||||
SEND_SOUND(B.current, sound(pick('sound/hallucinations/over_here2.ogg','sound/hallucinations/over_here3.ogg'),0,1,75))
|
||||
B.current.client.images += GLOB.blood_target_image
|
||||
attached_action.owner.update_action_buttons_icon()
|
||||
remove_ranged_ability("<span class='cult'>The marking rite is complete! It will last for 90 seconds.</span>")
|
||||
@@ -324,7 +324,7 @@
|
||||
return FALSE
|
||||
if(cooldown > world.time)
|
||||
if(!PM.active)
|
||||
owner << "<span class='cultlarge'><b>You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can pulse again!</b></span>"
|
||||
to_chat(owner, "<span class='cultlarge'><b>You need to wait [round((cooldown - world.time) * 0.1)] seconds before you can pulse again!</b></span>")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
@@ -367,7 +367,7 @@
|
||||
if(!attached_action.throwing)
|
||||
attached_action.throwing = TRUE
|
||||
attached_action.throwee = target
|
||||
ranged_ability_user << 'sound/weapons/thudswoosh.ogg'
|
||||
SEND_SOUND(ranged_ability_user, sound('sound/weapons/thudswoosh.ogg'))
|
||||
to_chat(ranged_ability_user,"<span class='cult'><b>You reach through the veil with your mind's eye and seize [target]!</b></span>")
|
||||
return
|
||||
else
|
||||
|
||||
@@ -161,11 +161,15 @@
|
||||
/obj/item/weapon/sharpener/cult
|
||||
name = "eldritch whetstone"
|
||||
desc = "A block, empowered by dark magic. Sharp weapons will be enhanced when used on the stone."
|
||||
icon_state = "cult_sharpener"
|
||||
used = 0
|
||||
increment = 5
|
||||
max = 40
|
||||
prefix = "darkened"
|
||||
|
||||
/obj/item/weapon/sharpener/cult/update_icon()
|
||||
icon_state = "cult_sharpener[used ? "_used" : ""]"
|
||||
|
||||
/obj/item/clothing/suit/hooded/cultrobes/cult_shield
|
||||
name = "empowered cultist armor"
|
||||
desc = "Empowered garb which creates a powerful shield around the user."
|
||||
|
||||
@@ -538,7 +538,7 @@ structure_check() searches for nearby cultist structures required for the invoca
|
||||
mob_to_revive = input(user, "Choose a cultist to revive.", "Cultist to Revive") as null|anything in potential_revive_mobs
|
||||
else
|
||||
mob_to_revive = potential_revive_mobs[1]
|
||||
if(!src || QDELETED(src) || rune_in_use || !validness_checks(mob_to_revive, user))
|
||||
if(QDELETED(src) || !validness_checks(mob_to_revive, user))
|
||||
rune_in_use = FALSE
|
||||
return
|
||||
if(user.name == "Herbert West")
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
return 0
|
||||
|
||||
/obj/item/weapon/paper/talisman/supply/Topic(href, href_list)
|
||||
world.log << "[usr], [href], [href_list]"
|
||||
if(QDELETED(src) || usr.incapacitated() || !in_range(src, usr))
|
||||
return
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user