diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index 0ee66ab3dd..c526550139 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -657,7 +657,9 @@ var/global/datum/controller/occupations/job_master
var/fail_deadly = FALSE
var/obj/belly/vore_spawn_gut
var/mob/living/prey_to_nomph
- var/obj/item/item_to_be
+ var/obj/item/item_to_be //CHOMPEdit - Item TF spawning
+ var/mob/living/item_carrier //CHOMPEdit - Capture crystal spawning
+ var/vorgans = FALSE //CHOMPEdit - capture crystal simplemob spawning
//CHOMPEdit - Remove fail_deadly addition on offmap_spawn
@@ -810,13 +812,22 @@ var/global/datum/controller/occupations/job_master
continue
carriers += null
- items += I
- if(I.name == initial(I.name))
+ if(istype(I, /obj/item/capture_crystal))
+ if(carrier)
+ items += I
+ var/obj/item/capture_crystal/cryst = I
+ if(cryst.spawn_mob_type)
+ item_names += "\a [cryst.spawn_mob_name] inside of [carrier]'s [I.name] ([I.loc.name])"
+ else
+ item_names += "Inside of [carrier]'s [I.name] ([I.loc.name])"
+ else if(I.name == initial(I.name))
+ items += I
if(carrier)
item_names += "[carrier]'s [I.name] ([I.loc.name])"
else
item_names += "[I.name] ([I.loc.name])"
else
+ items += I
if(carrier)
item_names += "[carrier]'s [I.name] (\a [initial(I.name)] at [I.loc.name])"
else
@@ -853,6 +864,7 @@ var/global/datum/controller/occupations/job_master
return
log_and_message_admins("[key_name(C)] has item spawned onto [key_name(carrier)]")
item_to_be = item
+ item_carrier = carrier
if(backup)
addtimer(CALLBACK(src, .proc/m_backup_client, C), 5 SECONDS)
else
@@ -863,6 +875,12 @@ var/global/datum/controller/occupations/job_master
item_to_be = item
if(backup)
addtimer(CALLBACK(src, .proc/m_backup_client, C), 5 SECONDS)
+ if(istype(item, /obj/item/capture_crystal))
+ var/obj/item/capture_crystal/cryst = item
+ if(cryst.spawn_mob_type)
+ var/confirm = alert(C, "Do you want to spawn with your slot's vore organs and prefs?", "Confirm", "No", "Yes")
+ if(confirm == "Yes")
+ vorgans = TRUE
else
to_chat(C, "No items were available to accept you.")
return
@@ -879,13 +897,15 @@ var/global/datum/controller/occupations/job_master
spawnpos = spawntypes[C.prefs.spawnpoint]
//We will return a list key'd by "turf" and "msg"
- . = list("turf","msg", "voreny", "prey", "itemtf") //CHOMPEdit - Item TF spawnpoints
+ . = list("turf","msg", "voreny", "prey", "itemtf", "vorgans", "carrier") //CHOMPEdit - Item TF spawnpoints, spawn as mob
if(vore_spawn_gut)
.["voreny"] = vore_spawn_gut
if(prey_to_nomph)
.["prey"] = prey_to_nomph //We pass this on later to reverse the vorespawn in new_player.dm
//CHOMPEdit Start - Item TF spawnpoints
if(item_to_be)
+ .["carrier"] = item_carrier
+ .["vorgans"] = vorgans
.["itemtf"] = item_to_be
//CHOMPEdit End
if(spawnpos && istype(spawnpos) && spawnpos.turfs.len)
diff --git a/code/modules/client/preference_setup/loadout/gear_tweaks_ch.dm b/code/modules/client/preference_setup/loadout/gear_tweaks_ch.dm
index 41a2dc0eb4..9a7b7b12c3 100644
--- a/code/modules/client/preference_setup/loadout/gear_tweaks_ch.dm
+++ b/code/modules/client/preference_setup/loadout/gear_tweaks_ch.dm
@@ -39,3 +39,27 @@ var/datum/gear_tweak/item_tf_spawn/gear_tweak_item_tf_spawn = new()
else if(metadata["state"] == "Only Specific Players")
I.item_tf_spawnpoint_set()
I.ckeys_allowed_itemspawn = metadata["valid"]
+
+/datum/gear_tweak/simplemob_picker
+ var/list/simplemob_list
+
+/datum/gear_tweak/simplemob_picker/New(var/list/valid_simplemobs)
+ src.simplemob_list = valid_simplemobs
+ ..()
+
+/datum/gear_tweak/simplemob_picker/get_contents(var/metadata)
+ return "Type: [metadata]"
+
+/datum/gear_tweak/simplemob_picker/get_default()
+ return simplemob_list[1]
+
+/datum/gear_tweak/simplemob_picker/get_metadata(var/user, var/metadata)
+ return tgui_input_list(user, "Choose a type.", "Character Preference", simplemob_list, metadata)
+
+/datum/gear_tweak/simplemob_picker/tweak_item(var/obj/item/capture_crystal/I, var/metadata)
+ if(!(metadata in simplemob_list))
+ return
+ if(!istype(I))
+ return
+ I.spawn_mob_type = simplemob_list[metadata]
+ I.spawn_mob_name = metadata
diff --git a/code/modules/client/preference_setup/loadout/loadout_utility_ch.dm b/code/modules/client/preference_setup/loadout/loadout_utility_ch.dm
index 3a882fb49f..0c6b4bc9e6 100644
--- a/code/modules/client/preference_setup/loadout/loadout_utility_ch.dm
+++ b/code/modules/client/preference_setup/loadout/loadout_utility_ch.dm
@@ -15,4 +15,41 @@
for(var/implant in typesof(/obj/item/weapon/implant/reagent_generator/egg))
var/obj/item/weapon/implant/reagent_generator/egg/implant_type = implant
implants[initial(implant_type.name)] = implant_type
- gear_tweaks += new/datum/gear_tweak/path(sortAssoc(implants))
\ No newline at end of file
+ gear_tweaks += new/datum/gear_tweak/path(sortAssoc(implants))
+
+/datum/gear/utility/capture_crystal_crew
+ display_name = "Capture Crystal (crew)"
+ description = "A capture crystal already containing someone! (Item TF will need to be enabled for someone to join into this crystal)"
+ path = /obj/item/capture_crystal/loadout
+ cost = 2
+
+/datum/gear/utility/capture_crystal_simplemob
+ display_name = "Capture Crystal (pet)"
+ description = "A capture crystal already containing a pet! (Item TF will need to be enabled for someone to join into this crystal)"
+ path = /obj/item/capture_crystal/loadout
+ cost = 2
+
+/datum/gear/utility/capture_crystal_simplemob/New()
+ ..()
+ var/list/mob_types = list(
+ "mouse" = /mob/living/simple_mob/animal/passive/mouse,
+ "rat" = /mob/living/simple_mob/animal/passive/mouse/rat,
+ "dust jumper" = /mob/living/simple_mob/vore/alienanimals/dustjumper,
+ "woof" = /mob/living/simple_mob/vore/woof,
+ "corgi" = /mob/living/simple_mob/animal/passive/dog/corgi,
+ "cat" = /mob/living/simple_mob/animal/passive/cat,
+ "chicken" = /mob/living/simple_mob/animal/passive/chicken,
+ "cow" = /mob/living/simple_mob/animal/passive/cow,
+ "lizard" = /mob/living/simple_mob/animal/passive/lizard,
+ "rabbit" = /mob/living/simple_mob/vore/rabbit,
+ "fox" = /mob/living/simple_mob/animal/passive/fox,
+ "fennec" = /mob/living/simple_mob/vore/fennec,
+ "cute fennec" = /mob/living/simple_mob/animal/passive/fennec,
+ "fennix" = /mob/living/simple_mob/vore/fennix,
+ "red panda" = /mob/living/simple_mob/vore/redpanda,
+ "opossum" = /mob/living/simple_mob/animal/passive/opossum,
+ "horse" = /mob/living/simple_mob/vore/horse,
+ "goose" = /mob/living/simple_mob/animal/space/goose,
+ "sheep" = /mob/living/simple_mob/vore/sheep
+ )
+ gear_tweaks += new/datum/gear_tweak/simplemob_picker(mob_types)
diff --git a/code/modules/mob/new_player/new_player.dm b/code/modules/mob/new_player/new_player.dm
index 2a6d694ab9..ba88d5cdc7 100644
--- a/code/modules/mob/new_player/new_player.dm
+++ b/code/modules/mob/new_player/new_player.dm
@@ -440,6 +440,32 @@
spawning = 1
close_spawn_windows()
+ //CHOMPEdit start - join as mob in crystal...
+ var/obj/item/itemtf = join_props["itemtf"]
+ if(itemtf && istype(itemtf, /obj/item/capture_crystal))
+ var/obj/item/capture_crystal/cryst = itemtf
+ if(cryst.spawn_mob_type)
+ // We want to be a spawned mob instead of a person aaaaa
+ var/mob/living/carrier = join_props["carrier"]
+ var/vorgans = join_props["vorgans"]
+ cryst.bound_mob = new cryst.spawn_mob_type(cryst)
+ cryst.spawn_mob_type = null
+ cryst.bound_mob.ai_holder_type = /datum/ai_holder/simple_mob/inert
+ cryst.bound_mob.key = src.key
+ log_and_message_admins("[key_name_admin(src)] joined [cryst.bound_mob] inside a capture crystal [ADMIN_FLW(cryst.bound_mob)]")
+ if(vorgans)
+ cryst.bound_mob.copy_from_prefs_vr()
+ if(istype(carrier))
+ cryst.capture(cryst.bound_mob, carrier)
+ else
+ //Something went wrong, but lets try to do as much as we can.
+ cryst.bound_mob.capture_caught = TRUE
+ cryst.persist_storable = FALSE
+ cryst.update_icon()
+ qdel(src)
+ return
+ //CHOMPEdit end
+
job_master.AssignRole(src, rank, 1)
var/mob/living/character = create_character(T) //creates the human and transfers vars and mind
@@ -503,8 +529,14 @@
var/gut = join_props["voreny"]
var/mob/living/prey = join_props["prey"]
//CHOMPEdit Start - Item TF
- var/obj/item/itemtf = join_props["itemtf"]
- if(itemtf)
+ if(itemtf && istype(itemtf, /obj/item/capture_crystal))
+ //We want to be in the crystal, not actually possessing the crystal.
+ var/obj/item/capture_crystal/cryst = itemtf
+ var/mob/living/carrier = join_props["carrier"]
+ cryst.capture(character, carrier)
+ character.forceMove(cryst)
+ cryst.update_icon()
+ else if(itemtf)
itemtf.inhabit_item(character, itemtf.name, character)
var/mob/living/possessed_voice = itemtf.possessed_voice
itemtf.trash_eatable = character.devourable
diff --git a/modular_chomp/code/game/objects/items/weapons/capture_crystal.dm b/modular_chomp/code/game/objects/items/weapons/capture_crystal.dm
index 4825e80760..f2ca181032 100644
--- a/modular_chomp/code/game/objects/items/weapons/capture_crystal.dm
+++ b/modular_chomp/code/game/objects/items/weapons/capture_crystal.dm
@@ -1,3 +1,26 @@
+/obj/item/capture_crystal
+ var/spawn_mob_name = "A mob"
+
+/obj/item/capture_crystal/loadout
+ active = TRUE
+
+/obj/item/capture_crystal/loadout/attack(mob/living/M, mob/living/user)
+ if(!bound_mob && M != user)
+ to_chat(user, "\The [src] emits an unpleasant tone...")
+ playsound(src, 'sound/effects/capture-crystal-negative.ogg', 75, 1, -1)
+ return
+ . = ..()
+
+/obj/item/capture_crystal/loadout/attack_self(mob/living/user)
+ if(!bound_mob)
+ to_chat(user, "\The [src] emits an unpleasant tone... It is not ready yet.")
+ playsound(src, 'sound/effects/capture-crystal-problem.ogg', 75, 1, -1)
+ return
+ . = ..()
+
+/obj/item/capture_crystal/loadout/capture_chance()
+ return 0
+
/obj/item/capture_crystal/cheap
name = "cheap capture crystal"
desc = "A silent, unassuming crystal in what appears to be some kind of steel housing. This one seems to be cheapley made and can only handle a willing mind."