Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 79 additions & 79 deletions code/modules/spells/spell_types/disguise.dm
Original file line number Diff line number Diff line change
@@ -1,79 +1,79 @@
/obj/effect/proc_holder/spell/disguise
name = "Mimicry"
desc = "Why fight your foes when you can simply outwit them? Disguises the caster as a random crewmember. The body-covering shell keeps your form as is, and protects you from body-altering effects."
invocation = "CONJR DIS GUISE"
invocation_type = "whisper"
school = "transmutation"
charge_max = 30 SECONDS
level_max = 2
cooldown_min = 25 SECONDS
clothes_req = FALSE
var/is_disguised = FALSE //Tells us if a disguise is currently up.
var/wasbeast = FALSE //We need this to make sure on can_cast, if they're found to be human and have this flag we can manually activate the uncloaking proc.
action_icon = 'icons/mob/actions/actions_spells.dmi'
action_icon_state = "disguise"
/obj/effect/proc_holder/spell/disguise/can_cast(mob/user = usr)
if(!ishuman(user))
//We need to undo the cloak after non-humanoid disguises because when the wizard becomes a non human during the spell, it will mess up their sprite. But since they are non human, we can't actually undo the spell. This leaves our recloaking bugged as hell, and breaks a lot of stuff.
return FALSE
if(ishuman(user) && (wasbeast == TRUE))
addtimer(CALLBACK(src, .proc/undocloak, user), 2)
return TRUE
/obj/effect/proc_holder/spell/disguise/choose_targets(mob/user = usr)
perform(user=user)
/obj/effect/proc_holder/spell/disguise/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/C = user //Turns the user into a carbon, we'll need this later.
var/list/potentials = list()
for(var/mob/living/carbon/human/H in GLOB.carbon_list) //Checks all the humanoid mobs.
if(H.job) //Checks if they're crew.
potentials += H //Adds the crewmember to the list.
if(potentials.len == 0)
to_chat(C, span_notice("There's nobody to disguise as!"))
revert_cast(user)
return
var/mob/living/carbon/human/target = pick(potentials) //Picks a random subject from the viable targets.
cloak(C, target, user)
/obj/effect/proc_holder/spell/disguise/proc/cloak(var/mob/living/carbon/human/C, var/mob/living/carbon/human/target, mob/user) //Code shortcut to enable the disguise.
if(is_disguised)
message_admins("[ADMIN_LOOKUPFLW(C)] just tried to disguise while disguised! That shouldn't happen!")
return
new /obj/effect/temp_visual/dir_setting/ninja/cloak(get_turf(C), C.dir) //Disguise animation.
C.name_override = target.name
C.SetSpecialVoice(target.name)
C.icon = target.icon
C.icon_state = target.icon_state
C.cut_overlays()
C.add_overlay(target.get_overlays_copy(list(HANDS_LAYER)))
C.update_inv_hands()
log_game("[C.name] has disguised as [target.name]!")
is_disguised = TRUE
addtimer(CALLBACK(src, .proc/undocloak, C), (15 SECONDS + (spell_level * 3 SECONDS)))
/obj/effect/proc_holder/spell/disguise/proc/undocloak(var/mob/living/carbon/human/C) //Code shortcut to disable the disguise.
if((ishuman(C) && (C.mind)) || wasbeast == TRUE) //Shapeshift spell takes out your mind, buckles you to a body, and then puts your mind in a summoned animal. We need this bullshit to both check that this is not happening, and then override it when we have to fix the bullshit.
new /obj/effect/temp_visual/dir_setting/ninja(get_turf(C), C.dir) //Makes an animation for disguising.
C.name_override = null
C.UnsetSpecialVoice()
C.cut_overlays()
C.regenerate_icons()
is_disguised = FALSE
wasbeast = FALSE
return
else
wasbeast = TRUE //Unfortunately we need this to counter shapeshifting bullshit, sets up the caster to immediatly revert when becoming human.
/datum/spellbook_entry/disguise //Spellbook entry, needed for the spell to be purchasable in game.
name = "Mimicry"
spell_type = /obj/effect/proc_holder/spell/disguise
category = "Assistance"
cost = 1
/obj/effect/proc_holder/spell/disguise
name = "Mimicry"
desc = "Why fight your foes when you can simply outwit them? Disguises the caster as a random crewmember. The body-covering shell keeps your form as is, and protects you from body-altering effects."
invocation = "CONJR DIS GUISE"
invocation_type = "whisper"
school = "transmutation"
charge_max = 30 SECONDS
level_max = 2
cooldown_min = 25 SECONDS
clothes_req = FALSE
var/is_disguised = FALSE //Tells us if a disguise is currently up.
var/wasbeast = FALSE //We need this to make sure on can_cast, if they're found to be human and have this flag we can manually activate the uncloaking proc.
action_icon = 'icons/mob/actions/actions_spells.dmi'
action_icon_state = "disguise"

