"
temp += ""
if("rank")
- var/list/L = list( "Head of Personnel", "Captain", "AI", "Central Command" )
- //This was so silly before the change. Now it actually works without beating your head against the keyboard. /N
- if((istype(active1, /datum/data/record) && L.Find(rank)))
+ if(istype(active1, /datum/data/record) && ((ACCESS_CAPTAIN in logged_access) || (ACCESS_HOP in logged_access)))
temp = "
Rank:
"
temp += "
"
for(var/rank in get_all_jobs())
diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm
index 382764c586..58d9627476 100644
--- a/code/game/objects/items/circuitboards/computer_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm
@@ -581,6 +581,10 @@
name = "Supply Request Console (Computer Board)"
build_path = /obj/machinery/computer/cargo/request
+/obj/item/circuitboard/computer/bounty
+ name = "Nanotrasen Bounty Console (Computer Board)"
+ build_path = /obj/machinery/computer/bounty
+
/obj/item/circuitboard/computer/ferry
name = "Transport Ferry (Computer Board)"
icon_state = "supply"
diff --git a/code/game/objects/structures/ghost_role_spawners.dm b/code/game/objects/structures/ghost_role_spawners.dm
index 084e2fefd8..4ed55e61a6 100644
--- a/code/game/objects/structures/ghost_role_spawners.dm
+++ b/code/game/objects/structures/ghost_role_spawners.dm
@@ -846,7 +846,8 @@
var/area/A = get_area(src)
var/datum/outfit/O = new /datum/outfit/ghostcafe()
O.equip(new_spawn, FALSE, new_spawn.client)
- SSjob.equip_loadout(null, new_spawn, FALSE)
+ SSjob.equip_loadout(null, new_spawn)
+ SSjob.post_equip_loadout(null, new_spawn)
SSquirks.AssignQuirks(new_spawn, new_spawn.client, TRUE, TRUE, null, FALSE, new_spawn)
new_spawn.AddElement(/datum/element/ghost_role_eligibility, free_ghosting = TRUE)
new_spawn.AddElement(/datum/element/dusts_on_catatonia)
diff --git a/code/modules/antagonists/bloodsucker/bloodsucker_objectives.dm b/code/modules/antagonists/bloodsucker/bloodsucker_objectives.dm
index 7043c2f429..c079e00342 100644
--- a/code/modules/antagonists/bloodsucker/bloodsucker_objectives.dm
+++ b/code/modules/antagonists/bloodsucker/bloodsucker_objectives.dm
@@ -157,7 +157,8 @@
else if (V.owner.current && ishuman(V.owner.current))
var/mob/living/carbon/human/H = V.owner.current
var/obj/item/card/id/I = H.wear_id ? H.wear_id.GetID() : null
- if (I && (I.assignment in valid_jobs) && !(I.assignment in counted_roles))
+ var/assign = GetJobName(I.assignment)
+ if (I && (assign in valid_jobs) && !(assign in counted_roles))
//to_chat(owner, "PROTEGE OBJECTIVE: (GET ID)")
thisRole = I.assignment
diff --git a/code/modules/cargo/bounty_console.dm b/code/modules/cargo/bounty_console.dm
new file mode 100644
index 0000000000..4158327c3c
--- /dev/null
+++ b/code/modules/cargo/bounty_console.dm
@@ -0,0 +1,67 @@
+#define PRINTER_TIMEOUT 10
+
+/obj/machinery/computer/bounty
+ name = "\improper Nanotrasen bounty console"
+ desc = "Used to check and claim bounties offered by Nanotrasen"
+ icon_screen = "bounty"
+ circuit = /obj/item/circuitboard/computer/bounty
+ light_color = "#E2853D"//orange
+ var/printer_ready = 0 //cooldown var
+ var/static/datum/bank_account/cargocash
+
+/obj/machinery/computer/bounty/Initialize(mapload)
+ . = ..()
+ printer_ready = world.time + PRINTER_TIMEOUT
+ cargocash = SSeconomy.get_dep_account(ACCOUNT_CAR)
+
+/obj/machinery/computer/bounty/proc/print_paper()
+ new /obj/item/paper/bounty_printout(loc)
+
+/obj/item/paper/bounty_printout
+ name = "paper - Bounties"
+
+/obj/item/paper/bounty_printout/Initialize(mapload)
+ . = ..()
+ info = "
Nanotrasen Cargo Bounties
"
+ update_icon()
+
+ for(var/datum/bounty/B in GLOB.bounties_list)
+ if(B.claimed)
+ continue
+ info += {"
[B.name]
+
Reward: [B.reward_string()]
+
Completed: [B.completion_string()]
"}
+
+/obj/machinery/computer/bounty/ui_interact(mob/user, datum/tgui/ui)
+ if(!GLOB.bounties_list.len)
+ setup_bounties()
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "CargoBountyConsole", name)
+ ui.open()
+
+/obj/machinery/computer/bounty/ui_data(mob/user)
+ var/list/data = list()
+ var/list/bountyinfo = list()
+ for(var/datum/bounty/B in GLOB.bounties_list)
+ bountyinfo += list(list("name" = B.name, "description" = B.description, "reward_string" = B.reward_string(), "completion_string" = B.completion_string() , "claimed" = B.claimed, "can_claim" = B.can_claim(), "priority" = B.high_priority, "bounty_ref" = REF(B)))
+ data["stored_cash"] = cargocash.account_balance
+ data["bountydata"] = bountyinfo
+ return data
+
+/obj/machinery/computer/bounty/ui_act(action,params)
+ if(..())
+ return
+ switch(action)
+ if("ClaimBounty")
+ var/datum/bounty/cashmoney = locate(params["bounty"]) in GLOB.bounties_list
+ if(cashmoney)
+ cashmoney.claim()
+ return TRUE
+ if("Print")
+ if(printer_ready < world.time)
+ printer_ready = world.time + PRINTER_TIMEOUT
+ print_paper()
+ return
+
+
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index c769ddeb3c..5ab30c7221 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -401,7 +401,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
load_path(C.ckey)
unlock_content = C.IsByondMember()
if(unlock_content)
- max_save_slots = 32
+ max_save_slots += 8 //SPLURT EDIT
var/loaded_preferences_successfully = load_preferences()
if(loaded_preferences_successfully)
if(load_character())
diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm
index 1b8b4d9e00..011f64d3ec 100644
--- a/code/modules/clothing/under/accessories.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -7,7 +7,8 @@
//
icon_state = "plasma"
item_state = "" //no inhands
- slot_flags = 0
+ slot_flags = ITEM_SLOT_ACCESSORY
+ slot_equipment_priority = list(ITEM_SLOT_ACCESSORY)
w_class = WEIGHT_CLASS_SMALL
var/above_suit = FALSE
var/minimize_when_attached = TRUE // TRUE if shown as a small icon in corner, FALSE if overlayed
diff --git a/code/modules/events/shuttle_catastrophe.dm b/code/modules/events/shuttle_catastrophe.dm
index 2e431a8a34..18b9dc61ca 100644
--- a/code/modules/events/shuttle_catastrophe.dm
+++ b/code/modules/events/shuttle_catastrophe.dm
@@ -9,6 +9,8 @@
/datum/round_event_control/shuttle_catastrophe/canSpawnEvent(players, gamemode)
if(SSshuttle.emergency.name == "Build your own shuttle kit")
return FALSE //don't undo manual player engineering, it also would unload people and ghost them, there's just a lot of problems
+ if(SSshuttle.emergency.in_flight())
+ return FALSE //ditto, problems
return ..()
diff --git a/code/modules/jobs/access.dm b/code/modules/jobs/access.dm
index 155efcd7dc..52ed3eca5e 100644
--- a/code/modules/jobs/access.dm
+++ b/code/modules/jobs/access.dm
@@ -366,7 +366,7 @@
"Research Director", "Scientist", "Roboticist", "Head of Security", "Warden", "Detective", "Security Officer", "Brig Physician", "Peacekeeper", "Prisoner")
/proc/get_all_job_icons() //For all existing HUD icons
- return get_all_jobs() + list("Prisoner")
+ return get_all_jobs()
/proc/get_all_centcom_jobs()
return list("VIP Guest","Custodian","Thunderdome Overseer","CentCom Official","Medical Officer","Death Commando","Research Officer","Special Ops Officer","Admiral","CentCom Commander","Emergency Response Team Commander","Security Response Officer","Engineer Response Officer", "Medical Response Officer","CentCom Bartender","Nuclear Waste Expert") //No idea how to modularly edit a global proc
diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm
index 378313311e..dd3d5186de 100644
--- a/code/modules/mob/dead/new_player/preferences_setup.dm
+++ b/code/modules/mob/dead/new_player/preferences_setup.dm
@@ -51,7 +51,8 @@
if(current_tab == LOADOUT_TAB)
//give it its loadout if not on the appearance tab
- SSjob.equip_loadout(parent.mob, mannequin, FALSE, bypass_prereqs = TRUE, can_drop = FALSE)
+ SSjob.equip_loadout(parent.mob, mannequin, bypass_prereqs = TRUE, can_drop = FALSE)
+ SSjob.post_equip_loadout(parent.mob, mannequin, bypass_prereqs = TRUE, can_drop = FALSE)
else
if(previewJob && equip_job)
mannequin.job = previewJob.title
diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm
index ca5f6b135b..e5cab7a6f5 100644
--- a/code/modules/mob/living/carbon/human/inventory.dm
+++ b/code/modules/mob/living/carbon/human/inventory.dm
@@ -190,6 +190,10 @@
if(ITEM_SLOT_SUITSTORE)
s_store = I
update_inv_s_store()
+ if(ITEM_SLOT_ACCESSORY)
+ var/obj/item/clothing/under/attach_target = w_uniform
+ attach_target.attach_accessory(I, src, TRUE)
+ // updates handled by attach_accessory
else
to_chat(src, "You are trying to equip this item to an unsupported inventory slot. Report this to a coder!")
not_handled = TRUE
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index 6052229e35..0c30c42a65 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1523,6 +1523,39 @@ GLOBAL_LIST_EMPTY(roundstart_race_names)
if(SEND_SIGNAL(H.back, COMSIG_TRY_STORAGE_CAN_INSERT, I, H, TRUE))
return TRUE
return FALSE
+ if(ITEM_SLOT_ACCESSORY)
+ if(istype(I, /obj/item/clothing/accessory/ring))
+ if(istype(H.gloves))
+ var/obj/item/clothing/gloves/attaching_target = H.gloves
+ if(length(attaching_target.attached_accessories) > attaching_target.max_accessories)
+ if(return_warning)
+ return_warning[1] = "\The [attaching_target] is at maximum capacity!"
+ return FALSE
+ if(attaching_target.dummy_thick)
+ if(return_warning)
+ return_warning[1] = "\The [attaching_target] are too bulky and cannot have accessories attached to it!"
+ return FALSE
+ else
+ return TRUE
+ else if(return_warning)
+ return_warning[1] = "\The [H.w_uniform] cannot have any attachments."
+ return FALSE
+ else
+ if(istype(H.w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/attaching_target = H.w_uniform
+ if(length(attaching_target.attached_accessories) > attaching_target.max_accessories)
+ if(return_warning)
+ return_warning[1] = "\The [attaching_target] is at maximum capacity!"
+ return FALSE
+ if(attaching_target.dummy_thick)
+ if(return_warning)
+ return_warning[1] = "\The [attaching_target] is too bulky and cannot have accessories attached to it!"
+ return FALSE
+ else
+ return TRUE
+ else if(return_warning)
+ return_warning[1] = "\The [H.w_uniform] cannot have any attachments."
+ return FALSE
return FALSE //Unsupported slot
/datum/species/proc/equip_delay_self_check(obj/item/I, mob/living/carbon/human/H, bypass_equip_delay_self)
diff --git a/code/modules/modular_computers/file_system/programs/card.dm b/code/modules/modular_computers/file_system/programs/card.dm
index 18e717191e..cfeae5730b 100644
--- a/code/modules/modular_computers/file_system/programs/card.dm
+++ b/code/modules/modular_computers/file_system/programs/card.dm
@@ -167,7 +167,8 @@
if(!computer || !authenticated)
return
if(minor)
- if(!(target_id_card.assignment in head_subordinates) && target_id_card.assignment != "Assistant")
+ var/assign = GetJobName(target_id_card)
+ if(!(assign in head_subordinates) && assign != "Assistant")
return
target_id_card.access -= get_all_centcom_access() + get_all_accesses()
diff --git a/code/modules/photography/_pictures.dm b/code/modules/photography/_pictures.dm
index 6f85cdb3a6..dace901cea 100644
--- a/code/modules/photography/_pictures.dm
+++ b/code/modules/photography/_pictures.dm
@@ -76,7 +76,7 @@
/proc/load_photo_from_disk(id, location)
var/datum/picture/P = load_picture_from_disk(id)
if(istype(P))
- var/obj/item/photo/p = new(location, P)
+ var/obj/item/photo/old/p = new(location, P)
return p
/proc/load_picture_from_disk(id)
diff --git a/code/modules/photography/photos/album.dm b/code/modules/photography/photos/album.dm
index 6f35e7a99d..48a9203553 100644
--- a/code/modules/photography/photos/album.dm
+++ b/code/modules/photography/photos/album.dm
@@ -48,7 +48,7 @@
for(var/i in ids)
if(i in current_ids)
continue
- var/obj/item/photo/P = load_photo_from_disk(i)
+ var/obj/item/photo/old/P = load_photo_from_disk(i)
if(istype(P))
if(!SEND_SIGNAL(src, COMSIG_TRY_STORAGE_INSERT, P, null, TRUE, TRUE))
qdel(P)
diff --git a/code/modules/photography/photos/frame.dm b/code/modules/photography/photos/frame.dm
index 4000bf843c..45aa4aeb79 100644
--- a/code/modules/photography/photos/frame.dm
+++ b/code/modules/photography/photos/frame.dm
@@ -98,7 +98,7 @@
load_from_id(data[persistence_id])
/obj/structure/sign/picture_frame/proc/load_from_id(id)
- var/obj/item/photo/P = load_photo_from_disk(id)
+ var/obj/item/photo/old/P = load_photo_from_disk(id)
if(istype(P))
if(istype(framed))
framed.forceMove(drop_location())
diff --git a/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo.dm b/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo.dm
index ea8e59a6b3..f2514b6f9c 100644
--- a/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo.dm
+++ b/code/modules/research/designs/comp_board_designs/comp_board_designs_cargo.dm
@@ -17,7 +17,15 @@
build_path = /obj/item/circuitboard/computer/cargo/request
category = list("Computer Boards")
departmental_flags = DEPARTMENTAL_FLAG_CARGO
-
+
+/datum/design/board/bounty
+ name = "Computer Design (Bounty Console)"
+ desc = "Allows for the construction of circuit boards used to build a Bounty Console."
+ id = "bounty"
+ build_path = /obj/item/circuitboard/computer/bounty
+ category = list("Computer Boards")
+ departmental_flags = DEPARTMENTAL_FLAG_CARGO
+
/datum/design/board/mining
name = "Computer Design (Outpost Status Display)"
desc = "Allows for the construction of circuit boards used to build an outpost status display console."
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 1f027c450c..10fab0ed06 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -685,6 +685,7 @@
to_chat(SM, "You also become depressingly aware that you are not a real creature, but instead a holoform. Your existence is limited to the parameters of the holodeck.")
to_chat(user, "[SM] accepts [src] and suddenly becomes attentive and aware. It worked!")
SM.copy_languages(user)
+ SM.add_overlay(mutable_appearance('icons/mob/hud.dmi', "brother", ANTAG_LAYER))
after_success(user, SM)
qdel(src)
else
@@ -754,6 +755,7 @@
to_chat(SM, "In a quick flash, you feel your consciousness flow into [SM]!")
to_chat(SM, "You are now [SM]. Your allegiances, alliances, and role is still the same as it was prior to consciousness transfer!")
SM.name = "[user.real_name]"
+ SM.add_overlay(mutable_appearance('icons/mob/hud.dmi', "brother", ANTAG_LAYER))
qdel(src)
/obj/item/slimepotion/slime/steroid
diff --git a/config/splurt/general.txt b/config/splurt/general.txt
index dcc4de101d..6eed643535 100644
--- a/config/splurt/general.txt
+++ b/config/splurt/general.txt
@@ -9,3 +9,8 @@ MAX_INFINIDORMS 5
# Weighted station traits
# If uncommented, the server will pick random station traits according to their weight configuration
WEIGHTED_STATION_TRAITS
+
+# Base amount of max save slots
+# Amount of character slots that players will have without modifiers being applied
+# default is 24
+#BASE_SAVE_SLOTS 24
diff --git a/html/changelogs/archive/2023-02.yml b/html/changelogs/archive/2023-02.yml
index 1b700a606c..49d8ef8a5e 100644
--- a/html/changelogs/archive/2023-02.yml
+++ b/html/changelogs/archive/2023-02.yml
@@ -16,6 +16,66 @@
- rscadd: Added the Dissociative Mirror
- tweak: Restored techweb node and circuit printing for Cryptominers
2023-02-04:
+ AshTheDerg:
+ - rscadd: Added 10 new varieties of Milkshake
LeDrascol:
- rscadd: Added variant of Subtle verb with typing indicator
- tweak: Default binding for Subtle is now Control-5
+2023-02-07:
+ LeDrascol:
+ - tweak: Added gain, lose, and medical text to werewolf quirk
+ - tweak: Updated werewolf ability tooltip
+ - tweak: Changed body part sprites used for werewolf
+ - tweak: Werewolves cannot transform while asleep, restrained, or stunned
+ - tweak: Werewolf transformation now has a five second cooldown
+ - tweak: Werewolf species name prefix is now based on gender
+ - tweak: Werewolves can be slime and jelly entities
+ - tweak: Werewolves will gain an appropriate taur body if the owner had one
+ - bugfix: Werewolves cannot transform while dead
+ - bugfix: Werewolf transformation organ bug fixed for some species
+ - bugfix: Werewolf old species attributes are no longer lost on action removal
+ - bugfix: Werewolves custom species name properly applies
+ - bugfix: Werewolves will regain exotic eye types
+ - code_imp: Added a werewolf quirk trait
+ - refactor: Updated werewolf quirk variable names
+ - tweak: Added Bluespace Light Replacer to the Science protolathe
+ The-Real-Goku:
+ - rscadd: Added persistent photo album.
+ - rscadd: Added custom name for player album. ([Player name]'s album)
+ - rscadd: Added specific names for the photo albums located in the Heads of Departments'
+ lockers. (Ex. Captain, HoP...)
+ - bugfix: Fixed in-hand sprite for Photo Album. (They looked like briefcases before).
+ zeroisthebiggay:
+ - bugfix: ai research
+2023-02-09:
+ BongaTheProto:
+ - rscadd: New tail, Snake Tail (Large)
+ - tweak: Now the max amount of character slots can be configured, and donators get
+ more slots
+ - bugfix: Photographer quirk will no longer fuck over your neck loadout items
+ Comicao1:
+ - rscadd: Added a few icons and code. Not modularized because it's not possible.
+ - rscadd: Adds the inflate verb.
+2023-02-10:
+ Comicao1:
+ - rscadd: Beach ball may be inserted a vibrator in it.
+ - rscadd: Syndicate beach ball also might be bought in the traitor's uplink.
+2023-02-11:
+ SandPoot:
+ - refactor: Interaction menu is no longer stored in your mind, and should clear
+ references and all properly when deleting.
+ WoolyAypa:
+ - rscadd: Added a new polychromic Princess Leia outfits to the ClothesMate (and
+ loadout)
+ - rscadd: Added a polychromic version of the "Performers one piece" to the ClothesMate
+ (and loadout)
+ - rscadd: Added high-heel sandals to the KinkMate (and loadout)
+2023-02-12:
+ BongaTheProto:
+ - bugfix: snake tail (large) is now available for humans and lizards too
+ WoolyAypa:
+ - bugfix: Space princess outfit now can be used along with digitigrade legs
+ - rscadd: Added some of the old dullahan stuff to the new one
+ - bugfix: Fixed the overlay glitches with the new dullahan quirk
+ - bugfix: Space princess outfit and the polychromic performers one piece can now
+ be colored in the loadout
diff --git a/icons/mob/augmentation/cosmetic_prosthetic/veymed.dmi b/icons/mob/augmentation/cosmetic_prosthetic/veymed.dmi
new file mode 100644
index 0000000000..aaf11cfd9f
Binary files /dev/null and b/icons/mob/augmentation/cosmetic_prosthetic/veymed.dmi differ
diff --git a/modular_citadel/code/modules/client/loadout/__donator.dm b/modular_citadel/code/modules/client/loadout/__donator.dm
index 4c09236872..197f088356 100644
--- a/modular_citadel/code/modules/client/loadout/__donator.dm
+++ b/modular_citadel/code/modules/client/loadout/__donator.dm
@@ -54,9 +54,10 @@
/datum/gear/donator/kiaramedal
name = "Insignia of Steele"
- slot = ITEM_SLOT_BACKPACK
+ slot = ITEM_SLOT_ACCESSORY
path = /obj/item/clothing/accessory/medal/steele
ckeywhitelist = list("inferno707")
+ handle_post_equip = TRUE
/datum/gear/donator/hheart
name = "The Hollow Heart"
diff --git a/modular_citadel/code/modules/client/loadout/_loadout.dm b/modular_citadel/code/modules/client/loadout/_loadout.dm
index 5f895c4805..f33beecb32 100644
--- a/modular_citadel/code/modules/client/loadout/_loadout.dm
+++ b/modular_citadel/code/modules/client/loadout/_loadout.dm
@@ -55,6 +55,7 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids)
var/geargroupID //defines the ID that the gear inherits from the config
var/loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION
var/list/loadout_initial_colors = list()
+ var/handle_post_equip = FALSE
//NEW DONATOR SYTSEM STUFF
var/donoritem //autoset on new if null
diff --git a/modular_citadel/code/modules/client/loadout/accessory.dm b/modular_citadel/code/modules/client/loadout/accessory.dm
new file mode 100644
index 0000000000..55cce181a5
--- /dev/null
+++ b/modular_citadel/code/modules/client/loadout/accessory.dm
@@ -0,0 +1,20 @@
+/datum/gear/accessory
+ category = LOADOUT_CATEGORY_ACCESSORY
+ slot = ITEM_SLOT_ACCESSORY
+ handle_post_equip = TRUE
+
+/datum/gear/accessory/necklace
+ name = "A renameable necklace"
+ path = /obj/item/clothing/accessory/necklace
+
+/datum/gear/accessory/polymaidapron
+ name = "Polychromic maid apron"
+ path = /obj/item/clothing/accessory/maidapron/polychromic
+ loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
+ loadout_initial_colors = list("#333333", "#FFFFFF")
+
+/datum/gear/accessory/pridepin
+ name = "Pride pin"
+ path = /obj/item/clothing/accessory/pride
+ loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION
+ cost = 0
diff --git a/modular_citadel/code/modules/client/loadout/backpack.dm b/modular_citadel/code/modules/client/loadout/backpack.dm
index a0be000b31..24545e7b4c 100644
--- a/modular_citadel/code/modules/client/loadout/backpack.dm
+++ b/modular_citadel/code/modules/client/loadout/backpack.dm
@@ -2,6 +2,7 @@
category = LOADOUT_CATEGORY_BACKPACK
subcategory = LOADOUT_SUBCATEGORY_BACKPACK_GENERAL
slot = ITEM_SLOT_BACKPACK
+ handle_post_equip = TRUE
/datum/gear/backpack/plushbox
name = "Plushie Choice Box"
@@ -172,25 +173,6 @@
path = /obj/item/storage/fancy/ringbox/diamond
cost = 5
-/datum/gear/backpack/necklace //this is here because loadout doesn't support proper accessories
- name = "A renameable necklace"
- path = /obj/item/clothing/accessory/necklace
- subcategory = LOADOUT_SUBCATEGORY_BACKPACK_ACCESSORIES
-
-/datum/gear/backpack/polymaidapron //this is ALSO here because loadout doesn't support proper accessories
- name = "Polychromic maid apron"
- path = /obj/item/clothing/accessory/maidapron/polychromic
- loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
- loadout_initial_colors = list("#333333", "#FFFFFF")
- subcategory = LOADOUT_SUBCATEGORY_BACKPACK_ACCESSORIES
-
-/datum/gear/backpack/pridepin //what the two comments above said
- name = "Pride pin"
- path = /obj/item/clothing/accessory/pride
- loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION
- subcategory = LOADOUT_SUBCATEGORY_BACKPACK_ACCESSORIES
- cost = 0
-
// Moved here from quirks
/datum/gear/backpack/dyespray
name = "Hair dye spray"
diff --git a/modular_sand/code/_globalvars/bitfields.dm b/modular_sand/code/_globalvars/bitfields.dm
index c149e1c11e..7a2bb8d87d 100644
--- a/modular_sand/code/_globalvars/bitfields.dm
+++ b/modular_sand/code/_globalvars/bitfields.dm
@@ -25,6 +25,7 @@ DEFINE_BITFIELD(flags_inv, list(
))
DEFINE_BITFIELD(slot_flags, list(
+ "ITEM_SLOT_ACCESSORY" = ITEM_SLOT_ACCESSORY,
"ITEM_SLOT_BACK" = ITEM_SLOT_BACK,
"ITEM_SLOT_BACKPACK" = ITEM_SLOT_BACKPACK,
"ITEM_SLOT_BELT" = ITEM_SLOT_BELT,
diff --git a/modular_sand/code/controllers/subsystem/interactions.dm b/modular_sand/code/controllers/subsystem/interactions.dm
index f4a1a08c5e..dee26167c3 100644
--- a/modular_sand/code/controllers/subsystem/interactions.dm
+++ b/modular_sand/code/controllers/subsystem/interactions.dm
@@ -4,6 +4,9 @@ SUBSYSTEM_DEF(interactions)
init_order = INIT_ORDER_INTERACTIONS
var/list/interactions
VAR_PROTECTED/list/blacklisted_mobs = list(
+ /mob/dead,
+ /mob/dview,
+ /mob/camera, // Although it would be funny to fuck the sentient disease or AI hologram
/mob/living/simple_animal/pet,
/mob/living/simple_animal/cockroach,
/mob/living/simple_animal/babyKiwi,
diff --git a/modular_sand/code/datums/interactions/interaction_interface.dm b/modular_sand/code/datums/components/interaction_menu_granter.dm
similarity index 80%
rename from modular_sand/code/datums/interactions/interaction_interface.dm
rename to modular_sand/code/datums/components/interaction_menu_granter.dm
index 2d7f794132..328f92346d 100644
--- a/modular_sand/code/datums/interactions/interaction_interface.dm
+++ b/modular_sand/code/datums/components/interaction_menu_granter.dm
@@ -1,59 +1,72 @@
/// Attempts to open the tgui menu
-/mob/living/verb/interact_with()
+/mob/proc/interact_with()
set name = "Interact With"
set desc = "Perform an interaction with someone."
set category = "IC"
set src in view(usr.client)
- if(!usr.mind) //Mindless boys, honestly just don't, it's better this way
+ if(!src)
return
- if(!usr.mind.interaction_holder)
- usr.mind.interaction_holder = new(usr.mind)
- usr.mind.interaction_holder.target = src
- usr.mind.interaction_holder.ui_interact(usr)
-
-/*
-/// Allows "cyborg" players to change gender at will
-/mob/living/silicon/robot/verb/toggle_gender()
- set name = "Set Gender"
- set desc = "Allows you to set your gender."
-
- if(stat != CONSCIOUS)
- to_chat(usr, span_warning("You cannot toggle your gender while unconcious!"))
- return
-
- var/choice = tgui_alert(usr, "Select Gender.", "Gender", list("Both", "Male", "Female"))
- switch(choice)
- if("Both")
- has_penis = TRUE
- has_vagina = TRUE
- if("Male")
- has_penis = TRUE
- has_vagina = FALSE
- if("Female")
- has_penis = FALSE
- has_vagina = TRUE
-*/
+ // I FUCKING HATE VERBS (NEED TO GRAB COMPONENT FROM USR, NOT SRC)
+ var/datum/component/interaction_menu_granter/menu = usr.GetComponent(/datum/component/interaction_menu_granter)
+ if(menu)
+ menu.open_menu(usr, src)
+ else // you bad
+ remove_verb(usr, /mob/proc/interact_with)
#define INTERACTION_NORMAL 0
#define INTERACTION_LEWD 1
#define INTERACTION_EXTREME 2
-/datum/mind
- var/datum/interaction_menu/interaction_holder
-
-/datum/mind/New(key)
- . = ..()
- interaction_holder = new(src)
-
/// The menu itself, only var is target which is the mob you are interacting with
-/datum/interaction_menu
+/datum/component/interaction_menu_granter
var/mob/living/target
-/datum/interaction_menu/ui_state(mob/user)
- return GLOB.conscious_state
+/datum/component/interaction_menu_granter/Initialize(...)
+ if(!ismob(parent))
+ return COMPONENT_INCOMPATIBLE
+ var/mob/parent_mob = parent
+ if(!parent_mob.client)
+ return COMPONENT_INCOMPATIBLE
+ add_verb(parent_mob, /mob/proc/interact_with)
+ /// > Why don't you attach it to COMSIG_CLICK_CTRL_SHIFT
+ /// I want to open the ui on myself, not everyone has it and it's just bad practice i guess.
+ RegisterSignal(parent_mob, COMSIG_MOB_CLICKON, .proc/open_menu)
+ . = ..()
-/datum/interaction_menu/ui_interact(mob/user, datum/tgui/ui)
+/datum/component/interaction_menu_granter/Destroy(force, ...)
+ var/mob/parent_mob = parent
+ remove_verb(parent_mob, /mob/proc/interact_with)
+ target = null
+ UnregisterSignal(parent_mob, COMSIG_MOB_CLICKON)
+ . = ..()
+
+/datum/component/interaction_menu_granter/proc/open_menu(mob/clicker, mob/clicked, mouse_params)
+ // Don't cancel admin quick spawn
+ if(isobserver(clicked) && check_rights(R_SPAWN, FALSE))
+ return FALSE
+ // COMSIG_MOB_CLICKON is sent for EVERYTHING your mob character clicks, avoid non-mob
+ if(!istype(clicked))
+ return FALSE
+ // Using the verb calls leaves this empty
+ if(mouse_params)
+ var/list/params = params2list(mouse_params)
+ if(!(params[LEFT_CLICK] && params[CTRL_CLICK] && params[SHIFT_CLICK]))
+ // Continue click normally
+ return FALSE
+ target = clicked
+ ui_interact(clicker)
+ return COMSIG_MOB_CANCEL_CLICKON
+
+/datum/component/interaction_menu_granter/ui_state(mob/user)
+ // Funny admin, don't you dare be the extra funny now.
+ if(user.client.holder && !user.client.holder.deadmined)
+ return GLOB.always_state
+ if(user == parent)
+ return GLOB.conscious_state
+ return GLOB.never_state
+
+/datum/component/interaction_menu_granter/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "MobInteraction", "Interactions")
@@ -68,10 +81,10 @@
else
return 0
-/datum/interaction_menu/ui_data(mob/user)
+/datum/component/interaction_menu_granter/ui_data(mob/user)
. = ..()
//Getting player
- var/mob/living/self = user
+ var/mob/living/self = parent
//Getting info
.["isTargetSelf"] = target == self
.["interactingWith"] = target != self ? "Interacting with \the [target]..." : "Interacting with yourself..."
@@ -136,22 +149,22 @@
genital_entry["arousal_state"] = genital.aroused_state
genital_entry["always_accessible"] = genital.always_accessible
genitals += list(genital_entry)
- if(iscarbon(self) && !self.getorganslot(ORGAN_SLOT_ANUS))
- var/simulated_ass = list()
- simulated_ass["name"] = "Anus"
- simulated_ass["key"] = "anus"
- var/visibility = "Invalid"
- switch(self.anus_exposed)
- if(1)
- visibility = "Always visible"
- if(0)
- visibility = "Hidden by underwear"
- else
- visibility = "Always hidden"
- simulated_ass["visibility"] = visibility
- simulated_ass["possible_choices"] = GLOB.genitals_visibility_toggles - GEN_VISIBLE_NO_CLOTHES
- simulated_ass["always_accessible"] = self.anus_always_accessible
- genitals += list(simulated_ass)
+ if(!get_genitals.getorganslot(ORGAN_SLOT_ANUS)) //SPLURT Edit
+ var/simulated_ass = list()
+ simulated_ass["name"] = "Anus"
+ simulated_ass["key"] = "anus"
+ var/visibility = "Invalid"
+ switch(get_genitals.anus_exposed)
+ if(1)
+ visibility = "Always visible"
+ if(0)
+ visibility = "Hidden by underwear"
+ else
+ visibility = "Always hidden"
+ simulated_ass["visibility"] = visibility
+ simulated_ass["possible_choices"] = GLOB.genitals_visibility_toggles - GEN_VISIBLE_NO_CLOTHES
+ simulated_ass["always_accessible"] = get_genitals.anus_always_accessible
+ genitals += list(simulated_ass)
.["genitals"] = genitals
//Get their genitals
@@ -227,18 +240,19 @@
else
return "No"
-/datum/interaction_menu/ui_act(action, params)
+/datum/component/interaction_menu_granter/ui_act(action, params)
if(..())
return
+ var/mob/living/parent_mob = parent
switch(action)
if("interact")
var/datum/interaction/o = SSinteractions.interactions[params["interaction"]]
if(o)
- o.do_action(usr, target)
+ o.do_action(parent_mob, target)
return TRUE
return FALSE
if("genital")
- var/mob/living/carbon/self = usr
+ var/mob/living/carbon/self = parent_mob
if("visibility" in params)
if(params["genital"] == "anus")
self.anus_toggle_visibility(params["visibility"])
@@ -301,7 +315,7 @@
return TRUE
return FALSE
if("char_pref")
- var/datum/preferences/prefs = usr.client.prefs
+ var/datum/preferences/prefs = parent_mob.client.prefs
var/value = num_to_pref(params["value"])
switch(params["char_pref"])
if("erp_pref")
@@ -341,7 +355,7 @@
prefs.save_character()
return TRUE
if("pref")
- var/datum/preferences/prefs = usr.client.prefs
+ var/datum/preferences/prefs = parent_mob.client.prefs
switch(params["pref"])
if("verb_consent")
TOGGLE_BITFIELD(prefs.toggles, VERB_CONSENT)
diff --git a/modular_sand/code/datums/elements/holder_micro.dm b/modular_sand/code/datums/elements/holder_micro.dm
index f264ded3b5..9a15bc6699 100644
--- a/modular_sand/code/datums/elements/holder_micro.dm
+++ b/modular_sand/code/datums/elements/holder_micro.dm
@@ -168,9 +168,10 @@
set category = "IC"
set src in view(usr.client)
- if(!usr.mind) //Mindless boys, honestly just don't, it's better this way
+ if(!src)
return
- if(!usr.mind.interaction_holder)
- usr.mind.interaction_holder = new(usr.mind)
- usr.mind.interaction_holder.target = src.held_mob
- usr.mind.interaction_holder.ui_interact(usr)
+ var/datum/component/interaction_menu_granter/menu = held_mob.GetComponent(/datum/component/interaction_menu_granter)
+ if(menu)
+ menu.open_menu(usr, src)
+ else // you bad
+ remove_verb(src, /mob/proc/interact_with)
diff --git a/modular_sand/code/datums/elements/skirt_peeking.dm b/modular_sand/code/datums/elements/skirt_peeking.dm
index e5be0fc434..96207fbffa 100644
--- a/modular_sand/code/datums/elements/skirt_peeking.dm
+++ b/modular_sand/code/datums/elements/skirt_peeking.dm
@@ -29,12 +29,17 @@
// And are you under us while we're standing up?
if(!(CHECK_BITFIELD(living_peeker.mobility_flags, MOBILITY_STAND)) && (CHECK_BITFIELD(peeked.mobility_flags, MOBILITY_STAND)) && (peeked.loc == living_peeker.loc))
return TRUE
+ // Do you happen to be small enough to easily look under us?
+ if(COMPARE_SIZES(peeked, peeker) >= 2)
+ return TRUE
// Or are you nearby and we are up high
// to-do SOMEONE PLEASE PORT /datum/element/climbable
- var/obj/structure/high_ground = locate(/obj/structure) in get_turf(peeked)
- if(high_ground && high_ground.climbable && CHECK_BITFIELD(peeked.mobility_flags, MOBILITY_STAND) && \
- peeked.Adjacent(peeker))
- return TRUE
+ var/obj/structure/high_ground_peeked = locate(/obj/structure) in get_turf(peeked)
+ var/obj/structure/high_ground_peeker = locate(/obj/structure) in get_turf(peeker)
+ if(high_ground_peeked && high_ground_peeked.climbable && CHECK_BITFIELD(peeked.mobility_flags, MOBILITY_STAND) && peeked.Adjacent(peeker))
+ // Funnily enough, if we're at the same height, they can't just peek under us!
+ if(!(high_ground_peeker && high_ground_peeker.climbable))
+ return TRUE
return FALSE
/datum/element/skirt_peeking/proc/on_examine(mob/living/carbon/human/peeked, mob/peeker, list/examine_list)
@@ -99,3 +104,22 @@
string += " on full display."
examine_content += span_purple(string)
+ // Let's see if we caught them, addtimer so it appears after the peek.
+ addtimer(CALLBACK(src, .proc/try_notice, peeked, peeker), 1)
+
+/// Alright, they've peeked us and everything, did we notice it though?
+/datum/element/skirt_peeking/proc/try_notice(mob/living/carbon/human/peeked, mob/living/peeker)
+ if(!peeked || !peeker)
+ return
+ if(!istype(peeked) || !istype(peeker))
+ return
+ var/obj/item/clothing/under/worn_uniform = peeked.get_item_by_slot(ITEM_SLOT_ICLOTHING)
+ if(!istype(worn_uniform))
+ return
+ var/obj/item/clothing/glasses/eye_blocker = peeker.get_item_by_slot(ITEM_SLOT_EYES)
+ if(!(!peeked.client && (peeked.stat == CONSCIOUS) && !HAS_TRAIT(peeked, TRAIT_BLIND) && !is_blind(peeked) && \
+ !peeker.is_eyes_covered(FALSE) && !(eye_blocker && eye_blocker.tint > 0) && \
+ !(peeker.invisibility > peeked.invisibility) && !(peeker.alpha <= 30)))
+ return
+ to_chat(peeked, span_warning("You notice [peeker] looking under your [worn_uniform.name]!"))
+ to_chat(peeker, span_warning("[peeked] notices you peeking under [peeked.p_their()] [worn_uniform.name]!"))
diff --git a/modular_sand/code/datums/interactions/_interaction.dm b/modular_sand/code/datums/interactions/_interaction.dm
index b7077ae80d..5ba1efe8e8 100644
--- a/modular_sand/code/datums/interactions/_interaction.dm
+++ b/modular_sand/code/datums/interactions/_interaction.dm
@@ -10,13 +10,15 @@
- Makes all the code good because yes as well - SandPoot
**/
-/mob/living/proc/list_interaction_attributes()
- var/dat = list()
+/mob/proc/list_interaction_attributes()
+ return list()
+
+/mob/living/list_interaction_attributes()
+ . = ..()
if(has_hands())
- dat += "...have hands."
+ . += "...have hands."
if(has_mouth())
- dat += "...have a mouth, which is [mouth_is_free() ? "uncovered" : "covered"]."
- return dat
+ . += "...have a mouth, which is [mouth_is_free() ? "uncovered" : "covered"]."
/// The base of all interactions
/datum/interaction
diff --git a/modular_sand/code/datums/interactions/lewd_interactions.dm b/modular_sand/code/datums/interactions/lewd_interactions.dm
index 2171ec0b7f..ccd0708d93 100644
--- a/modular_sand/code/datums/interactions/lewd_interactions.dm
+++ b/modular_sand/code/datums/interactions/lewd_interactions.dm
@@ -516,18 +516,18 @@
return ..()
/mob/living/list_interaction_attributes(mob/living/LM)
- var/dat = ..()
+ . = ..()
if(!COOLDOWN_FINISHED(LM, refractory_period))
- dat += "...are sexually exhausted for the time being."
+ . += "...are sexually exhausted for the time being."
switch(a_intent)
if(INTENT_HELP)
- dat += "...are acting gentle."
+ . += "...are acting gentle."
if(INTENT_DISARM)
- dat += "...are acting playful."
+ . += "...are acting playful."
if(INTENT_GRAB)
- dat += "...are acting rough."
+ . += "...are acting rough."
if(INTENT_HARM)
- dat += "...are fighting anyone who comes near."
+ . += "...are fighting anyone who comes near."
//Here comes the fucking weird shit.
if(client)
var/client/cli = client
@@ -536,45 +536,44 @@
if(!ucli || (ucli.prefs.extremepref != "No"))
if(!get_item_by_slot(ITEM_SLOT_EARS_LEFT) && !get_item_by_slot(ITEM_SLOT_EARS_RIGHT))
if(has_ears())
- dat += "...have unprotected ears."
+ . += "...have unprotected ears."
else
- dat += "...have a hole where their ears should be."
+ . += "...have a hole where their ears should be."
else
- dat += "...have covered ears."
+ . += "...have covered ears."
if(!get_item_by_slot(ITEM_SLOT_EYES))
if(has_eyes())
- dat += "...have exposed eyes."
+ . += "...have exposed eyes."
else
- dat += "...have exposed eyesockets."
+ . += "...have exposed eyesockets."
else
- dat += "...have covered eyes."
+ . += "...have covered eyes."
//
// check those loops only once, thanks
var/is_topless = is_topless()
var/is_bottomless = is_bottomless()
if(is_topless && is_bottomless)
- dat += "...are naked."
+ . += "...are naked."
else
if((is_topless && !is_bottomless) || (!is_topless && is_bottomless))
- dat += "...are partially clothed."
+ . += "...are partially clothed."
else
- dat += "...are clothed."
+ . += "...are clothed."
if(has_breasts(REQUIRE_EXPOSED))
- dat += "...have breasts."
+ . += "...have breasts."
if(has_penis(REQUIRE_EXPOSED))
- dat += "...have a penis."
+ . += "...have a penis."
if(has_strapon(REQUIRE_EXPOSED))
- dat += "...have a strapon."
+ . += "...have a strapon."
if(has_balls(REQUIRE_EXPOSED))
- dat += "...have a ballsack."
+ . += "...have a ballsack."
if(has_vagina(REQUIRE_EXPOSED))
- dat += "...have a vagina."
+ . += "...have a vagina."
if(has_anus(REQUIRE_EXPOSED))
- dat += "...have an anus."
+ . += "...have an anus."
if(has_feet(REQUIRE_EXPOSED))
switch(has_feet(REQUIRE_EXPOSED))
if(2)
- dat += "...have a pair of feet."
+ . += "...have a pair of feet."
if(1)
- dat += "...have a single foot."
- return dat
+ . += "...have a single foot."
diff --git a/modular_sand/code/game/objects/effects/contraband.dm b/modular_sand/code/game/objects/effects/contraband.dm
index 0ec0d17ab9..6272882944 100644
--- a/modular_sand/code/game/objects/effects/contraband.dm
+++ b/modular_sand/code/game/objects/effects/contraband.dm
@@ -1,5 +1,5 @@
/obj/structure/sign/poster/contraband/yes_erp
name = "Yes ERP"
- desc = "This poster negates that Eroticism, Rape and Pornography should be banned from Nanotrasen stations."
+ desc = "This poster scrutinizes the banning of Eroticism, Rape and Pornography from Nanotrasen stations."
icon = 'modular_sand/icons/obj/contraband.dmi'
- icon_state = "poster1" //It is one because different file
+ icon_state = "poster_yeserp"
diff --git a/modular_sand/code/modules/client/loadout/accessories.dm b/modular_sand/code/modules/client/loadout/accessories.dm
index a317069bf4..61562dd38b 100644
--- a/modular_sand/code/modules/client/loadout/accessories.dm
+++ b/modular_sand/code/modules/client/loadout/accessories.dm
@@ -1,6 +1,5 @@
/datum/gear/accessories/ring
- category = LOADOUT_CATEGORY_GLOVES
- slot = ITEM_SLOT_HANDS
+ slot = ITEM_SLOT_ACCESSORY
/datum/gear/accessories/ring/goldring
name = "A gold ring"
diff --git a/modular_sand/code/modules/clothing/gloves/accessories.dm b/modular_sand/code/modules/clothing/gloves/accessories.dm
index 1c3986de1f..e2afe193ff 100644
--- a/modular_sand/code/modules/clothing/gloves/accessories.dm
+++ b/modular_sand/code/modules/clothing/gloves/accessories.dm
@@ -3,7 +3,8 @@
desc = "A tiny gold ring, sized to wrap around a finger."
gender = NEUTER
w_class = WEIGHT_CLASS_TINY
- slot_flags = ITEM_SLOT_GLOVES
+ slot_flags = ITEM_SLOT_ACCESSORY | ITEM_SLOT_GLOVES
+ slot_equipment_priority = ITEM_SLOT_ACCESSORY | ITEM_SLOT_GLOVES | ITEM_SLOT_BACKPACK
icon = 'icons/obj/ring.dmi'
mob_overlay_icon = 'icons/mob/clothing/hands.dmi'
icon_state = "ringgold"
diff --git a/modular_sand/code/modules/mob/living/silicon/robot/robot.dm b/modular_sand/code/modules/mob/living/silicon/robot/robot.dm
index 1ae172a5c4..184b318d1e 100644
--- a/modular_sand/code/modules/mob/living/silicon/robot/robot.dm
+++ b/modular_sand/code/modules/mob/living/silicon/robot/robot.dm
@@ -18,3 +18,24 @@
/mob/living/silicon/robot/modules/roleplay/binarycheck()
return 0 //Roleplay borgs aren't truly borgs
+
+/// Allows "cyborg" players to change gender at will
+/mob/living/silicon/robot/verb/toggle_gender()
+ set name = "Set Gender"
+ set desc = "Allows you to set your gender."
+
+ if(stat != CONSCIOUS)
+ to_chat(usr, span_warning("You cannot toggle your gender while unconcious!"))
+ return
+
+ var/choice = tgui_alert(usr, "Select Gender.", "Gender", list("Both", "Male", "Female"))
+ switch(choice)
+ if("Both")
+ has_penis = TRUE
+ has_vagina = TRUE
+ if("Male")
+ has_penis = TRUE
+ has_vagina = FALSE
+ if("Female")
+ has_penis = FALSE
+ has_vagina = TRUE
diff --git a/modular_sand/code/modules/mob/mob.dm b/modular_sand/code/modules/mob/mob.dm
index 05b0920a20..3f8a2650d0 100644
--- a/modular_sand/code/modules/mob/mob.dm
+++ b/modular_sand/code/modules/mob/mob.dm
@@ -1,3 +1,12 @@
+// Only Clients should have a panel for them, okay?
+/mob/Login()
+ . = ..()
+ AddComponent(/datum/component/interaction_menu_granter)
+
+/mob/Logout()
+ qdel(GetComponent(/datum/component/interaction_menu_granter))
+ . = ..()
+
///Adjust the thirst of a mob
/mob/proc/adjust_thirst(change, max = THIRST_LEVEL_THRESHOLD)
thirst = clamp(thirst + change, 0, max)
diff --git a/modular_sand/code/modules/resize/resizing.dm b/modular_sand/code/modules/resize/resizing.dm
index 9d0302561d..913fcbb294 100644
--- a/modular_sand/code/modules/resize/resizing.dm
+++ b/modular_sand/code/modules/resize/resizing.dm
@@ -19,12 +19,12 @@
return TRUE
//Doing messages
- if(abs(get_size(user)/get_size(target) >= 2)) //if the initiator is twice the size of the micro
+ if(COMPARE_SIZES(user, target) >= 2) //if the initiator is twice the size of the micro
now_pushing = 0
user.forceMove(target.loc)
//Smaller person being stepped on
- if(get_size(user) > get_size(target) && iscarbon(src))
+ if(iscarbon(src))
if(istype(user) && user.dna.features["taur"] == "Naga" || user.dna.features["taur"] == "Tentacle")
target.visible_message(span_notice("[src] carefully slithers around [target]."), span_notice("[src]'s huge tail slithers besides you."))
else
@@ -32,7 +32,7 @@
return TRUE
//Smaller person stepping under a larger person
- if(abs(get_size(target)/get_size(user)) >= 2)
+ if(COMPARE_SIZES(target, user) >= 2)
user.forceMove(target.loc)
now_pushing = 0
micro_step_under(target)
@@ -59,7 +59,7 @@
user.forceMove(target.loc)
return TRUE
- if(abs(get_size(user)/get_size(target)) >= 2)
+ if(COMPARE_SIZES(user, target) >= 2)
log_combat(user, target, "stepped on", addition="[user.a_intent] trample")
if(user.a_intent == "disarm" && CHECK_MOBILITY(user, MOBILITY_MOVE) && !user.buckled)
now_pushing = 0
@@ -67,7 +67,7 @@
user.sizediffStamLoss(target)
user.add_movespeed_modifier(/datum/movespeed_modifier/stomp, TRUE) //Full stop
addtimer(CALLBACK(user, /mob/.proc/remove_movespeed_modifier, MOVESPEED_ID_STOMP, TRUE), 3) //0.3 seconds
- if(get_size(user) > get_size(target) && iscarbon(user))
+ if(iscarbon(user))
if(istype(user) && user.dna.features["taur"] == "Naga" || user.dna.features["taur"] == "Tentacle")
target.visible_message(span_danger("[src] carefully rolls their tail over [target]!"), span_danger("[src]'s huge tail rolls over you!"))
else
@@ -83,7 +83,7 @@
user.add_movespeed_modifier(/datum/movespeed_modifier/stomp, TRUE)
addtimer(CALLBACK(user, /mob/.proc/remove_movespeed_modifier, MOVESPEED_ID_STOMP, TRUE), 10) //1 second
//user.Stun(20)
- if(get_size(user) > get_size(target) && iscarbon(user))
+ if(iscarbon(user))
if(istype(user) && (user.dna.features["taur"] == "Naga" || user.dna.features["taur"] == "Tentacle"))
target.visible_message(span_danger("[src] mows down [target] under their tail!"), span_userdanger("[src] plows their tail over you mercilessly!"))
else
@@ -97,7 +97,7 @@
user.sizediffStun(target)
user.add_movespeed_modifier(/datum/movespeed_modifier/stomp, TRUE)
addtimer(CALLBACK(user, /mob/.proc/remove_movespeed_modifier, MOVESPEED_ID_STOMP, TRUE), 7)//About 3/4th a second
- if(get_size(user) > get_size(target) && iscarbon(user))
+ if(iscarbon(user))
var/feetCover = (user.wear_suit && (user.wear_suit.body_parts_covered & FEET)) || (user.w_uniform && (user.w_uniform.body_parts_covered & FEET) || (user.shoes && (user.shoes.body_parts_covered & FEET)))
if(feetCover)
if(user?.dna?.features["taur"] == "Naga" || user?.dna?.features["taur"] == "Tentacle")
@@ -116,7 +116,7 @@
SEND_SIGNAL(target, COMSIG_MICRO_PICKUP_FEET, user)
return TRUE
- if(abs(get_size(target)/get_size(user)) >= 2)
+ if(COMPARE_SIZES(target, user) >= 2)
user.forceMove(target.loc)
now_pushing = 0
micro_step_under(target)
@@ -141,17 +141,17 @@
//Proc for scaling stamina damage on size difference
/mob/living/carbon/proc/sizediffStamLoss(mob/living/carbon/target)
- var/S = (get_size(src)/get_size(target)*25) //macro divided by micro, times 25
+ var/S = COMPARE_SIZES(src, target) * 25 //macro divided by micro, times 25
target.Knockdown(S) //final result in stamina knockdown
//Proc for scaling stuns on size difference (for grab intent)
/mob/living/carbon/proc/sizediffStun(mob/living/carbon/target)
- var/T = (get_size(src)/get_size(target)*2) //Macro divided by micro, times 2
+ var/T = COMPARE_SIZES(src, target) * 2 //Macro divided by micro, times 2
target.Stun(T)
//Proc for scaling brute damage on size difference
/mob/living/carbon/proc/sizediffBruteloss(mob/living/carbon/target)
- var/B = (get_size(src)/get_size(target)*3) //macro divided by micro, times 3
+ var/B = COMPARE_SIZES(src, target) * 3 //macro divided by micro, times 3
target.adjustBruteLoss(B) //final result in brute loss
//Proc for instantly grabbing valid size difference. Code optimizations soon(TM)
diff --git a/modular_sand/icons/obj/contraband.dmi b/modular_sand/icons/obj/contraband.dmi
index 37d26caed6..81f26f8c34 100644
Binary files a/modular_sand/icons/obj/contraband.dmi and b/modular_sand/icons/obj/contraband.dmi differ
diff --git a/modular_splurt/code/controllers/configuration/entries/splurt_general.dm b/modular_splurt/code/controllers/configuration/entries/splurt_general.dm
index 8c79ccfe15..cf0b983434 100644
--- a/modular_splurt/code/controllers/configuration/entries/splurt_general.dm
+++ b/modular_splurt/code/controllers/configuration/entries/splurt_general.dm
@@ -4,3 +4,6 @@
config_entry_value = 5
/datum/config_entry/flag/weighted_station_traits
+
+/datum/config_entry/number/base_save_slots
+ config_entry_value = DEFAULT_SAVE_SLOTS
diff --git a/modular_splurt/code/datums/components/dullahan.dm b/modular_splurt/code/datums/components/dullahan.dm
index a8558a5835..6fae1b981d 100644
--- a/modular_splurt/code/datums/components/dullahan.dm
+++ b/modular_splurt/code/datums/components/dullahan.dm
@@ -1,3 +1,15 @@
+#define HEAD_ACCESSORIES_PATHS list(\
+ /obj/item/clothing/head = 'icons/mob/clothing/head.dmi',\
+ /obj/item/clothing/glasses = 'icons/mob/clothing/eyes.dmi',\
+ /obj/item/reagent_containers/glass/bucket = 'icons/mob/clothing/head.dmi',\
+ /obj/item/reagent_containers/rag/towel = 'icons/mob/clothing/head.dmi',\
+ /obj/item/paper = 'icons/mob/clothing/head.dmi',\
+ /obj/item/nullrod/fedora = 'icons/mob/clothing/head.dmi',\
+ )
+
+/obj/item/organ/eyes/dullahan
+ tint = 0
+
/datum/component/neckfire
var/mutable_appearance/neck_fire
@@ -30,7 +42,7 @@
neck_fire.icon_state = "neckfire"
neck_fire.color = fire_color
- neck_fire.plane = 19 // glowy i hope
+ //neck_fire.plane = 19 // glowy i hope
var/datum/action/neckfire/A = new /datum/action/neckfire(src)
A.Grant(M)
@@ -72,3 +84,84 @@
var/mob/living/carbon/human/H = quirk_holder
if(H.dna.features["neckfire"] && !istype(H, /mob/living/carbon/human/dummy))
H.AddComponent(/datum/component/neckfire, H.dna.features["neckfire_color"])
+
+/datum/component/dullahan
+ var/obj/item/clothing/head_accessory
+ var/mutable_appearance/head_accessory_MA
+
+/datum/component/dullahan/Initialize()
+ . = ..()
+ RegisterSignal(dullahan_head, COMSIG_MOUSEDROPPED_ONTO, .proc/on_mouse_dropped)
+ RegisterSignal(dullahan_head, COMSIG_MOUSEDROP_ONTO, .proc/on_mouse_drop)
+
+/datum/component/dullahan/proc/add_head_accessory(obj/item/clothing/I, item_path)
+ head_accessory_MA = mutable_appearance(I.mob_overlay_icon || HEAD_ACCESSORIES_PATHS[item_path])
+ head_accessory_MA.icon_state = I.icon_state
+ I.forceMove(dullahan_head)
+
+ dullahan_head.add_overlay(head_accessory_MA)
+ head_accessory = I
+
+/datum/component/dullahan/proc/remove_head_accessory(obj/item/clothing/I)
+ dullahan_head.cut_overlay(head_accessory_MA)
+ head_accessory = null
+
+/datum/component/dullahan/proc/on_mouse_dropped(datum/source, obj/item/I, mob/living/user)
+ var/mob/living/carbon/owner = dullahan_head.owner
+ var/item_path
+
+ for(var/type in HEAD_ACCESSORIES_PATHS)
+ if(istype(I, type))
+ item_path = type
+ break
+
+ if(item_path && !head_accessory)
+ if(istype(I, /obj/item/clothing))
+ var/obj/item/organ/eyes/dullahan/eyes = owner.getorganslot(ORGAN_SLOT_EYES)
+ var/obj/item/clothing/clothing = I
+
+ eyes.flash_protect = clothing.flash_protect
+ eyes.tint = clothing.tint
+ owner.update_tint()
+
+ add_head_accessory(I, item_path)
+ else
+ to_chat(user, span_notice("You can't put \the [I.name] on the head of \the [owner.name]"))
+ return
+
+/datum/component/dullahan/proc/on_mouse_drop(datum/source, atom/A, mob/living/user)
+ var/mob/living/carbon/owner = dullahan_head.owner
+
+ if(head_accessory)
+ if(istype(A, /turf/open))
+ head_accessory.forceMove(A)
+ else if(istype(A, /atom/movable/screen/inventory/hand))
+ var/atom/movable/screen/inventory/hand/H = A
+
+ user.put_in_hand(head_accessory, H.held_index)
+ else
+ return
+
+ var/obj/item/organ/eyes/dullahan/eyes = owner.getorganslot(ORGAN_SLOT_EYES)
+ eyes.flash_protect = 0
+ eyes.tint = 0
+ owner.update_tint()
+
+ remove_head_accessory(head_accessory)
+
+/datum/action/item_action/organ_action/dullahan/proc/toggle_monochromacy()
+ var/obj/item/organ/eyes/eyes = owner.getorganslot(ORGAN_SLOT_EYES)
+
+ if(eyes.monochromacy_on)
+ owner.remove_client_colour(/datum/client_colour/monochrome)
+ else
+ owner.add_client_colour(/datum/client_colour/monochrome)
+
+ eyes.monochromacy_on = !eyes.monochromacy_on
+
+/obj/item/organ/eyes
+ var/monochromacy_on = FALSE
+
+/datum/action/item_action/organ_action/dullahan/Grant(mob/M)
+ . = ..()
+ toggle_monochromacy()
diff --git a/modular_splurt/code/datums/interactions/lewd/lewd_datums.dm b/modular_splurt/code/datums/interactions/lewd/lewd_datums.dm
index ca6fddf6e8..896cc1c05f 100644
--- a/modular_splurt/code/datums/interactions/lewd/lewd_datums.dm
+++ b/modular_splurt/code/datums/interactions/lewd/lewd_datums.dm
@@ -469,6 +469,20 @@
if(gut)
gut.modify_size(-1)
+/datum/interaction/lewd/inflate_belly
+ description = "Inflate belly"
+ require_user_belly = REQUIRE_EXPOSED
+ interaction_sound = null
+ max_distance = 0
+ user_is_target = TRUE
+ write_log_user = "inflated their belly"
+ write_log_target = null
+
+/datum/interaction/lewd/inflate_belly/display_interaction(mob/living/carbon/user)
+ var/obj/item/organ/genital/belly/gut = user.getorganslot(ORGAN_SLOT_BELLY)
+ if(gut)
+ gut.modify_size(1)
+
/datum/interaction/lewd/nuzzle_belly
description = "Nuzzle their belly."
require_target_belly = REQUIRE_EXPOSED
diff --git a/modular_splurt/code/datums/traits/good.dm b/modular_splurt/code/datums/traits/good.dm
index 1984a6a73f..70a84f4d82 100644
--- a/modular_splurt/code/datums/traits/good.dm
+++ b/modular_splurt/code/datums/traits/good.dm
@@ -1,3 +1,18 @@
+//Main code edits
+/datum/quirk/photographer
+ desc = "You carry your camera and personal photo album everywhere you go, and you're quicker at taking pictures."
+
+/datum/quirk/photographer/on_spawn()
+ . = ..()
+ var/mob/living/carbon/human/H = quirk_holder
+ var/obj/item/storage/photo_album/photo_album = new(get_turf(H))
+ H.put_in_hands(photo_album)
+ H.equip_to_slot(photo_album, ITEM_SLOT_BACKPACK)
+ photo_album.persistence_id = "personal_[H.mind.key]" // this is a persistent album, the ID is tied to the account's key to avoid tampering
+ photo_album.persistence_load()
+ photo_album.name = "[H.real_name]'s photo album"
+
+//Own stuff
/datum/quirk/tough
name = "Tough"
desc = "Your body is abnormally enduring and can take 10% more damage."
diff --git a/modular_splurt/code/datums/traits/neutral.dm b/modular_splurt/code/datums/traits/neutral.dm
index 156a3fc4b3..5fdca5e6f5 100644
--- a/modular_splurt/code/datums/traits/neutral.dm
+++ b/modular_splurt/code/datums/traits/neutral.dm
@@ -510,21 +510,43 @@
/datum/quirk/werewolf //adds the werewolf quirk
name = "Werewolf"
- desc = "A beastly affliction allows you to shapeshift into a more wolfish appearance at will. This will increase your size (In general and below!) and cause you to behave as though you were an anthropomorphic canine. (This is still being tested. Please send any bugs to nukechicken on discord)"
+ desc = "A beastly affliction allows you to shape-shift into a large anthropomorphic canine at will."
value = 0
+ mob_trait = TRAIT_WEREWOLF
+ gain_text = span_notice("You feel the full moon beckon.")
+ lose_text = span_notice("The moon's call hushes into silence.")
+ medical_record_text = "Patient has been reported howling at the night sky."
+ var/list/old_features
/datum/quirk/werewolf/add()
- . = ..()
- var/mob/living/carbon/human/H = quirk_holder
- var/datum/action/werewolf/W = new
- W.Grant(H)
+ // Define old features
+ old_features = list("species" = SPECIES_HUMAN, "legs" = "Plantigrade", "size" = 1, "bark")
+
+ // Define quirk mob
+ var/mob/living/carbon/human/quirk_mob = quirk_holder
+
+ // Record features
+ old_features = quirk_mob.dna.features.Copy()
+ old_features["species"] = quirk_mob.dna.species.type
+ old_features["custom_species"] = quirk_mob.custom_species
+ old_features["size"] = get_size(quirk_mob)
+ old_features["bark"] = quirk_mob.vocal_bark_id
+ old_features["taur"] = quirk_mob.dna.features["taur"]
+ old_features["eye_type"] = quirk_mob.dna.species.eye_type
+
+/datum/quirk/werewolf/post_add()
+ // Define quirk action
+ var/datum/action/cooldown/werewolf/transform/quirk_action = new
+
+ // Grant quirk action
+ quirk_action.Grant(quirk_holder)
/datum/quirk/werewolf/remove()
- var/mob/living/carbon/human/H = quirk_holder
- var/datum/action/werewolf/W = locate() in H.actions
- W.Remove(H)
- . = ..()
+ // Define quirk action
+ var/datum/action/cooldown/werewolf/transform/quirk_action = locate() in quirk_holder.actions
+ // Revoke quirk action
+ quirk_action.Remove(quirk_holder)
/datum/quirk/gargoyle //Mmmm yes stone time
name = "Gargoyle"
diff --git a/modular_splurt/code/datums/traits/trait_actions.dm b/modular_splurt/code/datums/traits/trait_actions.dm
index 51b93106fd..da19988868 100644
--- a/modular_splurt/code/datums/traits/trait_actions.dm
+++ b/modular_splurt/code/datums/traits/trait_actions.dm
@@ -673,89 +673,221 @@
// Quirk: Werewolf
//
-/datum/action/werewolf
- name = "Transform"
- desc = "Transform into your wolf form."
+/datum/action/cooldown/werewolf
+ name = "Werewolf Ability"
+ desc = "Do something related to werewolves."
icon_icon = 'modular_splurt/icons/mob/actions/misc_actions.dmi'
button_icon_state = "Transform"
- var/transformed = FALSE
- var/list/old_features = list("species" = SPECIES_HUMAN, "legs" = "Plantigrade", "size" = 1, "bark")
+ check_flags = AB_CHECK_RESTRAINED | AB_CHECK_STUN | AB_CHECK_CONSCIOUS | AB_CHECK_ALIVE
+ cooldown_time = 5 SECONDS
+ transparent_when_unavailable = TRUE
-/datum/action/werewolf/Trigger()
+/datum/action/cooldown/werewolf/transform
+ name = "Toggle Werewolf Form"
+ desc = "Transform in or out of your wolf form."
+ var/transformed = FALSE
+ var/species_changed = FALSE
+ var/werewolf_gender = "Lycan"
+ var/list/old_features
+
+/datum/action/cooldown/werewolf/transform/Grant()
. = ..()
- var/mob/living/carbon/human/H = owner
- var/obj/item/organ/genital/penis/P = H.getorganslot(ORGAN_SLOT_PENIS)
- var/obj/item/organ/genital/breasts/B = H.getorganslot(ORGAN_SLOT_BREASTS)
- var/obj/item/organ/genital/vagina/V = H.getorganslot(ORGAN_SLOT_VAGINA)
- H.shake_animation(2)
- if(!transformed) // transform them
- H.visible_message(span_danger("[H] shivers, their flesh bursting with a sudden growth of thick fur and their features contorting to that of a beast's, fully transforming them into a werewolf!"))
- H.set_species(/datum/species/mammal, 1)
- H.dna.species.mutant_bodyparts["mam_tail"] = "Wolf"
- H.dna.species.mutant_bodyparts["legs"] = "Digitigrade"
- H.Digitigrade_Leg_Swap(FALSE)
- H.dna.species.mutant_bodyparts["mam_snouts"] = "Mammal, Thick"
- H.dna.features["mam_ears"] = "Wolf"
- H.dna.features["mam_tail"] = "Wolf"
- H.dna.features["mam_snouts"] = "Mammal, Thick"
- H.dna.features["legs"] = "Digitigrade"
- H.update_size(get_size(H) + 0.5)
- H.set_bark("bark")
- H.custom_species = "Werewolf"
- if(!(H.dna.species.species_traits.Find(DIGITIGRADE)))
- H.dna.species.species_traits += DIGITIGRADE
- H.update_body()
- H.update_body_parts()
- if(B)
- B.color = "#[H.dna.features["mcolor"]]"
- B.update()
- if(P)
- P.shape = "Knotted"
- P.color = "#ff7c80"
- P.update()
- P.modify_size(6)
- if(V)
- V.shape = "Furred"
- V.color = "#[H.dna.features["mcolor"]]"
- V.update()
- else // untransform them
- H.visible_message(span_danger("[H] shrinks, their wolfish features quickly receding."))
- H.set_species(old_features["species"], TRUE)
- H.set_bark(old_features["bark"])
- H.dna.features["mam_ears"] = old_features["mam_ears"]
- H.dna.features["mam_snouts"] = old_features["mam_snouts"]
- H.dna.features["mam_tail"] = old_features["mam_tail"]
- H.dna.features["legs"] = old_features["legs"] //i hate legs i hate legs i hate legs i hate legs i hate legs i hate legs i hate legs
+
+ // Define carbon owner
+ var/mob/living/carbon/action_owner_carbon = owner
+
+ // Define parent quirk
+ var/datum/quirk/werewolf/quirk_data = locate() in action_owner_carbon.roundstart_quirks
+
+ // Check if data was copied
+ if(!quirk_data)
+ // Log error and return
+ log_game("Failed to get species data for werewolf action!")
+ return
+
+ // Define stored features
+ old_features = quirk_data.old_features.Copy()
+
+ // Define action owner
+ var/mob/living/carbon/human/action_owner = owner
+
+ // Set species gendered name
+ switch(action_owner.gender)
+ if(MALE)
+ werewolf_gender = "Wer"
+ if(FEMALE)
+ werewolf_gender = "Wīf"
+ if(PLURAL)
+ werewolf_gender = "Hie"
+ if(NEUTER)
+ werewolf_gender = "Þing"
+
+/datum/action/cooldown/werewolf/transform/Trigger()
+ . = ..()
+
+ // Check if unavailable
+ // Checks the parent function's return value
+ if(!.)
+ // Messages will not display here
+ return FALSE
+
+ // Define action owner
+ var/mob/living/carbon/human/action_owner = owner
+
+ // Check for restraints
+ if(!CHECK_MOBILITY(action_owner, MOBILITY_USE))
+ // Warn user, then return
+ action_owner.visible_message(span_warning("You cannot transform while restrained!"))
+ return
+
+ // Define citadel organs
+ var/obj/item/organ/genital/penis/organ_penis = action_owner.getorganslot(ORGAN_SLOT_PENIS)
+ var/obj/item/organ/genital/breasts/organ_breasts = action_owner.getorganslot(ORGAN_SLOT_BREASTS)
+ var/obj/item/organ/genital/vagina/organ_vagina = action_owner.getorganslot(ORGAN_SLOT_VAGINA)
+
+ // Play shake animation
+ action_owner.shake_animation(2)
+
+ // Transform into wolf form
+ if(!transformed)
+ // Define current species type
+ var/datum/species/owner_species = action_owner.dna.species.type
+
+ // Check if species has changed
+ if(old_features["species"] != owner_species)
+ // Set old species
+ old_features["species"] = owner_species
+
+ // Define species prefix
+ var/custom_species_prefix
+
+ // Check if species is mammal (anthro)
+ if(ismammal(action_owner))
+ // Do nothing!
+
+ // Check if species is already a mammal sub-type
+ else if(owner_species in subtypesof(/datum/species/mammal))
+ // Do nothing!
+
+ // Check if species is a jelly
+ else if(isjellyperson(action_owner))
+ // Set species prefix
+ custom_species_prefix = "Jelly "
+
+ // Check if species is a jelly subtype
+ else if(owner_species in subtypesof(/datum/species/jelly))
+ // Set species prefix
+ custom_species_prefix = "Slime "
+
+ // Species is not a mammal
+ else
+ // Change species
+ action_owner.set_species(/datum/species/mammal, 1)
+
+ // Set species changed
+ species_changed = TRUE
+
+ // Set species features
+ action_owner.dna.custom_species = "[custom_species_prefix][werewolf_gender]wulf"
+ action_owner.dna.species.mutant_bodyparts["mam_tail"] = "Otusian"
+ action_owner.dna.species.mutant_bodyparts["legs"] = "Digitigrade"
+ action_owner.Digitigrade_Leg_Swap(FALSE)
+ action_owner.dna.species.mutant_bodyparts["mam_snouts"] = "Sergal"
+ action_owner.dna.features["mam_ears"] = "Jackal"
+ action_owner.dna.features["mam_tail"] = "Otusian"
+ action_owner.dna.features["mam_snouts"] = "Sergal"
+ action_owner.dna.features["legs"] = "Digitigrade"
+ action_owner.dna.features["insect_fluff"] = "Hyena"
+ action_owner.update_size(get_size(action_owner) + 0.5)
+ action_owner.set_bark("bark")
+ if(old_features["taur"] != "None")
+ action_owner.dna.features["taur"] = "Canine"
+ if(!(action_owner.dna.species.species_traits.Find(DIGITIGRADE)))
+ action_owner.dna.species.species_traits += DIGITIGRADE
+ action_owner.update_body()
+ action_owner.update_body_parts()
+
+ // Update possible citadel organs
+ if(organ_breasts)
+ organ_breasts.color = "#[action_owner.dna.features["mcolor"]]"
+ organ_breasts.update()
+ if(organ_penis)
+ organ_penis.shape = "Knotted"
+ organ_penis.color = "#ff7c80"
+ organ_penis.update()
+ organ_penis.modify_size(6)
+ if(organ_vagina)
+ organ_vagina.shape = "Furred"
+ organ_vagina.color = "#[action_owner.dna.features["mcolor"]]"
+ organ_vagina.update()
+
+ // Un-transform from wolf form
+ else
+ // Check if species was already mammal (anthro)
+ if(!species_changed)
+ // Do nothing!
+
+ // Species was not a mammal
+ else
+ // Revert species
+ action_owner.set_species(old_features["species"], TRUE)
+
+ // Clear species changed flag
+ species_changed = FALSE
+
+ // Revert species trait
+ action_owner.set_bark(old_features["bark"])
+ action_owner.dna.custom_species = old_features["custom_species"]
+ action_owner.dna.features["mam_ears"] = old_features["mam_ears"]
+ action_owner.dna.features["mam_snouts"] = old_features["mam_snouts"]
+ action_owner.dna.features["mam_tail"] = old_features["mam_tail"]
+ action_owner.dna.features["legs"] = old_features["legs"]
+ action_owner.dna.features["insect_fluff"] = old_features["insect_fluff"]
+ action_owner.dna.species.eye_type = old_features["eye_type"]
+ if(old_features["taur"] != "None")
+ action_owner.dna.features["taur"] = old_features["taur"]
if(old_features["legs"] == "Plantigrade")
- H.dna.species.species_traits -= DIGITIGRADE
- H.Digitigrade_Leg_Swap(TRUE)
- H.dna.species.mutant_bodyparts["legs"] = old_features["legs"]
- H.update_body()
- H.update_body_parts()
- H.update_size(get_size(H) - 0.5)
- if(B)
- B.color = "#[old_features["breasts_color"]]"
- B.update()
- if(H.has_penis())
- P.shape = old_features["cock_shape"]
- P.color = "#[old_features["cock_color"]]"
- P.update()
- P.modify_size(-6)
- if(H.has_vagina())
- V.shape = old_features["vag_shape"]
- V.color = "#[old_features["vag_color"]]"
- V.update()
- V.update_size()
+ action_owner.dna.species.species_traits -= DIGITIGRADE
+ action_owner.Digitigrade_Leg_Swap(TRUE)
+ action_owner.dna.species.mutant_bodyparts["legs"] = old_features["legs"]
+ action_owner.update_body()
+ action_owner.update_body_parts()
+ action_owner.update_size(get_size(action_owner) - 0.5)
+
+ // Revert citadel organs
+ if(organ_breasts)
+ organ_breasts.color = "#[old_features["breasts_color"]]"
+ organ_breasts.update()
+ if(action_owner.has_penis())
+ organ_penis.shape = old_features["cock_shape"]
+ organ_penis.color = "#[old_features["cock_color"]]"
+ organ_penis.update()
+ organ_penis.modify_size(-6)
+ if(action_owner.has_vagina())
+ organ_vagina.shape = old_features["vag_shape"]
+ organ_vagina.color = "#[old_features["vag_color"]]"
+ organ_vagina.update()
+ organ_vagina.update_size()
+
+ // Set transformation message
+ var/owner_p_their = action_owner.p_their()
+ var/toggle_message = (!transformed ? "[action_owner] shivers, [owner_p_their] flesh bursting with a sudden growth of thick fur as [owner_p_their] features contort to that of a beast, fully transforming [action_owner.p_them()] into a werewolf!" : "[action_owner] shrinks, [owner_p_their] wolfish features quickly receding.")
+
+ // Alert in local chat
+ action_owner.visible_message(span_danger(toggle_message))
+
+ // Toggle transformation state
transformed = !transformed
-/datum/action/werewolf/Grant()// on grant sets some variables
- . = ..()
- var/mob/living/carbon/human/H = owner
- old_features = H.dna.features.Copy()
- old_features["species"] = H.dna.species.type
- old_features["size"] = get_size(H)
- old_features["bark"] = H.vocal_bark_id
+ // Start cooldown
+ StartCooldown()
+ // Return success
+ return TRUE
+
+//
+// Quirk: Gargoyle
+//
/datum/action/gargoyle/transform
name = "Transform"
@@ -795,10 +927,6 @@
to_chat(H, span_warning("You have transformed too recently; you cannot yet transform again!"))
return 0
-//
-// Quirk: Gargoyle
-//
-
/datum/action/gargoyle/check
name = "Check"
desc = "Check your current energy levels."
diff --git a/modular_splurt/code/game/objects/items/toys.dm b/modular_splurt/code/game/objects/items/toys.dm
index 1d441a4a94..b131fd5c74 100644
--- a/modular_splurt/code/game/objects/items/toys.dm
+++ b/modular_splurt/code/game/objects/items/toys.dm
@@ -39,3 +39,70 @@
// Set flavor text
name = "generic action figure"
desc = "It\'s just a normal toy."
+
+/obj/item/toy/beach_ball
+ var/obj/item/vibrator
+ var/enabled = FALSE
+
+/obj/item/toy/beach_ball/syndicate
+ icon_state = "ballsyndicate"
+ icon = 'modular_splurt/icons/misc/beach.dmi'
+ desc = "Hmm. This ball is a bit heavier and tougher than the others."
+
+/obj/item/toy/beach_ball/attackby(obj/item/I, mob/living/user)
+ if(istype(I, /obj/item/electropack/vibrator))
+ if(vibrator)
+ to_chat(user, span_warning("There is already a vibrator inside this!"))
+ else
+ if(!user.transferItemToLoc(I,src))
+ return
+ to_chat(user, span_notice("You put [I] inside [src]."))
+ vibrator = I
+
+/obj/item/toy/beach_ball/attack_self(mob/user)
+ var/list/options_list = list()
+ if(vibrator)
+ options_list += list("Eject" = image(icon = 'icons/radials/taperecorder.dmi', icon_state = "eject", dir = EAST))
+ options_list += list("Play" = image(icon = 'icons/radials/taperecorder.dmi', icon_state = "play", dir = WEST))
+ if(options_list)
+ var/selection = show_radial_menu(user, src, options_list, radius = 38, require_near = TRUE, tooltips = TRUE)
+ if(!selection)
+ return
+ switch(selection)
+ if("Play")
+ playsound(user, 'sound/effects/clock_tick.ogg', 50, 1, -1)
+ enabled = !enabled
+ if(enabled)
+ START_PROCESSING(SSobj, src)
+ else
+ STOP_PROCESSING(SSobj, src)
+ to_chat(user, "You toggle the [vibrator].")
+ if("Eject")
+ playsound(user, 'sound/weapons/empty.ogg', 100, 1)
+ to_chat(user, "You remove [vibrator] from [src].")
+ user.put_in_hands(vibrator)
+ enabled = FALSE
+ vibrator = null
+ update_icon()
+
+/obj/item/toy/beach_ball/process()
+ if(vibrator && enabled)
+ throw_at(get_edge_target_turf(src,pick(GLOB.alldirs)),3,1)
+ playsound(src, 'modular_splurt/sound/lewd/vibrate.ogg', 40, 1, -1)
+
+/obj/item/toy/beach_ball/syndicate/process()
+ . = ..()
+ if(vibrator && enabled)
+ throwforce = 60
+
+/obj/item/toy/beach_ball/syndicate/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback)
+ if(ishuman(thrower))
+ throwforce = 0
+ . = ..()
+
+/obj/item/toy/beach_ball/syndicate/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ . = ..()
+ if(istype(hit_atom, /turf/closed/wall) && throwforce > 0)
+ var/turf/closed/wall/W = hit_atom
+ W.dismantle_wall()
+
diff --git a/modular_splurt/code/modules/client/loadout/shoes.dm b/modular_splurt/code/modules/client/loadout/shoes.dm
index d10f823444..b75b1cd621 100644
--- a/modular_splurt/code/modules/client/loadout/shoes.dm
+++ b/modular_splurt/code/modules/client/loadout/shoes.dm
@@ -2,7 +2,7 @@
/datum/gear/shoes/footwraps
name = "Cloth Footwraps"
path= /obj/item/clothing/shoes/footwraps
-
+
/datum/gear/shoes/invisiboots
name = "Invisifiber Footwraps"
path= /obj/item/clothing/shoes/invisiboots
@@ -36,3 +36,7 @@
/datum/gear/shoes/puttee
restricted_roles = list("Security Officer", "Warden", "Head of Security", "Brig Physician", "Blueshield")
+
+/datum/gear/shoes/highheel_sandals
+ name = "High-heel Sandals"
+ path = /obj/item/clothing/shoes/highheel_sandals
diff --git a/modular_splurt/code/modules/client/loadout/uniform.dm b/modular_splurt/code/modules/client/loadout/uniform.dm
index 29d91596d7..1333a8c764 100644
--- a/modular_splurt/code/modules/client/loadout/uniform.dm
+++ b/modular_splurt/code/modules/client/loadout/uniform.dm
@@ -146,3 +146,15 @@
path = /obj/item/clothing/under/goner/fake/poly
loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
loadout_initial_colors = list("#E6E6E6")
+
+/datum/gear/uniform/leia_outfit
+ name = "Princess Leia Outfit"
+ path = /obj/item/clothing/under/misc/leia_outfit
+ loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
+ loadout_initial_colors = list("#C61818", "#D4AF37")
+
+/datum/gear/uniform/performer/polychromic
+ name = "Polychromic performers one piece"
+ path = /obj/item/clothing/under/performer/polychromic
+ loadout_flags = LOADOUT_CAN_NAME | LOADOUT_CAN_DESCRIPTION | LOADOUT_CAN_COLOR_POLYCHROMIC
+ loadout_initial_colors = list("#ffffff")
diff --git a/modular_splurt/code/modules/client/preferences.dm b/modular_splurt/code/modules/client/preferences.dm
index 683afd00cf..13b9bc882b 100644
--- a/modular_splurt/code/modules/client/preferences.dm
+++ b/modular_splurt/code/modules/client/preferences.dm
@@ -1,12 +1,18 @@
/datum/preferences
+ max_save_slots = DEFAULT_SAVE_SLOTS
var/unholypref = "No" //Goin 2 hell fo dis one
-
var/list/gfluid_blacklist = list() //Stuff you don't want people to cum into you
/datum/preferences/New(client/C)
if(!GLOB.genital_fluids_list)
build_genital_fluids_list() //I DON'T KNOW where else to put it, ok??
+ //Extra saves for donators
+ max_save_slots = CONFIG_GET(number/base_save_slots)
+ if(istype(C))
+ var/extra_slots = (IS_CKEY_DONATOR_GROUP(C.key, DONATOR_GROUP_TIER_1) + IS_CKEY_DONATOR_GROUP(C.key, DONATOR_GROUP_TIER_2) + IS_CKEY_DONATOR_GROUP(C.key, DONATOR_GROUP_TIER_3)) * 10
+ max_save_slots += extra_slots
+
. = ..()
/proc/build_genital_fluids_list()
diff --git a/modular_splurt/code/modules/clothing/shoes/miscellaneous.dm b/modular_splurt/code/modules/clothing/shoes/miscellaneous.dm
index f5a8fac735..d87fd74ce7 100644
--- a/modular_splurt/code/modules/clothing/shoes/miscellaneous.dm
+++ b/modular_splurt/code/modules/clothing/shoes/miscellaneous.dm
@@ -84,3 +84,15 @@
build_path = /obj/item/clothing/shoes/jackboots/cbrn/mopp
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/obj/item/clothing/shoes/highheel_sandals
+ name = "high-heel sandals"
+ desc = "A pair of high-heel sandals"
+ icon = 'modular_splurt/icons/obj/clothing/shoes.dmi'
+ mob_overlay_icon = 'modular_splurt/icons/mob/clothing/shoes.dmi'
+ anthro_mob_worn_overlay = 'modular_splurt/icons/mob/clothing/shoes_digi.dmi'
+ icon_state = "highheel_sandals"
+
+/obj/item/clothing/shoes/highheel_sandals/Initialize()
+ . = ..()
+ AddComponent(/datum/component/squeak, list('modular_splurt/sound/effects/footstep/highheel1.ogg' = 1,'modular_splurt/sound/effects/footstep/highheel2.ogg' = 1), 20)
diff --git a/modular_splurt/code/modules/clothing/under/miscellaneous.dm b/modular_splurt/code/modules/clothing/under/miscellaneous.dm
index 3f6b806260..990dedb2a8 100644
--- a/modular_splurt/code/modules/clothing/under/miscellaneous.dm
+++ b/modular_splurt/code/modules/clothing/under/miscellaneous.dm
@@ -311,3 +311,25 @@
/obj/item/clothing/under/misc/gear_harness
body_parts_covered = NONE
+/obj/item/clothing/under/misc/leia_outfit
+ name = "space princess outfit"
+ desc = "Chain for your Master's erotic asphyxiation not included."
+ icon = 'modular_splurt/icons/obj/clothing/uniforms.dmi'
+ mob_overlay_icon = 'modular_splurt/icons/mob/clothing/uniform.dmi'
+ icon_state = "leia"
+ can_adjust = FALSE
+ mutantrace_variation = STYLE_DIGITIGRADE|STYLE_NO_ANTHRO_ICON
+
+/obj/item/clothing/under/misc/leia_outfit/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/polychromic, list("#C61818", "#D4AF37"), 2)
+
+/obj/item/clothing/under/performer/polychromic
+ name = "polychromic performers one piece"
+ icon = 'modular_splurt/icons/obj/clothing/uniforms.dmi'
+ mob_overlay_icon = 'modular_splurt/icons/mob/clothing/uniform.dmi'
+ icon_state = "poly_performer"
+
+/obj/item/clothing/under/performer/polychromic/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/polychromic, list("#ffffff"), 1)
diff --git a/modular_splurt/code/modules/food_and_drinks/recipes/drink_recipes.dm b/modular_splurt/code/modules/food_and_drinks/recipes/drink_recipes.dm
index a587e9fc71..c388d8fe3c 100644
--- a/modular_splurt/code/modules/food_and_drinks/recipes/drink_recipes.dm
+++ b/modular_splurt/code/modules/food_and_drinks/recipes/drink_recipes.dm
@@ -189,3 +189,104 @@
/datum/reagent/consumable/ethanol/moonshine = 2,
/datum/reagent/consumable/ethanol/brave_bull = 1
)
+
+//Milkshakes
+/datum/chemical_reaction/milkshake_base
+ name = "Plain Milkshake"
+ id = /datum/reagent/consumable/milkshake_base
+ results = list(/datum/reagent/consumable/milkshake_base = 3)
+ required_reagents = list(
+ /datum/reagent/consumable/milk = 1,
+ /datum/reagent/consumable/ice = 1,
+ /datum/reagent/consumable/cream =1
+ )
+
+/datum/chemical_reaction/milkshake_vanilla
+ name = "Vanilla Milkshake"
+ id = /datum/reagent/consumable/milkshake_vanilla
+ results = list(/datum/reagent/consumable/milkshake_vanilla = 2)
+ required_reagents = list(
+ /datum/reagent/consumable/milkshake_base =1,
+ /datum/reagent/consumable/vanilla =1
+ )
+
+/datum/chemical_reaction/milkshake_choc
+ name = "Chocolate Milkshake"
+ id = /datum/reagent/consumable/milkshake_choc
+ results = list(/datum/reagent/consumable/milkshake_choc = 2)
+ required_reagents = list(
+ /datum/reagent/consumable/milkshake_base = 1,
+ /datum/reagent/consumable/coco = 1
+ )
+
+/datum/chemical_reaction/milkshake_strawberry
+ name = "Strawberry Milkshake"
+ id = /datum/reagent/consumable/milkshake_strawberry
+ results = list(/datum/reagent/consumable/milkshake_strawberry = 2)
+ required_reagents = list(
+ /datum/reagent/consumable/milkshake_base = 1,
+ /datum/reagent/consumable/strawberryjuice = 1
+ )
+
+/datum/chemical_reaction/milkshake_banana
+ name = "Banana Milkshake"
+ id = /datum/reagent/consumable/milkshake_banana
+ results = list(/datum/reagent/consumable/milkshake_banana = 2)
+ required_reagents = list(
+ /datum/reagent/consumable/milkshake_base = 1,
+ /datum/reagent/consumable/banana = 1
+ )
+
+/datum/chemical_reaction/milkshake_berry
+ name = "Berry Milkshake"
+ id = /datum/reagent/consumable/milkshake_berry
+ results = list(/datum/reagent/consumable/milkshake_berry = 2)
+ required_reagents = list(
+ /datum/reagent/consumable/milkshake_base = 1,
+ /datum/reagent/consumable/berryjuice = 1
+ )
+
+/datum/chemical_reaction/milkshake_cola
+ name = "Cola Milkshake"
+ id = /datum/reagent/consumable/milkshake_cola
+ results = list(/datum/reagent/consumable/milkshake_cola = 2)
+ required_reagents = list(
+ /datum/reagent/consumable/milkshake_base = 1,
+ /datum/reagent/consumable/space_cola = 1
+ )
+
+/datum/chemical_reaction/milkshake_gibb
+ name = "Dr. Gibb Milkshake"
+ id = /datum/reagent/consumable/milkshake_gibb
+ results = list(/datum/reagent/consumable/milkshake_gibb = 2)
+ required_reagents = list(
+ /datum/reagent/consumable/milkshake_base = 1,
+ /datum/reagent/consumable/dr_gibb = 1
+ )
+
+/datum/chemical_reaction/milkshake_peach
+ name = "Peach Milkshake"
+ id = /datum/reagent/consumable/milkshake_peach
+ results = list(/datum/reagent/consumable/milkshake_peach = 2)
+ required_reagents = list(
+ /datum/reagent/consumable/milkshake_base = 1,
+ /datum/reagent/consumable/peachjuice = 1
+ )
+
+/datum/chemical_reaction/milkshake_pineapple
+ name = "Pineapple Milkshake"
+ id = /datum/reagent/consumable/milkshake_pineapple
+ results = list(/datum/reagent/consumable/milkshake_pineapple = 2)
+ required_reagents = list(
+ /datum/reagent/consumable/milkshake_base = 1,
+ /datum/reagent/consumable/pineapplejuice = 1
+ )
+
+/datum/chemical_reaction/milkshake_melon
+ name = "Watermelon Milkshake"
+ id = /datum/reagent/consumable/milkshake_melon
+ results = list(/datum/reagent/consumable/milkshake_melon = 2)
+ required_reagents = list(
+ /datum/reagent/consumable/milkshake_base = 1,
+ /datum/reagent/consumable/watermelonjuice = 1
+ )
diff --git a/modular_splurt/code/modules/mob/dead/new_player/sprite_accesories/tails.dm b/modular_splurt/code/modules/mob/dead/new_player/sprite_accesories/tails.dm
index 4bc73fc724..7f9eff453e 100644
--- a/modular_splurt/code/modules/mob/dead/new_player/sprite_accesories/tails.dm
+++ b/modular_splurt/code/modules/mob/dead/new_player/sprite_accesories/tails.dm
@@ -249,6 +249,24 @@
icon = 'modular_splurt/icons/mob/mam_tails.dmi'
matrixed_sections = MATRIX_RED_GREEN
+/datum/sprite_accessory/tails/mam_tails/snakelarge
+ name = "Snake Tail (Large)"
+ icon_state = "snakelarge"
+ color_src = MATRIXED
+ icon = 'modular_splurt/icons/mob/64_mam_tails.dmi'
+ dimension_x = 64
+ center = TRUE
+ matrixed_sections = MATRIX_RED_GREEN
+
+/datum/sprite_accessory/tails_animated/mam_tails_animated/snakelarge
+ name = "Snake Tail (Large)"
+ icon_state = "snakelarge"
+ color_src = MATRIXED
+ icon = 'modular_splurt/icons/mob/64_mam_tails.dmi'
+ dimension_x = 64
+ center = TRUE
+ matrixed_sections = MATRIX_RED_GREEN
+
//Lizard tails
/datum/sprite_accessory/tails/lizard/tailmaw
name = "Tailmaw"
@@ -306,6 +324,24 @@
icon = 'modular_splurt/icons/mob/mam_tails.dmi'
matrixed_sections = MATRIX_RED_GREEN
+/datum/sprite_accessory/tails/lizard/snakelarge
+ name = "Snake Tail (Large)"
+ icon_state = "snakelarge"
+ color_src = MATRIXED
+ icon = 'modular_splurt/icons/mob/64_mam_tails.dmi'
+ dimension_x = 64
+ center = TRUE
+ matrixed_sections = MATRIX_RED_GREEN
+
+/datum/sprite_accessory/tails_animated/lizard/snakelarge
+ name = "Snake Tail (Large)"
+ icon_state = "snakelarge"
+ color_src = MATRIXED
+ icon = 'modular_splurt/icons/mob/64_mam_tails.dmi'
+ dimension_x = 64
+ center = TRUE
+ matrixed_sections = MATRIX_RED_GREEN
+
//Human tails
/datum/sprite_accessory/tails/human/deer
name = "Deer"
@@ -400,3 +436,21 @@
color_src = MATRIXED
icon = 'modular_splurt/icons/mob/mam_tails.dmi'
matrixed_sections = MATRIX_RED_GREEN
+
+/datum/sprite_accessory/tails/human/snakelarge
+ name = "Snake Tail (Large)"
+ icon_state = "snakelarge"
+ color_src = MATRIXED
+ icon = 'modular_splurt/icons/mob/64_mam_tails.dmi'
+ dimension_x = 64
+ center = TRUE
+ matrixed_sections = MATRIX_RED_GREEN
+
+/datum/sprite_accessory/tails_animated/human/snakelarge
+ name = "Snake Tail (Large)"
+ icon_state = "snakelarge"
+ color_src = MATRIXED
+ icon = 'modular_splurt/icons/mob/64_mam_tails.dmi'
+ dimension_x = 64
+ center = TRUE
+ matrixed_sections = MATRIX_RED_GREEN
diff --git a/modular_splurt/code/modules/mob/living/carbon/human/emote.dm b/modular_splurt/code/modules/mob/living/carbon/human/emote.dm
new file mode 100644
index 0000000000..8877e15eab
--- /dev/null
+++ b/modular_splurt/code/modules/mob/living/carbon/human/emote.dm
@@ -0,0 +1,12 @@
+/datum/emote/sound/human/huh
+ key = "huh"
+ key_third_person = "huh's"
+ message = "seems confused."
+ sound = 'modular_splurt/sound/voice/huh.ogg'
+
+/datum/emote/sound/human/whine
+ key = "whine"
+ key_third_person = "whines"
+ message = "whines."
+ sound = 'modular_splurt/sound/voice/whine.ogg'
+
diff --git a/modular_splurt/code/modules/mob/living/silicon/robot/robot.dm b/modular_splurt/code/modules/mob/living/silicon/robot/robot.dm
index fa00e0ff44..65ece9be12 100644
--- a/modular_splurt/code/modules/mob/living/silicon/robot/robot.dm
+++ b/modular_splurt/code/modules/mob/living/silicon/robot/robot.dm
@@ -1,7 +1,7 @@
//Main code edits
/// Allows "cyborg" players to change gender at will - Modularised here
// FUNCTION MOVED TO living.dm AS PROC
-/mob/living/silicon/robot/verb/toggle_gender()
+/mob/living/silicon/robot/toggle_gender()
set name = "Set Gender"
set desc = "Allows you to set your gender."
set category = "Robot Commands"
diff --git a/modular_splurt/code/modules/photography/photos/album.dm b/modular_splurt/code/modules/photography/photos/album.dm
new file mode 100644
index 0000000000..f7795a670e
--- /dev/null
+++ b/modular_splurt/code/modules/photography/photos/album.dm
@@ -0,0 +1,27 @@
+/obj/item/storage/photo_album
+ desc = "A big book used to store photos and mementos."
+ item_state = "album"
+ lefthand_file = 'modular_splurt/icons/mob/inhands/misc/books_lefthand.dmi'
+ righthand_file = 'modular_splurt/icons/mob/inhands/misc/books_righthand.dmi'
+ w_class = WEIGHT_CLASS_SMALL
+
+/obj/item/storage/photo_album/HoS
+ name = "photo album (Head of Security)"
+
+/obj/item/storage/photo_album/RD
+ name = "photo album (Research Director)"
+
+/obj/item/storage/photo_album/HoP
+ name = "photo album (Head of Personnel)"
+
+/obj/item/storage/photo_album/Captain
+ name = "photo album (Captain)"
+
+/obj/item/storage/photo_album/CMO
+ name = "photo album (Chief Medical Officer)"
+
+/obj/item/storage/photo_album/QM
+ name = "photo album (Quartermaster)"
+
+/obj/item/storage/photo_album/CE
+ name = "photo album (Chief Engineer)"
diff --git a/modular_splurt/code/modules/photography/photos/photo.dm b/modular_splurt/code/modules/photography/photos/photo.dm
new file mode 100644
index 0000000000..3eb0f70752
--- /dev/null
+++ b/modular_splurt/code/modules/photography/photos/photo.dm
@@ -0,0 +1,3 @@
+/obj/item/photo/old
+ icon = 'modular_splurt/icons/obj/items_and_weapons.dmi'
+ icon_state = "photo_old"
diff --git a/modular_splurt/code/modules/reagents/chemistry/reagents/drink_reagents.dm b/modular_splurt/code/modules/reagents/chemistry/reagents/drink_reagents.dm
index 3b8aad9ea7..46ea1e07c5 100644
--- a/modular_splurt/code/modules/reagents/chemistry/reagents/drink_reagents.dm
+++ b/modular_splurt/code/modules/reagents/chemistry/reagents/drink_reagents.dm
@@ -50,3 +50,118 @@
glass_name = "glass of töchtaüse syrup"
glass_desc = "Not for drinking on its own."
+/datum/reagent/consumable/milkshake_base
+ name = "Milkshake"
+ description = "A basic milkshake. Could use something else?"
+ color = "#FFFDD0"
+ nutriment_factor = 1
+ taste_description = "thick, creamy, and sweet"
+ glass_icon_state = "vanillashake"
+ glass_name = "glass of plain milkshake"
+ glass_desc = "A glass of plain milkshake, a bit boring, but still good."
+
+/datum/reagent/consumable/milkshake_vanilla
+ name = "Vanilla Milkshake"
+ description = "A vanilla milkshake. Basic, but delicious."
+ color = "#FFFDD0"
+ nutriment_factor = 1
+ taste_description = "thick, creamy, and sweet"
+ glass_icon_state = "vanillashake"
+ glass_name = "glass of vanilla milkshake"
+ glass_desc = "A glass of vanilla milkshake, a bit boring, but still good."
+
+/datum/reagent/consumable/milkshake_choc
+ name = "Chocolate Milkshake"
+ description = "A delicious Chocolate Milkshake"
+ color = "#7B3F00"
+ nutriment_factor = 1
+ taste_description = "sweet, creamy chocolate"
+ glass_icon_state = "choccyshake"
+ glass_name = "glass of chocolate milkshake"
+ glass_desc = "A glass of chocolate milkshake, what a treat!"
+
+/datum/reagent/consumable/milkshake_strawberry
+ name = "Strawberry Milkshake"
+ description = "Frozen Strawberry Milk!"
+ color = "#F4E1EA"
+ nutriment_factor = 1
+ taste_description = "summer memories"
+ glass_icon_state = "strawberryshake"
+ glass_name = "glass of strawberry milkshake"
+ glass_desc = "A glass of sweet, pink Strawberry Shake"
+
+/datum/reagent/consumable/milkshake_banana
+ name = "Banana Milkshake"
+ description = "Deliciously tricky!"
+ color = "#FFE135"
+ nutriment_factor = 1
+ taste_description = "funny pranks and clowning around"
+ glass_icon_state = "bananashake"
+ glass_name = "glass of Banana Milkshake"
+ glass_desc = "A banana milkshake! Honk!"
+
+/datum/reagent/consumable/milkshake_berry
+ name = "Wild Berry Milkshake"
+ description = "A summer favorite!"
+ color = "#b17179"
+ nutriment_factor = 1
+ taste_description = "warm summer days"
+ glass_icon = 'modular_splurt/icons/obj/drinks.dmi'
+ glass_icon_state = "berryshake"
+ glass_name = "glass of Wild Berry Milkshake"
+ glass_desc = "A berry milkshake"
+
+/datum/reagent/consumable/milkshake_cola
+ name = "Cola Milkshake"
+ description = "Sweet milkshake mixed with cola"
+ color = "#3c3024"
+ nutriment_factor = 1
+ taste_description = "cola and milkshake"
+ glass_icon = 'modular_splurt/icons/obj/drinks.dmi'
+ glass_icon_state = "colashake"
+ glass_name = "glass of Cola Milkshake"
+ glass_desc = "A cola milkshake, it's like a ticker float!"
+
+/datum/reagent/consumable/milkshake_gibb
+ name = "Dr. Gibb Milkshake"
+ description = "Sweet milkshake mixed with Dr. Gibb"
+ color = "#5e312b"
+ nutriment_factor = 1
+ taste_description = "cola and milkshake"
+ glass_icon = 'modular_splurt/icons/obj/drinks.dmi'
+ glass_icon_state = "gibbshake"
+ glass_name = "glass of Gibb Milkshake"
+ glass_desc = "A Dr. Gibb milkshake, it's like a ticker float!"
+
+/datum/reagent/consumable/milkshake_peach
+ name = "Peach Milkshake"
+ description = "A tasty Peach Milkshake"
+ color = "#5e312b"
+ nutriment_factor = 1
+ taste_description = "peaches and cream"
+ glass_icon = 'modular_splurt/icons/obj/drinks.dmi'
+ glass_icon_state = "peachshake"
+ glass_name = "glass of Peace Milkshake"
+ glass_desc = "Peaches and Cream, Peaches and Cream!"
+
+/datum/reagent/consumable/milkshake_pineapple
+ name = "Pineapple Milkshake"
+ description = "A tangy Pineapple Milkshake"
+ color = "#feea63"
+ nutriment_factor = 1
+ taste_description = "citrus and cream"
+ glass_icon = 'modular_splurt/icons/obj/drinks.dmi'
+ glass_icon_state = "pineappleshake"
+ glass_name = "glass of Pineapple Milkshake"
+ glass_desc = "A Pineapple milkshake, a bit sweet and a bit sour, but all delicious!"
+
+/datum/reagent/consumable/milkshake_melon
+ name = "Watermelon Milkshake"
+ description = "Delicous Watermelon Milkshake"
+ color = "#E37383"
+ nutriment_factor = 1
+ taste_description = "warm sun and sweet cream"
+ glass_icon = 'modular_splurt/icons/obj/drinks.dmi'
+ glass_icon_state = "melonshake"
+ glass_name = "glass of Watermelon Milkshake"
+ glass_desc = "A Watermelon milkshake, it's like summer all over again!"
diff --git a/modular_splurt/code/modules/research/designs/misc_designs.dm b/modular_splurt/code/modules/research/designs/misc_designs.dm
new file mode 100644
index 0000000000..e6105fd3f3
--- /dev/null
+++ b/modular_splurt/code/modules/research/designs/misc_designs.dm
@@ -0,0 +1,2 @@
+/datum/design/light_replacer_blue/New()
+ departmental_flags |= DEPARTMENTAL_FLAG_SCIENCE
diff --git a/modular_splurt/code/modules/research/techweb/nodes/robotic_nodes.dm b/modular_splurt/code/modules/research/techweb/nodes/robotic_nodes.dm
index f90fac955d..9256485813 100644
--- a/modular_splurt/code/modules/research/techweb/nodes/robotic_nodes.dm
+++ b/modular_splurt/code/modules/research/techweb/nodes/robotic_nodes.dm
@@ -1,7 +1,7 @@
/datum/techweb_node/neural_programming
design_ids = list("impant_radio")
-/datum/techweb_node/ai/Initialize()
+/datum/techweb_node/ai/New()
var/extra_designs = list(
"slut_module",
"shebang_module",
diff --git a/modular_splurt/code/modules/uplink/uplink_items/uplink_devices.dm b/modular_splurt/code/modules/uplink/uplink_items/uplink_devices.dm
new file mode 100644
index 0000000000..fe3de42d03
--- /dev/null
+++ b/modular_splurt/code/modules/uplink/uplink_items/uplink_devices.dm
@@ -0,0 +1,6 @@
+/datum/uplink_item/device_tools/syndicate_ball
+ name = "Syndicate Beach Ball"
+ item = /obj/item/toy/beach_ball/syndicate
+ desc = "A beach ball, it reacts when a vibrator is inserted inside of it. Watch out!"
+ cost = 3
+
diff --git a/modular_splurt/code/modules/vending/clothesmate.dm b/modular_splurt/code/modules/vending/clothesmate.dm
index d7d67e4011..da97e25df6 100644
--- a/modular_splurt/code/modules/vending/clothesmate.dm
+++ b/modular_splurt/code/modules/vending/clothesmate.dm
@@ -16,7 +16,9 @@
/obj/item/clothing/under/officesexy = 3,
/obj/item/clothing/suit/toggle/tunnelfox = 3,
/obj/item/clothing/under/performer = 2,
- /obj/item/clothing/under/bluedress = 3
+ /obj/item/clothing/under/bluedress = 3,
+ /obj/item/clothing/under/misc/leia_outfit = 2,
+ /obj/item/clothing/under/performer/polychromic = 2
)
var/list/extra_contraband = list(
/obj/item/clothing/under/rank/civilian/lawyer/galaxy_red = 3,
diff --git a/modular_splurt/code/modules/vending/kinkmate.dm b/modular_splurt/code/modules/vending/kinkmate.dm
index 1d2f3c5a94..53b6abb542 100644
--- a/modular_splurt/code/modules/vending/kinkmate.dm
+++ b/modular_splurt/code/modules/vending/kinkmate.dm
@@ -29,7 +29,8 @@
/obj/item/restraints/bondage_rope = 5,
/obj/item/clothing/under/domina = 5,
/obj/item/clothing/under/performer = 3,
- /obj/item/clothing/shoes/invisiboots = 10 // Added here to go with the Gear Harness
+ /obj/item/clothing/shoes/invisiboots = 10, // Added here to go with the Gear Harness
+ /obj/item/clothing/shoes/highheel_sandals = 3
)
var/list/extra_contraband = list(
//Lewd-Clothes
diff --git a/modular_splurt/icons/misc/beach.dmi b/modular_splurt/icons/misc/beach.dmi
new file mode 100644
index 0000000000..0bc186df19
Binary files /dev/null and b/modular_splurt/icons/misc/beach.dmi differ
diff --git a/modular_splurt/icons/mob/64_mam_tails.dmi b/modular_splurt/icons/mob/64_mam_tails.dmi
index 115d051436..71249b8896 100644
Binary files a/modular_splurt/icons/mob/64_mam_tails.dmi and b/modular_splurt/icons/mob/64_mam_tails.dmi differ
diff --git a/modular_splurt/icons/mob/clothing/current_head_accessories.dmi b/modular_splurt/icons/mob/clothing/current_head_accessories.dmi
new file mode 100644
index 0000000000..6d189aeba5
Binary files /dev/null and b/modular_splurt/icons/mob/clothing/current_head_accessories.dmi differ
diff --git a/modular_splurt/icons/mob/clothing/shoes.dmi b/modular_splurt/icons/mob/clothing/shoes.dmi
index 0956dfbdd1..005bdc7b7d 100644
Binary files a/modular_splurt/icons/mob/clothing/shoes.dmi and b/modular_splurt/icons/mob/clothing/shoes.dmi differ
diff --git a/modular_splurt/icons/mob/clothing/shoes_digi.dmi b/modular_splurt/icons/mob/clothing/shoes_digi.dmi
index a37e1178f1..755d9c92e9 100644
Binary files a/modular_splurt/icons/mob/clothing/shoes_digi.dmi and b/modular_splurt/icons/mob/clothing/shoes_digi.dmi differ
diff --git a/modular_splurt/icons/mob/clothing/uniform.dmi b/modular_splurt/icons/mob/clothing/uniform.dmi
index 1555bade4d..dccf18cc43 100644
Binary files a/modular_splurt/icons/mob/clothing/uniform.dmi and b/modular_splurt/icons/mob/clothing/uniform.dmi differ
diff --git a/modular_splurt/icons/mob/inhands/misc/books_lefthand.dmi b/modular_splurt/icons/mob/inhands/misc/books_lefthand.dmi
new file mode 100644
index 0000000000..cd59fe6d03
Binary files /dev/null and b/modular_splurt/icons/mob/inhands/misc/books_lefthand.dmi differ
diff --git a/modular_splurt/icons/mob/inhands/misc/books_righthand.dmi b/modular_splurt/icons/mob/inhands/misc/books_righthand.dmi
new file mode 100644
index 0000000000..a2fc3cc73b
Binary files /dev/null and b/modular_splurt/icons/mob/inhands/misc/books_righthand.dmi differ
diff --git a/modular_splurt/icons/obj/clothing/shoes.dmi b/modular_splurt/icons/obj/clothing/shoes.dmi
index 71b62b42bc..311174d23d 100644
Binary files a/modular_splurt/icons/obj/clothing/shoes.dmi and b/modular_splurt/icons/obj/clothing/shoes.dmi differ
diff --git a/modular_splurt/icons/obj/clothing/uniforms.dmi b/modular_splurt/icons/obj/clothing/uniforms.dmi
index 3880f77532..f6648a1fac 100644
Binary files a/modular_splurt/icons/obj/clothing/uniforms.dmi and b/modular_splurt/icons/obj/clothing/uniforms.dmi differ
diff --git a/modular_splurt/icons/obj/drinks.dmi b/modular_splurt/icons/obj/drinks.dmi
index a1541fddb1..4ea6784f4e 100644
Binary files a/modular_splurt/icons/obj/drinks.dmi and b/modular_splurt/icons/obj/drinks.dmi differ
diff --git a/modular_splurt/icons/obj/items_and_weapons.dmi b/modular_splurt/icons/obj/items_and_weapons.dmi
index 0dd0e88c6a..a5b3d02d5b 100644
Binary files a/modular_splurt/icons/obj/items_and_weapons.dmi and b/modular_splurt/icons/obj/items_and_weapons.dmi differ
diff --git a/modular_splurt/sound/voice/huh.ogg b/modular_splurt/sound/voice/huh.ogg
new file mode 100644
index 0000000000..accf4cab3c
Binary files /dev/null and b/modular_splurt/sound/voice/huh.ogg differ
diff --git a/modular_splurt/sound/voice/whine.ogg b/modular_splurt/sound/voice/whine.ogg
new file mode 100644
index 0000000000..2d2f825a83
Binary files /dev/null and b/modular_splurt/sound/voice/whine.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index d7af3961da..4db1a854e4 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -262,6 +262,7 @@
#include "code\__SPLURTCODE\DEFINES\lewd.dm"
#include "code\__SPLURTCODE\DEFINES\login.dm"
#include "code\__SPLURTCODE\DEFINES\mobs.dm"
+#include "code\__SPLURTCODE\DEFINES\preferences.dm"
#include "code\__SPLURTCODE\DEFINES\pregnancy.dm"
#include "code\__SPLURTCODE\DEFINES\quirks.dm"
#include "code\__SPLURTCODE\DEFINES\radiation.dm"
@@ -1991,6 +1992,7 @@
#include "code\modules\buildmode\submodes\throwing.dm"
#include "code\modules\buildmode\submodes\variable_edit.dm"
#include "code\modules\cargo\bounty.dm"
+#include "code\modules\cargo\bounty_console.dm"
#include "code\modules\cargo\centcom_podlauncher.dm"
#include "code\modules\cargo\console.dm"
#include "code\modules\cargo\coupon.dm"
@@ -3716,6 +3718,7 @@
#include "code\modules\tgui\states\human_adjacent.dm"
#include "code\modules\tgui\states\inventory.dm"
#include "code\modules\tgui\states\language_menu.dm"
+#include "code\modules\tgui\states\never.dm"
#include "code\modules\tgui\states\new_player.dm"
#include "code\modules\tgui\states\not_incapacitated.dm"
#include "code\modules\tgui\states\notcontained.dm"
@@ -3860,6 +3863,7 @@
#include "modular_citadel\code\modules\client\loadout\_medical.dm"
#include "modular_citadel\code\modules\client\loadout\_security.dm"
#include "modular_citadel\code\modules\client\loadout\_service.dm"
+#include "modular_citadel\code\modules\client\loadout\accessory.dm"
#include "modular_citadel\code\modules\client\loadout\backpack.dm"
#include "modular_citadel\code\modules\client\loadout\glasses.dm"
#include "modular_citadel\code\modules\client\loadout\gloves.dm"
@@ -3943,6 +3947,7 @@
#include "modular_sand\code\datums\action.dm"
#include "modular_sand\code\datums\ai_laws.dm"
#include "modular_sand\code\datums\shuttles.dm"
+#include "modular_sand\code\datums\components\interaction_menu_granter.dm"
#include "modular_sand\code\datums\components\mood.dm"
#include "modular_sand\code\datums\components\riding.dm"
#include "modular_sand\code\datums\components\container_item\container_item.dm"
@@ -3953,7 +3958,6 @@
#include "modular_sand\code\datums\elements\holder_micro.dm"
#include "modular_sand\code\datums\elements\skirt_peeking.dm"
#include "modular_sand\code\datums\interactions\_interaction.dm"
-#include "modular_sand\code\datums\interactions\interaction_interface.dm"
#include "modular_sand\code\datums\interactions\interaction_mob.dm"
#include "modular_sand\code\datums\interactions\lewd_definitions.dm"
#include "modular_sand\code\datums\interactions\lewd_interactions.dm"
@@ -4683,6 +4687,7 @@
#include "modular_splurt\code\modules\mob\living\say.dm"
#include "modular_splurt\code\modules\mob\living\brain\brain_item.dm"
#include "modular_splurt\code\modules\mob\living\carbon\carbon.dm"
+#include "modular_splurt\code\modules\mob\living\carbon\human\emote.dm"
#include "modular_splurt\code\modules\mob\living\carbon\human\human.dm"
#include "modular_splurt\code\modules\mob\living\carbon\human\human_defines.dm"
#include "modular_splurt\code\modules\mob\living\carbon\human\inventory.dm"
@@ -4715,6 +4720,8 @@
#include "modular_splurt\code\modules\mob\living\simple_animal\hostile\megafauna\king_of_goats.dm"
#include "modular_splurt\code\modules\mob\living\simple_animal\hostile\megafauna\sand.dm"
#include "modular_splurt\code\modules\paperwork\pen.dm"
+#include "modular_splurt\code\modules\photography\photos\album.dm"
+#include "modular_splurt\code\modules\photography\photos\photo.dm"
#include "modular_splurt\code\modules\power\cell.dm"
#include "modular_splurt\code\modules\power\reactor\fluffed.dm"
#include "modular_splurt\code\modules\projectiles\ammunition\ballistic\pistol.dm"
@@ -4761,6 +4768,7 @@
#include "modular_splurt\code\modules\research\designs\mecha_designs.dm"
#include "modular_splurt\code\modules\research\designs\mechfabricator_designs.dm"
#include "modular_splurt\code\modules\research\designs\medical_designs.dm"
+#include "modular_splurt\code\modules\research\designs\misc_designs.dm"
#include "modular_splurt\code\modules\research\designs\power_designs.dm"
#include "modular_splurt\code\modules\research\designs\stock_parts_designs.dm"
#include "modular_splurt\code\modules\research\designs\tool_designs.dm"
diff --git a/tgui/packages/tgui/interfaces/CargoBountyConsole.js b/tgui/packages/tgui/interfaces/CargoBountyConsole.js
new file mode 100644
index 0000000000..ad485231eb
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/CargoBountyConsole.js
@@ -0,0 +1,119 @@
+import { useBackend } from '../backend';
+import { AnimatedNumber, Box, Button, Section, Table } from '../components';
+import { formatMoney } from '../format';
+import { Window } from '../layouts';
+
+export const CargoBountyConsole = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ bountydata = [],
+ } = data;
+ return (
+
+
+ }
+ buttons={(
+
+
+ );
+};
+
+const BountyHeader = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ stored_cash,
+ } = data;
+ return (
+
+ formatMoney(value)} />
+ {' credits'}
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/NtosBountyConsole.js b/tgui/packages/tgui/interfaces/NtosBountyConsole.js
new file mode 100644
index 0000000000..bfd2b0e4c9
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/NtosBountyConsole.js
@@ -0,0 +1,119 @@
+import { useBackend } from '../backend';
+import { AnimatedNumber, Box, Button, Section, Table } from '../components';
+import { formatMoney } from '../format';
+import { NtosWindow } from '../layouts';
+
+export const NtosBountyConsole = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ bountydata = [],
+ } = data;
+ return (
+
+
+ }
+ buttons={(
+ act('Print')} />
+ )}>
+