Merge branch 'master' into giant-rat-that-makes-all-of-the-rules

This commit is contained in:
Heroman
2022-08-02 07:27:25 +10:00
53 changed files with 1199 additions and 285 deletions
+1
View File
@@ -1,4 +1,5 @@
// Normal digestion modes
#define DM_DEFAULT "Default" // Not a real bellymode, used for handling on 'selective' bellymode prefs.
#define DM_HOLD "Hold"
#define DM_HOLD_ABSORBED "Hold Absorbed" // Not a real bellymode, used for handling different idle messages for absorbed prey.
#define DM_DIGEST "Digest"
+4
View File
@@ -65,6 +65,7 @@ var/global/list/classic_vore_sounds = list(
"Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg',
"Rustle 4 (cloth)" = 'sound/effects/rustle4.ogg',
"Rustle 5 (cloth)" = 'sound/effects/rustle5.ogg',
"Zipper" = 'sound/items/zip.ogg',
"None" = null)
var/global/list/classic_release_sounds = list(
@@ -73,6 +74,7 @@ var/global/list/classic_release_sounds = list(
"Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg',
"Rustle 4 (cloth)" = 'sound/effects/rustle4.ogg',
"Rustle 5 (cloth)" = 'sound/effects/rustle5.ogg',
"Zipper" = 'sound/items/zip.ogg',
"Splatter" = 'sound/effects/splat.ogg',
"None" = null
)
@@ -95,6 +97,7 @@ var/global/list/fancy_vore_sounds = list(
"Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg',
"Rustle 4 (cloth)" = 'sound/effects/rustle4.ogg',
"Rustle 5 (cloth)" = 'sound/effects/rustle5.ogg',
"Zipper" = 'sound/items/zip.ogg',
"None" = null
)
@@ -104,6 +107,7 @@ var/global/list/fancy_release_sounds = list(
"Rustle 3 (cloth)" = 'sound/effects/rustle3.ogg',
"Rustle 4 (cloth)" = 'sound/effects/rustle4.ogg',
"Rustle 5 (cloth)" = 'sound/effects/rustle5.ogg',
"Zipper" = 'sound/items/zip.ogg',
"Stomach Move" = 'sound/vore/sunesound/pred/stomachmove.ogg',
"Pred Escape" = 'sound/vore/sunesound/pred/escape.ogg',
"Splatter" = 'sound/effects/splat.ogg',
+3 -3
View File
@@ -1161,7 +1161,7 @@ var/list/WALLITEMS = list(
if(length(temp_col )<2)
temp_col = "0[temp_col]"
colour += temp_col
return colour
return "#[colour]"
/proc/color_square(red, green, blue, hex)
var/color = hex ? hex : "#[num2hex(red, 2)][num2hex(green, 2)][num2hex(blue, 2)]"
@@ -1178,7 +1178,7 @@ var/mob/dview/dview_mob = new
log_error("Had to recreate the dview mob!")
dview_mob.loc = center
dview_mob.see_invisible = invis_flags
. = view(range, dview_mob)
@@ -1497,7 +1497,7 @@ GLOBAL_REAL_VAR(list/stack_trace_storage)
. += new /obj/screen/plane_master/lighting //Lighting system (but different!)
. += new /obj/screen/plane_master/o_light_visual //Object lighting (using masks)
. += new /obj/screen/plane_master/emissive //Emissive overlays
. += new /obj/screen/plane_master/ghosts //Ghosts!
. += new /obj/screen/plane_master{plane = PLANE_AI_EYE} //AI Eye!
+7 -2
View File
@@ -27,13 +27,18 @@
/datum/job/engineer
pto_type = PTO_ENGINEERING
alt_titles = list("Maintenance Technician" = /datum/alt_title/maint_tech, "Engine Technician" = /datum/alt_title/engine_tech,
"Electrician" = /datum/alt_title/electrician, "Construction Engineer" = /datum/alt_title/construction_engi)
"Electrician" = /datum/alt_title/electrician, "Construction Engineer" = /datum/alt_title/construction_engi, "Engineering Contractor" = /datum/alt_title/engineering_contractor)
/datum/alt_title/construction_engi
title = "Construction Engineer"
title_blurb = "A Construction Engineer fulfills similar duties to other engineers, but usually occupies spare time with construction of extra facilities in dedicated areas or \
as additions to station layout."
/datum/alt_title/engineering_contractor
title = "Engineering Contractor"
title_blurb = "An Engineering Contractor fulfills similar duties to other engineers, but isn't directly employed by NT proper."
/datum/job/atmos
@@ -49,4 +54,4 @@
/datum/alt_title/disposals_tech
title = "Disposals Technician"
title_blurb = "A Disposals Technician is an Atmospheric Technician still and can fulfill all the same duties, although specializes more in disposals delivery system's operations and configurations."
title_blurb = "A Disposals Technician is an Atmospheric Technician still and can fulfill all the same duties, although specializes more in disposals delivery system's operations and configurations."
+6 -2
View File
@@ -27,7 +27,7 @@
pto_type = PTO_MEDICAL
alt_titles = list("Physician" = /datum/alt_title/physician, "Medical Practitioner" = /datum/alt_title/medical_practitioner, "Surgeon" = /datum/alt_title/surgeon,
"Emergency Physician" = /datum/alt_title/emergency_physician, "Nurse" = /datum/alt_title/nurse, "Orderly" = /datum/alt_title/orderly,
"Virologist" = /datum/alt_title/virologist)
"Virologist" = /datum/alt_title/virologist, "Medical Contractor" = /datum/alt_title/medical_contractor)
/datum/alt_title/physician
@@ -42,6 +42,10 @@
and dirty labor around the department."
title_outfit = /decl/hierarchy/outfit/job/medical/doctor/nurse
/datum/alt_title/medical_contractor
title = "Medical Contractor"
title_blurb = "A Medical Contractor can be anything from a full-blown doctor to the likes of a nurse or orderly, but isn't directly employed by NT proper."
/datum/job/chemist
pto_type = PTO_MEDICAL
@@ -80,4 +84,4 @@
title_outfit = /decl/hierarchy/outfit/job/medical/paramedic/emt
/datum/alt_title/sar
title = "Search and Rescue"
title = "Search and Rescue"
@@ -52,7 +52,7 @@ var/global/list/image/splatter_cache=list()
addtimer(CALLBACK(src, .proc/dry), DRYING_TIME * (amount+1))
/obj/effect/decal/cleanable/blood/update_icon()
if(basecolor == "rainbow") basecolor = "#[get_random_colour(1)]"
if(basecolor == "rainbow") basecolor = get_random_colour(1)
color = basecolor
if(basecolor == SYNTH_BLOOD_COLOUR)
@@ -184,11 +184,11 @@ var/global/list/image/splatter_cache=list()
var/image/giblets = new(base_icon, "[icon_state]_flesh", dir)
if(!fleshcolor || fleshcolor == "rainbow")
fleshcolor = "#[get_random_colour(1)]"
fleshcolor = get_random_colour(1)
giblets.color = fleshcolor
var/icon/blood = new(base_icon,"[icon_state]",dir)
if(basecolor == "rainbow") basecolor = "#[get_random_colour(1)]"
if(basecolor == "rainbow") basecolor = get_random_colour(1)
blood.Blend(basecolor,ICON_MULTIPLY)
icon = blood
+13
View File
@@ -159,6 +159,10 @@
var/obj/item/organ/external/hand = H.organs_by_name[check_hand]
if(istype(hand) && hand.is_usable())
return TRUE
var/mob/living/simple_mob/S = M
if(istype(S) && S.has_hands) //Are they a mob? And do they have hands?
return TRUE
return FALSE
@@ -254,6 +258,15 @@
var/obj/effect/temporary_effect/item_pickup_ghost/ghost = new(old_loc)
ghost.assumeform(src)
ghost.animate_towards(user)
//VORESTATION EDIT START. This handles possessed items.
if(src.possessed_voice.len && !(user.ckey in warned_of_possession)) //Is this item possessed?
warned_of_possession |= user.ckey
tgui_alert_async(user,{"
THIS ITEM IS POSSESSED BY A PLAYER CURRENTLY IN THE ROUND. This could be by anomalous means or otherwise.
If this is not something you wish to partake in, it is highly suggested you place the item back down.
If this is fine to you, ensure that the other player is fine with you doing things to them beforehand!
"},"OOC Warning")
//VORESTATION EDIT END.
return
/obj/item/attack_ai(mob/user as mob)
@@ -23,7 +23,7 @@
/obj/item/device/analyzer/attack_self(mob/user as mob)
if (user.stat)
return
if (!(ishuman(user) || ticker) && ticker.mode.name != "monkey")
if (!user.IsAdvancedToolUser())
to_chat(usr, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
@@ -41,7 +41,7 @@
dat += "Body Temperature: ???"
user.show_message("<span class='notice'>[dat]</span>", 1)
return
if (!(ishuman(user) || ticker) && ticker.mode.name != "monkey")
if (!user.IsAdvancedToolUser())
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
@@ -30,7 +30,7 @@
/obj/item/device/mass_spectrometer/attack_self(mob/user as mob)
if (user.stat)
return
if (!(ishuman(user) || ticker) && ticker.mode.name != "monkey")
if (!user.IsAdvancedToolUser())
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
if(reagents.total_volume)
+2 -3
View File
@@ -20,8 +20,7 @@
to_chat(user, "<span class='warning'>\The [src] cannot be applied to [M]!</span>")
return 1
if ( ! (istype(user, /mob/living/carbon/human) || \
istype(user, /mob/living/silicon)) )
if (!M.IsAdvancedToolUser())
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return 1
@@ -129,7 +128,7 @@
if(used >= available)
to_chat(user, "<span class='warning'>You run out of [src]!</span>")
break
if (W.current_stage <= W.max_bleeding_stage)
user.visible_message("<b>\The [user]</b> bandages \a [W.desc] on [M]'s [affecting.name].", \
"<span class='notice'>You bandage \a [W.desc] on [M]'s [affecting.name].</span>" )
@@ -57,7 +57,7 @@
// Randomizes color
/obj/item/weapon/melee/umbrella/random/New()
color = "#"+get_random_colour()
color = get_random_colour()
..()
/obj/item/weapon/melee/cursedblade
@@ -95,4 +95,4 @@
new_voice.name = "cursed sword" //Cursed swords shouldn't be known characters.
new_voice.real_name = "cursed sword"
voice_mobs.Add(new_voice)
listening_objects |= src
listening_objects |= src
@@ -107,7 +107,7 @@
/obj/item/weapon/storage/wallet/poly/New()
..()
verbs |= /obj/item/weapon/storage/wallet/poly/proc/change_color
color = "#"+get_random_colour()
color = get_random_colour()
update_icon()
/obj/item/weapon/storage/wallet/poly/proc/change_color()
@@ -196,4 +196,4 @@
icon_state = "casinowallet_white"
return
else
icon_state = "casinowallet_black"
icon_state = "casinowallet_black"
+1 -1
View File
@@ -31,4 +31,4 @@
/obj/item/weapon/towel/random/New()
..()
color = "#"+get_random_colour()
color = get_random_colour()
+1 -1
View File
@@ -19,7 +19,7 @@
user.setClickCooldown(user.get_attack_speed(src))
user.do_attack_animation(M)
if (!(istype(user, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey")
if (!user.IsAdvancedToolUser())
to_chat(user, "<span class='danger'>You don't have the dexterity to do this!</span>")
return
+27
View File
@@ -0,0 +1,27 @@
/obj/item
var/list/possessed_voice //Allows for items to be possessed/inhabited by voices.
var/list/warned_of_possession //Checks to see who has been informed this item is possessed.
/obj/item/proc/inhabit_item(var/mob/candidate, var/candidate_name, var/mob/living/candidate_original_form)
//This makes it so that any object in the game can have something put in it like the cursed sword!
//This means the proc can also be manually called by admin commands.
//Handle moving the person into the object.
if(!possessed_voice) //Create the list for possessed_voice if it doesn't already have one.
possessed_voice = list()
if(!warned_of_possession) //Creates a list of warned users.
warned_of_possession = list()
var/mob/living/voice/new_voice = new /mob/living/voice(src) //Make the voice mob the person is going to be.
new_voice.transfer_identity(candidate) //Now make the voice mob load from the ghost's active character in preferences.
new_voice.mind = candidate.mind //Transfer the mind, if any.
new_voice.ckey = candidate.ckey //Finally, bring the client over.
new_voice.tf_mob_holder = candidate_original_form //Save what mob they are! We'll need this for OOC escape and transformation back to their normal form.
if(candidate_name) //Were we given a candidate_name? Great! Name them that.
new_voice.name = "[candidate_name]"
else
new_voice.name = "[name]" //No name given? Give them the name of the object they're inhabiting.
new_voice.real_name = "[new_voice.real_name]" //We still know their real name though!
possessed_voice.Add(new_voice)
listening_objects |= src
new_voice.verbs -= /mob/living/voice/verb/change_name //No changing your name! Bad!
new_voice.verbs -= /mob/living/voice/verb/hang_up //Also you can't hang up. You are the item!
@@ -84,6 +84,49 @@
else
return ..()
/obj/structure/trash_pile/attack_ghost(mob/observer/user as mob)
if(config.disable_player_mice)
to_chat(user, "<span class='warning'>Spawning as a mouse is currently disabled.</span>")
return
//VOREStation Add Start
if(jobban_isbanned(user, "GhostRoles"))
to_chat(user, "<span class='warning'>You cannot become a mouse because you are banned from playing ghost roles.</span>")
return
//VOREStation Add End
if(!user.MayRespawn(1))
return
var/turf/T = get_turf(src)
if(!T || (T.z in using_map.admin_levels))
to_chat(user, "<span class='warning'>You may not spawn as a mouse on this Z-level.</span>")
return
var/timedifference = world.time - user.client.time_died_as_mouse
if(user.client.time_died_as_mouse && timedifference <= mouse_respawn_time * 600)
var/timedifference_text
timedifference_text = time2text(mouse_respawn_time * 600 - timedifference,"mm:ss")
to_chat(user, "<span class='warning'>You may only spawn again as a mouse more than [mouse_respawn_time] minutes after your death. You have [timedifference_text] left.</span>")
return
var/response = tgui_alert(user, "Are you -sure- you want to become a mouse?","Are you sure you want to squeek?",list("Squeek!","Nope!"))
if(response != "Squeek!") return //Hit the wrong key...again.
var/mob/living/simple_mob/animal/passive/mouse/host
host = new /mob/living/simple_mob/animal/passive/mouse(get_turf(src))
if(host)
if(config.uneducated_mice)
host.universal_understand = 0
announce_ghost_joinleave(src, 0, "They are now a mouse.")
host.ckey = user.ckey
to_chat(host, "<span class='info'>You are now a mouse. Try to avoid interaction with players, and do not give hints away that you are more than a simple rodent.</span>")
var/atom/A = get_holder_at_turf_level(src)
A.visible_message("[host] crawls out of \the [src].")
return
/obj/structure/trash_pile/attack_hand(mob/user)
//Human mob
if(ishuman(user))
+2
View File
@@ -18,6 +18,8 @@
if(can_flee)
if(special_flee_check())
return TRUE
if(isbelly(holder.loc)) //VOREStation Add - Don't flee while you're in a tummy, silly
return FALSE //VOREStation Add
if(!hostile && !retaliate)
return TRUE // We're not hostile and someone attacked us first.
if(flee_when_dying && (holder.health / holder.getMaxHealth()) <= dying_threshold)
+14 -2
View File
@@ -35,6 +35,8 @@
if(istype(I,/obj/item/weapon/holder/micro))
var/full = 0
for(var/mob/M in src)
if(istype(M,/mob/living/voice)) //Don't count voices as people!
continue
full++
if(full >= 2)
to_chat(user, "<span class='warning'>You can't fit anyone else into \the [src]!</span>")
@@ -51,6 +53,8 @@
/obj/item/clothing/shoes/attack_self(var/mob/user)
for(var/mob/M in src)
if(istype(M,/mob/living/voice)) //Don't knock voices out!
continue
M.forceMove(get_turf(user))
to_chat(M, "<span class='warning'>[user] shakes you out of \the [src]!</span>")
to_chat(user, "<span class='notice'>You shake [M] out of \the [src]!</span>")
@@ -59,6 +63,8 @@
/obj/item/clothing/shoes/container_resist(mob/living/micro)
var/mob/living/carbon/human/macro = loc
if(istype(micro,/mob/living/voice)) //Voices shouldn't be able to resist but we have this here just in case.
return
if(!istype(macro))
to_chat(micro, "<span class='notice'>You start to climb out of [src]!</span>")
if(do_after(micro, 50, src))
@@ -106,14 +112,20 @@
spawn(100)
recent_struggle = 0
if(ishuman(src.loc))
if(ishuman(src.loc)) //Is this on a person?
var/mob/living/carbon/human/H = src.loc
if(H.shoes == src)
if(istype(user,/mob/living/voice)) //Is this a possessed item? Spooky. It can move on it's own!
to_chat(H, "<font color='red'>The [src] shifts about, almost as if squirming!</font>")
to_chat(user, "<font color='red'>You cause the [src] to shift against [H]'s form! Well, what little you can get to, given your current state!</font>")
else if(H.shoes == src)
to_chat(H, "<font color='red'>[user]'s tiny body presses against you in \the [src], squirming!</font>")
to_chat(user, "<font color='red'>Your body presses out against [H]'s form! Well, what little you can get to!</font>")
else
to_chat(H, "<font color='red'>[user]'s form shifts around in the \the [src], squirming!</font>")
to_chat(user, "<font color='red'>You move around inside the [src], to no avail.</font>")
else if(istype(user,/mob/living/voice)) //Possessed!
src.visible_message("<font color='red'>The [src] shifts about!</font>")
to_chat(user, "<font color='red'>You cause the [src] to shift about!</font>")
else
src.visible_message("<font color='red'>\The [src] moves a little!</font>")
to_chat(user, "<font color='red'>You throw yourself against the inside of \the [src]!</font>")
+4 -4
View File
@@ -419,8 +419,8 @@
set_trait(TRAIT_POTENCY,rand(5,30),200,0)
set_trait(TRAIT_PRODUCT_ICON,pick(SSplants.accessible_product_sprites))
set_trait(TRAIT_PLANT_ICON,pick(SSplants.accessible_plant_sprites))
set_trait(TRAIT_PLANT_COLOUR,"#[get_random_colour(0,75,190)]")
set_trait(TRAIT_PRODUCT_COLOUR,"#[get_random_colour(0,75,190)]")
set_trait(TRAIT_PLANT_COLOUR,get_random_colour(0,75,190))
set_trait(TRAIT_PRODUCT_COLOUR,get_random_colour(0,75,190))
update_growth_stages()
if(prob(20))
@@ -548,7 +548,7 @@
if(prob(5))
set_trait(TRAIT_BIOLUM,1)
set_trait(TRAIT_BIOLUM_COLOUR,"#[get_random_colour(0,75,190)]")
set_trait(TRAIT_BIOLUM_COLOUR,get_random_colour(0,75,190))
if(prob(3))
set_trait(TRAIT_SPORING,1)
@@ -654,7 +654,7 @@
if(get_trait(TRAIT_BIOLUM))
source_turf.visible_message("<b>\The [display_name]</b> begins to glow!")
if(prob(degree*2))
set_trait(TRAIT_BIOLUM_COLOUR,"#[get_random_colour(0,75,190)]")
set_trait(TRAIT_BIOLUM_COLOUR,get_random_colour(0,75,190))
source_turf.visible_message("<span class='notice'>\The [display_name]'s glow </span><font color='[get_trait(TRAIT_BIOLUM_COLOUR)]'>changes colour</font>!")
else
source_turf.visible_message("<span class='notice'>\The [display_name]'s glow dims...</span>")
+1 -1
View File
@@ -409,7 +409,7 @@
// harvested yet and it's safe to assume it's restricted to this tray.
if(!isnull(SSplants.seeds[seed.name]))
seed = seed.diverge()
seed.mutate(severity,get_turf(src))
seed.mutate(severity,get_turf(src))
return
+1 -1
View File
@@ -352,7 +352,7 @@ var/list/mining_overlay_cache = list()
//Not even going to touch this pile of spaghetti
/turf/simulated/mineral/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (!(istype(usr, /mob/living/carbon/human) || ticker) && ticker.mode.name != "monkey")
if (!user.IsAdvancedToolUser())
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
@@ -1,60 +1,77 @@
/datum/unarmed_attack/bite/sharp/numbing //Is using this against someone you are truly trying to fight a bad idea? Yes. Yes it is.
attack_verb = list("bit")
attack_noun = list("fangs")
attack_sound = 'sound/weapons/bite.ogg'
shredding = 0
sharp = TRUE
edge = TRUE
/datum/unarmed_attack/bite/sharp/numbing/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
var/obj/item/organ/external/affecting = target.get_organ(zone)
attack_damage = CLAMP(attack_damage, 1, 5)
if(target == user)
user.visible_message("<span class='danger'>[user] [pick(attack_verb)] \himself in the [affecting.name]!</span>")
return 0 //No venom for you.
switch(zone)
if(BP_HEAD, O_MOUTH, O_EYES)
// ----- HEAD ----- //
switch(attack_damage)
if(1 to 2)
user.visible_message("<span class='danger'>[user]'s fangs scrape across [target]'s cheek!</span>")
to_chat(target, "<font color='red'><b>Your face feels tingly!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage) //Have to add this here, otherwise the swtich fails.
if(3 to 4)
user.visible_message("<span class='danger'>[user]'s fangs pierce into [target]'s neck at an odd, awkward angle!</span>")
to_chat(target, "<font color='red'><b>Your neck feels like it's on fire before going numb!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(5)
user.visible_message("<span class='danger'>[user] sinks \his [pick(attack_noun)] <b><i>deep</i></b> into [target]'s neck, causing the vein to bulge outwards at some type of chemical is pumped into it!</span>")
to_chat(target, "<font color='red'><b>Your neck feels like it's going to burst! Moments later, you simply can't feel your neck any longer, the numbness beginning to spread throughout your body!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
else
// ----- BODY ----- //
switch(attack_damage)
if(1 to 2)
user.visible_message("<span class='danger'>[user]'s fangs scrape across [target]'s [affecting.name]!</span>")
to_chat(target, "<font color='red'><b>Your [affecting.name] feels tingly!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(3 to 4)
user.visible_message("<span class='danger'>[user]'s fangs pierce [pick("", "", "the side of")] [target]'s [affecting.name]!</span>")
to_chat(target, "<font color='red'><b>Your [affecting.name] feels like it's on fire before going numb!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(5)
user.visible_message("<span class='danger'>[user]'s fangs sink deep into [target]'s [affecting.name], one of their veins bulging outwards from the sudden fluid pumped into it!</span>")
to_chat(target, "<font color='red'><b>Your [affecting.name] feels like it's going to burst! Moments later, you simply can't feel your [affecting.name] any longer, the numbness slowly spreading throughout your body!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
/datum/unarmed_attack/claws/shadekin
/datum/unarmed_attack/claws/shadekin/apply_effects(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
..()
if(!(target == user))
user.shadekin_adjust_energy(attack_damage)
/datum/unarmed_attack/bite/sharp/shadekin
/datum/unarmed_attack/bite/sharp/shadekin/apply_effects(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
..()
if(!(target == user))
user.shadekin_adjust_energy(attack_damage)
/datum/unarmed_attack/bite/sharp/numbing //Is using this against someone you are truly trying to fight a bad idea? Yes. Yes it is.
attack_verb = list("bit")
attack_noun = list("fangs")
attack_sound = 'sound/weapons/bite.ogg'
shredding = 0
sharp = TRUE
edge = TRUE
/datum/unarmed_attack/bite/sharp/numbing/show_attack(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
var/obj/item/organ/external/affecting = target.get_organ(zone)
attack_damage = CLAMP(attack_damage, 1, 5)
if(target == user)
user.visible_message("<span class='danger'>[user] [pick(attack_verb)] \himself in the [affecting.name]!</span>")
return 0 //No venom for you.
switch(zone)
if(BP_HEAD, O_MOUTH, O_EYES)
// ----- HEAD ----- //
switch(attack_damage)
if(1 to 2)
user.visible_message("<span class='danger'>[user]'s fangs scrape across [target]'s cheek!</span>")
to_chat(target, "<font color='red'><b>Your face feels tingly!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage) //Have to add this here, otherwise the swtich fails.
if(3 to 4)
user.visible_message("<span class='danger'>[user]'s fangs pierce into [target]'s neck at an odd, awkward angle!</span>")
to_chat(target, "<font color='red'><b>Your neck feels like it's on fire before going numb!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(5)
user.visible_message("<span class='danger'>[user] sinks \his [pick(attack_noun)] <b><i>deep</i></b> into [target]'s neck, causing the vein to bulge outwards at some type of chemical is pumped into it!</span>")
to_chat(target, "<font color='red'><b>Your neck feels like it's going to burst! Moments later, you simply can't feel your neck any longer, the numbness beginning to spread throughout your body!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
else
// ----- BODY ----- //
switch(attack_damage)
if(1 to 2)
user.visible_message("<span class='danger'>[user]'s fangs scrape across [target]'s [affecting.name]!</span>")
to_chat(target, "<font color='red'><b>Your [affecting.name] feels tingly!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(3 to 4)
user.visible_message("<span class='danger'>[user]'s fangs pierce [pick("", "", "the side of")] [target]'s [affecting.name]!</span>")
to_chat(target, "<font color='red'><b>Your [affecting.name] feels like it's on fire before going numb!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
if(5)
user.visible_message("<span class='danger'>[user]'s fangs sink deep into [target]'s [affecting.name], one of their veins bulging outwards from the sudden fluid pumped into it!</span>")
to_chat(target, "<font color='red'><b>Your [affecting.name] feels like it's going to burst! Moments later, you simply can't feel your [affecting.name] any longer, the numbness slowly spreading throughout your body!</b></font>")
target.bloodstr.add_reagent("numbenzyme",attack_damage)
/datum/unarmed_attack/claws/shadekin
/datum/unarmed_attack/claws/shadekin/apply_effects(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
..()
if(!(target == user))
user.shadekin_adjust_energy(attack_damage)
/datum/unarmed_attack/bite/sharp/shadekin
/datum/unarmed_attack/bite/sharp/shadekin/apply_effects(var/mob/living/carbon/human/user, var/mob/living/carbon/human/target, var/zone, var/attack_damage)
..()
if(!(target == user))
user.shadekin_adjust_energy(attack_damage)
/datum/unarmed_attack/claws/chimera //special feral attack that gets stronger as they get angrier
/datum/unarmed_attack/claws/chimera/get_unarmed_damage(var/mob/living/carbon/human/user)
return user.feral/5
/datum/unarmed_attack/claws/chimera/apply_effects(var/mob/living/carbon/human/user,var/mob/living/carbon/human/target,var/armour,var/attack_damage,var/zone)
..()
if(user.feral && !(target == user))
var/selfdamage = ((user.feral/10)-7.5)
if(selfdamage > 0)
var/selfdamagezone = null
if (user.hand)
selfdamagezone=pick(BP_L_ARM, BP_L_HAND)
else
selfdamagezone=pick(BP_R_ARM, BP_R_HAND)
user.apply_damage(selfdamage, BRUTE, selfdamagezone, 0, 0, sharp=FALSE, edge=FALSE)
@@ -3,10 +3,18 @@
set category = "Abilities"
// Sanity is mostly handled in chimera_regenerate()
var/confirm = tgui_alert(usr, "Are you sure you want to completely reconstruct your form? This process can take up to twenty minutes, depending on how hungry you are, and you will be unable to move.", "Confirm Regeneration", list("Yes", "No"))
if(confirm == "Yes")
chimera_regenerate()
if(stat == DEAD)
var/confirm = tgui_alert(usr, "Are you sure you want to regenerate your corpse? This process can take up to thirty minutes.", "Confirm Regeneration", list("Yes", "No"))
if(confirm == "Yes")
chimera_regenerate()
else if (quickcheckuninjured())
var/confirm = tgui_alert(usr, "Are you sure you want to regenerate? As you are uninjured this will only take 30 seconds and match your appearance to your character slot.", "Confirm Regeneration", list("Yes", "No"))
if(confirm == "Yes")
chimera_regenerate()
else
var/confirm = tgui_alert(usr, "Are you sure you want to completely reconstruct your form? This process can take up to fifteen minutes, depending on how hungry you are, and you will be unable to move.", "Confirm Regeneration", list("Yes", "No"))
if(confirm == "Yes")
chimera_regenerate()
/mob/living/carbon/human/proc/chimera_regenerate()
//If they're already regenerating
@@ -21,40 +29,40 @@
to_chat(src, "You can't use that ability again so soon!")
return
var/nutrition_used = nutrition * 0.5
var/time = (240+960/(1 + nutrition_used/75))
var/time = min(900, (120+780/(1 + nutrition/100))) //capped at 15 mins, roughly 6 minutes at 250 (yellow) nutrition, 4.1 minutes at 500 (grey), cannot be below 2 mins
if (quickcheckuninjured()) //if you're completely uninjured, then you get a speedymode - check health first for quickness
time = 30
//Clicked regen while dead.
if(stat == DEAD)
//Has nutrition and dead, allow regen.
if(hasnutriment())
to_chat(src, "You begin to reconstruct your form. You will not be able to move during this time. It should take aproximately [round(time)] seconds.")
//reviving from dead takes extra nutriment to be provided from outside OR takes twice as long and consumes extra at the end
if(!hasnutriment())
time = time*2
//Scary spawnerization.
revive_ready = REVIVING_NOW
revive_finished = (world.time + time SECONDS) // When do we finish reviving? Allows us to find out when we're done, called by the alert currently.
throw_alert("regen", /obj/screen/alert/xenochimera/reconstitution)
spawn(time SECONDS)
// Was dead, now not dead.
if(stat != DEAD)
to_chat(src, "<span class='notice'>Your body has recovered from its ordeal, ready to regenerate itself again.</span>")
revive_ready = REVIVING_READY //reset their cooldown
clear_alert("regen")
throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
to_chat(src, "You begin to reconstruct your form. You will not be able to move during this time. It should take aproximately [round(time)] seconds.")
// Was dead, still dead.
else
to_chat(src, "<span class='notice'>Consciousness begins to stir as your new body awakens, ready to hatch.</span>")
verbs |= /mob/living/carbon/human/proc/hatch
revive_ready = REVIVING_DONE
src << sound('sound/effects/mob_effects/xenochimera/hatch_notification.ogg',0,0,0,30)
clear_alert("regen")
throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
//Scary spawnerization.
revive_ready = REVIVING_NOW
revive_finished = (world.time + time SECONDS) // When do we finish reviving? Allows us to find out when we're done, called by the alert currently.
throw_alert("regen", /obj/screen/alert/xenochimera/reconstitution)
spawn(time SECONDS)
// check to see if they've been fixed by outside forces in the meantime such as defibbing
if(stat != DEAD)
to_chat(src, "<span class='notice'>Your body has recovered from its ordeal, ready to regenerate itself again.</span>")
revive_ready = REVIVING_READY //reset their cooldown
clear_alert("regen")
throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
// Was dead, still dead.
else
to_chat(src, "<span class='notice'>Consciousness begins to stir as your new body awakens, ready to hatch.</span>")
verbs |= /mob/living/carbon/human/proc/hatch
revive_ready = REVIVING_DONE
src << sound('sound/effects/mob_effects/xenochimera/hatch_notification.ogg',0,0,0,30)
clear_alert("regen")
throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
//Dead until nutrition injected.
else
to_chat(src, "<span class='warning'>Your body is too damaged to regenerate without additional nutrients to feed what few living cells remain.</span>")
//Clicked regen while NOT dead
else
@@ -66,29 +74,17 @@
throw_alert("regen", /obj/screen/alert/xenochimera/reconstitution)
spawn(time SECONDS)
//If they're still alive after regenning.
if(stat != DEAD)
//Slightly different flavour messages
if(stat != DEAD || hasnutriment())
to_chat(src, "<span class='notice'>Consciousness begins to stir as your new body awakens, ready to hatch..</span>")
verbs |= /mob/living/carbon/human/proc/hatch
revive_ready = REVIVING_DONE
src << sound('sound/effects/mob_effects/xenochimera/hatch_notification.ogg',0,0,0,30)
clear_alert("regen")
throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
//Was alive, now dead
else if(hasnutriment())
to_chat(src, "<span class='notice'>Consciousness begins to stir as your new body awakens, ready to hatch..</span>")
verbs |= /mob/living/carbon/human/proc/hatch
revive_ready = REVIVING_DONE
src << sound('sound/effects/mob_effects/xenochimera/hatch_notification.ogg',0,0,0,30)
clear_alert("regen")
throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
//Dead until nutrition injected.
else
to_chat(src, "<span class='warning'>Your body was unable to regenerate, what few living cells remain require additional nutrients to complete the process.</span>")
revive_ready = REVIVING_READY //reset their cooldown
clear_alert("regen")
to_chat(src, "<span class='warning'>Consciousness begins to stir as your battered body struggles to recover from its ordeal..</span>")
verbs |= /mob/living/carbon/human/proc/hatch
revive_ready = REVIVING_DONE
src << sound('sound/effects/mob_effects/xenochimera/hatch_notification.ogg',0,0,0,30)
clear_alert("regen")
throw_alert("hatch", /obj/screen/alert/xenochimera/readytohatch)
/mob/living/carbon/human/proc/hasnutriment()
if (bloodstr.has_reagent("nutriment", 30) || src.bloodstr.has_reagent("protein", 15)) //protein needs half as much. For reference, a steak contains 9u protein.
@@ -97,6 +93,16 @@
return TRUE
else return FALSE
/mob/living/carbon/human/proc/quickcheckuninjured()
if (getBruteLoss() || getFireLoss() || getHalLoss() || getToxLoss() || getOxyLoss() || getBrainLoss()) //fails if they have any of the main damage types
return FALSE
for (var/obj/item/organ/O in organs) //check their organs just in case they're being sneaky and somehow have organ damage but no health damage
if (O.damage)
return FALSE
for (var/obj/item/organ/O in internal_organs) //check their organs just in case they're being sneaky and somehow have organ damage but no health damage
if (O.damage)
return FALSE
return TRUE
/mob/living/carbon/human/proc/hatch()
set name = "Hatch"
@@ -112,58 +118,54 @@
//Dead when hatching
if(stat == DEAD)
//Check again for nutriment (necessary?)
if(hasnutriment())
chimera_hatch()
adjustBrainLoss(10) // if they're reviving from dead, they come back with 10 brainloss on top of whatever's unhealed.
visible_message("<span class='danger'><p><font size=4>The lifeless husk of [src] bursts open, revealing a new, intact copy in the pool of viscera.</font></p></span>") //Bloody hell...
clear_alert("hatch")
return
//Don't have nutriment to hatch! Or you somehow died in between completing your revive and hitting hatch.
else
to_chat(src, "Your body was unable to regenerate, what few living cells remain require additional nutrients to complete the process.")
verbs -= /mob/living/carbon/human/proc/hatch
revive_ready = REVIVING_READY //reset their cooldown they can try again when they're given a kickstart
clear_alert("hatch")
//Reviving from ded takes extra nutrition - if it isn't provided from outside sources, it comes from you
if(!hasnutriment())
nutrition=nutrition * 0.75
chimera_hatch()
adjustBrainLoss(5) // if they're reviving from dead, they come back with 5 brainloss on top of whatever's unhealed.
visible_message("<span class='warning'><p><font size=4>The former corpse staggers to its feet, all its former wounds having vanished...</font></p></span>") //Bloody hell...
clear_alert("hatch")
return
//Alive when hatching
else
chimera_hatch()
visible_message("<span class='danger'><p><font size=4>The dormant husk of [src] bursts open, revealing a new, intact copy in the pool of viscera.</font></p></span>") //Bloody hell...
visible_message("<span class='warning'><p><font size=4>[src] rises to \his feet.</font></p></span>") //Bloody hell...
clear_alert("hatch")
/mob/living/carbon/human/proc/chimera_hatch()
verbs -= /mob/living/carbon/human/proc/hatch
to_chat(src, "<span class='notice'>Your new body awakens, bursting free from your old skin.</span>")
//Modify and record values (half nutrition and braindamage)
var/old_nutrition = nutrition * 0.5
var/braindamage = (brainloss * 0.5) //Can only heal half brain damage.
var/old_nutrition = nutrition
var/braindamage = min(5, max(0, (brainloss-1) * 0.5)) //brainloss is tricky to heal and might take a couple of goes to get rid of completely.
var/uninjured=quickcheckuninjured()
//I did have special snowflake code, but this is easier.
revive()
mutations.Remove(HUSK)
nutrition = old_nutrition
setBrainLoss(braindamage)
//Drop everything
for(var/obj/item/W in src)
drop_from_inventory(W)
if(!uninjured)
nutrition = old_nutrition * 0.5
//Drop everything
for(var/obj/item/W in src)
drop_from_inventory(W)
//Visual effects
var/T = get_turf(src)
var/blood_color = species.blood_color
var/flesh_color = species.flesh_color
new /obj/effect/gibspawner/human/xenochimera(T, null, flesh_color, blood_color)
visible_message("<span class='danger'><p><font size=4>The lifeless husk of [src] bursts open, revealing a new, intact copy in the pool of viscera.</font></p></span>") //Bloody hell...
playsound(T, 'sound/effects/mob_effects/xenochimera/hatch.ogg', 50)
else //lower cost for doing a quick cosmetic revive
nutrition = old_nutrition * 0.9
//Unfreeze some things
does_not_breathe = FALSE
update_canmove()
weakened = 2
//Visual effects
var/T = get_turf(src)
var/blood_color = species.blood_color
var/flesh_color = species.flesh_color
new /obj/effect/gibspawner/human/xenochimera(T, null, flesh_color, blood_color)
playsound(T, 'sound/effects/mob_effects/xenochimera/hatch.ogg', 50)
revive_ready = world.time + 10 MINUTES //set the cooldown CHOMPEdit: Reduced this to 10 minutes, you're playing with fire if you're reviving that often.
/mob/living/carbon/human/proc/revivingreset() // keep this as a debug proc or potential future use
@@ -9,7 +9,7 @@
name_plural = "Xenochimeras"
icobase = 'icons/mob/human_races/r_xenochimera.dmi'
deform = 'icons/mob/human_races/r_def_xenochimera.dmi'
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws, /datum/unarmed_attack/bite/sharp)
unarmed_types = list(/datum/unarmed_attack/stomp, /datum/unarmed_attack/kick, /datum/unarmed_attack/claws/chimera, /datum/unarmed_attack/bite/sharp)
darksight = 8 //critters with instincts to hide in the dark need to see in the dark - about as good as tajara.
slowdown = -0.2 //scuttly, but not as scuttly as a tajara or a teshari.
brute_mod = 0.8 //About as tanky to brute as a Unathi. They'll probably snap and go feral when hurt though.
@@ -55,13 +55,13 @@
genders = list(MALE, FEMALE, PLURAL, NEUTER)
has_organ = list( //Same organ list as tajarans.
has_organ = list( //Same organ list as tajarans, except for their SPECIAL BRAIN.
O_HEART = /obj/item/organ/internal/heart,
O_LUNGS = /obj/item/organ/internal/lungs,
O_VOICE = /obj/item/organ/internal/voicebox,
O_LIVER = /obj/item/organ/internal/liver,
O_KIDNEYS = /obj/item/organ/internal/kidneys,
O_BRAIN = /obj/item/organ/internal/brain,
O_BRAIN = /obj/item/organ/internal/brain/xenochimera,
O_EYES = /obj/item/organ/internal/eyes,
O_STOMACH = /obj/item/organ/internal/stomach,
O_INTESTINE = /obj/item/organ/internal/intestine
@@ -97,6 +97,9 @@
//Very low pressure damage
if(adjusted_pressure2 <= 20)
H.take_overall_damage(brute=LOW_PRESSURE_DAMAGE, used_weapon = "Low Pressure")
//they handle areas where they can't breathe better than most, but it still lowers their effective health as well as all the other bad stuff that comes with unbreathable environments
if(H.getOxyLoss() >= 50)
H.does_not_breathe = TRUE
//Cold hurts and gives them pain messages, eventually weakening and paralysing, but doesn't damage or trigger feral.
//NB: 'body_temperature' used here is the 'setpoint' species var
@@ -105,17 +108,24 @@
H.shock_stage = min(H.shock_stage + (temp_diff/20), 160) // Divided by 20 is the same as previous numbers, but a full scale
H.eye_blurry = max(5,H.eye_blurry)
/obj/item/organ/internal/brain/xenochimera
var/laststress = 0
/datum/species/xenochimera/proc/handle_feralness(var/mob/living/carbon/human/H)
//first, calculate how stressed the chimera is
var/laststress = 0
var/obj/item/organ/internal/brain/xenochimera/B = H.internal_organs_by_name[O_BRAIN]
if(B) //if you don't have a chimera brain in a chimera body somehow, you don't get the feraless protection
laststress = B.laststress
//Low-ish nutrition has messages and eventually feral
var/hungry = H.nutrition <= 200
//Low-ish nutrition has messages and can eventually cause feralness
var/hunger = max(0, 150 - H.nutrition)
//At 360 nutrition, this is 30 brute/burn, or 18 halloss. Capped at 50 brute/30 halloss - if they take THAT much, no amount of satiation will help them. Also they're fat.
var/shock = H.traumatic_shock > min(60, H.nutrition/10)
//pain makes feralness a thing
var/shock = 0.75*H.traumatic_shock
//Caffeinated xenochimera can become feral and have special messages
var/jittery = H.jitteriness >= 100
//Caffeinated or otherwise overexcited xenochimera can become feral and have special messages
var/jittery = max(0, H.jitteriness - 100)
//To reduce distant object references
var/feral = H.feral
@@ -124,11 +134,25 @@
var/danger = FALSE
var/feral_state = FALSE
//Handle feral triggers and pre-feral messages
if(!feral && (hungry || shock || jittery))
//finally, calculate the current stress total the chimera is operating under, and the cause
var/currentstress = (hunger + shock + jittery)
var/cause = "stress"
if(hunger > shock && hunger > jittery)
cause = "hunger"
else if (shock > hunger && shock > jittery)
cause = "shock"
else if (jittery > shock && jittery > hunger)
cause = "jittery"
// If they're hungry, give nag messages (when not bellied)
if(H.nutrition >= 100 && prob(0.5) && !isbelly(H.loc))
//check to see if they go feral if they weren't before
if(!feral)
// if stress is below 15, no chance of snapping. Also if they weren't feral before, they won't suddenly become feral unless they get MORE stressed
if((currentstress > laststress) && prob(clamp(currentstress-15, 0, 100)) )
go_feral(H, currentstress, cause)
feral = currentstress //update the local var
//they didn't go feral, give 'em a chance of hunger messages
else if(H.nutrition <= 200 && prob(0.5) && !isbelly(H.loc))
switch(H.nutrition)
if(150 to 200)
to_chat(H,"<span class='info'>You feel rather hungry. It might be a good idea to find some some food...</span>")
@@ -136,81 +160,26 @@
to_chat(H,"<span class='warning'>You feel like you're going to snap and give in to your hunger soon... It would be for the best to find some [pick("food","prey")] to eat...</span>")
danger = TRUE
// Going feral due to hunger
else if(H.nutrition < 100 && !isbelly(H.loc))
to_chat(H,"<span class='danger'><big>Something in your mind flips, your instincts taking over, no longer able to fully comprehend your surroundings as survival becomes your primary concern - you must feed, survive, there is nothing else. Hunt. Eat. Hide. Repeat.</big></span>")
log_and_message_admins("has gone feral due to hunger.", H)
feral = 5
danger = TRUE
feral_state = TRUE
if(!H.stat)
H.emote("twitch")
// If they're hurt, chance of snapping.
else if(shock)
//If the majority of their shock is due to halloss, greater chance of snapping.
if(2.5*H.halloss >= H.traumatic_shock)
if(prob(min(10,(0.2 * H.traumatic_shock))))
to_chat(H,"<span class='danger'><big>The pain! It stings! Got to get away! Your instincts take over, urging you to flee, to hide, to go to ground, get away from here...</big></span>")
log_and_message_admins("has gone feral due to halloss.", H)
feral = 5
danger = TRUE
feral_state = TRUE
if(!H.stat)
H.emote("twitch")
//Majority due to other damage sources
else if(prob(min(10,(0.1 * H.traumatic_shock))))
to_chat(H,"<span class='danger'><big>Your fight-or-flight response kicks in, your injuries too much to simply ignore - you need to flee, to hide, survive at all costs - or destroy whatever is threatening you.</big></span>")
feral = 5
danger = TRUE
feral_state = TRUE
log_and_message_admins("has gone feral due to injury.", H)
if(!H.stat)
H.emote("twitch")
//No hungry or shock, but jittery
else if(jittery)
to_chat(H,"<span class='warning'><big>Suddenly, something flips - everything that moves is... potential prey. A plaything. This is great! Time to hunt!</big></span>")
feral = 5
danger = TRUE
feral_state = TRUE
log_and_message_admins("has gone feral due to jitteriness.", H)
if(!H.stat)
H.emote("twitch")
//now the check's done, update their brain so it remembers how stressed they were
B.laststress = currentstress
// Handle being feral
if(feral)
//We're feral
feral_state = TRUE
//Shock due to mostly halloss. More feral.
if(shock && 2.5*H.halloss >= H.traumatic_shock)
//If they're still stressed, they stay feral
if(currentstress >= 15)
danger = TRUE
feral = max(feral, H.halloss)
feral = max(feral, currentstress)
//Shock due to mostly injury. More feral.
else if(shock)
danger = TRUE
feral = max(feral, H.traumatic_shock * 2)
//Still jittery? More feral.
if(jittery)
danger = TRUE
feral = max(feral, H.jitteriness-100)
//Still hungry? More feral.
if(H.feral + H.nutrition < 150)
danger = TRUE
feral++
else
feral = max(0,--feral)
// Being in a belly or in the darkness decreases stress further. Helps mechanically reward players for staying in darkness + RP'ing appropriately. :9
var/turf/T = get_turf(H)
if(feral && (isbelly(H.loc) || T.get_lumcount() <= 0.1))
feral = max(0,--feral)
// Being in a belly or in the darkness decreases stress further. Helps mechanically reward players for staying in darkness + RP'ing appropriately. :9
var/turf/T = get_turf(H)
if(feral && (isbelly(H.loc) || T.get_lumcount() <= 0.1))
feral = max(0,--feral)
//Set our real mob's var to our temp var
H.feral = feral
@@ -227,7 +196,7 @@
H.shock_stage = max(H.shock_stage-(feral/20), 0)
//Handle light/dark areas
// var/turf/T = get_turf(H) // Moved up to before the in-belly/dark combined check, should still safely reach here just fine.
var/turf/T = get_turf(H)
if(!T)
update_xenochimera_hud(H, danger, feral_state)
return //Nullspace
@@ -257,15 +226,15 @@
// In the darkness, or "hidden", or in a belly. No need for custom scene-protection checks as it's just an occational infomessage.
if(darkish || !isturf(H.loc) || isbelly(H.loc)) // Specific check for if in belly. !isturf should do this, but JUST in case.
// If hurt, tell 'em to heal up
if (shock)
if (cause == "shock")
to_chat(H,"<span class='info'>This place seems safe, secure, hidden, a place to lick your wounds and recover...</span>")
//If hungry, nag them to go and find someone or something to eat.
else if(hungry)
else if(cause == "hunger")
to_chat(H,"<span class='info'>Secure in your hiding place, your hunger still gnaws at you. You need to catch some food...</span>")
//If jittery, etc
else if(jittery)
else if(cause == "jittery")
to_chat(H,"<span class='info'>sneakysneakyyesyesyescleverhidingfindthingsyessssss</span>")
//Otherwise, just tell them to keep hiding.
@@ -284,16 +253,16 @@
// Someone/something nearby
if(nearby.len)
var/M = pick(nearby)
if(shock)
if(cause == "shock")
to_chat(H,"<span class='danger'>You're hurt, in danger, exposed, and [M] looks to be a little too close for comfort...</span>")
else if(hungry || jittery)
else
to_chat(H,"<span class='danger'>Every movement, every flick, every sight and sound has your full attention, your hunting instincts on high alert... In fact, [M] looks extremely appetizing...</span>")
// Nobody around
else
if(hungry)
if(cause == "hunger")
to_chat(H,"<span class='danger'>Confusing sights and sounds and smells surround you - scary and disorienting it may be, but the drive to hunt, to feed, to survive, compels you.</span>")
else if(jittery)
else if(cause == "jittery")
to_chat(H,"<span class='danger'>yesyesyesyesyesyesgetthethingGETTHETHINGfindfoodsfindpreypounceyesyesyes</span>")
else
to_chat(H,"<span class='danger'>Confusing sights and sounds and smells surround you, this place is wrong, confusing, frightening. You need to hide, go to ground...</span>")
@@ -301,6 +270,37 @@
// HUD update time
update_xenochimera_hud(H, danger, feral_state)
/datum/species/xenochimera/proc/go_feral(var/mob/living/carbon/human/H, var/stress, var/cause)
// Going feral due to hunger
if(cause == "hunger")
to_chat(H,"<span class='danger'><big>Something in your mind flips, your instincts taking over, no longer able to fully comprehend your surroundings as survival becomes your primary concern - you must feed, survive, there is nothing else. Hunt. Eat. Hide. Repeat.</big></span>")
log_and_message_admins("has gone feral due to hunger.", H)
// If they're hurt, chance of snapping.
else if(cause == "shock")
//If the majority of their shock is due to halloss, give them a different message (3x multiplier on check as halloss is 2x - meaning t_s must be at least 3x for other damage sources to be the greater part)
if(3*H.halloss >= H.traumatic_shock)
to_chat(H,"<span class='danger'><big>The pain! It stings! Got to get away! Your instincts take over, urging you to flee, to hide, to go to ground, get away from here...</big></span>")
log_and_message_admins("has gone feral due to halloss.", H)
//Majority due to other damage sources
else
to_chat(H,"<span class='danger'><big>Your fight-or-flight response kicks in, your injuries too much to simply ignore - you need to flee, to hide, survive at all costs - or destroy whatever is threatening you.</big></span>")
log_and_message_admins("has gone feral due to injury.", H)
//No hungry or shock, but jittery
else if(cause == "jittery")
to_chat(H,"<span class='warning'><big>Suddenly, something flips - everything that moves is... potential prey. A plaything. This is great! Time to hunt!</big></span>")
log_and_message_admins("has gone feral due to jitteriness.", H)
else // catch-all just in case something weird happens
to_chat(H,"<span class='warning'><big>The stress of your situation is too much for you, and your survival instincts kick in!</big></span>")
log_and_message_admins("has gone feral for unknown reasons.", H)
//finally, set their feral var
H.feral = stress
if(!H.stat)
H.emote("twitch")
/datum/species/xenochimera/get_race_key()
var/datum/species/real = GLOB.all_species[base_species]
return real.race_key
@@ -47,4 +47,12 @@
add_modifier(/datum/modifier/berserk, 30 SECONDS)
/decl/mob_organ_names/goose
hit_zones = list("head", "chest", "left leg", "right leg", "left wing", "right wing", "neck")
hit_zones = list("head", "chest", "left leg", "right leg", "left wing", "right wing", "neck")
/mob/living/simple_mob/animal/space/goose/white
icon = 'icons/mob/animal_vr.dmi'
icon_state = "whitegoose"
icon_living = "whitegoose"
icon_dead = "whitegoose_dead"
name = "white goose"
desc = "And just when you thought it was a lovely day..."
@@ -24,6 +24,7 @@
allowmobvore = client.prefs_vr.allowmobvore
permit_healbelly = client.prefs_vr.permit_healbelly
noisy = client.prefs_vr.noisy
selective_preference = client.prefs_vr.selective_preference
drop_vore = client.prefs_vr.drop_vore
stumble_vore = client.prefs_vr.stumble_vore
+28
View File
@@ -175,3 +175,31 @@ VS Edit - anyone can select these. */
/obj/item/weapon/disk/limb/dsi_teshari
company = "DSI - Teshari"
/datum/robolimb/dsi_zorren
company = "DSI - Zorren"
desc = "This limb feels soft and fluffy, realistic design and squish. Seems a little mischievous. By Darkside Incorperated."
icon = 'icons/mob/human_races/cyberlimbs/DSIZorren/dsi_zorren.dmi'
blood_color = "#ffe2ff"
lifelike = 1
unavailable_to_build = 1
includes_tail = 1
skin_tone = 1
suggested_species = "Zorren"
/obj/item/weapon/disk/limb/dsi_zorren
company = "DSI - Zorren"
/datum/robolimb/dsi_fennec
company = "DSI - Fennec"
desc = "This limb feels soft and fluffy, realistic design and squish. Seems a little mischievous. By Darkside Incorperated."
icon = 'icons/mob/human_races/cyberlimbs/DSIFennec/dsi_fennec.dmi'
blood_color = "#ffe2ff"
lifelike = 1
unavailable_to_build = 1
includes_tail = 1
skin_tone = 1
suggested_species = "Fennec"
/obj/item/weapon/disk/limb/dsi_fennec
company = "DSI - Fennec"
@@ -10,7 +10,7 @@
#
# Use this format, followed by the caliber. For example, a shotgun's caliber
# variable is "12g" as a result. Ergo, a shotgun round's path would have "a12g",
# or a magazine with shotgun shells would be "m12g" instead. To avoid confusion
# or a magazine with shotgun shells would be "m12g" instead. To avoid confusion // Avoid confusion my ass, when ammo is called only shells and suddenly switches to being called some obscure-ass military number
# for developers and in-game admins spawning these items, stick to this format.
# Likewise, when creating new rounds, the caliber variable should match whatever
# the name says.
+1 -1
View File
@@ -21,7 +21,7 @@
else
active++
return "Current server status:\n**Web Manifest:** <https://vore-station.net/manifest.php>\n**Players:** [counts]\n**AFK:** [afks]\n**Active:** [active]\n**Bellied:** [bellied]\n\nRound Duration:** [roundduration2text()]"
return "Current server status:\n**Web Manifest:** <https://vore-station.net/manifest.php>\n**Players:** [counts]\n**Active:** [active]\n**AFK:** [afks]\n**Bellied:** [bellied]\n\n**Round Duration:** [roundduration2text()]"
/datum/tgs_chat_command/parsetest
name = "parsetest"
+4 -1
View File
@@ -50,6 +50,7 @@
var/emote_time = 60 // How long between stomach emotes at prey (in seconds)
var/emote_active = TRUE // Are we even giving emotes out at all or not?
var/next_emote = 0 // When we're supposed to print our next emote, as a world.time
var/selective_preference = DM_DIGEST // Which type of selective bellymode do we default to?
// Generally just used by AI
var/autotransferchance = 0 // % Chance of prey being autotransferred to transfer location
@@ -58,7 +59,7 @@
//I don't think we've ever altered these lists. making them static until someone actually overrides them somewhere.
//Actual full digest modes
var/tmp/static/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_ABSORB,DM_DRAIN,DM_UNABSORB,DM_HEAL,DM_SHRINK,DM_GROW,DM_SIZE_STEAL,DM_EGG)
var/tmp/static/list/digest_modes = list(DM_HOLD,DM_DIGEST,DM_ABSORB,DM_DRAIN,DM_SELECT,DM_UNABSORB,DM_HEAL,DM_SHRINK,DM_GROW,DM_SIZE_STEAL,DM_EGG)
//Digest mode addon flags
var/tmp/static/list/mode_flag_list = list("Numbing" = DM_FLAG_NUMBING, "Stripping" = DM_FLAG_STRIPPING, "Leave Remains" = DM_FLAG_LEAVEREMAINS, "Muffles" = DM_FLAG_THICKBELLY, "Affect Worn Items" = DM_FLAG_AFFECTWORN, "Jams Sensors" = DM_FLAG_JAMSENSORS, "Complete Absorb" = DM_FLAG_FORCEPSAY)
//Item related modes
@@ -200,6 +201,7 @@
"emote_lists",
"emote_time",
"emote_active",
"selective_preference",
"mode_flags",
"item_digest_mode",
"contaminates",
@@ -1128,6 +1130,7 @@
dupe.egg_type = egg_type
dupe.emote_time = emote_time
dupe.emote_active = emote_active
dupe.selective_preference = selective_preference
dupe.save_digest_mode = save_digest_mode
//// Object-holding variables
+30 -10
View File
@@ -223,15 +223,35 @@ GLOBAL_LIST_INIT(digest_modes, list())
id = DM_SELECT
/datum/digest_mode/selective/process_mob(obj/belly/B, mob/living/L)
var/datum/digest_mode/tempmode = GLOB.digest_modes["Hold"]
var/datum/digest_mode/tempmode = GLOB.digest_modes[DM_HOLD] // Default to Hold in case of big oof fallback
//if not absorbed, see if they're food
if(L.digestable)
tempmode = GLOB.digest_modes["Digest"]
//if they're indigestible, then try to absorb them
else if(L.absorbable)
tempmode = GLOB.digest_modes["Absorb"]
//if they're not absorbable, just drain
else
tempmode = GLOB.digest_modes["Drain"]
//finally, process the mob as if they were subject to the chosen mode
switch(L.selective_preference) // First, we respect prey prefs
if(DM_DIGEST)
if(L.digestable)
tempmode = GLOB.digest_modes[DM_DIGEST] // They want to be digested and can be, Digest
else
tempmode = GLOB.digest_modes[DM_DRAIN] // They want to be digested but can't be! Drain.
if(DM_ABSORB)
if(L.absorbable)
tempmode = GLOB.digest_modes[DM_ABSORB] // They want to be absorbed and can be. Absorb.
else
tempmode = GLOB.digest_modes[DM_DRAIN] // They want to be absorbed but can't be! Drain.
if(DM_DRAIN)
tempmode = GLOB.digest_modes[DM_DRAIN] // They want to be drained. Drain.
if(DM_DEFAULT)
switch(B.selective_preference) // They don't actually care? Time for our own preference.
if(DM_DIGEST)
if(L.digestable)
tempmode = GLOB.digest_modes[DM_DIGEST] // We prefer digestion and they're digestible? Digest
else if(L.absorbable)
tempmode = GLOB.digest_modes[DM_ABSORB] // If not digestible, are they absorbable? Then absorb.
else
tempmode = GLOB.digest_modes[DM_DRAIN] // Otherwise drain.
if(DM_ABSORB)
if(L.absorbable)
tempmode = GLOB.digest_modes[DM_ABSORB] // We prefer absorption and they're absorbable? Absorb.
else if(L.digestable)
tempmode = GLOB.digest_modes[DM_DIGEST] // If not absorbable, are they digestible? Then digest.
else
tempmode = GLOB.digest_modes[DM_DRAIN] // Otherwise drain.
return tempmode.process_mob(B, L)
@@ -9,6 +9,9 @@
var/obj/item/device/pda/P = src
if(P.id)
P.id = null
for(var/mob/living/voice/V in possessed_voice) // Delete voices.
V.Destroy() //Destroy the voice.
for(var/mob/living/M in contents)//Drop mobs from objects(shoes) before deletion
M.forceMove(item_storage)
for(var/obj/item/O in contents)
@@ -40,6 +43,8 @@
var/obj/item/device/pda/P = src
if(P.id)
P.id = null
for(var/mob/living/voice/V in possessed_voice) // Delete voices.
V.Destroy() //Destroy the voice.
for(var/mob/living/M in contents)//Drop mobs from objects(shoes) before deletion
M.forceMove(item_storage)
for(var/obj/item/O in contents)
+22 -3
View File
@@ -45,6 +45,7 @@
var/adminbus_eat_minerals = FALSE // This creature subsists on a diet of pure adminium.
var/vis_height = 32 // Sprite height used for resize features.
var/show_vore_fx = TRUE // Show belly fullscreens
var/selective_preference = DM_DEFAULT // Preference for selective bellymode
var/regen_sounds = list(
'sound/effects/mob_effects/xenochimera/regen_1.ogg',
'sound/effects/mob_effects/xenochimera/regen_2.ogg',
@@ -55,8 +56,8 @@
var/nutrition_message_visible = TRUE
var/list/nutrition_messages = list(
"They are starving! You can hear their stomach snarling from across the room!" = 1,
"They are extremely hungry. A deep growl occasionally rumbles from their empty stomach." = 2,
"They are starving! You can hear their stomach snarling from across the room!",
"They are extremely hungry. A deep growl occasionally rumbles from their empty stomach.",
"",
"They have a stuffed belly, bloated fat and round from eating too much.",
"They have a rotund, thick gut. It bulges from their body obscenely, close to sagging under its own weight.",
@@ -263,6 +264,7 @@
P.vore_smell = src.vore_smell
P.permit_healbelly = src.permit_healbelly
P.noisy = src.noisy
P.selective_preference = src.selective_preference
P.show_vore_fx = src.show_vore_fx
P.can_be_drop_prey = src.can_be_drop_prey
P.can_be_drop_pred = src.can_be_drop_pred
@@ -307,6 +309,7 @@
vore_taste = P.vore_taste
vore_smell = P.vore_smell
permit_healbelly = P.permit_healbelly
selective_preference = P.selective_preference
noisy = P.noisy
show_vore_fx = P.show_vore_fx
can_be_drop_prey = P.can_be_drop_prey
@@ -508,8 +511,23 @@
crystal.bound_mob = null
crystal.bound_mob = capture_crystal = 0
log_and_message_admins("[key_name(src)] used the OOC escape button to get out of [crystal] owned by [crystal.owner]. [ADMIN_FLW(src)]")
//You've been turned into an item!
else if(tf_mob_holder && istype(src, /mob/living/voice) && istype(src.loc, /obj/item))
var/obj/item/item_to_destroy = src.loc //If so, let's destroy the item they just TF'd out of.
if(istype(src.loc, /obj/item/clothing)) //Are they in clothes? Delete the item then revert them.
qdel(item_to_destroy)
log_and_message_admins("[key_name(src)] used the OOC escape button to revert back to their original form from being TFed into an object.")
revert_mob_tf()
else //Are they in any other type of object? If qdel is done first, the mob is deleted from the world.
forceMove(get_turf(src))
qdel(item_to_destroy)
log_and_message_admins("[key_name(src)] used the OOC escape button to revert back to their original form from being TFed into an object.")
revert_mob_tf()
//You've been turned into a mob!
else if(tf_mob_holder)
log_and_message_admins("[key_name(src)] used the OOC escape button to revert back to their original form from being TFed into another mob. [ADMIN_FLW(src)]")
log_and_message_admins("[key_name(src)] used the OOC escape button to revert back to their original form from being TFed into another mob.")
revert_mob_tf()
//Don't appear to be in a vore situation
else
@@ -1013,6 +1031,7 @@
dispvoreprefs += "<b>Leaves Remains:</b> [digest_leave_remains ? "Enabled" : "Disabled"]<br>"
dispvoreprefs += "<b>Mob Vore:</b> [allowmobvore ? "Enabled" : "Disabled"]<br>"
dispvoreprefs += "<b>Healbelly permission:</b> [permit_healbelly ? "Allowed" : "Disallowed"]<br>"
dispvoreprefs += "<b>Selective Mode Pref:</b> [src.selective_preference]<br>"
dispvoreprefs += "<b>Spontaneous vore prey:</b> [can_be_drop_prey ? "Enabled" : "Disabled"]<br>"
dispvoreprefs += "<b>Spontaneous vore pred:</b> [can_be_drop_pred ? "Enabled" : "Disabled"]<br>"
dispvoreprefs += "<b>Drop Vore:</b> [drop_vore ? "Enabled" : "Disabled"]<br>"
+8 -2
View File
@@ -70,11 +70,13 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
var/vore_taste = "nothing in particular"
var/vore_smell = "nothing in particular"
var/selective_preference = DM_DEFAULT
var/nutrition_message_visible = TRUE
var/list/nutrition_messages = list(
"They are starving! You can hear their stomach snarling from across the room!" = 1,
"They are extremely hungry. A deep growl occasionally rumbles from their empty stomach." = 2,
"They are starving! You can hear their stomach snarling from across the room!",
"They are extremely hungry. A deep growl occasionally rumbles from their empty stomach.",
"",
"They have a stuffed belly, bloated fat and round from eating too much.",
"They have a rotund, thick gut. It bulges from their body obscenely, close to sagging under its own weight.",
@@ -168,6 +170,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
vore_smell = json_from_file["vore_smell"]
permit_healbelly = json_from_file["permit_healbelly"]
noisy = json_from_file["noisy"]
selective_preference = json_from_file["selective_preference"]
show_vore_fx = json_from_file["show_vore_fx"]
can_be_drop_prey = json_from_file["can_be_drop_prey"]
can_be_drop_pred = json_from_file["can_be_drop_pred"]
@@ -201,6 +204,8 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
allowmobvore = TRUE
if(isnull(permit_healbelly))
permit_healbelly = TRUE
if(isnull(selective_preference))
selective_preference = DM_DEFAULT
if (isnull(noisy))
noisy = FALSE
if(isnull(show_vore_fx))
@@ -274,6 +279,7 @@ V::::::V V::::::VO:::::::OOO:::::::ORR:::::R R:::::REE::::::EEEEEE
"vore_smell" = vore_smell,
"permit_healbelly" = permit_healbelly,
"noisy" = noisy,
"selective_preference" = selective_preference,
"show_vore_fx" = show_vore_fx,
"can_be_drop_prey" = can_be_drop_prey,
"can_be_drop_pred" = can_be_drop_pred,
+15
View File
@@ -181,6 +181,7 @@
"shrink_grow_size" = selected.shrink_grow_size,
"emote_time" = selected.emote_time,
"emote_active" = selected.emote_active,
"selective_preference" = selected.selective_preference,
"nutrition_ex" = host.nutrition_message_visible,
"weight_ex" = host.weight_message_visible,
"belly_fullscreen" = selected.belly_fullscreen,
@@ -487,6 +488,14 @@
host.stumble_vore = !host.stumble_vore
unsaved_changes = TRUE
return TRUE
if("switch_selective_mode_pref")
host.selective_preference = tgui_input_list(usr, "What would you prefer happen to you with selective bellymode?","Selective Bellymode", list(DM_DEFAULT, DM_DIGEST, DM_ABSORB, DM_DRAIN))
if(!(host.selective_preference))
host.selective_preference = DM_DEFAULT
if(host.client.prefs_vr)
host.client.prefs_vr.selective_preference = host.selective_preference
unsaved_changes = TRUE
return TRUE
if("toggle_nutrition_ex")
host.nutrition_message_visible = !host.nutrition_message_visible
unsaved_changes = TRUE
@@ -1079,6 +1088,12 @@
if("b_emoteactive")
host.vore_selected.emote_active = !host.vore_selected.emote_active
. = TRUE
if("b_selective_mode_pref_toggle")
if(host.vore_selected.selective_preference == DM_DIGEST)
host.vore_selected.selective_preference = DM_ABSORB
else
host.vore_selected.selective_preference = DM_DIGEST
. = TRUE
if("b_emotetime")
var/new_time = tgui_input_number(user, "Choose the period it takes for idle belly emotes to be shown to prey. Measured in seconds, Minimum 1 minute, Maximum 10 minutes.", "Set Belly Emote Delay.", host.vore_selected.digest_brute, 600, 60)
if(new_time == null)
+17
View File
@@ -230,6 +230,7 @@
new_mob.allowmobvore = allowmobvore
new_mob.permit_healbelly = permit_healbelly
new_mob.noisy = noisy
new_mob.selective_preference = selective_preference
new_mob.drop_vore = drop_vore
new_mob.stumble_vore = stumble_vore
new_mob.slip_vore = slip_vore
@@ -268,6 +269,22 @@
tf_admin_pref_override = FALSE
/obj/item/projectile/beam/mouselaser/reversion/on_hit(var/atom/target)
if(istype(target,/obj/item)) //Are we shooting an item?
var/obj/item/O = target
if(O.possessed_voice.len) //Does the object have a voice? AKA, if someone inhabiting it?
for(var/mob/living/M in O.possessed_voice)
if(M.tf_mob_holder) //Is this item possessed by IC methods?
if(istype(M.loc, /obj/item/clothing)) //Are they in clothes? Delete the item then revert them.
qdel(O)
M.revert_mob_tf() //Voices can't eat, so this is the least intensive way to revert them.
else
M.forceMove(get_turf(O)) //Non-clothing items require a bit extra work since they don't drop contents when qdeleted.
qdel(O)
M.revert_mob_tf()
else
continue //In case they have multiple voices through adminbus.
else
return
var/mob/living/M = target
if(!istype(M))
return
@@ -13,6 +13,7 @@
25;/obj/machinery/power/supermatter/shard,
100;/obj/machinery/auto_cloner,
100;/obj/machinery/giga_drill,
100;/obj/machinery/replicator,
100;/obj/machinery/replicator/clothing, //VOREStation Edit: use virgo-specific subtype that allows TF into items.
100;/obj/machinery/replicator/vore, //VOREStation Edit: use virgo-specific subtype that allows TF into mobs.
150;/obj/structure/crystal,
1000;/obj/machinery/artifact)
@@ -0,0 +1,598 @@
//////////////////////////////
//////VORE-MOB REPLICATOR/////
//////////////////////////////
/obj/machinery/replicator/vore
name = "alien machine"
desc = "It's some kind of pod with strange wires and gadgets all over it. This one appears to have a humanoid shaped slot as an input. It has depictions of various creatures on the buttons." //Explain to the user that it turns people into mobs.
icon = 'icons/obj/xenoarchaeology.dmi'
icon_state = "borgcharger0(old)"
var/quantity = 18 //This needs to be replaced with a GUI that lets you select the item you want.
var/list/created_mobs = list()
var/list/tgui_vore_selection = list()
var/list/viable_mobs = list(
/mob/living/simple_mob/animal/passive/fox,
/mob/living/simple_mob/animal/passive/cow,
/mob/living/simple_mob/animal/passive/chicken,
/mob/living/simple_mob/animal/passive/opossum,
/mob/living/simple_mob/animal/passive/mouse,
/mob/living/simple_mob/vore/rabbit,
/mob/living/simple_mob/animal/goat,
/mob/living/simple_mob/animal/sif/tymisian,
/mob/living/simple_mob/animal/wolf/direwolf,
/mob/living/simple_mob/otie/friendly,
/mob/living/simple_mob/vore/alienanimals/catslug,
/mob/living/simple_mob/vore/alienanimals/teppi,
/mob/living/simple_mob/vore/fennec,
/mob/living/simple_mob/vore/xeno_defanged,
/mob/living/simple_mob/vore/redpanda/fae,
/mob/living/simple_mob/vore/aggressive/rat,
/mob/living/simple_mob/vore/aggressive/panther,
/mob/living/simple_mob/vore/aggressive/frog
)
//Mostly friendly mobs, but occasionally some dangerous ones.
//So if xenoarch isn't careful and is just shoving items willy-nilly without taking the proper precautions they can end up in a bit of trouble!
/obj/machinery/replicator/vore/New() //This replicator turns people into mobs!
..() //TODO: Someone can replace the 'alien' interface with something neater sometime. It is simply out of my abilities at the current moment.
for(var/i=0, i<quantity, i++)
var/background = pick("yellow","purple","green","blue","red","orange","white")
var/list/icons = list(
"round" = "circle",
"square" = "square",
"diamond" = "gem",
"heart" = "heart",
"dog" = "dog",
"human" = "user",
)
var/icon = pick(icons)
var/list/colors = list(
"toggle" = "pink",
"switch" = "yellow",
"lever" = "red",
"button" = "black",
"pad" = "white",
"hole" = "black",
)
var/color = pick(colors)
var/button_desc = "a [background], [icon] shaped [color]"
var/generated_mob = pick(viable_mobs)
viable_mobs.Remove(type)
created_mobs[button_desc] = generated_mob
tgui_vore_selection.Add(list(list(
"key" = button_desc,
"background" = background,
"icon" = icons[icon],
"foreground" = colors[color],
)))
/obj/machinery/replicator/vore/process()
if(spawning_types.len && powered())
spawn_progress_time += world.time - last_process_time
if(spawn_progress_time > max_spawn_time)
src.visible_message("<span class='notice'>\icon[src][bicon(src)] [src] pings!</span>")
var/obj/source_material = pop(stored_materials)
var/spawn_type = pop(spawning_types)
var/mob/living/simple_mob/new_mob = new spawn_type(src.loc) //The MOB that's spawned in.
if(source_material)
if(length(source_material.name) < MAX_MESSAGE_LEN)
new_mob.name = "[source_material] " + new_mob.name
if(length(source_material.desc) < MAX_MESSAGE_LEN * 2)
if(new_mob.desc)
new_mob.desc += " It is made of [source_material]."
else
new_mob.desc = "It is made of [source_material]."
//Did they use an item? If so, we're done here.
//Did they put a micro in it?
if(istype(source_material,/obj/item/weapon/holder/micro))
var/obj/item/weapon/holder/micro/micro_holder = source_material
var/mob/mob_to_be_changed = micro_holder.held_mob
var/mob/living/M = mob_to_be_changed
//Start of mob code shamelessly ripped from mouseray
new_mob.faction = M.faction
if(new_mob && isliving(new_mob))
for(var/obj/belly/B as anything in new_mob.vore_organs)
new_mob.vore_organs -= B
qdel(B)
new_mob.vore_organs = list()
new_mob.name = M.name
new_mob.real_name = M.real_name
for(var/lang in M.languages)
new_mob.languages |= lang
M.copy_vore_prefs_to_mob(new_mob)
new_mob.vore_selected = M.vore_selected
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(ishuman(new_mob))
var/mob/living/carbon/human/N = new_mob
N.gender = H.gender
N.identifying_gender = H.identifying_gender
else
new_mob.gender = H.identifying_gender
else
new_mob.gender = M.gender
if(ishuman(new_mob))
var/mob/living/carbon/human/N = new_mob
N.identifying_gender = M.gender
for(var/obj/belly/B as anything in M.vore_organs)
B.loc = new_mob
B.forceMove(new_mob)
B.owner = new_mob
M.vore_organs -= B
new_mob.vore_organs += B
new_mob.ckey = M.ckey
if(M.ai_holder && new_mob.ai_holder)
var/datum/ai_holder/old_AI = M.ai_holder
old_AI.set_stance(STANCE_SLEEP)
var/datum/ai_holder/new_AI = new_mob.ai_holder
new_AI.hostile = old_AI.hostile
new_AI.retaliate = old_AI.retaliate
M.loc = new_mob
M.forceMove(new_mob)
new_mob.tf_mob_holder = M
///End of mobcode.
qdel(source_material)
M.forceMove(new_mob)
//Did they put a person in it?
else if(istype(source_material,/mob/living))
var/mob/living/M = source_material
//Start of mob code shamelessly ripped from mouseray
new_mob.faction = M.faction
if(new_mob && isliving(new_mob))
for(var/obj/belly/B as anything in new_mob.vore_organs)
new_mob.vore_organs -= B
qdel(B)
new_mob.vore_organs = list()
new_mob.name = M.name
new_mob.real_name = M.real_name
for(var/lang in M.languages)
new_mob.languages |= lang
M.copy_vore_prefs_to_mob(new_mob)
new_mob.vore_selected = M.vore_selected
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(ishuman(new_mob))
var/mob/living/carbon/human/N = new_mob
N.gender = H.gender
N.identifying_gender = H.identifying_gender
else
new_mob.gender = H.identifying_gender
else
new_mob.gender = M.gender
if(ishuman(new_mob))
var/mob/living/carbon/human/N = new_mob
N.identifying_gender = M.gender
for(var/obj/belly/B as anything in M.vore_organs)
B.loc = new_mob
B.forceMove(new_mob)
B.owner = new_mob
M.vore_organs -= B
new_mob.vore_organs += B
new_mob.ckey = M.ckey
if(M.ai_holder && new_mob.ai_holder)
var/datum/ai_holder/old_AI = M.ai_holder
old_AI.set_stance(STANCE_SLEEP)
var/datum/ai_holder/new_AI = new_mob.ai_holder
new_AI.hostile = old_AI.hostile
new_AI.retaliate = old_AI.retaliate
M.loc = new_mob
M.forceMove(new_mob)
new_mob.tf_mob_holder = M
///End of mobcode.
spawn_progress_time = 0
max_spawn_time = rand(30,100)
if(!spawning_types.len || !stored_materials.len)
update_use_power(USE_POWER_IDLE)
icon_state = "borgcharger0(old)"
else if(prob(5))
src.visible_message("<span class='notice'>\icon[src][bicon(src)] [src] [pick("clicks","whizzes","whirrs","whooshes","clanks","clongs","clonks","bangs")].</span>")
last_process_time = world.time
/obj/machinery/replicator/vore/attackby(obj/item/weapon/W as obj, mob/living/user as mob)
if(!W.canremove || !user.canUnEquip(W) || W.possessed_voice || is_type_in_list(W,item_vore_blacklist)) //No armblades, no putting possessed items in it!
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine.</span>")
return
if(istype(W, /obj/item/weapon/holder/micro)) //Are you putting a micro in it?
var/obj/item/weapon/holder/micro/micro_holder = W
var/mob/living/inserted_mob = micro_holder.held_mob //Get the actual mob.
if(!inserted_mob.allow_spontaneous_tf) //Do they allow TF?
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine. ((The prefs of the micro forbid this action.))</span>")
return
if(inserted_mob.stat == DEAD) //Hey medical...
to_chat(user, "<span class='notice'>[W] is dead.</span>")
return
if(inserted_mob.tf_mob_holder)
to_chat(user, "<span class='notice'>[W] must be in their original form.</span>")
return
if(inserted_mob.client)
var/response //Let's see if they are SURE they accept the fact they will be a clothing, plushie, or something else.
response = tgui_alert(inserted_mob, "Are you -sure- you want to be put in this machine?\n(This machine will turn you into one of the various types of mobs in the game.)", "WARNING: Are you sure you want to be put in the machine and transformed?", list("No", "Certain"))
if(response != "Certain") //If they don't agree, stop.
to_chat(user, "<span class='notice'>[W] stops you from placing them in the machine.</span>")
return
else //If they /do/ agree, give them one last chance.
response = tgui_alert(inserted_mob, "This is the last warning: Are you absolutely certain you want to be transformed into a mob?", "WARNING: FINAL CHANCE!", list("No", "Certain"))
if(response != "Certain")
to_chat(user, "<span class='notice'>[W] stops you from placing them in the machine.</span>")
return
if(istype(inserted_mob, /mob/living/voice) || W.loc == src) //Sanity.
return
log_and_message_admins("[user] has just placed [inserted_mob] into a mob transformation machine.", user)
else
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine. ((The micro must be connected to the server.))</span>")
return
else if(istype(W,/obj/item/weapon/grab)) //Is someone being shoved into the machine?
var/obj/item/weapon/grab/the_grab = W
var/mob/living/inserted_mob = the_grab.affecting //Get the mob that is grabbed.
if(!inserted_mob.allow_spontaneous_tf)
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine. ((The prefs of the micro forbid this action.))</span>")
return
if(inserted_mob.stat == DEAD)
to_chat(user, "<span class='notice'>[W] is dead.</span>")
return
if(inserted_mob.tf_mob_holder)
to_chat(user, "<span class='notice'>[W] must be in their original form.</span>")
return
if(inserted_mob.client)
var/response
response = tgui_alert(inserted_mob, "Are you -sure- you want to be put in this machine?\n(This machine will turn you into one of the various types of mobs in the game.)", "WARNING: Are you sure you want to be put in the machine and transformed?", list("No", "Certain"))
if(response != "Certain")
to_chat(user, "<span class='notice'>[W] stops you from placing them in the machine.</span>")
return
else
response = tgui_alert(inserted_mob, "This is the last warning: Are you absolutely certain you want to be transformed into a mob?", "WARNING: FINAL CHANCE!", list("No", "Certain"))
if(response != "Certain")
to_chat(user, "<span class='notice'>[W] stops you from placing them in the machine.</span>")
return
if(istype(inserted_mob, /mob/living/voice) || W.loc == src)
return
log_and_message_admins("[user] has just placed [inserted_mob] into a mob transformation machine.", user)
user.drop_item() //Dropping a grab destroys it.
//Grabs require a bit of extra work.
//We want them to drop their clothing/items as well.
if(istype(inserted_mob, /mob/living/carbon/human)) //So, this WORKS. Works very well!
var/mob/living/carbon/human/inserted_human = inserted_mob
for(var/obj/item/I in inserted_mob)
if(istype(I, /obj/item/weapon/implant) || istype(I, /obj/item/device/nif))
continue
inserted_human.drop_from_inventory(I)
inserted_mob.loc = src
stored_materials.Add(inserted_mob)
src.visible_message("<b>\The [user]</b> inserts \the [inserted_mob] into \the [src].")
return
else
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine. ((The micro must be connected to the server.))</span>")
return
else if(istype(W, /obj/item/weapon/holder/mouse)) //No you can't turn your army of mice into giant rats.
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine. The machine reads 'NOT ENOUGH BIOMASS'.</span>")
return
user.drop_item() //Put the micro on the floor (or drop the item)
if(istype(W, /obj/item/weapon/holder/micro)) //I hate this but it's the only way to get their stuff to drop.
var/obj/item/weapon/holder/micro/micro_holder = W
var/mob/living/inserted_mob = micro_holder.held_mob //Get the actual mob.
if(istype(inserted_mob, /mob/living/carbon/human)) //Only humans have the drop_from_inventory proc.
var/mob/living/carbon/human/inserted_human = inserted_mob
for(var/obj/item/I in inserted_human) //Drop any remaining items! This only really seems to affect hands.
if(istype(I, /obj/item/weapon/implant) || istype(I, /obj/item/device/nif))
continue
inserted_human.drop_from_inventory(I)
//Now that we've dropped all the items they have, let's shove them back into the micro holder.
W.loc = src
stored_materials.Add(W)
src.visible_message("<b>\The [user]</b> inserts \the [W] into \the [src].")
/obj/machinery/replicator/vore/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state)
var/list/data = ..()
data["tgui_construction"] = tgui_vore_selection
return data
/obj/machinery/replicator/vore/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return TRUE
switch(action)
if("construct")
var/key = params["key"]
if(key in created_mobs)
if(LAZYLEN(stored_materials) > LAZYLEN(spawning_types))
if(LAZYLEN(spawning_types))
visible_message("<span class='notice'>\icon[src][bicon(src)] a [pick("light","dial","display","meter","pad")] on [src]'s front [pick("blinks","flashes")] [pick("red","yellow","blue","orange","purple","green","white")].</span>")
else
visible_message("<span class='notice'>\icon[src][bicon(src)] [src]'s front compartment slides shut.</span>")
spawning_types.Add(created_mobs[key])
spawn_progress_time = 0
update_use_power(USE_POWER_ACTIVE)
icon_state = "borgcharger1(old)"
else
visible_message(fail_message)
/obj/machinery/replicator/clothing/tgui_interact(mob/user, datum/tgui/ui) //This creates the menu.
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "XenoarchReplicator_voremob_vr", name)
ui.open()
//////////////////////////////
//////CLOTHING REPLICATOR/////
//////////////////////////////
/obj/machinery/replicator/clothing
name = "alien machine"
desc = "It's some kind of pod with strange wires and gadgets all over it. This one appears to have a humanoid shaped slot as an input and images of various objects on the buttons." //This hole was made for me!
icon = 'icons/obj/xenoarchaeology.dmi'
icon_state = "borgcharger0(old)"
var/quantity = 35 //This needs to be replaced with a GUI that lets you select the item you want.
var/list/created_items = list()
var/list/tgui_vore_selection = list()
var/list/viable_items = list(
/obj/item/clothing/gloves/ring,
/obj/item/clothing/gloves/evening,
/obj/item/clothing/gloves/black,
/obj/item/clothing/under/swimsuit/black,
/obj/item/clothing/under/shorts/black,
/obj/item/clothing/under/wetsuit_skimpy,
/obj/item/clothing/under/dress/maid,
/obj/item/clothing/under/fluff/latexmaid,
/obj/item/clothing/suit/oversize,
/obj/item/clothing/suit/kimono/red,
/obj/item/clothing/suit/storage/fluff/loincloth,
/obj/item/toy/plushie/lizardplushie/kobold,
/obj/item/toy/plushie/borgplushie/medihound,
/obj/item/toy/plushie/marble_fox,
/obj/item/toy/plushie/lizard,
/obj/item/toy/plushie/tuxedo_cat,
/obj/item/clothing/head/pin/flower,
/obj/item/clothing/head/wizard,
/obj/item/clothing/head/wizard/marisa,
/obj/item/clothing/head/beret,
/obj/item/clothing/head/that,
/obj/item/clothing/head/bowler,
/obj/item/clothing/shoes/hitops/red,
/obj/item/clothing/shoes/boots/jackboots,
/obj/item/clothing/shoes/boots/workboots,
/obj/item/clothing/shoes/boots/workboots/toeless,
/obj/item/clothing/shoes/flipflop,
/obj/item/clothing/shoes/boots/duty,
/obj/item/clothing/shoes/footwraps,
/obj/item/weapon/storage/smolebrickcase,
/obj/item/weapon/lipstick,
/obj/item/weapon/material/fishing_rod/modern,
/obj/item/weapon/inflatable_duck,
/obj/item/toy/syndicateballoon,
/obj/item/weapon/towel,
/obj/item/weapon/bedsheet/rainbowdouble
) // Currently: 3 gloves, 5 undersuits, 3 oversuits, 5 plushies, 5 headwear, 7 shoes, 7 misc. = 35
//Fishing hat was going to be added, but it was simply too powerful for this world.
/obj/machinery/replicator/clothing/New() //The specific thing about the VORE replicator is that it will only contain obj/items. Only things that can be picked up, used, and worn!
..() //TODO: Someone can replace the 'alien' interface with something neater sometime. It is simply out of my abilities at the current moment.
for(var/i=0, i<quantity, i++)
var/background = pick("yellow","purple","green","blue","red","orange","white")
var/list/icons = list(
"round" = "circle",
"square" = "square",
"diamond" = "gem",
"heart" = "heart",
"dog" = "dog",
"human" = "user",
)
var/icon = pick(icons)
var/list/colors = list(
"toggle" = "pink",
"switch" = "yellow",
"lever" = "red",
"button" = "black",
"pad" = "white",
"hole" = "black",
)
var/color = pick(colors)
var/button_desc = "a [background], [icon] shaped [color]"
var/generated_item = pick(viable_items)
viable_items.Remove(type)
created_items[button_desc] = generated_item
tgui_vore_selection.Add(list(list(
"key" = button_desc,
"background" = background,
"icon" = icons[icon],
"foreground" = colors[color],
)))
/obj/machinery/replicator/clothing/process()
if(spawning_types.len && powered())
spawn_progress_time += world.time - last_process_time
if(spawn_progress_time > max_spawn_time)
src.visible_message("<span class='notice'>\icon[src][bicon(src)] [src] pings!</span>")
var/obj/source_material = pop(stored_materials)
var/spawn_type = pop(spawning_types)
var/obj/item/spawned_obj = new spawn_type(src.loc)
var/obj/item/original_name = spawned_obj.name //Get the item's name before it's prefixed. Used for micro code.
if(source_material)
if(length(source_material.name) < MAX_MESSAGE_LEN)
spawned_obj.name = "[source_material] " + spawned_obj.name
if(length(source_material.desc) < MAX_MESSAGE_LEN * 2)
if(spawned_obj.desc)
spawned_obj.desc += " It is made of [source_material]."
else
spawned_obj.desc = "It is made of [source_material]."
if(istype(source_material,/obj/item/weapon/holder/micro))
var/obj/item/weapon/holder/micro/micro_holder = source_material //Tells the machine that a micro is the material being used
var/mob/mob_to_be_changed = micro_holder.held_mob //Get the mob.
var/mob/living/M = mob_to_be_changed
M.release_vore_contents(TRUE, TRUE) //Release their stomach contents. Don't spam the chat, either.
spawned_obj.inhabit_item(M, original_name, M) //Take the spawned mob and call the TF proc on it.
var/mob/living/possessed_voice = spawned_obj.possessed_voice //Get the possessed voice.
qdel(source_material) //Deletes the micro holder, we don't need it anymore.
spawned_obj.trash_eatable = M.devourable //Can this item be eaten? Let's decide based on the person's prefs!
spawned_obj.unacidable = !M.digestable //Can this item be digested?
M.forceMove(possessed_voice) //Places them in the 'voice' for later recovery! Essentially: The item contains a 'possessed voice' mob, which contains their original mob.
else if(istype(source_material,/mob/living))//Did they shove a person in there normally?
var/mob/living/M = source_material //If so, this cuts down the work we have to do!
M.release_vore_contents(TRUE, TRUE) //Release their stomach contents. Don't spam the chat, either.
spawned_obj.inhabit_item(M, original_name, M)
var/mob/living/possessed_voice = spawned_obj.possessed_voice
spawned_obj.trash_eatable = M.devourable
spawned_obj.unacidable = !M.digestable
M.forceMove(possessed_voice)
spawn_progress_time = 0
max_spawn_time = rand(30,100)
if(!spawning_types.len || !stored_materials.len)
update_use_power(USE_POWER_IDLE)
icon_state = "borgcharger0(old)"
else if(prob(5))
src.visible_message("<span class='notice'>\icon[src][bicon(src)] [src] [pick("clicks","whizzes","whirrs","whooshes","clanks","clongs","clonks","bangs")].</span>")
last_process_time = world.time
/obj/machinery/replicator/clothing/attackby(obj/item/weapon/W as obj, mob/living/user as mob)
if(!W.canremove || !user.canUnEquip(W) || W.possessed_voice || is_type_in_list(W,item_vore_blacklist)) //No armblades, no putting already possessed items in it!
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine.</span>")
return
if(istype(W, /obj/item/weapon/holder/micro) || istype(W, /obj/item/weapon/holder/mouse)) //Are you putting a micro/mouse in it?
var/obj/item/weapon/holder/micro/micro_holder = W
var/mob/living/inserted_mob = micro_holder.held_mob //Get the actual mob.
if(!inserted_mob.allow_spontaneous_tf) //Do they allow TF?
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine. ((The prefs of the micro forbid this action.))</span>")
return
if(inserted_mob.stat == DEAD) //Hey medical...
to_chat(user, "<span class='notice'>[W] is dead.</span>")
return
if(inserted_mob.tf_mob_holder) //No recursion!!!
to_chat(user, "<span class='notice'>[W] must be in their original form.</span>")
return
if(inserted_mob.client)
var/response //Let's see if they are SURE they accept the fact they will be a clothing, plushie, or something else.
response = tgui_alert(inserted_mob, "Are you -sure- you want to be put in this machine?\n(This machine can turn you into various clothing, footwear, plushies, and other miscellaneous objects. This means that more likely than not, you will be used as whatever object is used. Make certain your preferences align with this possibility.)", "WARNING: Are you sure you want to be put in the machine and transformed?", list("No", "Certain"))
if(response != "Certain") //If they don't agree, stop.
to_chat(user, "<span class='notice'>[W] stops you from placing them in the machine.</span>")
return
else //If they /do/ agree, give them one last chance.
response = tgui_alert(inserted_mob, "This is the last warning: Are you absolutely certain you want to be transformed into an object and have the possibility of being used as such?", "WARNING: FINAL CHANCE!", list("No", "I accept the possibilities"))
if(response != "I accept the possibilities")
to_chat(user, "<span class='notice'>[W] stops you from placing them in the machine.</span>")
return
if(istype(inserted_mob, /mob/living/voice) || W.loc == src) //This is a sanity check to keep them from entering it multiple times.
return
log_and_message_admins("[user] has just placed [inserted_mob] into an item transformation machine.", user)
else
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine. ((The micro must be connected to the server.))</span>")
return
else if(istype(W,/obj/item/weapon/grab)) //Is someone being shoved into the machine?
var/obj/item/weapon/grab/the_grab = W
var/mob/living/inserted_mob = the_grab.affecting //Get the mob that is grabbed.
if(!inserted_mob.allow_spontaneous_tf)
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine. ((The prefs of the micro forbid this action.))</span>")
return
if(inserted_mob.stat == DEAD)
to_chat(user, "<span class='notice'>[W] is dead.</span>")
return
if(inserted_mob.tf_mob_holder)
to_chat(user, "<span class='notice'>[W] must be in their original form.</span>")
return
if(inserted_mob.client)
var/response
response = tgui_alert(inserted_mob, "Are you -sure- you want to be put in this machine?\n(This machine can turn you into various clothing, footwear, plushies, and other miscellaneous objects. This means that more likely than not, you will be used as whatever object is used. Make certain your preferences align with this possibility.)", "WARNING: Are you sure you want to be put in the machine and transformed?", list("No", "Certain"))
if(response != "Certain")
to_chat(user, "<span class='notice'>[W] stops you from placing them in the machine.</span>")
return
else
response = tgui_alert(inserted_mob, "This is the last warning: Are you absolutely certain you want to be transformed into an object and have the possibility of being used as such?", "WARNING: FINAL CHANCE!", list("No", "I accept the possibilities"))
if(response != "I accept the possibilities")
to_chat(user, "<span class='notice'>[W] stops you from placing them in the machine.</span>")
return
if(istype(inserted_mob, /mob/living/voice) || W.loc == src)
return
log_and_message_admins("[user] has just placed [inserted_mob] into an item transformation machine.", user)
user.drop_item() //Dropping a grab destroys it.
//Grabs require a bit of extra work.
//We want them to drop their clothing/items as well.
if(istype(inserted_mob, /mob/living/carbon/human)) //So, this WORKS. Works very well!
var/mob/living/carbon/human/inserted_human = inserted_mob
for(var/obj/item/I in inserted_mob)
if(istype(I, /obj/item/weapon/implant) || istype(I, /obj/item/device/nif))
continue
inserted_human.drop_from_inventory(I)
inserted_mob.loc = src
stored_materials.Add(inserted_mob)
src.visible_message("<b>\The [user]</b> inserts \the [inserted_mob] into \the [src].")
return
else
to_chat(user, "<span class='notice'>You cannot put \the [W] into the machine. ((They must be connected to the server.))</span>")
return
user.drop_item() //Put the micro on the floor (or drop the item)
if(istype(W, /obj/item/weapon/holder/micro)) //I hate this but it's the only way to get their stuff to drop.
var/obj/item/weapon/holder/micro/micro_holder = W
var/mob/living/inserted_mob = micro_holder.held_mob //Get the actual mob.
if(istype(inserted_mob, /mob/living/carbon/human)) //Only humans have the drop_from_inventory proc.
var/mob/living/carbon/human/inserted_human = inserted_mob
for(var/obj/item/I in inserted_human) //Drop any remaining items! This only really seems to affect hands.
if(istype(I, /obj/item/weapon/implant) || istype(I, /obj/item/device/nif))
continue
inserted_human.drop_from_inventory(I)
//Now that we've dropped all the items they have, let's shove them back into the micro holder.
W.loc = src
stored_materials.Add(W)
src.visible_message("<b>\The [user]</b> inserts \the [W] into \the [src].")
/obj/machinery/replicator/clothing/tgui_interact(mob/user, datum/tgui/ui) //This creates the menu.
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "XenoarchReplicator_clothing_vr", name) //This is required to prevent UI contamination.
ui.open()
/obj/machinery/replicator/clothing/tgui_data(mob/user, datum/tgui/ui, datum/tgui_state/state) //Gives data to the menu.
var/list/data = ..()
data["tgui_construction"] = tgui_vore_selection
return data
/obj/machinery/replicator/clothing/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return TRUE
switch(action)
if("construct")
var/key = params["key"]
if(key in created_items)
if(LAZYLEN(stored_materials) > LAZYLEN(spawning_types))
if(LAZYLEN(spawning_types))
visible_message("<span class='notice'>\icon[src][bicon(src)] a [pick("light","dial","display","meter","pad")] on [src]'s front [pick("blinks","flashes")] [pick("red","yellow","blue","orange","purple","green","white")].</span>")
else
visible_message("<span class='notice'>\icon[src][bicon(src)] [src]'s front compartment slides shut.</span>")
spawning_types.Add(created_items[key])
spawn_progress_time = 0
update_use_power(USE_POWER_ACTIVE)
icon_state = "borgcharger1(old)"
else
visible_message(fail_message)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

+2 -2
View File
@@ -48,6 +48,7 @@
"aV" = (/obj/machinery/light/floortube{dir = 8},/obj/structure/casino_table/roulette_chart,/turf/simulated/floor/carpet/brown,/area/awaymission/lucky7/casinofloor)
"aW" = (/obj/structure/cable/green,/obj/machinery/power/fractal_reactor/fluff/smes,/turf/simulated/floor/plating,/area/awaymission/lucky7/maint2)
"aX" = (/obj/effect/floor_decal/borderfloor{dir = 10},/obj/effect/floor_decal/corner/yellow/border{dir = 10},/obj/machinery/telecomms/allinone/casino,/turf/simulated/floor/tiled,/area/awaymission/lucky7/workshop)
"aY" = (/obj/machinery/firealarm{dir = 4; pixel_x = 24},/obj/item/weapon/storage/box/roulette_balls_normal,/obj/item/weapon/storage/box/roulette_balls_fancy,/obj/item/weapon/storage/box/roulette_balls_cheat,/obj/structure/table/rack/shelf,/turf/simulated/floor/tiled/dark,/area/awaymission/lucky7/breakroom)
"ba" = (/obj/structure/table/borosilicate,/turf/simulated/floor/wood,/area/awaymission/lucky7/lounge)
"bc" = (/obj/structure/cable/green{icon_state = "1-4"},/turf/simulated/floor/tiled/dark,/area/awaymission/lucky7/gateway)
"be" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/obj/effect/floor_decal/industrial/warning/cee{dir = 8},/turf/simulated/floor/tiled/dark,/area/awaymission/lucky7/dock1)
@@ -705,7 +706,6 @@
"Gz" = (/obj/structure/disposalpipe/segment,/obj/structure/cable/green{d1 = 1; d2 = 2; icon_state = "1-2"},/turf/simulated/floor/tiled/dark,/area/awaymission/lucky7/breakroom)
"GA" = (/obj/effect/floor_decal/techfloor/orange{dir = 4},/obj/effect/floor_decal/techfloor/hole/right{dir = 4},/turf/simulated/floor/tiled/techfloor,/area/awaymission/lucky7/gateway)
"GE" = (/obj/machinery/atmospherics/pipe/simple/hidden{dir = 4},/obj/effect/floor_decal/industrial/warning/cee{dir = 8},/turf/simulated/floor/tiled/dark,/area/awaymission/lucky7/dock2)
"GH" = (/obj/machinery/firealarm{dir = 4; pixel_x = 24},/turf/simulated/floor/tiled/dark,/area/awaymission/lucky7/breakroom)
"GJ" = (/turf/simulated/wall,/area/awaymission/lucky7/privategameroom/two)
"GO" = (/obj/structure/disposalpipe/segment{dir = 4; icon_state = "pipe-c"},/obj/structure/cable/green{d1 = 2; d2 = 4; icon_state = "2-4"},/turf/simulated/floor/carpet/brown,/area/awaymission/lucky7/hotelhall)
"GP" = (/obj/structure/table/glass,/obj/structure/window/reinforced{dir = 4},/obj/item/weapon/storage/firstaid/regular{pixel_x = 5; pixel_y = 8},/obj/effect/floor_decal/borderfloorwhite,/obj/effect/floor_decal/corner/paleblue/border,/turf/simulated/floor/tiled/white,/area/awaymission/lucky7/medical)
@@ -1206,7 +1206,7 @@ rmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmidrmrmrmMwrf
rmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmidrmrmrmDiDiDiDiDiDiDiDiDiDinAWEYkJLsTsTsTsTsTsTsTsTsTsTsTsTsTsTsTUWrAUWUWUWUWUWqFNlNlNlqFqFqFqFqFkxkxTuypypnhnhbpMdCGAGscsqGJTZnvWmxtwTfHZPQttYlLYYfHrmrmidrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrm
rmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmidrmrmrmDisHsSsZsZtdtvtHtMDiWRWEYkupsTeruyuzuIrprMsThhhhjPFNuOuvhhhhvavksTvNvTsTvUwbwewkwtqFImbXqFwGlwTuypypLEVwbpwLscQascxdGJNVxtqMxtrBfHLhlLtZlLwlfHrmrmvOrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrm
rmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmvOvOvOvODixqyoyHCCCCCCzazgSXzpWEYkobsTGSzqzEaWzRzYAxQKQKQKQKQKAFAFQKAXAFAxQKBeBmBEBHBTBVCiCnruCoqFmXmXTuypypvyvybprUscscscsqGJqYxtxtxtwTfHpPlLlLlLYYfHrmrmidrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrm
rmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmididvOididrmvOrmDiCMCUCWCZCCCCDHYnEtXSEBYkCDsTcmECESEWFKFTsTFUFYhhFZhhFNjPGiGiGisThhWVsTSrGzKLSrGHqFGRHaqFypypTuypypypypbpRMHbHfHbRMGJfNNIoHNIfNfHFrHAHBHAFrfHvOidHFrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrm
rmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmididvOididrmvOrmDiCMCUCWCZCCCCDHYnEtXSEBYkCDsTcmECESEWFKFTsTFUFYhhFZhhFNjPGiGiGisThhWVsTSrGzKLSraYqFGRHaqFypypTuypypypypbpRMHbHfHbRMGJfNNIoHNIfNfHFrHAHBHAFrfHvOidHFrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrm
rmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmvOrmrmrmrmvOrmDixqCCCCCCCCHJCCHMSXHWJzXSJPJUKiKnbDKwKxKIkDkDkDKNKNKNKNKNKShhKYsThhGrsTqFLjqFqFqFqFqFqFqFmKmKOwmVmVmKmKbpbpbpbpbpbpGJGJGJGJGJGJfHfHfHfHfHfHfHrmrmidrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrm
rmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmidrmrmrmvOrmrmrmrmvOrmDiaXLrLxLBLFMaMmMsDiMEMGYkMJsTMVMXMYNdNyNFkDQCNRNTOtOBOOKNPcOWPnsTjPLiKfPqPsPTPVQmQoGsQGKfmVQMOwmVmVkVmVQRmVQVRcRfmVRkmVkVRTRVmVmVmVmVkVmVmVmKrmrmvOrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrm
rmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmidrmrmKlKlNYNYNYKlKlKlKlKlKlKlKlKlKlKlYXYXsoSEWBsoYXYXYXYXSRTaTfkDyOyOThDhDhDhKNKNKNKNKNhhLiKfTyUbUdUfUgUgUgUgVamVVkahmVmVmVmVmVmVmVmVmVmVmVmVmVmVmVmVmVmVmVmVmVVVrjrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrmrm
@@ -13,7 +13,7 @@
"m" = (/obj/structure/table/steel,/obj/item/weapon/paper{desc = "This is some bullshit. First chance we got to knick something that looks half decent turns out to be mostly junk. And now we're getting calls that the other stash we've got has got a spider problem. Fuck this, Between the shitty weather, The pissed of bugs, And now apparently some NT goon running around in the area there's hardly enough reason to stick around. I'm telling Carl I'm out tommorow."; name = "Note"},/turf/simulated/floor/outdoors/dirt{outdoors = 0},/area/submap/Thiefc)
"n" = (/obj/vehicle/train/trolley,/turf/simulated/floor/outdoors/dirt{outdoors = 0},/area/submap/Thiefc)
"o" = (/obj/structure/closet/crate,/obj/item/weapon/cell/device/weapon,/obj/item/weapon/cell/device/weapon,/turf/simulated/floor/outdoors/dirt{outdoors = 0},/area/submap/Thiefc)
"p" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/ammo_box/b12g,/obj/item/weapon/storage/box/practiceshells,/obj/random/projectile/scrapped_gun,/turf/simulated/floor/outdoors/dirt{outdoors = 0},/area/submap/Thiefc)
"p" = (/obj/structure/closet/crate,/obj/item/ammo_magazine/ammo_box/b12g,/obj/item/ammo_magazine/ammo_box/b12g/practice,/obj/random/projectile/scrapped_gun,/turf/simulated/floor/outdoors/dirt{outdoors = 0},/area/submap/Thiefc)
(1,1,1) = {"
aaaaaaaaaaaaaaaaaaaaaaaaa
@@ -119,7 +119,7 @@
/area/submap/Thiefc)
"p" = (
/obj/structure/closet/crate,
/obj/item/weapon/storage/box/practiceshells,
/obj/item/ammo_magazine/ammo_box/b12g/practice,
/turf/simulated/floor/outdoors/dirt/virgo3b{
outdoors = 0
},
+1 -1
View File
@@ -1895,7 +1895,7 @@
/obj/machinery/vending/cigarette{
name = "hacked cigarette machine";
prices = list();
products = list(/obj/item/weapon/storage/fancy/cigarettes=10,/obj/item/weapon/storage/box/matches=10,/obj/item/weapon/flame/lighter/zippo=4,/obj/item/clothing/mask/smokable/cigarette/cigar/havana=2)
products = list(/obj/item/weapon/storage/fancy/cigarettes = 10, /obj/item/weapon/storage/box/matches = 10, /obj/item/weapon/flame/lighter/zippo = 4, /obj/item/clothing/mask/smokable/cigarette/cigar/havana = 2)
},
/turf/simulated/floor/wood,
/area/centcom/specops)
@@ -499,6 +499,7 @@ const VoreSelectedBellyOptions = (props, context) => {
contaminate_flavor,
contaminate_color,
egg_type,
selective_preference,
save_digest_mode,
} = belly;
@@ -610,6 +611,12 @@ const VoreSelectedBellyOptions = (props, context) => {
content={capitalize(egg_type)}
/>
</LabeledList.Item>
<LabeledList.Item label="Selective Mode Preference">
<Button
onClick={() => act('set_attribute', { attribute: 'b_selective_mode_pref_toggle' })}
content={capitalize(selective_preference)}
/>
</LabeledList.Item>
</LabeledList>
</Flex.Item>
</Flex>
@@ -1257,6 +1264,9 @@ const VoreUserPreferences = (props, context) => {
<Flex.Item basis="32%">
<VoreUserPreferenceItem spec={preferences.spontaneous_tf} />
</Flex.Item>
<Flex.Item basis="32%">
<Button fluid content="Slective Mode Preference" onClick={() => act('switch_selective_mode_pref')} />
</Flex.Item>
</Flex>
<Section title="Aesthetic Preferences">
<Flex spacing={1} wrap="wrap" justify="center">
@@ -0,0 +1,26 @@
import { useBackend } from '../backend';
import { Button } from '../components';
import { Window } from '../layouts';
export const XenoarchReplicator_clothing_vr = (props, context) => {
const { act, data } = useBackend(context);
const { tgui_construction } = data;
return (
<Window theme="abductor" width={400} height={400} resizable>
<Window.Content scrollable>
{tgui_construction.map((button, i) => (
<Button
key={button.key}
color={button.background}
icon={button.icon}
iconColor={button.foreground}
fontSize={4}
onClick={() => act('construct', { key: button.key })}
/>
))}
</Window.Content>
</Window>
);
};
@@ -0,0 +1,26 @@
import { useBackend } from '../backend';
import { Button } from '../components';
import { Window } from '../layouts';
export const XenoarchReplicator_voremob_vr = (props, context) => {
const { act, data } = useBackend(context);
const { tgui_construction } = data;
return (
<Window theme="abductor" width={400} height={400} resizable>
<Window.Content scrollable>
{tgui_construction.map((button, i) => (
<Button
key={button.key}
color={button.background}
icon={button.icon}
iconColor={button.foreground}
fontSize={4}
onClick={() => act('construct', { key: button.key })}
/>
))}
</Window.Content>
</Window>
);
};
File diff suppressed because one or more lines are too long
+3 -1
View File
@@ -1079,6 +1079,7 @@
#include "code\game\objects\explosion.dm"
#include "code\game\objects\explosion_recursive.dm"
#include "code\game\objects\items.dm"
#include "code\game\objects\items_vr.dm"
#include "code\game\objects\mob_spawner_vr.dm"
#include "code\game\objects\objs.dm"
#include "code\game\objects\structures.dm"
@@ -4035,6 +4036,7 @@
#include "code\modules\xenoarcheaology\artifacts\crystal.dm"
#include "code\modules\xenoarcheaology\artifacts\gigadrill.dm"
#include "code\modules\xenoarcheaology\artifacts\replicator.dm"
#include "code\modules\xenoarcheaology\artifacts\replicator_vr.dm"
#include "code\modules\xenoarcheaology\artifacts\predefined\_predefined.dm"
#include "code\modules\xenoarcheaology\artifacts\predefined\hungry_statue.dm"
#include "code\modules\xenoarcheaology\effects\animate_anomaly.dm"
@@ -4146,6 +4148,7 @@
#include "maps\southern_cross\loadout\loadout_suit.dm"
#include "maps\southern_cross\loadout\loadout_uniform.dm"
#include "maps\southern_cross\loadout\loadout_vr.dm"
#include "maps\stellar_delight\stellar_delight.dm"
#include "maps\submaps\_helpers.dm"
#include "maps\submaps\_readme.dm"
#include "maps\submaps\engine_submaps\engine.dm"
@@ -4155,6 +4158,5 @@
#include "maps\submaps\space_submaps\debrisfield\debrisfield.dm"
#include "maps\submaps\surface_submaps\wilderness\wilderness.dm"
#include "maps\submaps\surface_submaps\wilderness\wilderness_areas.dm"
#include "maps\tether\tether.dm"
#include "maps\~map_system\maps.dm"
// END_INCLUDE