/obj/effect/proc_holder/spell/disguise/can_cast(mob/user = usr)
if(!ishuman(user))
//We need to undo the cloak after non-humanoid disguises because when the wizard becomes a non human during the spell, it will mess up their sprite. But since they are non human, we can't actually undo the spell. This leaves our recloaking bugged as hell, and breaks a lot of stuff.
return FALSE
if(ishuman(user) && (wasbeast == TRUE))
addtimer(CALLBACK(src, .proc/undocloak, user), 2)
return TRUE

/obj/effect/proc_holder/spell/disguise/choose_targets(mob/user = usr)
perform(user=user)

/obj/effect/proc_holder/spell/disguise/cast(list/targets, mob/user = usr)
var/mob/living/carbon/human/C = user //Turns the user into a carbon, we'll need this later.
var/list/potentials = list()
for(var/mob/living/carbon/human/H in GLOB.carbon_list) //Checks all the humanoid mobs.
if(H.job) //Checks if they're crew.
potentials += H //Adds the crewmember to the list.
if(potentials.len == 0)
to_chat(C, span_notice("There's nobody to disguise as!"))
revert_cast(user)
return
var/mob/living/carbon/human/target = pick(potentials) //Picks a random subject from the viable targets.
cloak(C, target, user)



/obj/effect/proc_holder/spell/disguise/proc/cloak(var/mob/living/carbon/human/C, var/mob/living/carbon/human/target, mob/user) //Code shortcut to enable the disguise.
if(is_disguised)
message_admins("[ADMIN_LOOKUPFLW(C)] just tried to disguise while disguised! That shouldn't happen!")
return
new /obj/effect/temp_visual/dir_setting/ninja/cloak(get_turf(C), C.dir) //Disguise animation.
C.name_override = target.name
C.SetSpecialVoice(target.name)
C.icon = target.icon
C.icon_state = target.icon_state
C.cut_overlays()
C.add_overlay(target.get_overlays_copy(list(HANDS_LAYER)))
C.update_inv_hands()
log_game("[C.name] has disguised as [target.name]!")
is_disguised = TRUE
addtimer(CALLBACK(src, .proc/undocloak, C), (15 SECONDS + (spell_level * 3 SECONDS)))

/obj/effect/proc_holder/spell/disguise/proc/undocloak(var/mob/living/carbon/human/C) //Code shortcut to disable the disguise.
if((ishuman(C) && (C.mind)) || wasbeast == TRUE) //Shapeshift spell takes out your mind, buckles you to a body, and then puts your mind in a summoned animal. We need this bullshit to both check that this is not happening, and then override it when we have to fix the bullshit.
new /obj/effect/temp_visual/dir_setting/ninja(get_turf(C), C.dir) //Makes an animation for disguising.
C.name_override = null
C.UnsetSpecialVoice()
C.cut_overlays()
C.regenerate_icons()
is_disguised = FALSE
wasbeast = FALSE
return
else
wasbeast = TRUE //Unfortunately we need this to counter shapeshifting bullshit, sets up the caster to immediatly revert when becoming human.

/datum/spellbook_entry/disguise //Spellbook entry, needed for the spell to be purchasable in game.
name = "Mimicry"
spell_type = /obj/effect/proc_holder/spell/disguise
category = "Assistance"
cost = 1




87 changes: 50 additions & 37 deletions tgui/packages/tgui/interfaces/Autolathe.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import { Fragment } from 'inferno';
import { createSearch } from 'common/string';
import { flow } from 'common/fp';
import { filter, sortBy } from 'common/collections';
import { useBackend, useLocalState } from '../backend';
import { Box, Button, Flex, Input, Grid, NumberInput, NoticeBox, Section } from '../components';
import { Window } from '../layouts';
import { useDebug } from '../debug';

export const searchDesigns = (designs, searchText = '') => {
const testSearch = createSearch(searchText, design => design.name);
return flow([
// Optional search term
searchText && filter(testSearch),
// Slightly expensive, but way better than sorting in BYOND
sortBy(design => design.name),
])(designs);
};

const MaxMultiplier = (materials, design) => {
let maxmulti = [];
Expand All @@ -19,11 +33,6 @@ const MaxMultiplier = (materials, design) => {
};

export const Autolathe = (props, context) => {

const [
searchterms,
setSearchText,
] = useLocalState(context, 'searchterms', '');
const [
sheetnumberglass,
setGlassSheetCount,
Expand All @@ -38,6 +47,11 @@ export const Autolathe = (props, context) => {
] = useLocalState(context, 'setcategory', 'Tools');

const { act, data } = useBackend(context);
const [
searchText,
setSearchText,
] = useLocalState(context, 'searchText', '');
const searchdesign = searchDesigns(data.designs, searchText);
return (
<Window width={1116} height={703} resizable>
<Window.Content scrollable>
Expand All @@ -47,7 +61,7 @@ export const Autolathe = (props, context) => {
<Box inline ml={80}>
Search:
<Input
value={searchterms}
value={searchText}
width="250px"
onInput={(e, value) => setSearchText(value)}
ml={2}
Expand Down Expand Up @@ -187,15 +201,15 @@ export const Autolathe = (props, context) => {
fluid
mr={2}
selected={
(searchterms.length > 1 ? (
(searchText.length > 1 ? (
(categoryName === 'Search' ? 1 : 0)
):(
setcategory === categoryName
))
}
color="transparent"
content={categoryName}
onClick={(!searchterms ? (
onClick={(!searchText ? (
() => setCategory(categoryName)
):(
() => setSearchText("")))}
Expand All @@ -204,57 +218,56 @@ export const Autolathe = (props, context) => {
</Section>
</Flex.Item>
<Flex.Item>
{searchterms.length > 1 ? (
{searchText.length > 2 ? (
<Section fluid title="Search Results" width={50}>
<div>
<Flex.Item>
{data.designs.filter(design => {
const searchTerm = searchterms.toLowerCase();
const searchableString = String(design.name).toLowerCase();
return (searchterms.length < 2 ? (
null
) : (
(searchableString.match(new RegExp(searchterms, "i")))
));
}).map(design => (
{searchdesign.map(design => (
<div key={data.designs}>
<Grid>
<Grid.Column size={2.5}>
<Button
inline
key={design.name}
content={design.name}
disabled={data.disabled}
disabled={
(data.stored_materials.iron < design.materials.iron)
|| (data.stored_materials.glass < design.materials.glass)
|| data.disabled
}
title={design.name}
mr={1}
icon="print"
onClick={() => act('make', {
item_id: design.id,
multiplier: 1,
})} />
{design.max_multiplier.map(max => (
<Button
key={max}
disabled={data.disabled}
content={max + "x"}
onClick={() => act('make', {
item_id: design.id,
multiplier: max,
})}
/>
))}

{MaxMultiplier(data.stored_materials, design)
.map(max => (
<Button
inline
key={max}
disabled={data.disabled}
content={max + "x"}
onClick={() => act('make', {
item_id: design.id,
multiplier: max,
})}
/>
))}
</Grid.Column>
<Grid.Column size={1}>
{design.materials.iron === 0 ? (
''
{!design.materials.glass ? (
""
):(
<Box ml={0} mr={0} inline
color={(
data.stored_materials.iron > design.materials.iron ? 'white' : 'bad'
data.stored_materials.glass >= design.materials.glass ? 'white' : 'bad'
)}>
{data.stored_materials.iron > design.materials.iron ? (
<div>Metal: {design.materials.iron}</div>
{data.stored_materials.glass >= design.materials.glass ? (
<div>Glass: {design.materials.glass} cm³</div>
) : (
<b>Metal: {design.materials.iron}</b>
<b>Glass: {design.materials.glass} cm³</b>
)}
</Box>

Expand Down