diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 1a40253df7..5edfdc2f80 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -58,13 +58,13 @@ #define CAN_CUM_INTO (1<<21) //DEfault genital flags, for preferences -#define DEF_BUTT_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESIZE | GENITAL_CAN_HAVE -#define DEF_VAG_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESHAPE | GENITAL_CAN_HAVE -#define DEF_WOMB_FLAGS GENITAL_CAN_HAVE -#define DEF_BALLS_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESHAPE | GENITAL_CAN_HAVE | GENITAL_CAN_RESIZE -#define DEF_PENIS_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESHAPE | GENITAL_CAN_RESIZE | GENITAL_CAN_HAVE -#define DEF_BREASTS_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESHAPE | GENITAL_CAN_RESIZE | GENITAL_CAN_HAVE -#define DEF_BELLY_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESHAPE | GENITAL_CAN_RESIZE | GENITAL_CAN_HAVE +#define DEF_WOMB_FLAGS GENITAL_CAN_HAVE | GENITAL_INTERNAL | GENITAL_FLUID_PRODUCTION +#define DEF_VAG_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESHAPE | GENITAL_CAN_HAVE | CAN_MASTURBATE_WITH | GENITAL_CAN_AROUSE +#define DEF_BALLS_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESHAPE | GENITAL_CAN_RESIZE | GENITAL_CAN_HAVE | CAN_MASTURBATE_WITH | MASTURBATE_LINKED_ORGAN | GENITAL_FLUID_PRODUCTION | UPDATE_OWNER_APPEARANCE +#define DEF_PENIS_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESHAPE | GENITAL_CAN_RESIZE | GENITAL_CAN_HAVE | CAN_MASTURBATE_WITH | CAN_CLIMAX_WITH | GENITAL_CAN_AROUSE | UPDATE_OWNER_APPEARANCE | GENITAL_CAN_TAUR +#define DEF_BREASTS_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESHAPE | GENITAL_CAN_RESIZE | GENITAL_CAN_HAVE | CAN_MASTURBATE_WITH | CAN_CLIMAX_WITH | GENITAL_FLUID_PRODUCTION | GENITAL_CAN_AROUSE | UPDATE_OWNER_APPEARANCE +#define DEF_BUTT_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESIZE | GENITAL_CAN_HAVE | UPDATE_OWNER_APPEARANCE +#define DEF_BELLY_FLAGS GENITAL_CAN_RECOLOR | GENITAL_CAN_RESHAPE | GENITAL_CAN_RESIZE | GENITAL_CAN_HAVE | UPDATE_OWNER_APPEARANCE //NEW genital flags #define GENITAL_NO_OVERRIDE (1<<0) // Not actually used, passed to the visibility toggle to unset the lower two @@ -97,6 +97,8 @@ #define DEF_VAGINA_SHAPE "Human" #define COCK_SIZE_DEF 6 +#define COCK_SIZE_MIN 1 +#define COCK_SIZE_MAX 100 #define COCK_DIAMETER_RATIO_MAX 0.42 #define COCK_DIAMETER_RATIO_DEF 0.25 @@ -177,7 +179,7 @@ #define HYPNO (1<<7) #define NEVER_HYPNO (1<<8) #define NO_APHRO (1<<9) -#define NO_ASS_SLAP (1<<10) +#define NO_BUTT_SLAP (1<<10) #define BIMBOFICATION (1<<11) #define NO_AUTO_WAG (1<<12) #define GENITAL_EXAMINE (1<<13) diff --git a/code/__DEFINES/loadout.dm b/code/__DEFINES/loadout.dm index 1a53df28ee..4e352f415e 100644 --- a/code/__DEFINES/loadout.dm +++ b/code/__DEFINES/loadout.dm @@ -4,21 +4,17 @@ #define LOADOUT_SUBCATEGORY_NONE "Miscellaneous" #define LOADOUT_SUBCATEGORIES_NONE list("Miscellaneous") -//the names of the customization tabs -#define SETTINGS_TAB 0 -#define GAME_PREFERENCES_TAB 1 -#define APPEARANCE_TAB 2 + #define CHAR_INFO_TAB 3 #define ERP_TAB 4 //#define SPEECH_TAB 3 -#define LOADOUT_TAB 5 -#define CONTENT_PREFERENCES_TAB 6 -#define KEYBINDINGS_TAB 7 +#define PPT_ADULT_PREFERENCES 6 //the names of the erp tabs - can be 0, 1, or "has_cock" thru "has_womb" #define ERP_TAB_HOME 0 #define ERP_TAB_REARRANGE 1 +#define GEAR_CAT_ALL_EQUIPPED "Your Stuff" //backpack #define LOADOUT_CATEGORY_BACKPACK "In backpack" #define LOADOUT_SUBCATEGORY_BACKPACK_GENERAL "General" //basically anything that there's not enough of to have its own subcategory @@ -113,19 +109,20 @@ #define LOADOUT_ALLOWED_LIMB_TARGETS list(BODY_ZONE_L_ARM,BODY_ZONE_R_ARM,BODY_ZONE_L_LEG,BODY_ZONE_R_LEG) //options for modifiying limbs -#define LOADOUT_LIMB_NORMAL "Normal" -#define LOADOUT_LIMB_PROSTHETIC "Prosthetic" -#define LOADOUT_LIMB_AMPUTATED "Amputated" +#define LOADOUT_LIMB_NORMAL "Normal" +#define LOADOUT_LIMB_PROSTHETIC "Prosthetic" +#define LOADOUT_LIMB_AMPUTATED "Amputated" -#define LOADOUT_LIMBS list(LOADOUT_LIMB_NORMAL,LOADOUT_LIMB_PROSTHETIC,LOADOUT_LIMB_AMPUTATED) //you can amputate your legs/arms though +#define LOADOUT_LIMBS list(/* LOADOUT_LIMB_NORMAL, */LOADOUT_LIMB_PROSTHETIC,LOADOUT_LIMB_AMPUTATED) //you can amputate your legs/arms though //loadout saving/loading specific defines #define MAXIMUM_LOADOUT_SAVES 30 //Remember to increase this if more slots are added -#define LOADOUT_ITEM "loadout_item" -#define LOADOUT_COLOR "loadout_color" -#define LOADOUT_CUSTOM_NAME "loadout_custom_name" +#define LOADOUT_ITEM "loadout_item" +#define LOADOUT_COLOR "loadout_color" +#define LOADOUT_CUSTOM_NAME "loadout_custom_name" #define LOADOUT_CUSTOM_DESCRIPTION "loadout_custom_description" -#define LOADOUT_CUSTOM_COLOR "loadout_custom_description" +#define LOADOUT_CUSTOM_COLOR "loadout_custom_description" +#define LOADOUT_UID "loadout_uid" //loadout item flags #define LOADOUT_CAN_NAME (1<<0) //renaming items diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 1d6a54bf65..2921b84e9e 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -167,6 +167,7 @@ GLOBAL_LIST_INIT(undie_position_strings, list("Under Clothes", "Over Clothes", " #define PMR_ADDED_RADIO_STATIC "PMR_ADDED_RADIO_STATIC" // Player Master Changelog #define PMR_ADDED_COOLCHAT "fill-me-to-the-brimcon" // Player Master Changelog #define PMR_RUNECHAT_LENGTHENING "long_long_maaaaaaaaaaaaan" // Player Master Changelog +#define PMR_REMOVE_CORK_STRING "yes_it_was_funny_once" // Player Master Changelog /// The master Preferences Changelog to check the player's prefs against. /// includes a list of actions that need to be taken to update the player's prefs. @@ -177,4 +178,349 @@ GLOBAL_LIST_INIT(undie_position_strings, list("Under Clothes", "Over Clothes", " PMR_DAN_MESSED_UP_CHATPREFS,\ PMR_ADDED_COOLCHAT,\ PMR_RUNECHAT_LENGTHENING,\ + PMR_REMOVE_CORK_STRING,\ ) + +#define PREFCMD_ACTION_BUTTONS "PREFCMD_ACTION_BUTTONS" +#define PREFCMD_ADD_LIMB "PREFCMD_ADD_LIMB" +#define PREFCMD_ADMINHELP "PREFCMD_ADMINHELP" +#define PREFCMD_ALLOW_BEING_FED_PREY "PREFCMD_ALLOW_BEING_FED_PREY" +#define PREFCMD_ALLOW_BEING_PREY "PREFCMD_ALLOW_BEING_PREY" +#define PREFCMD_ALLOW_DEATH_MESSAGES "PREFCMD_ALLOW_DEATH_MESSAGES" +#define PREFCMD_ALLOW_DIGESTION_DAMAGE "PREFCMD_ALLOW_DIGESTION_DAMAGE" +#define PREFCMD_ALLOW_DIGESTION_DEATH "PREFCMD_ALLOW_DIGESTION_DEATH" +#define PREFCMD_ALLOW_DIGESTION_SOUNDS "PREFCMD_ALLOW_DIGESTION_SOUNDS" +#define PREFCMD_ALLOW_EATING_SOUNDS "PREFCMD_ALLOW_EATING_SOUNDS" +#define PREFCMD_ALLOW_TRASH_MESSAGES "PREFCMD_ALLOW_TRASH_MESSAGES" +#define PREFCMD_ALLOW_VORE_MESSAGES "PREFCMD_ALLOW_VORE_MESSAGES" +#define PREFCMD_ALT_PREFIX "PREFCMD_ALT_PREFIX" +#define PREFCMD_AMBIENTOCCLUSION "PREFCMD_AMBIENTOCCLUSION" +#define PREFCMD_ANNOUNCE_LOGIN "PREFCMD_ANNOUNCE_LOGIN" +#define PREFCMD_AROUSABLE "PREFCMD_AROUSABLE" +#define PREFCMD_AUTO_FIT_VIEWPORT "PREFCMD_AUTO_FIT_VIEWPORT" +#define PREFCMD_AUTO_OOC "PREFCMD_AUTO_OOC" +#define PREFCMD_AUTO_WAG "PREFCMD_AUTO_WAG" +#define PREFCMD_AUTOSTAND_TOGGLE "PREFCMD_AUTOSTAND_TOGGLE" +#define PREFCMD_BACKPACK_KIND "PREFCMD_BACKPACK_KIND" +#define PREFCMD_BLURBLE_MAX_WORDS "PREFCMD_BLURBLE_MAX_WORDS" +#define PREFCMD_BLURBLE_PITCH "PREFCMD_BLURBLE_PITCH" +#define PREFCMD_BLURBLE_SOUND "PREFCMD_BLURBLE_SOUND" +#define PREFCMD_BLURBLE_SPEED "PREFCMD_BLURBLE_SPEED" +#define PREFCMD_BLURBLE_TRIGGER "PREFCMD_BLURBLE_TRIGGER" +#define PREFCMD_BLURBLE_VARY "PREFCMD_BLURBLE_VARY" +#define PREFCMD_BLURBLE_VOLUME "PREFCMD_BLURBLE_VOLUME" +#define PREFCMD_BODY_MODEL "PREFCMD_BODY_MODEL" +#define PREFCMD_BODY_SPRITE "PREFCMD_BODY_SPRITE" +#define PREFCMD_BUTT_SLAP "PREFCMD_BUTT_SLAP" +#define PREFCMD_BYOND_PUBLICITY "PREFCMD_BYOND_PUBLICITY" +#define PREFCMD_CHANGE_AGE "PREFCMD_CHANGE_AGE" +#define PREFCMD_CHANGE_FLAVOR_TEXT "PREFCMD_CHANGE_FLAVOR_TEXT" +#define PREFCMD_CHANGE_GENDER "PREFCMD_CHANGE_GENDER" +#define PREFCMD_CHANGE_GENITAL_SHAPE "PREFCMD_CHANGE_GENITAL_SHAPE" +#define PREFCMD_CHANGE_GENITAL_SIZE "PREFCMD_CHANGE_GENITAL_SIZE" +#define PREFCMD_CHANGE_KISSER "PREFCMD_CHANGE_KISSER" +#define PREFCMD_CHANGE_NAME "PREFCMD_CHANGE_NAME" +#define PREFCMD_CHANGE_OOC_NOTES "PREFCMD_CHANGE_OOC_NOTES" +#define PREFCMD_CHANGE_PART "PREFCMD_CHANGE_PART" +#define PREFCMD_CHANGE_SLOT "PREFCMD_CHANGE_SLOT" +#define PREFCMD_CHANGE_TBS "PREFCMD_CHANGE_TBS" +#define PREFCMD_CHAT_ON_MAP "PREFCMD_CHAT_ON_MAP" +#define PREFCMD_CHAT_WIDTH "PREFCMD_CHAT_WIDTH" +#define PREFCMD_CLIENTFPS "PREFCMD_CLIENTFPS" +#define PREFCMD_COLOR_CHANGE "PREFCMD_COLOR_CHANGE" +#define PREFCMD_COLOR_CHAT_LOG "PREFCMD_COLOR_CHAT_LOG" +#define PREFCMD_COLOR_COPY "PREFCMD_COLOR_COPY" +#define PREFCMD_COLOR_DEL "PREFCMD_COLOR_DEL" +#define PREFCMD_COLOR_PASTE "PREFCMD_COLOR_PASTE" +#define PREFCMD_COMBOHUD_LIGHTING "PREFCMD_COMBOHUD_LIGHTING" +#define PREFCMD_DAMAGESCREENSHAKE_TOGGLE "PREFCMD_DAMAGESCREENSHAKE_TOGGLE" +#define PREFCMD_EYE_TYPE "PREFCMD_EYE_TYPE" +#define PREFCMD_FACIAL_HAIR_STYLE "PREFCMD_FACIAL_HAIR_STYLE" +#define PREFCMD_FUZZY "PREFCMD_FUZZY" +#define PREFCMD_GENITAL_EXAMINE "PREFCMD_GENITAL_EXAMINE" +#define PREFCMD_GHOST_ACCS "PREFCMD_GHOST_ACCS" +#define PREFCMD_GHOST_EARS "PREFCMD_GHOST_EARS" +#define PREFCMD_GHOST_FORM "PREFCMD_GHOST_FORM" +#define PREFCMD_GHOST_ORBIT "PREFCMD_GHOST_ORBIT" +#define PREFCMD_GHOST_OTHERS "PREFCMD_GHOST_OTHERS" +#define PREFCMD_GHOST_PDA "PREFCMD_GHOST_PDA" +#define PREFCMD_GHOST_RADIO "PREFCMD_GHOST_RADIO" +#define PREFCMD_GHOST_SIGHT "PREFCMD_GHOST_SIGHT" +#define PREFCMD_GHOST_WHISPERS "PREFCMD_GHOST_WHISPERS" +#define PREFCMD_GUNCURSOR_TOGGLE "PREFCMD_GUNCURSOR_TOGGLE" +#define PREFCMD_HAIR_GRADIENT_1 "PREFCMD_HAIR_GRADIENT_1" +#define PREFCMD_HAIR_GRADIENT_2 "PREFCMD_HAIR_GRADIENT_2" +#define PREFCMD_HAIR_STYLE_1 "PREFCMD_HAIR_STYLE_1" +#define PREFCMD_HAIR_STYLE_2 "PREFCMD_HAIR_STYLE_2" +#define PREFCMD_HEALTH_SMILEYS "PREFCMD_HEALTH_SMILEYS" +#define PREFCMD_HIDE_GENITAL "PREFCMD_HIDE_GENITAL" +#define PREFCMD_HOTKEY_HELP "PREFCMD_HOTKEY_HELP" +#define PREFCMD_HOTKEYS "PREFCMD_HOTKEYS" +#define PREFCMD_HUD_TOGGLE_FLASH "PREFCMD_HUD_TOGGLE_FLASH" +#define PREFCMD_HUNTINGHORN "PREFCMD_HUNTINGHORN" +#define PREFCMD_INCOME_UPDATES "PREFCMD_INCOME_UPDATES" +#define PREFCMD_INPUT_MODE_HOTKEY "PREFCMD_INPUT_MODE_HOTKEY" +#define PREFCMD_KEYBINDING_CAPTURE "keybindings_set" +#define PREFCMD_KEYBINDING_CATEGORY_TOGGLE "PREFCMD_KEYBINDING_CATEGORY_TOGGLE" +#define PREFCMD_KEYBINDING_SET "PREFCMD_KEYBINDING_SET" +#define PREFCMD_LEGS "PREFCMD_LEGS" +#define PREFCMD_LOADOUT_CATEGORY "PREFCMD_LOADOUT_CATEGORY" +#define PREFCMD_LOADOUT_REDESC "PREFCMD_LOADOUT_REDESC" +#define PREFCMD_LOADOUT_RENAME "PREFCMD_LOADOUT_RENAME" +#define PREFCMD_LOADOUT_RESET "PREFCMD_LOADOUT_RESET" +#define PREFCMD_LOADOUT_SEARCH "PREFCMD_LOADOUT_SEARCH" +#define PREFCMD_LOADOUT_SEARCH_CLEAR "PREFCMD_LOADOUT_SEARCH_CLEAR" +#define PREFCMD_LOADOUT_SUBCATEGORY "PREFCMD_LOADOUT_SUBCATEGORY" +#define PREFCMD_LOADOUT_TOGGLE "PREFCMD_LOADOUT_TOGGLE" +#define PREFCMD_LOBBY_MUSIC "PREFCMD_LOBBY_MUSIC" +#define PREFCMD_MARKING_ADD "PREFCMD_MARKING_ADD" +#define PREFCMD_MARKING_EDIT "PREFCMD_MARKING_EDIT" +#define PREFCMD_MARKING_MOVE_DOWN "PREFCMD_MARKING_MOVE_DOWN" +#define PREFCMD_MARKING_MOVE_UP "PREFCMD_MARKING_MOVE_UP" +#define PREFCMD_MARKING_NEXT "PREFCMD_MARKING_NEXT" +#define PREFCMD_MARKING_PREV "PREFCMD_MARKING_PREV" +#define PREFCMD_MARKING_REMOVE "PREFCMD_MARKING_REMOVE" +#define PREFCMD_MASTER_VORE_TOGGLE "PREFCMD_MASTER_VORE_TOGGLE" +#define PREFCMD_MAX_CHAT_LENGTH "PREFCMD_MAX_CHAT_LENGTH" +#define PREFCMD_MAX_PFP_HEIGHT "PREFCMD_MAX_PFP_HEIGHT" +#define PREFCMD_MAX_PFP_WIDTH "PREFCMD_MAX_PFP_WIDTH" +#define PREFCMD_MEAT_TYPE "PREFCMD_MEAT_TYPE" +#define PREFCMD_MIDIS "PREFCMD_MIDIS" +#define PREFCMD_MISMATCHED_MARKINGS "PREFCMD_MISMATCHED_MARKINGS" +#define PREFCMD_MODIFY_LIMB "PREFCMD_MODIFY_LIMB" +#define PREFCMD_OFFSCREEN "PREFCMD_OFFSCREEN" +#define PREFCMD_OVERRIDE_GENITAL "PREFCMD_OVERRIDE_GENITAL" +#define PREFCMD_PDA_KIND "PREFCMD_PDA_KIND" +#define PREFCMD_PDA_RINGTONE "PREFCMD_PDA_RINGTONE" +#define PREFCMD_PHUD_WHITELIST "PREFCMD_PHUD_WHITELIST" +#define PREFCMD_PIXEL_X "PREFCMD_PIXEL_X" +#define PREFCMD_PIXEL_Y "PREFCMD_PIXEL_Y" +#define PREFCMD_PULL_REQUESTS "PREFCMD_PULL_REQUESTS" +#define PREFCMD_RADIO_BLURBLES "PREFCMD_RADIO_BLURBLES" +#define PREFCMD_RADIO_STATIC "PREFCMD_RADIO_STATIC" +#define PREFCMD_RAINBOW_BLOOD "PREFCMD_RAINBOW_BLOOD" +#define PREFCMD_REMOVE_LIMB "PREFCMD_REMOVE_LIMB" +#define PREFCMD_SAVE "PREFCMD_SAVE" +#define PREFCMD_SCALE "PREFCMD_SCALE" +#define PREFCMD_SCARS "PREFCMD_SCARS" +#define PREFCMD_SCARS_CLEAR "PREFCMD_SCARS_CLEAR" +#define PREFCMD_SCREENSHAKE_TOGGLE "PREFCMD_SCREENSHAKE_TOGGLE" +#define PREFCMD_SEE_CHAT_NON_MOB "PREFCMD_SEE_CHAT_NON_MOB" +#define PREFCMD_SEE_GENITAL "PREFCMD_SEE_GENITAL" +#define PREFCMD_SEE_RC_EMOTES "PREFCMD_SEE_RC_EMOTES" +#define PREFCMD_SET_SUBSUBTAB "PREFCMD_SET_SUBSUBTAB" +#define PREFCMD_SET_SUBTAB "PREFCMD_SET_SUBTAB" +#define PREFCMD_SET_TAB "PREFCMD_SET_TAB" +#define PREFCMD_SHIFT_GENITAL "PREFCMD_SHIFT_GENITAL" +#define PREFCMD_SHOW_THIS_MANY_CHARS "PREFCMD_SHOW_THIS_MANY_CHARS" +#define PREFCMD_SKIN_TONE "PREFCMD_SKIN_TONE" +#define PREFCMD_SLOT_COPY "PREFCMD_SLOT_COPY" +#define PREFCMD_SLOT_DELETE "PREFCMD_SLOT_DELETE" +#define PREFCMD_SLOT_PASTE "PREFCMD_SLOT_PASTE" +#define PREFCMD_SOCKS "PREFCMD_SOCKS" +#define PREFCMD_SOCKS_OVERCLOTHES "PREFCMD_SOCKS_OVERCLOTHES" +#define PREFCMD_SPECIES "PREFCMD_SPECIES" +#define PREFCMD_SPECIES_NAME "PREFCMD_SPECIES_NAME" +#define PREFCMD_SPLIT_ADMIN_TABS "PREFCMD_SPLIT_ADMIN_TABS" +#define PREFCMD_SPRINTBUFFER "PREFCMD_SPRINTBUFFER" +#define PREFCMD_STAT_CHANGE "PREFCMD_STAT_CHANGE" +#define PREFCMD_TASTE "PREFCMD_TASTE" +#define PREFCMD_TETRIS_STORAGE_TOGGLE "PREFCMD_TETRIS_STORAGE_TOGGLE" +#define PREFCMD_TGUI_FANCY "PREFCMD_TGUI_FANCY" +#define PREFCMD_TGUI_LOCK "PREFCMD_TGUI_LOCK" +#define PREFCMD_TOGGLE_GENITAL "PREFCMD_TOGGLE_GENITAL" +#define PREFCMD_TOGGLE_SHOW_CHARACTER_LIST "PREFCMD_TOGGLE_SHOW_CHARACTER_LIST" +#define PREFCMD_UI_STYLE "PREFCMD_UI_STYLE" +#define PREFCMD_UNDERSHIRT "PREFCMD_UNDERSHIRT" +#define PREFCMD_UNDERSHIRT_OVERCLOTHES "PREFCMD_UNDERSHIRT_OVERCLOTHES" +#define PREFCMD_UNDERWEAR "PREFCMD_UNDERWEAR" +#define PREFCMD_UNDERWEAR_OVERCLOTHES "PREFCMD_UNDERWEAR_OVERCLOTHES" +#define PREFCMD_UNDO "PREFCMD_UNDO" +#define PREFCMD_UPPERLOWERFLOOR "PREFCMD_UPPERLOWERFLOOR" +#define PREFCMD_VCHAT "PREFCMD_VCHAT" +#define PREFCMD_WIDESCREEN_TOGGLE "PREFCMD_WIDESCREEN_TOGGLE" +#define PREFCMD_WIDTH "PREFCMD_WIDTH" +#define PREFCMD_WINFLASH "PREFCMD_WINFLASH" + +#define PREFDAT_CATEGORY "PREFDAT_CATEGORY" +#define PREFDAT_COLOR_HEX "PREFDAT_COLOR_HEX" +#define PREFDAT_COLOR_KEY "PREFDAT_COLOR_KEY" +#define PREFDAT_COLKEY_GEAR "PREFDAT_COLKEY_GEAR" +#define PREFDAT_COLKEY_MARKING "PREFDAT_COLKEY_MARKING" +#define PREFDAT_COLKEY_IS_COLOR "PREFDAT_COLKEY_IS_COLOR" +#define PREFDAT_COLKEY_IS_FEATURE "PREFDAT_COLKEY_IS_FEATURE" +#define PREFDAT_GEAR_PATH "PREFDAT_GEAR_PATH" +#define PREFDAT_GEAR_TYPE "PREFDAT_GEAR_TYPE" +#define PREFDAT_LOADOUT_GEAR_NAME "PREFDAT_LOADOUT_GEAR_NAME" +#define PREFDAT_GENITAL_HAS "PREFDAT_GENITAL_HAS" +#define PREFDAT_GO_NEXT "PREFDAT_GO_NEXT" +#define PREFDAT_GO_PREV "PREFDAT_GO_PREV" +#define PREFDAT_HIDDEN_BY "PREFDAT_HIDDEN_BY" +#define PREFDAT_INDEPENDENT "PREFDAT_INDEPENDENT" +#define PREFDAT_INDEX_IS_MARKING_UID "PREFDAT_INDEX_IS_MARKING_UID" +#define PREFDAT_IS_GEAR "PREFDAT_IS_GEAR" +#define PREFDAT_IS_MARKING "PREFDAT_IS_MARKING" +#define PREFDAT_KEYBINDING "PREFDAT_KEYBINDING" +#define PREFDAT_LOADOUT_CATEGORY "PREFDAT_LOADOUT_CATEGORY" +#define PREFDAT_LOADOUT_SEARCH "PREFDAT_LOADOUT_SEARCH" +#define PREFDAT_LOADOUT_SLOT "PREFDAT_LOADOUT_SLOT" +#define PREFDAT_LOADOUT_SUBCATEGORY "PREFDAT_LOADOUT_SUBCATEGORY" +#define PREFDAT_MARKING_ACTION "PREFDAT_MARKING_ACTION" +#define PREFDAT_MARKING_SLOT "PREFDAT_MARKING_SLOT" +#define PREFDAT_MARKING_UID "PREFDAT_MARKING_UID" +#define PREFDAT_MODIFY_LIMB_MOD "PREFDAT_MODIFY_LIMB_MOD" +#define PREFDAT_OLD_KEY "PREFDAT_OLD_KEY" +#define PREFDAT_PARTKIND "PREFDAT_PARTKIND" +#define PREFDAT_REMOVE_LIMB_MOD "PREFDAT_REMOVE_LIMB_MOD" +#define PREFDAT_SLOT "PREFDAT_SLOT" +#define PREFDAT_SUBSUBTAB "PREFDAT_SUBSUBTAB" +#define PREFDAT_SUBTAB "PREFDAT_SUBTAB" +#define PREFDAT_SUPPRESS_MESSAGE "PREFDAT_SUPPRESS_MESSAGE" +#define PREFDAT_STAT "PREFDAT_STAT" +#define PREFDAT_TAB "PREFDAT_TAB" +#define PREFDAT_TOGGLE_HIDE_UNDIES "PREFDAT_TOGGLE_HIDE_UNDIES" + +#define STAT_STRENGTH "special_s" +#define STAT_PERCEPTION "special_p" +#define STAT_ENDURANCE "special_e" +#define STAT_CHARISMA "special_c" +#define STAT_INTELLIGENCE "special_i" +#define STAT_AGILITY "special_a" +#define STAT_LUCK "special_l" + +// supported parts +#define BPART_DECO_WINGS "deco_wings" +#define BPART_DERG_BELLY "derg_belly" +#define BPART_DERG_BODY "derg_body" +#define BPART_DERG_EARS "derg_ears" +#define BPART_DERG_EYES "derg_eyes" +#define BPART_DERG_HORNS "derg_horns" +#define BPART_DERG_MANE "derg_mane" +#define BPART_EARS "ears" +#define BPART_FRILLS "frills" +#define BPART_HORNS "horns" +#define BPART_HORNS_COLOR "horns_color" +#define BPART_INSECT_FLUFF "insect_fluff" +#define BPART_INSECT_MARKINGS "insect_markings" +#define BPART_INSECT_WINGS "insect_wings" +#define BPART_IPC_ANTENNA "ipc_antenna" +#define BPART_IPC_SCREEN "ipc_screen" +#define BPART_MAM_EARS "mam_ears" +#define BPART_MAM_SNOUTS "mam_snouts" +#define BPART_MAM_TAIL "mam_tail" +#define BPART_SNOUT "snout" +#define BPART_SPINES "spines" +#define BPART_TAIL_HUMAN "tail_human" +#define BPART_TAIL_LIZARD "tail_lizard" +#define BPART_TAUR "taur" +#define BPART_WINGS "wings" +#define BPART_WINGS_COLOR "wings_color" +#define BPART_XENODORSAL "xenodorsal" +#define BPART_XENOHEAD "xenohead" +#define BPART_XENOTAIL "xenotail" + +#define PRACT_DIALOG_ACCEPT "PRACT_DIALOG_ACCEPT" +#define PRACT_DIALOG_ACCEPT_BIG "PRACT_DIALOG_ACCEPT_BIG" +#define PRACT_DIALOG_ACCEPT_SMOL "PRACT_DIALOG_ACCEPT_SMOL" +#define PRACT_DIALOG_CANCEL "PRACT_DIALOG_CANCEL" +#define PRACT_DIALOG_DENIED "PRACT_DIALOG_DENIED" +#define PRACT_DIALOG_ERROR "PRACT_DIALOG_ERROR" +#define PRACT_DIALOG_FAILED "PRACT_DIALOG_FAILED" +#define PRACT_TOGGLE(something) ((something) ? PRACT_DIALOG_ACCEPT : PRACT_DIALOG_DENIED) +#define PRACT_TOGGLE_INV(something) ((something) ? PRACT_DIALOG_DENIED : PRACT_DIALOG_ACCEPT) + +#define BOOP_BIG_MENU_OPEN "BOOP_BIG_MENU_OPEN" +#define BOOP_MENU_OPEN "BOOP_MENU_OPEN" +#define BOOP_SUB_PROMPT "BOOP_SUB_PROMPT" +#define BOOP_ACCEPT "BOOP_ACCEPT" +#define BOOP_ACCEPT_BIG "BOOP_ACCEPT_BIG" +#define BOOP_ACCEPT_SMOL "BOOP_ACCEPT_SMOL" +#define BOOP_CANCEL "BOOP_CANCEL" +#define BOOP_DENIED "BOOP_DENIED" +#define BOOP_ERROR "BOOP_ERROR" +#define BOOP_FAILED "BOOP_FAILED" + +#define PPT_CHARCTER_PROPERTIES "PPT_CHARCTER_PROPERTIES" + #define PPT_CHARCTER_PROPERTIES_INFO "PPT_CHARCTER_PROPERTIES_INFO" + #define PPT_CHARCTER_PROPERTIES_VOICE "PPT_CHARCTER_PROPERTIES_VOICE" + #define PPT_CHARCTER_PROPERTIES_MISC "PPT_CHARCTER_PROPERTIES_MISC" +#define PPT_CHARCTER_APPEARANCE "PPT_CHARCTER_APPEARANCE" + #define PPT_CHARCTER_APPEARANCE_MISC "PPT_CHARCTER_APPEARANCE_MISC" + #define PPT_CHARCTER_APPEARANCE_HAIR_EYES "PPT_CHARCTER_APPEARANCE_HAIR_EYES" + #define PPT_CHARCTER_APPEARANCE_PARTS "PPT_CHARCTER_APPEARANCE_PARTS" + #define PPT_CHARCTER_APPEARANCE_MARKINGS "PPT_CHARCTER_APPEARANCE_MARKINGS" + #define PPT_CHARCTER_APPEARANCE_UNDERLYING "PPT_CHARCTER_APPEARANCE_UNDERLYING" + #define PPT_CHARCTER_APPEARANCE_UNDERLYING_UNDIES "PPT_CHARCTER_APPEARANCE_UNDERLYING_UNDIES" + #define PPT_CHARCTER_APPEARANCE_UNDERLYING_LAYERING "PPT_CHARCTER_APPEARANCE_UNDERLYING_LAYERING" +#define PPT_LOADOUT "PPT_LOADOUT" +#define PPT_GAME_PREFERENCES "PPT_GAME_PREFERENCES" + #define PPT_GAME_PREFERENCES_GENERAL "PPT_GAME_PREFERENCES_GENERAL" + #define PPT_GAME_PREFERENCES_UI "PPT_GAME_PREFERENCES_UI" + #define PPT_GAME_PREFERENCES_CHAT "PPT_GAME_PREFERENCES_CHAT" + #define PPT_GAME_PREFERENCES_RUNECHAT "PPT_GAME_PREFERENCES_RUNECHAT" + #define PPT_GAME_PREFERENCES_GHOST "PPT_GAME_PREFERENCES_GHOST" + #define PPT_GAME_PREFERENCES_AUDIO "PPT_GAME_PREFERENCES_AUDIO" + #define PPT_GAME_PREFERENCES_ADMIN "PPT_GAME_PREFERENCES_ADMIN" + #define PPT_GAME_PREFERENCES_CONTENT "PPT_GAME_PREFERENCES_CONTENT" +#define PPT_KEYBINDINGS "PPT_KEYBINDINGS" + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +GLOBAL_LIST_INIT(pref_cat_2_words, list( + PPT_CHARCTER_PROPERTIES = "Character Properties", + PPT_CHARCTER_PROPERTIES_INFO = "Info", + PPT_CHARCTER_PROPERTIES_VOICE = "Voice", + PPT_CHARCTER_PROPERTIES_MISC = "Misc", + PPT_CHARCTER_APPEARANCE = "Character Appearance", + PPT_CHARCTER_APPEARANCE_MISC = "General", + PPT_CHARCTER_APPEARANCE_HAIR_EYES = "Hair / Eyes", + PPT_CHARCTER_APPEARANCE_PARTS = "Cool Parts", + PPT_CHARCTER_APPEARANCE_MARKINGS = "Markings", + PPT_CHARCTER_APPEARANCE_UNDERLYING = "Unmentionables", + PPT_CHARCTER_APPEARANCE_UNDERLYING_UNDIES = "Underwear", + PPT_CHARCTER_APPEARANCE_UNDERLYING_LAYERING = "Layering", + PPT_LOADOUT = "Loadout", + PPT_GAME_PREFERENCES = "Game Preferences", + PPT_GAME_PREFERENCES_GENERAL = "General", + PPT_GAME_PREFERENCES_UI = "UI", + PPT_GAME_PREFERENCES_CHAT = "Chat", + PPT_GAME_PREFERENCES_RUNECHAT = "Runechat", + PPT_GAME_PREFERENCES_GHOST = "GhostADMINONLY", + PPT_GAME_PREFERENCES_AUDIO = "Audio", + PPT_GAME_PREFERENCES_ADMIN = "AdminADMINONLY", + PPT_GAME_PREFERENCES_CONTENT = "Adult Content", + PPT_KEYBINDINGS = "Keybindings", +)) + + + + + diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index 05cd8dc505..416d908382 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -51,6 +51,8 @@ #define MAX_CHARTER_LEN 80 // Template for OOC notes. +#define OOC_NOTE_TEMPLATE "" +/* #define OOC_NOTE_TEMPLATE "Non-ERP Notes\n\ This exist for things like how to approach this character for IC things such as how to ask for going on adventurers!\n\ But this person hasn't changed the info yet!\n\ @@ -90,7 +92,7 @@ \n\ ...Desired RP System: Ask, this is for subtle, subtler, or emote. Or, when its added, a mechanical erotic roleplay system! Or some mix inbetween, but this person hasn't changed the text so ASK!\n\ .My Post Perspective: Ask!" - + */ #define BACKGROUND_INFO_NOTE_TEMPLATE "Background Info Template\n\ Keep in mind that you do not need to have answers for all of these questions from the word go, but having answers for some of them should greatly improve your playing experience due to it solidifying your character more robustly in a very fluid world.\n\ BiG FeNnys wIdE waRning: So, I'm passing this information to you as a player on my own server with thousands of hours roleplaying here. While I understand that shy people do absolutely exist and that playing one may be something that you want to do (or maybe you just are shy and your character is as well by extension) understand that the more of these answers you can define the better off you're going to be. Being shy here is much like being shy in the real world, you often end up spending a lot of time by yourself. If that is not your long term goal then you should, by all means, do what you can to fight back against your shyness. Because I can say with all certainty that if its people you want to hang out with standing alone on top of a building wishing that you were talking to someone is about the slowest way to find someone to actually talk to.\n\ diff --git a/code/__HELPERS/_lists.dm b/code/__HELPERS/_lists.dm index 1cade27168..5e79e17ec0 100644 --- a/code/__HELPERS/_lists.dm +++ b/code/__HELPERS/_lists.dm @@ -947,11 +947,18 @@ return maybelist return list(maybelist) +// Takes in something that might be a number, and returns something that is a nummmber /proc/numberfy(maybenum) if(isnum(maybenum)) return maybenum return text2num(maybenum) +// Takes in something that might be a path, and returns something that is a path +/proc/pathify(maybepath) + if(ispath(maybepath)) + return maybepath + return text2path(maybepath) + /// Used to have a var automagically swap between a list of options /// returns the next option (or the first if its the end) /proc/rotate_vars(current, list/options) diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm index bd07ea5279..17b013191a 100644 --- a/code/__HELPERS/cmp.dm +++ b/code/__HELPERS/cmp.dm @@ -158,3 +158,6 @@ GLOBAL_VAR_INIT(cmp_field, "name") /proc/cmp_typepaths_length_asc(A, B) return length("[A]") - length("[B]") + +/proc/cmp_gear_name_asc(datum/gear/A, datum/gear/B) + return sorttext(B.name, A.name) diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm index ce92866a3d..4c48b67d43 100644 --- a/code/__HELPERS/text.dm +++ b/code/__HELPERS/text.dm @@ -294,6 +294,14 @@ . = t[1] return uppertext(.) + copytext(t, 1 + length(.)) +//returns a string where all the words separated by spaces are capitalized +/proc/capitalize_all(str) + var/list/words = splittext(str, " ") + var/list/out = list() + for(var/word in words) + out += capitalize(word) + return jointext(out, " ") + /proc/stringmerge(text,compare,replace = "*") //This proc fills in all spaces with the "replace" var (* by default) with whatever //is in the other string at the same spot (assuming it is not a replace char). diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 7e6f68d5ea..cb698aa075 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -413,6 +413,79 @@ GLOBAL_LIST_INIT(unlocked_mutant_parts, list("horns", "insect_fluff")) //parts in either of the above two lists that require a second option that allows them to be coloured GLOBAL_LIST_INIT(colored_mutant_parts, list("insect_wings" = "wings_color", "deco_wings" = "wings_color", "horns" = "horns_color")) +/// These are features that are colors (otherwise, they're vars, because THANKS DNA) +GLOBAL_LIST_INIT(features_that_are_colors, list( + "derg_body_primary" = TRUE, + "derg_body_secondary" = TRUE, + "derg_body_tertiary" = TRUE, + "derg_belly_primary" = TRUE, + "derg_belly_secondary" = TRUE, + "derg_belly_tertiary" = TRUE, + "derg_horns_primary" = TRUE, + "derg_horns_secondary" = TRUE, + "derg_horns_tertiary" = TRUE, + "derg_ears_primary" = TRUE, + "derg_ears_secondary" = TRUE, + "derg_ears_tertiary" = TRUE, + "derg_mane_primary" = TRUE, + "derg_mane_secondary" = TRUE, + "derg_mane_tertiary" = TRUE, + "derg_eyes_primary" = TRUE, + "derg_eyes_secondary" = TRUE, + "derg_eyes_tertiary" = TRUE, + "xenodorsal_primary" = TRUE, + "xenodorsal_secondary" = TRUE, + "xenodorsal_tertiary" = TRUE, + "xhead_primary" = TRUE, + "xhead_secondary" = TRUE, + "xhead_tertiary" = TRUE, + "tail_primary" = TRUE, + "tail_secondary" = TRUE, + "tail_tertiary" = TRUE, + "insect_markings_primary" = TRUE, + "insect_markings_secondary" = TRUE, + "insect_markings_tertiary" = TRUE, + "insect_fluff_primary" = TRUE, + "insect_fluff_secondary" = TRUE, + "insect_fluff_tertiary" = TRUE, + "ears_primary" = TRUE, + "ears_secondary" = TRUE, + "ears_tertiary" = TRUE, + "frills_primary" = TRUE, + "frills_secondary" = TRUE, + "frills_tertiary" = TRUE, + "ipc_antenna_primary" = TRUE, + "ipc_antenna_secondary" = TRUE, + "ipc_antenna_tertiary" = TRUE, + "taur_primary" = TRUE, + "taur_secondary" = TRUE, + "taur_tertiary" = TRUE, + "snout_primary" = TRUE, + "snout_secondary" = TRUE, + "snout_tertiary" = TRUE, + "spines_primary" = TRUE, + "spines_secondary" = TRUE, + "spines_tertiary" = TRUE, + "mam_body_markings_primary" = TRUE, + "mam_body_markings_secondary" = TRUE, + "mam_body_markings_tertiary" = TRUE, + "mcolor" = TRUE, + "mcolor2" = TRUE, + "mcolor3" = TRUE, + "horns_color" = TRUE, + "wings_color" = TRUE, + "cock_color" = TRUE, + "balls_color" = TRUE, + "breasts_color" = TRUE, + "butt_color" = TRUE, + "belly_color" = TRUE, + "vag_color" = TRUE, + "blood_color" = TRUE, + "chat_color" = TRUE, +)) + + + //body ids that have greyscale sprites GLOBAL_LIST_INIT(greyscale_limb_types, list( "human", @@ -487,3 +560,44 @@ GLOBAL_LIST_INIT(eye_types, list( GLOBAL_LIST_INIT(bodypart_names, list(num2text(HEAD) = "Head", num2text(CHEST) = "Chest", num2text(LEG_LEFT) = "Left Leg", num2text(LEG_RIGHT) = "Right Leg", num2text(ARM_LEFT) = "Left Arm", num2text(ARM_RIGHT) = "Right Arm")) // list linking bodypart names back to the bitflags GLOBAL_LIST_INIT(bodypart_values, list("Head" = num2text(HEAD), "Chest" = num2text(CHEST), "Left Leg" = num2text(LEG_LEFT), "Right Leg" = num2text(LEG_RIGHT), "Left Arm" = num2text(ARM_LEFT), "Right Arm" = num2text(ARM_RIGHT))) + + +#define MARKING_LIMB_INDEX_NUM 1 +#define MARKING_NAME 2 +#define MARKING_COLOR_LIST 3 +#define MARKING_UID 4 +#define MARKING_LIST_LENGTH 4 + +#define MARKING_COLOR_LIST_LENGTH 3 + +// Globals/helpers/randomness. +GLOBAL_LIST_INIT(hair_gradients, list( + "None" = "none", + "Fade (Up)" = "fadeup", + "Fade (Down)" = "fadedown", + "Fade Low (Up)" = "fadeup_low", + "Bottom Flat" = "bottomflat", + "Fade Low (Down)" = "fadedown_low", + "Vertical Split" = "vsplit", + "Reflected" = "reflected", + "Reflected (Inverted)" = "reflected_inverse", + "Reflected High" = "reflected_high", + "Reflected High (Inverted)" = "reflected_inverse_high", + "Wavy" = "wavy", + "Striped" = "striped", + "Reversed Stripe" = "stripedreverse", + "Squigly" = "squigly", + "Swayed" = "sinewave", + "Vertical Swayed" = "sinewavesideways", + "Mixy" = "dots", + "Mixy Faded Down" = "fadedowndots", + "Spots" = "skrell_gradient_spots", + "Stripey" = "skr_headtail_stripes", //My beloved + "Horizontal Fading Stripes" = "stripeshorzfade", + "Horizontal Stripes" = "stripeshorz", + "Vertical Fading Stripes" = "stripesvertfaded", + "Vertical Stripes" = "stripesvert", + "Swirly" = "swirls", + "Suspect" = "amogus" //ඞ// + )) + diff --git a/code/_globalvars/lists/keybindings.dm b/code/_globalvars/lists/keybindings.dm index c455b18146..0536796863 100644 --- a/code/_globalvars/lists/keybindings.dm +++ b/code/_globalvars/lists/keybindings.dm @@ -10,6 +10,8 @@ /// Adds an instanced keybinding to the global tracker /proc/add_keybinding(datum/keybinding/instance) GLOB.keybindings_by_name[instance.name] = instance + LAZYINITLIST(GLOB.keybindings_by_category[instance.category]) + GLOB.keybindings_by_category[instance.category][instance.name] = instance // Classic if(LAZYLEN(instance.classic_keys)) diff --git a/code/controllers/subsystem/job.dm b/code/controllers/subsystem/job.dm index ad363250b6..049f70c6f9 100644 --- a/code/controllers/subsystem/job.dm +++ b/code/controllers/subsystem/job.dm @@ -726,17 +726,17 @@ SUBSYSTEM_DEF(job) return var/list/displaceables = DISPLACEABLE_SLOTS for(var/i in chosen_gear) - var/datum/gear/G = istext(i[LOADOUT_ITEM]) ? text2path(i[LOADOUT_ITEM]) : i[LOADOUT_ITEM] + var/datum/gear/G = pathify(i[LOADOUT_ITEM]) if(!G) // aint there? ditch it message_admins("Invalid gear in loadout for [the_mob] at slot [the_prefs.loadout_slot]: [i[LOADOUT_ITEM]]") stack_trace("Invalid gear in loadout for [the_mob] at slot [the_prefs.loadout_slot]: [i[LOADOUT_ITEM]]") - the_prefs.remove_gear_from_loadout(the_prefs.loadout_slot, i[LOADOUT_ITEM]) + the_prefs.RemoveGearFromLoadout(the_prefs.loadout_slot, i[LOADOUT_ITEM]) continue G = GLOB.loadout_items[initial(G.category)][initial(G.subcategory)][initial(G.name)] if(!G || !G.path) // are you *sure* its there? cus, it aint message_admins("Invalid gear in loadout for [the_mob] at slot [the_prefs.loadout_slot]: [i[LOADOUT_ITEM]]. G.path is [G ? G.path : "wow it doesnt even have a fucking path, its a [G.type]"]. Eat me, Fenny.") stack_trace("Invalid gear in loadout for [the_mob] at slot [the_prefs.loadout_slot]: [i[LOADOUT_ITEM]]. G.path is [G ? G.path : "wow it doesnt even have a fucking path, its a [G.type]"]. Eat me, Fenny.") - the_prefs.remove_gear_from_loadout(the_prefs.loadout_slot, i[LOADOUT_ITEM]) + the_prefs.RemoveGearFromLoadout(the_prefs.loadout_slot, i[LOADOUT_ITEM]) continue var/permitted = TRUE if(!bypass_prereqs && G.restricted_roles && G.restricted_roles.len && !(M.mind.assigned_role in G.restricted_roles)) @@ -752,23 +752,23 @@ SUBSYSTEM_DEF(job) if(!G || !G.path || !ispath(G.path)) // are you *sure* its there? cus, it aint message_admins("Invalid gear in loadout for [the_mob] at slot [the_prefs.loadout_slot]: [i[LOADOUT_ITEM]]. G.path is [G ? G.path : "wow it doesnt even have a fucking path, its a [G.type]"]. Eat me, Fenny.") stack_trace("Invalid gear in loadout for [the_mob] at slot [the_prefs.loadout_slot]: [i[LOADOUT_ITEM]]. G.path is [G ? G.path : "wow it doesnt even have a fucking path, its a [G.type]"]. Eat me, Fenny.") - the_prefs.remove_gear_from_loadout(the_prefs.loadout_slot, i[LOADOUT_ITEM]) + the_prefs.RemoveGearFromLoadout(the_prefs.loadout_slot, i[LOADOUT_ITEM]) continue var/obj/item/I = this_fucking_thing_keeps_runtiming_eat_my_ass(G) if(!I) message_admins("Invalid gear in loadout for [the_mob] at slot [the_prefs.loadout_slot]: [i[LOADOUT_ITEM]]. G.path is [G ? G.path : "wow it doesnt even have a fucking path, its a [G.type]"]. Eat me, Fenny.") stack_trace("Invalid gear in loadout for [the_mob] at slot [the_prefs.loadout_slot]: [i[LOADOUT_ITEM]]. G.path is [G ? G.path : "wow it doesnt even have a fucking path, its a [G.type]"]. Eat me, Fenny.") - the_prefs.remove_gear_from_loadout(the_prefs.loadout_slot, i[LOADOUT_ITEM]) + the_prefs.RemoveGearFromLoadout(the_prefs.loadout_slot, i[LOADOUT_ITEM]) continue - if(i[LOADOUT_CUSTOM_NAME]) + if(LAZYLEN(i[LOADOUT_CUSTOM_NAME])) var/custom_name = i[LOADOUT_CUSTOM_NAME] I.name = custom_name - if(i[LOADOUT_CUSTOM_DESCRIPTION]) + if(LAZYLEN(i[LOADOUT_CUSTOM_DESCRIPTION])) var/custom_description = i[LOADOUT_CUSTOM_DESCRIPTION] I.desc = custom_description if(i[LOADOUT_CUSTOM_COLOR]) var/custom_cllor = i[LOADOUT_CUSTOM_COLOR] - I.color = "[custom_cllor]" + I.color = "#[custom_cllor]" var/displace_me = FALSE if(G.slot in displaceables) /// mm yes, displace me in my G.slot~ displace_me = TRUE diff --git a/code/controllers/subsystem/pornhud.dm b/code/controllers/subsystem/pornhud.dm index 13760ee5c1..aaf5c8dac1 100644 --- a/code/controllers/subsystem/pornhud.dm +++ b/code/controllers/subsystem/pornhud.dm @@ -400,7 +400,7 @@ SUBSYSTEM_DEF(pornhud) var/mob/living/carbon/human/myowner = GET_WEAKREF(owner) if(!ishuman(myowner)) return - var/list/image_order = myowner.dna.decode_cockstring(FALSE) + var/list/image_order = myowner.dna.features["genital_order"] var/preflag = is_whitelisted(P.parent.mob) ? NONE : P.features["genital_hide"] for(var/entry in image_order) switch(entry) diff --git a/code/datums/browser.dm b/code/datums/browser.dm index da2f64f5c4..f42384f5f3 100644 --- a/code/datums/browser.dm +++ b/code/datums/browser.dm @@ -64,6 +64,7 @@ /datum/browser/proc/get_header() var/file head_content += "" + head_content += "" for (file in stylesheets) head_content += "" @@ -81,7 +82,7 @@
[title ? "
[title]
" : ""] -
+
"} //" This is here because else the rest of the file looks like a string in notepad++. /datum/browser/proc/get_footer() @@ -114,7 +115,8 @@ SSassets.transport.send_assets(user, stylesheets) if(scripts.len) SSassets.transport.send_assets(user, scripts) - user << browse(get_content(), "window=[window_id];[window_size][window_options]") + var/thecontent = get_content() + user << browse(thecontent, "window=[window_id];[window_size][window_options]") if(use_onclose) setup_onclose() diff --git a/code/game/genital_hud.dm b/code/game/genital_hud.dm index a17e9a013c..f3fba62245 100644 --- a/code/game/genital_hud.dm +++ b/code/game/genital_hud.dm @@ -15,7 +15,7 @@ SEND_SIGNAL(A, COMSIG_HUMAN_UPDATE_GENITALS) SEND_SIGNAL(M, COMSIG_HUMAN_UPDATE_GENITALS) var/mob/living/carbon/human/owner = A - var/list/order = splittext(owner?.dna?.features["genital_order"], ":") + var/list/order = owner?.dna?.features["genital_order"] var/list/true_order = getApprovedGenitalList(M, order) for(var/i in hud_icons) if(A.hud_list[i]) diff --git a/code/modules/arousal/genital_data.dm b/code/modules/arousal/genital_data.dm new file mode 100644 index 0000000000..abe5504c70 --- /dev/null +++ b/code/modules/arousal/genital_data.dm @@ -0,0 +1,86 @@ +/* + * File: genital_data.dm + * Author: Cogwerks The Fox + * Date: 2019-12-10 + * License: WWW.PLAYAPOCALYPSE.COM + * + * I shoudla known after the 500th define for all genitals that I needed to remember my golden rule + * 'Anything a fuuckhuge list can do, a datum does better' + */ + +/datum/genital_data + var/name + var/has_key + var/shape_key + var/size_key + var/color_key + var/phud_key + var/vis_flags_key + var/override_key + var/hide_flag + var/genital_flags + var/list/sizelist + var/list/shapelist + var/taurable + var/size_min + var/size_max + var/size_name + var/size_units + var/one_or_some + +/datum/genital_data/New(obj/item/organ/genital/nad) + shapelist = nad.GetShapeList() + sizelist = nad.GetSizeList() + taurable = nad.CanTaur() + size_min = nad.GetMinSize() + size_max = nad.GetMaxSize() + size_name = nad.GetSizeKind() + has_key = nad.associated_has + shape_key = nad.shape_key + size_key = nad.size_key + color_key = nad.color_key + phud_key = nad.pornhud_slot + vis_flags_key = nad.vis_flags_key + override_key = nad.override_key + hide_flag = nad.hide_flag + name = nad.name + genital_flags = nad.genital_flags + size_units = nad.size_units + one_or_some = nad.one_or_some + if(!pref_cat_2_words[has_key]) + pref_cat_2_words[has_key] = "[name]" + +/datum/genital_data/proc/SizeString(size) + var/out = size_name + out = replacetext(out, "", "[capitalize(size)]") + if(isnum(size) && size > 1) + out = replacetext(out, "", "s") + out = replacetext(out, "", "es") + else + out = replacetext(out, "", "") + out = replacetext(out, "", "") + return out + +/datum/genital_data/proc/CanHave() + if(!has_key) + return FALSE + if(!(genital_flags & GENITAL_CAN_HAVE)) + return FALSE + return TRUE + +/datum/genital_data/proc/CanLayer() + if(!CanHave()) + return FALSE + if(!(genital_flags & GENITAL_INTERNAL)) + return FALSE + return TRUE + + + + + + + + + + diff --git a/code/modules/arousal/genitals.dm b/code/modules/arousal/genitals.dm index 407bf0997d..efe1e9ed5e 100644 --- a/code/modules/arousal/genitals.dm +++ b/code/modules/arousal/genitals.dm @@ -1,15 +1,24 @@ +GLOBAL_LIST_EMPTY(genital_data_system) /obj/item/organ/genital color = "#fcccb3" w_class = WEIGHT_CLASS_SMALL organ_flags = ORGAN_NO_DISMEMBERMENT|ORGAN_EDIBLE var/pornhud_slot = PHUD_NONE var/associated_has = CS_MISC // for cockstring stuff + var/shape_key + var/size_key + var/color_key + var/vis_flags_key + var/override_key + var/size_units = "Vix" + var/one_or_some = "one" + /// What flag is this associated with? + var/hide_flag = HIDE_MISC + var/pickable = FALSE // deprecated var/shape var/sensitivity = 1 // wow if this were ever used that'd be cool but it's not but i'm keeping it for my unshit code var/genital_flags //see citadel_defines.dm var/genital_visflags - /// What flag is this associated with? - var/hide_flag = HIDE_MISC var/masturbation_verb = "masturbate" var/orgasm_verb = "cumming" //present continous var/arousal_verb = "I feel aroused" @@ -30,6 +39,7 @@ var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in. /obj/item/organ/genital/Initialize(mapload, do_update = TRUE) + register_genital() . = ..() if(do_update) update() @@ -40,6 +50,11 @@ linked_organ = null . = ..() +/obj/item/organ/genital/proc/register_genital() + if(GLOB.genital_data_system["[associated_has]"]) + return // already registered! + GLOB.genital_data_system["[associated_has]"] = new /datum/genital_data(src) + /obj/item/organ/genital/proc/format_for_tgui() return @@ -485,6 +500,24 @@ G.Insert(src) return G +/obj/item/organ/genital/proc/GetShapeList() + return list() + +/obj/item/organ/genital/proc/GetSizeList() + return null + +/obj/item/organ/genital/proc/GetMinSize() + return + +/obj/item/organ/genital/proc/GetMaxSize() + return + +/obj/item/organ/genital/proc/CanTaur() + return + +/obj/item/organ/genital/proc/GetSizeKind() + return + /// Called when the giblet is first stuffed into the mob /obj/item/organ/genital/proc/get_features(mob/living/carbon/human/H, update = TRUE) return @@ -560,7 +593,7 @@ GLOBAL_LIST_INIT(genital_layers, list( //okay cool, compile a list of genitals that are visible var/list/genitals_to_add[GENITAL_LAYER_INDEX_LENGTH] var/has_nads = FALSE - var/list/nad_order = splittext(dna?.features["genital_order"], ":") // NOT reversed cus the reversal is only for UI shit + var/list/nad_order = dna?.features["genital_order"] // NOT reversed cus the reversal is only for UI shit for(var/obj/item/organ/genital/geni in internal_organs) if(geni.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes genitals_to_add[clamp(nad_order.Find(geni.associated_has), 1, GENITAL_LAYER_INDEX_LENGTH)] = geni diff --git a/code/modules/arousal/organs/belly.dm b/code/modules/arousal/organs/belly.dm index 3abe678650..9c6b7f73de 100644 --- a/code/modules/arousal/organs/belly.dm +++ b/code/modules/arousal/organs/belly.dm @@ -293,7 +293,7 @@ GLOBAL_LIST_INIT(belly_descriptors, list( slot = ORGAN_SLOT_BELLY w_class = WEIGHT_CLASS_NORMAL size = 1 - genital_flags = UPDATE_OWNER_APPEARANCE|GENITAL_CAN_RECOLOR|GENITAL_CAN_RESIZE|GENITAL_CAN_RESHAPE + genital_flags = DEF_BELLY_FLAGS layer_index = BELLY_LAYER_INDEX shape = DEF_BELLY_SHAPE // either tummy or obese masturbation_verb = "massage" @@ -301,6 +301,13 @@ GLOBAL_LIST_INIT(belly_descriptors, list( associated_has = CS_BELLY // for cockstring stuff hide_flag = HIDE_BELLY // for hideflag stuff pornhud_slot = PHUD_BELLY + shape_key = "belly_shape" + size_key = "belly_size" + color_key = "belly_color" + vis_flags_key = "belly_visibility_flags" + override_key = "belly_visibility_override" + size_units = "XL" + pickable = TRUE /obj/item/organ/genital/belly/format_for_tgui() var/list/out = list() @@ -389,8 +396,8 @@ GLOBAL_LIST_INIT(belly_descriptors, list( return "[size]XL" /obj/item/organ/genital/belly/resize_genital(mob/user) - var/min_size = CONFIG_GET(number/belly_min_size_prefs) - var/max_size = CONFIG_GET(number/belly_max_size_prefs) + var/min_size = GetMinSize() + var/max_size = GetMaxSize() var/new_size = input(user, "Belly size:\n([min_size]-[max_size])", "Character Preference") as num|null if(new_size) set_size(clamp(round(new_size), min_size, max_size)) @@ -407,6 +414,18 @@ GLOBAL_LIST_INIT(belly_descriptors, list( /obj/item/organ/genital/belly/get_sprite_accessory() return GLOB.belly_shapes_list[shape] +/obj/item/organ/genital/belly/GetShapeList() + return GLOB.belly_shapes_list + +/obj/item/organ/genital/belly/GetMinSize() + return BELLY_SIZE_MIN + +/obj/item/organ/genital/belly/GetMaxSize() + return BELLY_SIZE_MAX + +/obj/item/organ/genital/belly/GetSizeKind() + return "XL" + /obj/item/organ/genital/belly/get_layer_number(position) switch(position) if("FRONT") diff --git a/code/modules/arousal/organs/breasts.dm b/code/modules/arousal/organs/breasts.dm index 51e3deb7a0..1127fbc9e4 100644 --- a/code/modules/arousal/organs/breasts.dm +++ b/code/modules/arousal/organs/breasts.dm @@ -13,7 +13,7 @@ fluid_rate = MILK_RATE layer_index = BREAST_LAYER_INDEX shape = DEF_BREASTS_SHAPE - genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FLUID_PRODUCTION|GENITAL_CAN_AROUSE|UPDATE_OWNER_APPEARANCE|GENITAL_CAN_RECOLOR|GENITAL_CAN_RESIZE|GENITAL_CAN_RESHAPE + genital_flags = DEF_BREASTS_FLAGS masturbation_verb = "massage" arousal_verb = "My breasts start feeling sensitive" unarousal_verb = "My breasts no longer feel sensitive" @@ -22,6 +22,14 @@ associated_has = CS_BOOB // for cockstring stuff hide_flag = HIDE_BOOBS // for hideflag stuff pornhud_slot = PHUD_BOOB + shape_key = "breasts_shape" + size_key = "breasts_size" + color_key = "breasts_color" + vis_flags_key = "breasts_visibility_flags" + override_key = "breasts_visibility_override" + size_units = "Cupsize" + pickable = TRUE + one_or_some = "some" GLOBAL_LIST_INIT(breast_values, list( "a" = 1, @@ -204,7 +212,7 @@ GLOBAL_LIST_INIT(massive_breast_descriptors, list( return "[uppertext(size)]-cup" /obj/item/organ/genital/breasts/resize_genital(mob/user) - var/new_size = input(user, "Pick a new cup size", "Character Preference", size) as null|anything in CONFIG_GET(keyed_list/breasts_cups_prefs) + var/new_size = input(user, "Pick a new cup size", "Character Preference", size) as null|anything in GetSizeList() if(new_size) set_size(new_size) . = ..() @@ -235,6 +243,15 @@ GLOBAL_LIST_INIT(massive_breast_descriptors, list( /obj/item/organ/genital/breasts/get_sprite_accessory() return GLOB.breasts_shapes_list[shape] +/obj/item/organ/genital/breasts/GetShapeList() + return GLOB.breasts_shapes_list + +/obj/item/organ/genital/breasts/GetSizeList() + return GLOB.breast_values + +/obj/item/organ/genital/breasts/GetSizeKind() + return "-cup" + /obj/item/organ/genital/breasts/get_layer_number(position) switch(position) if("FRONT") diff --git a/code/modules/arousal/organs/butt.dm b/code/modules/arousal/organs/butt.dm index b5a0f71bad..1d846376cc 100644 --- a/code/modules/arousal/organs/butt.dm +++ b/code/modules/arousal/organs/butt.dm @@ -44,11 +44,18 @@ GLOBAL_LIST_INIT(butt_descriptors, list( var/size_name = "nonexistent" layer_index = BUTT_LAYER_INDEX shape = DEF_BUTT_SHAPE // unused - genital_flags = UPDATE_OWNER_APPEARANCE|GENITAL_CAN_RECOLOR|GENITAL_CAN_RESIZE + genital_flags = DEF_BUTT_FLAGS masturbation_verb = "massage" associated_has = CS_BUTT // for cockstring stuff hide_flag = HIDE_BUTT // for hideflag stuff pornhud_slot = PHUD_BUTT + shape_key = "butt_shape" + size_key = "butt_size" + color_key = "butt_color" + vis_flags_key = "butt_visibility_flags" + override_key = "butt_visibility_override" + size_units = "XL" + pickable = TRUE /obj/item/organ/genital/butt/format_for_tgui() var/list/out = list() @@ -163,6 +170,18 @@ GLOBAL_LIST_INIT(butt_descriptors, list( /obj/item/organ/genital/butt/get_sprite_accessory() return GLOB.butt_shapes_list[shape] +/obj/item/organ/genital/butt/GetShapeList() + return GLOB.butt_shapes_list + +/obj/item/organ/genital/butt/GetMinSize() + return BUTT_SIZE_MIN + +/obj/item/organ/genital/butt/GetMaxSize() + return BUTT_SIZE_MAX + +/obj/item/organ/genital/butt/GetSizeKind() + return "XL" + /obj/item/organ/genital/butt/get_layer_number(position) switch(position) if("FRONT") diff --git a/code/modules/arousal/organs/penis.dm b/code/modules/arousal/organs/penis.dm index 552ca7f4ac..660307d10a 100644 --- a/code/modules/arousal/organs/penis.dm +++ b/code/modules/arousal/organs/penis.dm @@ -8,7 +8,7 @@ masturbation_verb = "stroke" arousal_verb = "I pop a boner" unarousal_verb = "My boner goes down" - genital_flags = CAN_MASTURBATE_WITH|GENITAL_CAN_AROUSE|UPDATE_OWNER_APPEARANCE|GENITAL_CAN_TAUR|GENITAL_CAN_RECOLOR|GENITAL_CAN_RESIZE|GENITAL_CAN_RESHAPE + genital_flags = DEF_PENIS_FLAGS linked_organ_slot = ORGAN_SLOT_TESTICLES fluid_transfer_factor = 0.5 shape = DEF_COCK_SHAPE @@ -22,6 +22,13 @@ associated_has = CS_PENIS // for cockstring stuff hide_flag = HIDE_PENIS // for hideflag stuff pornhud_slot = PHUD_TALLYWHACKER + shape_key = "cock_shape" + size_key = "cock_size" + color_key = "cock_color" + vis_flags_key = "cock_visibility_flags" + override_key = "cock_visibility_override" + size_units = "Inches" + pickable = TRUE /obj/item/organ/genital/penis/format_for_tgui() var/list/out = list() @@ -124,8 +131,8 @@ return "[size] inch[size!=1?"es":""]" /obj/item/organ/genital/penis/resize_genital(mob/user) - var/min_size = CONFIG_GET(number/penis_min_inches_prefs) - var/max_size = CONFIG_GET(number/penis_max_inches_prefs) + var/min_size = GetMinSize() + var/max_size = GetMaxSize() var/new_length = input(user, "Penis length in inches:\n([min_size]-[max_size])", "Character Preference") as num|null if(new_length) set_size(clamp(round(new_length), min_size, max_size)) @@ -154,6 +161,22 @@ /obj/item/organ/genital/penis/get_sprite_accessory() return GLOB.cock_shapes_list[shape] +/// Returns its respective sprite accessory from the global list (full of init'd types, hopefully) +/obj/item/organ/genital/penis/GetShapeList() + return GLOB.cock_shapes_list + +/obj/item/organ/genital/penis/GetMinSize() + return COCK_SIZE_MIN + +/obj/item/organ/genital/penis/GetMaxSize() + return COCK_SIZE_MAX + +/obj/item/organ/genital/penis/GetSizeKind() + return " inch" + +/obj/item/organ/genital/penis/CanTaur() + return TRUE + /obj/item/organ/genital/penis/get_layer_number(position) switch(position) if("FRONT") diff --git a/code/modules/arousal/organs/testicles.dm b/code/modules/arousal/organs/testicles.dm index a2e0c29f46..232848189f 100644 --- a/code/modules/arousal/organs/testicles.dm +++ b/code/modules/arousal/organs/testicles.dm @@ -9,7 +9,7 @@ arousal_verb = "My balls ache a little" unarousal_verb = "My balls finally stop aching, again" linked_organ_slot = ORGAN_SLOT_PENIS - genital_flags = CAN_MASTURBATE_WITH|MASTURBATE_LINKED_ORGAN|GENITAL_FLUID_PRODUCTION|UPDATE_OWNER_APPEARANCE|GENITAL_CAN_RECOLOR|GENITAL_CAN_RESHAPE|GENITAL_CAN_RESIZE + genital_flags = DEF_BALLS_FLAGS var/size_name = "average" shape = DEF_BALLS_SHAPE fluid_id = /datum/reagent/consumable/semen @@ -18,6 +18,14 @@ associated_has = CS_BALLS // for cockstring stuff hide_flag = HIDE_BALLS // for hideflag stuff pornhud_slot = PHUD_BALLS + shape_key = "balls_shape" + size_key = "balls_size" + color_key = "balls_color" + vis_flags_key = "balls_visibility_flags" + override_key = "balls_visibility_override" + size_units = "Decigrundles" + pickable = TRUE + one_or_some = "some" /obj/item/organ/genital/testicles/format_for_tgui() var/list/out = list() @@ -102,6 +110,18 @@ /obj/item/organ/genital/testicles/get_sprite_accessory() return GLOB.balls_shapes_list[shape] +/obj/item/organ/genital/testicles/GetShapeList() + return GLOB.balls_shapes_list + +/obj/item/organ/genital/testicles/GetMinSize() + return BALLS_SIZE_MIN + +/obj/item/organ/genital/testicles/GetMaxSize() + return BALLS_SIZE_MAX + +/obj/item/organ/genital/testicles/GetSizeKind() + return " decigrundle" + /// fun fact, these used to be broken cus of a typo /obj/item/organ/genital/testicles/get_layer_number(position) switch(position) diff --git a/code/modules/arousal/organs/vagina.dm b/code/modules/arousal/organs/vagina.dm index e0bc17bf5e..eb380194c5 100644 --- a/code/modules/arousal/organs/vagina.dm +++ b/code/modules/arousal/organs/vagina.dm @@ -7,7 +7,7 @@ slot = "vagina" size = 1 //There is only 1 size right now shape = DEF_VAGINA_SHAPE - genital_flags = CAN_MASTURBATE_WITH|GENITAL_CAN_AROUSE|GENITAL_CAN_RECOLOR|GENITAL_CAN_RESHAPE + genital_flags = DEF_VAG_FLAGS masturbation_verb = "finger" arousal_verb = "I feel wetness on your crotch" unarousal_verb = "I no longer feel wet" @@ -22,7 +22,13 @@ var/list/vag_types = list("tentacle", "dentata", "hairy", "spade", "furred", "inconspicuous") associated_has = CS_VAG // for cockstring stuff hide_flag = HIDE_VAG // for hideflag stuff + shape_key = "vag_shape" + size_key = "vag_size" + color_key = "vag_color" + vis_flags_key = "vag_visibility_flags" + override_key = "vag_visibility_override" pornhud_slot = PHUD_VAG + pickable = TRUE /obj/item/organ/genital/vagina/format_for_tgui() var/list/out = list() @@ -111,6 +117,9 @@ /obj/item/organ/genital/vagina/get_sprite_accessory() return GLOB.vagina_shapes_list[shape] +/obj/item/organ/genital/vagina/GetShapeList() + return GLOB.vagina_shapes_list + /obj/item/organ/genital/vagina/get_layer_number(position) switch(position) if("FRONT") diff --git a/code/modules/arousal/organs/womb.dm b/code/modules/arousal/organs/womb.dm index dfe411738c..8fb6637e47 100644 --- a/code/modules/arousal/organs/womb.dm +++ b/code/modules/arousal/organs/womb.dm @@ -5,9 +5,15 @@ icon_state = "womb" zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_WOMB - genital_flags = GENITAL_INTERNAL|GENITAL_FLUID_PRODUCTION + genital_flags = DEF_WOMB_FLAGS fluid_id = /datum/reagent/consumable/semen/femcum linked_organ_slot = ORGAN_SLOT_VAGINA + shape_key = "womb_shape" + size_key = "womb_size" + color_key = "womb_color" + vis_flags_key = "womb_visibility_flags" + override_key = "womb_visibility_override" + pickable = TRUE /obj/item/organ/genital/womb/format_for_tgui() var/list/out = list() diff --git a/code/modules/asset_cache/asset_list_items.dm b/code/modules/asset_cache/asset_list_items.dm index 55bed7cd34..293113069e 100644 --- a/code/modules/asset_cache/asset_list_items.dm +++ b/code/modules/asset_cache/asset_list_items.dm @@ -1,5 +1,10 @@ //DEFINITIONS FOR ASSET DATUMS START HERE. +/datum/asset/simple/coolcss + assets = list( + "cool.css" = 'html/browser/cool.css', + ) + /datum/asset/simple/tgui_common keep_local_name = TRUE assets = list( @@ -153,7 +158,10 @@ /datum/asset/simple/namespaced/common assets = list("padlock.png" = 'icons/ui_icons/common/padlock.png') - parents = list("common.css" = 'html/browser/common.css') + parents = list( + "common.css" = 'html/browser/common.css', + "cool.css" = 'html/browser/cool.css', + ) /datum/asset/simple/permissions assets = list( diff --git a/code/modules/client/OLD_PREFS_JUNK.dm b/code/modules/client/OLD_PREFS_JUNK.dm new file mode 100644 index 0000000000..b56f063ec2 --- /dev/null +++ b/code/modules/client/OLD_PREFS_JUNK.dm @@ -0,0 +1,3744 @@ +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +/// DONT TICK THIS FILE + +/* + dat += "

Quest Board UID

" + dat += "[quester_uid]
" + var/cash_change = SSeconomy.player_login(src) + var/list/llogin_msg = list() + llogin_msg += "
Last Login: [time2text(last_quest_login)]" + llogin_msg += " Banked Cash: [SSeconomy.format_currency(saved_unclaimed_points, TRUE)]" + if(cash_change > 0) + llogin_msg += " ([span_green("[SSeconomy.format_currency(cash_change, TRUE)]")] activity bonus)" + else if(cash_change < 0) + llogin_msg += " ([span_alert("[SSeconomy.format_currency(cash_change, TRUE)]")] inactivity tax)" + llogin_msg += "
" + dat += llogin_msg.Join() + if(CONFIG_GET(flag/roundstart_traits)) + dat += "
" + if(SSquirks.initialized && !(PMC_QUIRK_OVERHAUL_2K23 in current_version)) + dat += "CLICK HERE to migrate your old quirks to the new system!" + dat += "" + dat += "

Configure Quirks


" + dat += "" + dat += "
Current Quirks: [get_my_quirks()]
" + dat += "

S.P.E.C.I.A.L.

" + dat += "Allocate Points
" + //Left Column + dat += "" + // //Middle Column + // dat +="" + + //Right column + dat +="" + /* + dat += "Special Names:
" + var/old_group + for(var/custom_name_id in GLOB.preferences_custom_names) + var/namedata = GLOB.preferences_custom_names[custom_name_id] + if(!old_group) + old_group = namedata["group"] + else if(old_group != namedata["group"]) + old_group = namedata["group"] + dat += "
" + dat += "[namedata["pref_name"]]: [custom_names[custom_name_id]] " + dat += "

" + + Records disabled until a use for them is found + dat += "Custom job preferences:
" + dat += "Preferred AI Core Display: [preferred_ai_core_display]
" + dat += "Preferred Security Department: [prefered_security_department]
" + dat += "
Records
" + dat += "
Security Records
" + if(length_char(security_records) <= 40) + if(!length(security_records)) + dat += "\[...\]" + else + dat += "[security_records]" + else + dat += "[TextPreview(security_records)]...
" + + dat += "
Medical Records
" + if(length_char(medical_records) <= 40) + if(!length(medical_records)) + dat += "\[...\]
" + else + dat += "[medical_records]" + else + dat += "[TextPreview(medical_records)]...
" + dat += "
Hide ckey: [hide_ckey ? "Enabled" : "Disabled"]
" + */ + dat += "
" + dat += "

Identity

" + if(jobban_isbanned(user, "appearance")) + dat += "You are banned from using custom names and appearances. You can continue to adjust your characters, but you will be randomised once you join the game.
" + + dat += "Configure VisualChat / Profile Pictures!
" + dat += "Name: " + dat += "[real_name]
" + + dat += "Gender: [gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" + dat += "Age: [age]
" + dat += "Top/Bottom/Switch: [tbs || "Set me!"]
" + dat += "Orientation: [kisser || "Set me!"]
" + dat += "When you despawn, all your equipment... [stash_equipment_on_logout?"will be left where you despawn":"will be deleted"]
" + dat += "Your equipment, if left behind... [lock_equipment_on_logout?"will be locked (only you can open it)":"will be open for everyone"]
" + dat += "
" + // dat += "

Matchmaking preferences:

" + // if(SSmatchmaking.initialized) + // for(var/datum/matchmaking_pref/match_pref as anything in SSmatchmaking.all_match_types) + // var/max_matches = initial(match_pref.max_matches) + // if(!max_matches) + // continue // Disabled. + // var/current_value = clamp((matchmaking_prefs[match_pref] || 0), 0, max_matches) + // var/set_name = !current_value ? "Disabled" : (max_matches == 1 ? "Enabled" : "[current_value]") + // dat += "[initial(match_pref.pref_text)]: [set_name]
" + // else + // dat += "Loading matchmaking preferences...
" + // dat += "Refresh once the game has finished setting up...
" + // dat += "
" + dat += "Configure VisualChat / Profile Pictures!
" + // dat += "

Profile Picture ([pfphost]):


" + var/pfplink = SSchat.GetPicForMode(user, MODE_PROFILE_PIC) + dat += "Picture: [pfplink ? "" : "Upload a picture!"]
" + dat += "
" + */ + + + + +/* + for(var/mutant_part in GLOB.all_mutant_parts) + if(mutant_part == "mam_body_markings") + continue + if(parent.can_have_part(mutant_part)) + if(!mutant_category) + dat += APPEARANCE_CATEGORY_COLUMN + dat += "

[GLOB.all_mutant_parts[mutant_part]]

" + dat += "[features[mutant_part]]" + var/color_type = GLOB.colored_mutant_parts[mutant_part] //if it can be coloured, show the appropriate button + if(color_type) + dat += "    Change
" + else + if(features["color_scheme"] == ADVANCED_CHARACTER_COLORING) //advanced individual part colouring system + //is it matrixed or does it have extra parts to be coloured? + var/find_part = features[mutant_part] || pref_species.mutant_bodyparts[mutant_part] + var/find_part_list = GLOB.mutant_reference_list[mutant_part] + if(find_part && find_part != "None" && find_part_list) + var/datum/sprite_accessory/accessory = find_part_list[find_part] + if(accessory) + if(accessory.color_src == MATRIXED || accessory.color_src == MUTCOLORS || accessory.color_src == MUTCOLORS2 || accessory.color_src == MUTCOLORS3) //mutcolors1-3 are deprecated now, please don't rely on these in the future + var/mutant_string = accessory.mutant_part_string + var/primary_feature = "[mutant_string]_primary" + var/secondary_feature = "[mutant_string]_secondary" + var/tertiary_feature = "[mutant_string]_tertiary" + if(!features[primary_feature]) + features[primary_feature] = features["mcolor"] + if(!features[secondary_feature]) + features[secondary_feature] = features["mcolor2"] + if(!features[tertiary_feature]) + features[tertiary_feature] = features["mcolor3"] + + var/matrixed_sections = accessory.matrixed_sections + if(accessory.color_src == MATRIXED && !matrixed_sections) + message_admins("Sprite Accessory Failure (customization): Accessory [accessory.type] is a matrixed item without any matrixed sections set!") + continue + else if(accessory.color_src == MATRIXED) + switch(matrixed_sections) + if(MATRIX_GREEN) //only composed of a green section + primary_feature = secondary_feature //swap primary for secondary, so it properly assigns the second colour, reserved for the green section + if(MATRIX_BLUE) + primary_feature = tertiary_feature //same as above, but the tertiary feature is for the blue section + if(MATRIX_RED_BLUE) //composed of a red and blue section + secondary_feature = tertiary_feature //swap secondary for tertiary, as blue should always be tertiary + if(MATRIX_GREEN_BLUE) //composed of a green and blue section + primary_feature = secondary_feature //swap primary for secondary, as first option is green, which is linked to the secondary + secondary_feature = tertiary_feature //swap secondary for tertiary, as second option is blue, which is linked to the tertiary + dat += "Primary Color
" + dat += "    Change
" + if((accessory.color_src == MATRIXED && (matrixed_sections == MATRIX_RED_BLUE || matrixed_sections == MATRIX_GREEN_BLUE || matrixed_sections == MATRIX_RED_GREEN || matrixed_sections == MATRIX_ALL)) || (accessory.extra && (accessory.extra_color_src == MUTCOLORS || accessory.extra_color_src == MUTCOLORS2 || accessory.extra_color_src == MUTCOLORS3))) + dat += "Secondary Color
" + dat += "    Change
" + if((accessory.color_src == MATRIXED && matrixed_sections == MATRIX_ALL) || (accessory.extra2 && (accessory.extra2_color_src == MUTCOLORS || accessory.extra2_color_src == MUTCOLORS2 || accessory.extra2_color_src == MUTCOLORS3))) + dat += "Tertiary Color
" + dat += "    Change
" + + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) + dat += "" + mutant_category = 0 + */ + +/* + + // START COLUMN 1 + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Body

" + + dat += "Species:[pref_species.name]
" + + if(LAZYLEN(pref_species.alt_prefixes)) + dat += "Alt Appearance:[alt_appearance ? alt_appearance : "Select"]
" + + dat += "Custom Species Name:[custom_species ? custom_species : "None"]
" + + dat += "Gender:[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" + + if(gender != NEUTER && pref_species.sexes) + dat += "Body Model:[features["body_model"] == MALE ? "Masculine" : "Feminine"]
" + + if(length(pref_species.allowed_limb_ids)) + if(!chosen_limb_id || !(chosen_limb_id in pref_species.allowed_limb_ids)) + chosen_limb_id = pref_species.limbs_id || pref_species.id + dat += "Body Sprite:[chosen_limb_id]
" + dat += "" + dat += APPEARANCE_CATEGORY_COLUMN + var/use_skintones = pref_species.use_skintones + var/mutant_colors + if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits)) + if(!use_skintones) + dat += "Primary Color:
" + dat += "    Change
" + + dat += "Secondary Color:
" + dat += "    Change
" + + dat += "Tertiary Color:
" + dat += "    Change
" + mutant_colors = TRUE + + if(use_skintones) + dat += "

Skin Tone

" + dat += "[use_custom_skin_tone ? "custom:    " : skin_tone]
" + + if (CONFIG_GET(number/body_size_min) != CONFIG_GET(number/body_size_max)) + dat += "Sprite Size: [features["body_size"]*100]%
" + if (CONFIG_GET(number/body_width_min) != CONFIG_GET(number/body_width_max)) + dat += "Sprite Width: [features["body_width"]*100]%
" + dat += "Scaling: [fuzzy ? "Fuzzy" : "Sharp"]
" + + + dat += "" + // END COLUMN 1 + // START COLUMN 2 + dat += APPEARANCE_CATEGORY_COLUMN + if(!(NOEYES in pref_species.species_traits)) + dat += "

Eyes

" + dat += "[eye_type]" + if((EYECOLOR in pref_species.species_traits)) + if(!use_skintones && !mutant_colors) + dat += APPEARANCE_CATEGORY_COLUMN + if(left_eye_color != right_eye_color) + split_eye_colors = TRUE + dat += "[eye_over_hair ? "Over Hair" : "Under Hair"]" + dat += "Heterochromia
" + dat += "[split_eye_colors ? "Enabled" : "Disabled"]" + if(!split_eye_colors) + dat += "Eye Color
" + dat += "    Change
" + else + dat += "Left Color
" + dat += "    Change
" + dat += "Right Color
" + dat += "    Change
" + // END COLUMN 2 + dat += APPEARANCE_CATEGORY_COLUMN + if(HAIR in pref_species.species_traits) + dat += "

Hair

" + dat += "Style Up:
" + dat += "[hair_style]
" + dat += "
< >
" + dat += "    Change

" + + // Coyote ADD: Hair gradients + dat += "Gradient Up:
" + dat += "[features_override["grad_style"]]" + dat += "    Change

" + // Coyote ADD: End + + dat += "Style Down:
" + dat += "[features_override["hair_style_2"]]" + dat += "< >
" + dat += "    Change

" + + dat += "Gradient Down:
" + dat += "[features_override["grad_style_2"]]" + dat += "    Change

" + + dat += "Facial Style:
" + dat += "[facial_hair_style]
" + dat += "
< >
" + dat += "    Change

" + + dat += "Show/hide Undies:
" + dat += "[preview_hide_undies ? "Hidden" : "Visible"]
" + + dat += "" + + //end column 3 or something + //start column 4 + dat += APPEARANCE_CATEGORY_COLUMN + //Waddling + dat += "

Waddling

" + dat += "Waddle Amount:
[waddle_amount]
" + if(waddle_amount > 0) + dat += "↔ Speed:[up_waddle_time]
" + dat += "↕ Speed:[side_waddle_time]
" + + + dat += "

Misc

" + dat += "Custom Taste:[features["taste"] ? features["taste"] : "something"]
" + dat += "Runechat Color:#[features["chat_color"]]
" + dat += "Blood Color:#[features["blood_color"]]
" + dat += "Reset Blood Color
" + dat += "Rainbow Blood Color
" + dat += "Background:[bgstate]
" + dat += "Pixel Offsets
" + var/px = custom_pixel_x > 0 ? "+[custom_pixel_x]" : "[custom_pixel_x]" + var/py = custom_pixel_y > 0 ? "+[custom_pixel_y]" : "[custom_pixel_y]" + dat += "↔[px]
" + dat += "↕[py]
" + + dat += "" + //Mutant stuff + var/mutant_category = 0 + mutant_category++ + if(mutant_category >= MAX_MUTANT_ROWS) //just in case someone sets the max rows to 1 or something dumb like that + dat += "" + mutant_category = 0 + + // rp marking selection + // assume you can only have mam markings or regular markings or none, never both + var/marking_type + dat += APPEARANCE_CATEGORY_COLUMN + if(parent.can_have_part("mam_body_markings")) + marking_type = "mam_body_markings" + if(marking_type) + dat += "

[GLOB.all_mutant_parts[marking_type]]

" // give it the appropriate title for the type of marking + dat += "Add marking" + // list out the current markings you have + if(length(features[marking_type])) + dat += "" + var/list/markings = features[marking_type] + if(!islist(markings)) + // something went terribly wrong + markings = list() + var/list/reverse_markings = reverseList(markings) + for(var/list/marking_list in reverse_markings) + var/marking_index = markings.Find(marking_list) // consider changing loop to go through indexes over lists instead of using Find here + var/limb_value = marking_list[1] + var/actual_name = GLOB.bodypart_names[num2text(limb_value)] // get the actual name from the bitflag representing the part the marking is applied to + var/color_marking_dat = "" + var/number_colors = 1 + var/datum/sprite_accessory/mam_body_markings/S = GLOB.mam_body_markings_list[marking_list[2]] + var/matrixed_sections = S.covered_limbs[actual_name] + if(S && matrixed_sections) + // if it has nothing initialize it to white + if(length(marking_list) == 2) + var/first = "#FFFFFF" + var/second = "#FFFFFF" + var/third = "#FFFFFF" + if(features["mcolor"]) + first = "#[features["mcolor"]]" + if(features["mcolor2"]) + second = "#[features["mcolor2"]]" + if(features["mcolor3"]) + third = "#[features["mcolor3"]]" + marking_list += list(list(first, second, third)) // just assume its 3 colours if it isnt it doesnt matter we just wont use the other values + // index magic + var/primary_index = 1 + var/secondary_index = 2 + var/tertiary_index = 3 + switch(matrixed_sections) + if(MATRIX_GREEN) + primary_index = 2 + if(MATRIX_BLUE) + primary_index = 3 + if(MATRIX_RED_BLUE) + secondary_index = 2 + if(MATRIX_GREEN_BLUE) + primary_index = 2 + secondary_index = 3 + + // we know it has one matrixed section at minimum + color_marking_dat += "   " + // if it has a second section, add it + if(matrixed_sections == MATRIX_RED_BLUE || matrixed_sections == MATRIX_GREEN_BLUE || matrixed_sections == MATRIX_RED_GREEN || matrixed_sections == MATRIX_ALL) + color_marking_dat += "   " + number_colors = 2 + // if it has a third section, add it + if(matrixed_sections == MATRIX_ALL) + color_marking_dat += "   " + number_colors = 3 + color_marking_dat += " Change
" + dat += "" + dat += "
[marking_list[2]] - [actual_name] ˄ ˅ X [color_marking_dat]
" + + +/////////////////////////////////////////////////////////////////////////////////// + if(mutant_category) + dat += "" + mutant_category = 0 + + dat += "" + + dat += "" + + dat += "" + /*Uplink choice disabled since not implemented, pointless button + dat += "Uplink Location:[uplink_spawn_loc]" + dat += ""*/ + + /// HA HA! I HAVE DELETED YOUR PRECIOUS NAUGHTY PARTS, YOU HORNY ANIMALS! + /* dat +="" // + if(NOGENITALS in pref_species.species_traits) + dat += "Your species ([pref_species.name]) does not support genitals!
" + else + dat += "

Penis

" + dat += "[features["has_cock"] == TRUE ? "Yes" : "No"]" + if(features["has_cock"]) + if(!pref_species.use_skintones) + dat += "Penis Color:
" + dat += "    Change
" + var/tauric_shape = FALSE + if(features["cock_taur"]) + var/datum/sprite_accessory/penis/P = GLOB.cock_shapes_list[features["cock_shape"]] + if(P.taur_icon && parent.can_have_part("taur")) + var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]] + if(T.taur_mode & P.accepted_taurs) + tauric_shape = TRUE + dat += "Penis Shape: [features["cock_shape"]][tauric_shape ? " (Taur)" : ""]" + dat += "Penis Length: [features["cock_length"]] inch(es)" + dat += "Penis Visibility:[features["cock_visibility"]]" + dat += "Has Testicles:[features["has_balls"] == TRUE ? "Yes" : "No"]" + if(features["has_balls"]) + if(!pref_species.use_skintones) + dat += "Testicles Type: [features["balls_shape"]]" + dat += "Testicles Color:
" + dat += "    Change
" + dat += "Testicles Visibility:[features["balls_visibility"]]" + dat += APPEARANCE_CATEGORY_COLUMN + dat += "

Vagina

" + dat += "[features["has_vag"] == TRUE ? "Yes": "No" ]" + if(features["has_vag"]) + dat += "Vagina Type: [features["vag_shape"]]" + if(!pref_species.use_skintones) + dat += "Vagina Color:
" + dat += "    Change
" + dat += "Vagina Visibility:[features["vag_visibility"]]" + dat += "Has Womb:[features["has_womb"] == TRUE ? "Yes" : "No"]" + dat += "" + dat += APPEARANCE_CATEGORY_COLUMN + dat += "

Breasts

" + dat += "[features["has_breasts"] == TRUE ? "Yes" : "No" ]" + if(features["has_breasts"]) + if(!pref_species.use_skintones) + dat += "Color:
" + dat += "    Change
" + dat += "Cup Size:[features["breasts_size"]]" + dat += "Breasts Shape:[features["breasts_shape"]]" + dat += "Breasts Visibility:[features["breasts_visibility"]]" + dat += "Lactates:[features["breasts_producing"] == TRUE ? "Yes" : "No"]" + dat += "" + dat += APPEARANCE_CATEGORY_COLUMN + dat += "

Belly

" + dat += "[features["has_belly"] == TRUE ? "Yes" : "No" ]" + if(features["has_belly"]) + if(!pref_species.use_skintones) + dat += "Color:
" + dat += "    Change
" + dat += "Belly Size:[features["belly_size"]]" + dat += "Belly Shape:[features["belly_shape"]]" + dat += "Belly Visibility:[features["belly_visibility"]]" + dat += "" + dat += APPEARANCE_CATEGORY_COLUMN + dat += "

Butt

" + dat += "[features["has_butt"] == TRUE ? "Yes" : "No"]" + if(features["has_butt"]) + if(!pref_species.use_skintones) + dat += "Color:
" + dat += "    Change
" + dat += "Butt Size:[features["butt_size"]]" + dat += "Butt Visibility:[features["butt_visibility"]]" + dat += "" + dat += "" + dat += ""*/ + + +/////////////////////////////////////////////////////// + if(NOGENITALS in pref_species.species_traits) + dat += "
Your species ([pref_species.name]) does not support genitals! These won't apply to your species!


" + dat += {" + Layering and Visibility + "} + dat += {" + Underwear and Socks + "} + dat += "
" + // here be gonads + for(var/dic in PREFS_ALL_HAS_GENITALS) + dat += {" + [GLOB.hasgenital2genital[dic]] + "} + dat += "" + dat += "
" + + switch(erp_tab_page) + if(ERP_TAB_REARRANGE) + var/list/all_genitals = decode_cockstring() // i made it i can call it whatever I want + var/list/genitals_we_have = list() + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + + for(var/nad in all_genitals) + genitals_we_have += nad + if(LAZYLEN(all_genitals)) + for(var/i in 1 to LAZYLEN(genitals_we_have)) + dat += add_genital_layer_piece(genitals_we_have[i], i, LAZYLEN(genitals_we_have)) + else + dat += "I dont seem to have any movable genitals!" + dat += "" + dat += "" + /* var/genital_shirtlayer + if(CHECK_BITFIELD(features["genital_visibility_flags"], GENITAL_ABOVE_UNDERWEAR)) + genital_shirtlayer = "Over Underwear" + else if(CHECK_BITFIELD(features["genital_visibility_flags"], GENITAL_ABOVE_CLOTHING)) + genital_shirtlayer = "Over Clothes" + else + genital_shirtlayer = "Under Underwear" */ + dat += {""} + + dat += {""} + dat += {""} + dat += "
ShiftHidden by...OverrideSee on others?
Hide Undies In Preview + + [preview_hide_undies ? "Hidden" : "Visible"] + + + Over Clothes + + + Whitelisted Names + +
" + if(ERP_TAB_HOME)/// UNDERWEAR GOES HERE + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += {"" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "
" + dat += "

Clothing & Equipment

" + dat += "
" + dat += "
Topwear
" + dat += {" + [undershirt] + "} + dat += {" + \t#[shirt_color] + "} + dat += {" + [LAZYACCESS(GLOB.undie_position_strings, undershirt_overclothes + 1)] + "} + dat += "
" + dat += "
Bottomwear
" + dat += {" + [underwear] + "} + dat += {" + \t#[undie_color] + "} + dat += {" + [LAZYACCESS(GLOB.undie_position_strings, undies_overclothes + 1)] + "} + dat += "
+
Legwear
+ + [socks] + "} + dat += {" + \t#[socks_color] + "} + dat += {" + [LAZYACCESS(GLOB.undie_position_strings, socks_overclothes + 1)] + "} + dat += "
" + dat += "
Backpack
" + dat += {" + [backbag] + "} + dat += "" + dat += "
" + dat += "
Persistent Scars
" + dat += {" + [persistent_scars ? "Enabled" : "Disabled"] + "} + dat += {" + \tClear them? + "} + dat += "
" + dat += "
Underwear Settings
" + dat += {" + Layered [underwear_overhands ? "OVER" : "UNDER"] hands + "} + dat += {" + Cuteness: 100% + "} + dat += "
" + dat += "
Hide Undies In Preview
" + dat += {" + [preview_hide_undies ? "Hidden" : "Visible"] + "} + dat += "
" + dat += "
PDA Style
" + dat += {" + [pda_skin] + "} + dat += "
" + dat += "
PDA Ringmessage
" + dat += {" + [pda_ringmessage] + "} + dat += "
" + if(PREFS_ALL_HAS_GENITALS_SET) // fuck it + dat += build_genital_setup() + + + */ + +/* + + + //calculate your gear points from the chosen item + gear_points = CONFIG_GET(number/initial_gear_points) + var/list/chosen_gear = loadout_data["SAVE_[loadout_slot]"] + if(chosen_gear) + for(var/loadout_item in chosen_gear) + var/loadout_item_path = loadout_item[LOADOUT_ITEM] + if(loadout_item_path) + var/datum/gear/loadout_gear = text2path(loadout_item_path) + if(loadout_gear) + gear_points -= initial(loadout_gear.cost) + else + chosen_gear = list() + + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + + dat += "" + + dat += "" + dat += "" + dat += "" + dat += "" + for(var/name in GLOB.loadout_items[gear_category][gear_subcategory]) + var/datum/gear/gear = GLOB.loadout_items[gear_category][gear_subcategory][name] + var/donoritem = gear.donoritem + if(donoritem && !gear.donator_ckey_check(user.ckey)) + continue + var/class_link = "" + var/list/loadout_item = has_loadout_gear(loadout_slot, "[gear.type]") + var/extra_loadout_data = "" + if(loadout_item) + class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=0'" + if(gear.loadout_flags & LOADOUT_CAN_NAME) + extra_loadout_data += "
Name [loadout_item[LOADOUT_CUSTOM_NAME] ? loadout_item[LOADOUT_CUSTOM_NAME] : "N/A"]" + if(gear.loadout_flags & LOADOUT_CAN_DESCRIPTION) + extra_loadout_data += "
Description" + if(gear.loadout_flags & LOADOUT_CAN_COLOR) + extra_loadout_data += "
Color   " + else if((gear_points - gear.cost) < 0) + class_link = "style='white-space:normal;' class='linkOff'" + else if(donoritem) + class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'" + else + class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'" + dat += "" + dat += "" + + dat += "
[gear_points] loadout points remaining. \[Clear Loadout\]
You can choose up to [MAX_FREE_PER_CAT] free items per category.
" + + if(!length(GLOB.loadout_items)) + dat += "
ERROR: No loadout categories - something is horribly wrong!" + else + if(!GLOB.loadout_categories[gear_category]) + gear_category = GLOB.loadout_categories[1] + var/firstcat = TRUE + for(var/category in GLOB.loadout_categories) + if(firstcat) + firstcat = FALSE + else + dat += " |" + if(category == gear_category) + dat += " [category] " + else + dat += " [category] " + + dat += "

" + + if(!length(GLOB.loadout_categories[gear_category])) + dat += "No subcategories detected. Something is horribly wrong!" + else + var/list/subcategories = GLOB.loadout_categories[gear_category] + if(!subcategories.Find(gear_subcategory)) + gear_subcategory = subcategories[1] + + var/firstsubcat = TRUE + for(var/subcategory in subcategories) + if(firstsubcat) + firstsubcat = FALSE + else + dat += " |" + if(gear_subcategory == subcategory) + dat += " [subcategory] " + else + dat += " [subcategory] " + dat += "
NameCostRestrictionsDescription
[name][extra_loadout_data][gear.cost]" + if(islist(gear.restricted_roles)) + if(gear.restricted_roles.len) + if(gear.restricted_desc) + dat += "" + dat += gear.restricted_desc + dat += "" + else + dat += "" + dat += gear.restricted_roles.Join(";") + dat += "" + // the below line essentially means "if the loadout item is picked by the user and has a custom description, give it the custom description, otherwise give it the default description" + //This would normally be part if an if else but because we dont have unlockable loadout items it's not + dat += "[loadout_item ? (loadout_item[LOADOUT_CUSTOM_DESCRIPTION] ? loadout_item[LOADOUT_CUSTOM_DESCRIPTION] : gear.description) : gear.description]
" + + */ + +/* + + dat += "" + if(user.client.holder) + dat +="" + + dat +="" + dat += "
" + dat += "

General Settings

" + dat += "Input Mode Hotkey: [input_mode_hotkey]
" + dat += "UI Style: [UI_style]
" + dat += "tgui Monitors: [(tgui_lock) ? "Primary" : "All"]
" + dat += "tgui Style: [(tgui_fancy) ? "Fancy" : "No Frills"]
" + dat += "Show Runechat Chat Bubbles: [chat_on_map ? "Enabled" : "Disabled"]
" + dat += "Runechat message char limit: [max_chat_length]
" + dat += "Runechat message width: [chat_width]
" + dat += "Runechat off-screen: [see_fancy_offscreen_runechat ? "Enabled" : "Disabled"]
" + dat += "See Runechat for non-mobs: [see_chat_non_mob ? "Enabled" : "Disabled"]
" + dat += "See Runechat emotes: [see_rc_emotes ? "Enabled" : "Disabled"]
" + dat += "Use Runechat color in chat log: [color_chat_log ? "Enabled" : "Disabled"]
" + dat += "
" + dat += "See Runechat / hear sounds above/below you: [hear_people_on_other_zs ? "Enabled" : "Disabled"]
" + dat += "
" + dat += "Action Buttons: [(buttons_locked) ? "Locked In Place" : "Unlocked"]
" + dat += "
" + dat += "PDA Color:     Change
" + //dat += "PDA Style: [pda_style]
" + //dat += "PDA Reskin: [pda_skin]
" + dat += "
" + dat += "Ghost Ears: [(chat_toggles & CHAT_GHOSTEARS) ? "All Speech":"Nearest Creatures"]
" + dat += "Ghost Radio: [(chat_toggles & CHAT_GHOSTRADIO) ? "All Messages":"No Messages"]
" + dat += "Ghost Sight: [(chat_toggles & CHAT_GHOSTSIGHT) ? "All Emotes":"Nearest Creatures" ]
" + dat += "Ghost Whispers: [(chat_toggles & CHAT_GHOSTWHISPER) ? "All Speech":"Nearest Creatures"]
" + dat += "Ghost PDA: [(chat_toggles & CHAT_GHOSTPDA) ? "All Messages" : "Nearest Creatures"]
" + //dat += "Window Flashing: [(windowflashing) ? "Enabled":"Disabled"]
" + dat += "
" + dat += "Play Hunting Horn Sounds: [(toggles & SOUND_HUNTINGHORN) ? "Enabled":"Disabled"]
" + dat += "Sprint Depletion Sound: [(toggles & SOUND_SPRINTBUFFER) ? "Enabled":"Disabled"]
" + dat += "Play Admin MIDIs: [(toggles & SOUND_MIDI) ? "Enabled":"Disabled"]
" + dat += "Play Lobby Music: [(toggles & SOUND_LOBBY) ? "Enabled":"Disabled"]
" + dat += "See Pull Requests: [(chat_toggles & CHAT_PULLR) ? "Enabled":"Disabled"]
" + dat += "
" + if(user.client) + if(unlock_content) + dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]
" + if(unlock_content || check_rights_for(user.client, R_ADMIN)) + dat += "OOC Color:     Change
" + dat += "Antag OOC Color:     Change
" + + dat += "
" + dat += "

Admin Settings

" + dat += "Adminhelp Sounds: [(toggles & SOUND_ADMINHELP)?"Enabled":"Disabled"]
" + dat += "Announce Login: [(toggles & ANNOUNCE_LOGIN)?"Enabled":"Disabled"]
" + dat += "
" + dat += "Combo HUD Lighting: [(toggles & COMBOHUD_LIGHTING)?"Full-bright":"No Change"]
" + dat += "Split Admin Tabs: [(toggles & SPLIT_ADMIN_TABS)?"Enabled":"Disabled"]
" + dat += "
" + dat += "

Preferences

" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe. + dat += "End of round deathmatch: [end_of_round_deathmatch ? "Enabled" : "Disabled"]
" + dat += "

Citadel Preferences

" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe. + dat += "Widescreen: [widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"]
" + dat += "Auto stand: [autostand ? "Enabled" : "Disabled"]
" + dat += "Auto OOC: [auto_ooc ? "Disabled" : "Enabled" ]
" + dat += "Force Slot Storage HUD: [no_tetris_storage ? "Enabled" : "Disabled"]
" + dat += "Gun Cursor: [(cb_toggles & AIM_CURSOR_ON) ? "Enabled" : "Disabled"]
" + dat += "Screen Shake: [(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")]
" + if (user && user.client && !user.client.prefs.screenshake==0) + dat += "Damage Screen Shake: [(damagescreenshake==1) ? "On" : ((damagescreenshake==0) ? "Off" : "Only when down")]
" + + dat += "Show Health Smileys: [show_health_smilies ? "Enabled" : "Disabled"]
" + dat += "
" + dat += "Max PFP Examine Image Height px: [see_pfp_max_hight]px
" + dat += "Max PFP Examine Image Width %: [see_pfp_max_widht]%
" + dat += "
" + if(unlock_content) + dat += "Ghost Form: [ghost_form]
" + dat += "Ghost Orbit: [ghost_orbit]
" + var/button_name = "If you see this something went wrong." + switch(ghost_accs) + if(GHOST_ACCS_FULL) + button_name = GHOST_ACCS_FULL_NAME + if(GHOST_ACCS_DIR) + button_name = GHOST_ACCS_DIR_NAME + if(GHOST_ACCS_NONE) + button_name = GHOST_ACCS_NONE_NAME + + dat += "Ghost Accessories: [button_name]
" + switch(ghost_others) + if(GHOST_OTHERS_THEIR_SETTING) + button_name = GHOST_OTHERS_THEIR_SETTING_NAME + if(GHOST_OTHERS_DEFAULT_SPRITE) + button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME + if(GHOST_OTHERS_SIMPLE) + button_name = GHOST_OTHERS_SIMPLE_NAME + + dat += "Ghosts of Others: [button_name]
" + dat += "
" + + dat += "FPS: [clientfps]
" + + dat += "Income Updates: [(chat_toggles & CHAT_BANKCARD) ? "Allowed" : "Muted"]
" + dat += "Hear Radio Static: [(chat_toggles & CHAT_HEAR_RADIOSTATIC) ? "Allowed" : "Muted"]
" + dat += "Hear Radio Blurbles: [(chat_toggles & CHAT_HEAR_RADIOBLURBLES) ? "Allowed" : "Muted"]
" + dat += "
" + + dat += "Parallax (Fancy Space): " + switch (parallax) + if (PARALLAX_LOW) + dat += "Low" + if (PARALLAX_MED) + dat += "Medium" + if (PARALLAX_INSANE) + dat += "Insane" + if (PARALLAX_DISABLE) + dat += "Disabled" + else + dat += "High" + dat += "
" + dat += "Ambient Occlusion: [ambientocclusion ? "Enabled" : "Disabled"]
" + dat += "Fit Viewport: [auto_fit_viewport ? "Auto" : "Manual"]
" + dat += "HUD Button Flashes: [hud_toggle_flash ? "Enabled" : "Disabled"]
" + dat += "HUD Button Flash Color:     Change
" + + if (CONFIG_GET(flag/maprotation) && CONFIG_GET(flag/tgstyle_maprotation)) + var/p_map = preferred_map + if (!p_map) + p_map = "Default" + if (config.defaultmap) + p_map += " ([config.defaultmap.map_name])" + else + if (p_map in config.maplist) + var/datum/map_config/VM = config.maplist[p_map] + if (!VM) + p_map += " (No longer exists)" + else + p_map = VM.map_name + else + p_map += " (No longer exists)" + if(CONFIG_GET(flag/allow_map_voting)) + dat += "Preferred Map: [p_map]
" + + dat += "" + + /*dat += "

Special Role Settings

" + + if(jobban_isbanned(user, ROLE_SYNDICATE)) + dat += "You are banned from antagonist roles." + src.be_special = list() + + + for (var/i in GLOB.special_roles) + if(jobban_isbanned(user, i)) + dat += "Be [capitalize(i)]: BANNED
" + else + var/days_remaining = null + if(ispath(GLOB.special_roles[i]) && CONFIG_GET(flag/use_age_restriction_for_jobs)) //If it's a game mode antag, check if the player meets the minimum age + var/mode_path = GLOB.special_roles[i] + var/datum/game_mode/temp_mode = new mode_path + days_remaining = temp_mode.get_remaining_days(user.client) + + if(days_remaining) + dat += "Be [capitalize(i)]: \[IN [days_remaining] DAYS]
" + else + dat += "Be [capitalize(i)]: [(i in be_special) ? "Enabled" : "Disabled"]
" + dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Enabled" : "Disabled"]
" + + dat += "
" + */ + + + dat += "
" + dat += "

Adult content prefs

" + dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"]
" + dat += "Genital examine text:[(cit_toggles & GENITAL_EXAMINE) ? "Enabled" : "Disabled"]
" + dat += "Ass Slapping: [(cit_toggles & NO_BUTT_SLAP) ? "Disallowed" : "Allowed"]
" + dat += "

Vore prefs

" + dat += "Master Vore Toggle: [(master_vore_toggle) ? "Per Preferences" : "All Disabled"]
" + if(master_vore_toggle) + dat += "Being Prey: [(allow_being_prey) ? "Allowed" : "Disallowed"]
" + dat += "Being Fed Prey: [(allow_being_fed_prey) ? "Allowed" : "Disallowed"]
" + dat += "Digestion Damage: [(allow_digestion_damage) ? "Allowed" : "Disallowed"]
" + dat += "Digestion Death: [(allow_digestion_death) ? "Allowed" : "Disallowed"]
" + dat += "Vore Messages: [(allow_vore_messages) ? "Visible" : "Hidden"]
" + dat += "Vore Trash Messages: [(allow_trash_messages) ? "Visible" : "Hidden"]
" + dat += "Vore Death Messages: [(allow_death_messages) ? "Visible" : "Hidden"]
" + dat += "Vore Eating Sounds: [(allow_eating_sounds) ? "Audible" : "Muted"]
" + dat += "Digestion Sounds: [(allow_digestion_sounds) ? "Audible" : "Muted"]
" + dat += "
" + dat += "
" + + dat += "" + dat += APPEARANCE_CATEGORY_COLUMN + + + + dat += "" + dat += APPEARANCE_CATEGORY_COLUMN + + dat += "

Voice

" + + // Coyote ADD: Blurbleblurhs + dat += "Voice Sound:[features_speech["typing_indicator_sound"]]
" + dat += "Voice When:[features_speech["typing_indicator_sound_play"]]
" + dat += "[features_speech["typing_indicator_speed"]]
" + dat += "[features_speech["typing_indicator_pitch"]]
" + dat += "[features_speech["typing_indicator_variance"]]
" + dat += "[features_speech["typing_indicator_volume"]]
" + dat += "[features_speech["typing_indicator_max_words_spoken"]]
" + dat += "" + + dat += APPEARANCE_CATEGORY_COLUMN + dat += "

Custom Say Verbs

" + dat += "Says" + dat += "
Whispers" + dat += "
Asks" + dat += "
Exclaims" + dat += "
Yells" + dat += "
Sings" + //dat += "
Preview Sound Indicator
" + dat += "" + // Coyote ADD: End + /// just kidding I moved it down here lol + + // Create an inverted list of keybindings -> key + var/list/user_binds = list() + var/list/user_modless_binds = list() + for (var/key in key_bindings) + for(var/kb_name in key_bindings[key]) + user_binds[kb_name] += list(key) + for (var/key in modless_key_bindings) + user_modless_binds[modless_key_bindings[key]] = key + + var/list/kb_categories = list() + // Group keybinds by category + for (var/name in GLOB.keybindings_by_name) + var/datum/keybinding/kb = GLOB.keybindings_by_name[name] + kb_categories[kb.category] += list(kb) + + dat += {" + + "} + + for (var/category in kb_categories) + dat += "

[category]

" + for (var/i in kb_categories[category]) + var/datum/keybinding/kb = i + var/current_independent_binding = user_modless_binds[kb.name] || "Unbound" + if(!length(user_binds[kb.name])) + dat += "[kb.full_name]Unbound" + var/list/default_keys = hotkeys ? kb.hotkey_keys : kb.classic_keys + if(LAZYLEN(default_keys)) + dat += "| Default: [default_keys.Join(", ")]" + dat += "" + if(!kb.special && !kb.clientside) + dat += "Independent Binding: [current_independent_binding]" + dat += "
" + else + var/bound_key = user_binds[kb.name][1] + dat += "[kb.full_name][bound_key]" + for(var/bound_key_index in 2 to length(user_binds[kb.name])) + bound_key = user_binds[kb.name][bound_key_index] + dat += " | [bound_key]" + if(length(user_binds[kb.name]) < MAX_KEYS_PER_KEYBIND) + dat += "| Add Secondary" + var/list/default_keys = hotkeys ? kb.classic_keys : kb.hotkey_keys + if(LAZYLEN(default_keys)) + dat += "| Default: [default_keys.Join(", ")]" + dat += "" + if(!kb.special && !kb.clientside) + dat += "Independent Binding: [current_independent_binding]" + dat += "
" + + dat += "

" + dat += "\[Reset to default\]" + dat += "" + + + */ + + + + + + + if(CONFIG_GET(flag/use_role_whitelist)) + user.client.set_job_whitelist_from_db() + + var/list/dat = list() + dat += CharacterList() + dat += CoolDivider() + dat += HeaderTabs() + dat += CoolDivider() + dat += SubTabs() + + switch(current_tab) + if(PPT_CHARCTER_PROPERTIES) + switch(current_subtab) + if(PPT_CHARCTER_PROPERTIES_INFO) + dat += CharacterProperties() + if(PPT_CHARCTER_PROPERTIES_VOICE) + dat += VoiceProperties() + if(PPT_CHARCTER_PROPERTIES_MISC) + dat += MiscProperties() + + //Character Appearance + if(PPT_CHARCTER_APPEARANCE) + if(current_subtab != PPT_CHARCTER_APPEARANCE_UNDERLYING) + dat += ColorToolbar() + switch(current_subtab) + if(PPT_CHARCTER_APPEARANCE_MISC) + dat += AppearanceMisc() + if(PPT_CHARCTER_APPEARANCE_HAIR_EYES) + dat += AppearanceHairEyes() + if(PPT_CHARCTER_APPEARANCE_PARTS) + dat += AppearanceParts() + if(PPT_CHARCTER_APPEARANCE_MARKINGS) + dat += AppearanceMarkings() + if(PPT_CHARCTER_APPEARANCE_UNDERLYING) + dat += SubSubTabs() + dat += ColorToolbar() + var/static/list/allnads = list() + if(!LAZYLEN(allnads)) + for(var/has_nad in GLOB.genital_data_system) + var/datum/genital_data/GD = GLOB.genital_data_system[has_nad] + if(GD.genital_flags & GENITAL_CAN_HAVE) + allnads += GD.has_key + switch(current_sub_subtab) + if(PPT_CHARCTER_APPEARANCE_UNDERLYING_UNDIES) + dat += AppearanceUnderlyingUndies() + if(PPT_CHARCTER_APPEARANCE_UNDERLYING_LAYERING) + dat += AppearanceUnderlyingLayering() + else + if(current_subtab in allnads) + dat += AppearanceUnderlyingGenitals() + else + dat += "OH NO! This is a bug! Please report it to the staff! Error code SNACKY SWEET SUNFISH" + + //Loadout heck + if(PPT_LOADOUT) + dat += Loadout() + + //Game Preferences + if(PPT_GAME_PREFERENCES) + switch(current_subtab) + if(PPT_GAME_PREFERENCES_GENERAL) + dat += GamePreferencesGeneral() + if(PPT_GAME_PREFERENCES_UI) + dat += GamePreferencesUI() + if(PPT_GAME_PREFERENCES_CHAT) + dat += GamePreferencesChat() + if(PPT_GAME_PREFERENCES_RUNECHAT) + dat += GamePreferencesRunechat() + if(PPT_GAME_PREFERENCES_GHOST) + dat += GamePreferencesGhost() + if(PPT_GAME_PREFERENCES_AUDIO) + dat += GamePreferencesAudio() + if(PPT_GAME_PREFERENCES_ADMIN) + dat += GamePreferencesAdmin() + if(PPT_GAME_PREFERENCES_CONTENT) + dat += GamePreferencesContent() + + + if(PPT_KEYBINDINGS) // Custom keybindings + dat += Keybindings() + + // dat += CoolDivider() + // dat += FooterBar() + + winset(user, "preferences_window", "is-visible=1;focus=0;") + var/datum/browser/popup = new(user, "preferences_browser", "
Character Setup - [real_name]
", 640, 770) + popup.set_content(dat.Join()) + popup.open(FALSE) + onclose(user, "preferences_window", src) + + +/datum/preferences/proc/HeaderTabs() + var/static/list/tablist = list( + "[PPT_CHARCTER_PROPERTIES]" = "Properties", + "[PPT_CHARCTER_APPEARANCE]" = "Appearance", + "[PPT_LOADOUT]" = "Loadout", + "new_row", + "[PPT_GAME_PREFERENCES]" = "Game Settings", + "[PPT_KEYBINDINGS]" = "Keybindings", + ) + var/list/dat = list() + dat += "
" + dat += "
" + dat += APPEARANCE_CATEGORY_COLUMN + dat += "

Flavor Text

" + dat += "Set Examine Text
" + dat += "Configure VisualChat / Profile Pictures!
" + if(length(features["flavor_text"]) <= 40) + if(!length(features["flavor_text"])) + dat += "\[...\]" + else + dat += "[features["flavor_text"]]" + else + dat += "[TextPreview(features["flavor_text"])]...
" + dat += "

Silicon Flavor Text

" + dat += "Set Silicon Examine Text
" + if(length(features["silicon_flavor_text"]) <= 40) + if(!length(features["silicon_flavor_text"])) + dat += "\[...\]" + else + dat += "[features["silicon_flavor_text"]]" + else + dat += "[TextPreview(features["silicon_flavor_text"])]...
" + dat += "

OOC notes

" + dat += "Set OOC notes
" + var/ooc_notes_len = length(features["ooc_notes"]) + if(ooc_notes_len <= 40) + if(!ooc_notes_len) + dat += "\[...\]
" + else + dat += "[features["ooc_notes"]]
" + else + dat += "[TextPreview(features["ooc_notes"])]...
" + + // dat += "Set Background Info Notes
" + // var/background_info_notes_len = length(features["background_info_notes"]) + // if(background_info_notes_len <= 40) + // if(!background_info_notes_len) + // dat += "\[...\]
" + // else + // dat += "[features["background_info_notes"]]
" + // else + // dat += "[TextPreview(features["background_info_notes"])]...
" + + //outside link stuff + dat += "

Outer hyper-links settings

" + dat += "Set F-list link
" + var/flist_len = length(features["flist"]) + if(flist_len <= 40) + if(!flist_len) + dat += "\[...\]" + else + dat += "[features["flist"]]" + else + dat += "[TextPreview(features["flist"])]...
" + + dat += "
" + dat += "" + var/colspan = 2 + for(var/supertab in tablist) + if(supertab == "new_row") + dat += "" + colspan = 3 // brilliant + else + dat += "" + dat += "" + dat += "
" + var/cspan = current_tab == supertab ? "TabCellselected" : "" + dat += PrefLink("[tablist["[supertab]"]]", PREFCMD_SET_TAB, list(PREFDAT_TAB = url_encode(supertab)), "BUTTON", cspan) + dat += "
" + if(!path) + dat += "
Hi Guest! You need to have a BYOND account to save anything.
" + dat += "" + return dat.Join() + +/datum/preferences/proc/SubTabs() + var/static/list/subtablist = list( + "[PPT_CHARCTER_PROPERTIES]" = list( + "[PPT_CHARCTER_PROPERTIES_INFO]" = "Background", + "[PPT_CHARCTER_PROPERTIES_VOICE]" = "Voice", + "[PPT_CHARCTER_PROPERTIES_MISC]" = "Miscellaneous", + ), + "[PPT_CHARCTER_APPEARANCE]" = list( + "[PPT_CHARCTER_APPEARANCE_MISC]" = "General", + "[PPT_CHARCTER_APPEARANCE_HAIR_EYES]" = "Hair & Eyes", + "[PPT_CHARCTER_APPEARANCE_PARTS]" = "Body Parts", + "[PPT_CHARCTER_APPEARANCE_MARKINGS]" = "Markings", + "[PPT_CHARCTER_APPEARANCE_UNDERLYING]" = "Unmentionables", + ), + "[PPT_GAME_PREFERENCES]" = list( + "[PPT_GAME_PREFERENCES_GENERAL]" = "General", + "[PPT_GAME_PREFERENCES_UI]" = "UI", + "[PPT_GAME_PREFERENCES_CHAT]" = "Chat", + "[PPT_GAME_PREFERENCES_RUNECHAT]" = "Runechat", + "[PPT_GAME_PREFERENCES_GHOST]" = "Ghost", + "[PPT_GAME_PREFERENCES_AUDIO]" = "Audio", + "[PPT_GAME_PREFERENCES_ADMIN]" = "Admin", + "[PPT_GAME_PREFERENCES_CONTENT]" = "Content", + ), + ) + var/static/list/subtablist_nonadmin = list( + "[PPT_CHARCTER_PROPERTIES]" = list( + "[PPT_CHARCTER_PROPERTIES_INFO]" = "Background", + "[PPT_CHARCTER_PROPERTIES_VOICE]" = "Voice", + "[PPT_CHARCTER_PROPERTIES_MISC]" = "Miscellaneous", + ), + "[PPT_CHARCTER_APPEARANCE]" = list( + "[PPT_CHARCTER_APPEARANCE_MISC]" = "General", + "[PPT_CHARCTER_APPEARANCE_HAIR_EYES]" = "Hair & Eyes", + "[PPT_CHARCTER_APPEARANCE_PARTS]" = "Body Parts", + "[PPT_CHARCTER_APPEARANCE_MARKINGS]" = "Markings", + "[PPT_CHARCTER_APPEARANCE_UNDERLYING]" = "Unmentionables", + ), + "[PPT_GAME_PREFERENCES]" = list( + "[PPT_GAME_PREFERENCES_GENERAL]" = "General", + "[PPT_GAME_PREFERENCES_UI]" = "UI", + "[PPT_GAME_PREFERENCES_CHAT]" = "Chat", + "[PPT_GAME_PREFERENCES_RUNECHAT]" = "Runechat", + "[PPT_GAME_PREFERENCES_AUDIO]" = "Audio", + "[PPT_GAME_PREFERENCES_CONTENT]" = "Content", + ), + ) + var/list/touse + if(check_rights(R_ADMIN, FALSE)) + touse = subtablist + else + touse = subtablist_nonadmin + if(!LAZYLEN(touse["[current_tab]"])) + return "" + var/list/dat = list() + dat += "
" + dat += "" + dat += "" + var/list/sub_listab = touse["[current_tab]"] + for(var/subtab in sub_listab) + dat += "" + dat += "" + dat += "
" + var/cspan = current_subtab == subtab ? "TabCellselected" : "" + var/textsay = "[sub_listab["[subtab]"]]" + dat += PrefLink(textsay, PREFCMD_SET_SUBTAB, list(PREFDAT_SUBTAB = url_encode(subtab)), span = cspan) + dat += "
" + dat += "
" + return dat.Join() + +/// sub tabs, for undies, genitals, and layering +/datum/preferences/proc/SubSubTabs() + var/list/dat = list() + dat += "
" + dat += "
" + dat += "
" + var/coolstyle = "flex-basis: 48%;" + var/undiespan = current_sub_subtab == PPT_CHARCTER_APPEARANCE_UNDERLYING_UNDIES ? "TabCellselected" : "" + dat += PrefLink("Underwear", PREFCMD_SET_SUBSUBTAB, list(PREFDAT_SUBSUBTAB = url_encode(PPT_CHARCTER_APPEARANCE_UNDERLYING_UNDIES)), span = undiespan, style = coolstyle) + var/layeringspan = current_sub_subtab == PPT_CHARCTER_APPEARANCE_UNDERLYING_LAYERING ? "TabCellselected" : "" + dat += PrefLink("Layering", PREFCMD_SET_SUBSUBTAB, list(PREFDAT_SUBSUBTAB = url_encode(PPT_CHARCTER_APPEARANCE_UNDERLYING_LAYERING)), span = layeringspan, style = coolstyle) + /// and now, the rest of the tabs + for(var/datum/genital_data/GD in GLOB.genital_data_system) + var/genispan = current_sub_subtab == GD.has_key ? "TabCellselected" : "" + dat += PrefLink(GD.name, PREFCMD_SET_SUBSUBTAB, list(PREFDAT_SUBSUBTAB = url_encode(GD.has_key)), span = genispan) + dat += "
" + dat += "
" + dat += "
" + return dat.Join() + +/datum/preferences/proc/CharacterList() + if(!path) + return "You're a guest! You can't save characters, you dorito!" + var/savefile/S = new /savefile(path) + if(!S) + return "Error loading savefile! Please contact an admin." + var/list/dat = list() + dat += "
" + dat += "
" + if(charlist_hidden) + dat += PrefLink("Show Character List", PREFCMD_TOGGLE_SHOW_CHARACTER_LIST) + dat += "
" + else + var/name + for(var/i=1, i<=min(max_save_slots, show_this_many), i++) + S.cd = "/character[i]" + S["real_name"] >> name + if(!name) + name = "Character[i]" + var/coolspan = i == default_slot ? "TabCellselected" : "" + dat += PrefLink("[name]", PREFCMD_CHANGE_SLOT, list(PREFDAT_SLOT = i), span = coolspan) + dat += "
" + dat += "
" + dat += "Showing [PrefLink("[show_this_many]", PREFCMD_SHOW_THIS_MANY_CHARS)] characters" + dat += "
" + dat += PrefLink("Copy", PREFCMD_SLOT_COPY) + dat += PrefLink("Paste", PREFCMD_SLOT_PASTE) + if(copyslot) + dat += "
Copying FROM: [copyslot] ([copyname])" + dat += "
" + dat += PrefLink("Hide Character List", PREFCMD_TOGGLE_SHOW_CHARACTER_LIST) + dat += "
" + dat += "" + return dat.Join() + + +/datum/preferences/proc/FooterBar() + var/list/dat = list() + dat += "
" + dat += PrefLink("Visual Chat Options", PREFCMD_VCHAT, span = "WideBarDark") + dat += PrefLink("Save", PREFCMD_SAVE, span = "WideBarDark") + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + return dat.Join() + +/datum/preferences/proc/CharacterProperties() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + var/pfplink = SSchat.GetPicForMode(src, MODE_PROFILE_PIC) + if(pfplink) + pfplink = "" + else + pfplink = "" + dat += "
" + dat += PrefLink(pfplink, PREFCMD_VCHAT) + dat += "
" + dat += "
" // End of DIV A A A A + dat += "
" // DIV A A A B + dat += "
" // DIV A A A B A + dat += "Name:" + dat += "
" // End of DIV A A A B A + dat += PrefLink("[real_name]", PREFCMD_CHANGE_NAME) + dat += "
" // End of DIV A A A B + dat += "
" // DIV A A A C + dat += "
" // DIV A A A C A + dat += "Age:" + dat += "
" // End of DIV A A A C A + dat += PrefLink("[age]", PREFCMD_CHANGE_AGE) + dat += "
" // End of DIV A A A C + dat += "
" // DIV A A A D + dat += "
" // DIV A A A D A + dat += "Gender:" + dat += "
" // End of DIV A A A D A + var/genwords = "amazing" + switch(gender) + if(MALE) + genwords = "Male" + if(FEMALE) + genwords = "Female" + if("object") + genwords = "Agender" + if("nonbinary") + genwords = "Nonbinary" + dat += PrefLink("[genwords]", PREFCMD_CHANGE_GENDER) + dat += "
" // End of DIV A A A D + dat += "
" // DIV A A A E + dat += "
" // DIV A A A E A + dat += "I am a..." + dat += "
" // End of DIV A A A E A + dat += PrefLink("[tbs]", PREFCMD_CHANGE_TBS) + dat += "
" // End of DIV A A A E + dat += "
" // DIV A A A F + dat += "
" // DIV A A A F A + dat += "I like to kiss..." + dat += "
" // End of DIV A A A F A + dat += PrefLink("[kisser]]", PREFCMD_CHANGE_KISSER) + dat += "
" // End of DIV A A A F + dat += "
" // End of DIV A A A + dat += "
" // End of DIV A A + dat += "
" // DIV A B + dat += "
" // DIV A B A + dat += "
" // DIV A B A A + dat += "
" // DIV A B A A A + dat += "Flavor Text:" + dat += "
" // End of DIV A B A A A + var/ftbutless = "[features["flavor_text"]]" + if(ftbutless == initial(features["flavor_text"])) + ftbutless = "Click to add flavor text!" + if(LAZYLEN(ftbutless) > 100) + ftbutless = copytext(ftbutless, 1, 100) + "..." + dat += PrefLink("[ftbutless]", PREFCMD_CHANGE_FLAVOR_TEXT) + dat += "
" // End of DIV A B A A + dat += "
" // DIV A B A B + dat += "
" // DIV A B A B A + dat += "OOC Notes:" + dat += "
" // End of DIV A B A B A + var/oocbutless = "[features["ooc_notes"]]" + if(oocbutless == initial(features["ooc_notes"])) + oocbutless = "Click to add OOC notes!" + if(LAZYLEN(oocbutless) > 100) + oocbutless = copytext(oocbutless, 1, 100) + "..." + dat += PrefLink("[oocbutless]", PREFCMD_CHANGE_OOC_NOTES) + dat += "
" // End of DIV A B A B + dat += "
" // End of DIV A B A + dat += "
" // End of DIV A B + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/VoiceProperties() + var/list/dat = list() + dat += "
" // DIV A + + dat += "
" // DIV A A + dat += "
" // DIV A A A + dat += "Blurble Sound" + dat += "
" // End of DIV A A A + dat += PrefLink("[features_speech["typing_indicator_sound"]]", PREFCMD_BLURBLE_SOUND, span = "SettingValue") + dat += "
" // End of DIV A A + + dat += "
" // DIV A B + dat += "
" // DIV A B A + dat += "You will blurble when you..." + dat += "
" // End of DIV A B A + dat += PrefLink("[features_speech["typing_indicator_sound_play"]]", PREFCMD_BLURBLE_TRIGGER, span = "SettingValue") + dat += "
" // End of DIV A B + + dat += "
" // DIV A B + dat += "
" // DIV A B A + dat += "Your blurbles will vary..." + dat += "
" // End of DIV A B A + dat += PrefLink("[features_speech["typing_indicator_variance"]]", PREFCMD_BLURBLE_VARY, span = "SettingValue") + dat += "
" // End of DIV A B + + dat += "
" // DIV A C + dat += "
" // DIV A C A + dat += "Blurble Speed" + dat += "
" // End of DIV A C A + dat += PrefLink("[features_speech["typing_indicator_speed"]]", PREFCMD_BLURBLE_SPEED, span = "SettingValue") + dat += "
" // End of DIV A C + + dat += "
" // DIV A D + dat += "
" // DIV A D A + dat += "Blurble Volume" + dat += "
" // End of DIV A D A + dat += PrefLink("[features_speech["typing_indicator_volume"]]", PREFCMD_BLURBLE_VOLUME, span = "SettingValue") + dat += "
" // End of DIV A D + + dat += "
" // DIV A E + dat += "
" // DIV A E A + dat += "Blurble Pitch" + dat += "
" // End of DIV A E A + dat += PrefLink("[features_speech["typing_indicator_pitch"]]", PREFCMD_BLURBLE_PITCH, span = "SettingValue") + dat += "
" // End of DIV A E + + dat += "
" // DIV A F + dat += "
" // DIV A F A + dat += "Max Words Blurbled" + dat += "
" // End of DIV A F A + dat += PrefLink("[features_speech["typing_indicator_max_words_spoken"]]", PREFCMD_BLURBLE_MAX_WORDS, span = "SettingValue") + dat += "
" // End of DIV A F + + dat += "
" // DIV A G + dat += "
" // DIV A G A + dat += "Runechat Color" + dat += "
" // End of DIV A G A + var/list/data = list(PREFDAT_COLKEY_IS_FEATURE = TRUE) + dat += ColorBox("runechat_color", data = data) + dat += "
" // End of DIV A G + + dat += "
" // DIV A H + dat += "
" // End of DIV A H ^ This is a spacer + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/MiscProperties() + var/list/dat = list() + dat += "
" // DIV Q + dat += "
" // DIV Q A + dat += "
" // DIV Q A A + dat += "
" // DIV Q A A A + dat += "
" // DIV Q A A A A + dat += "Account ID (Do not share!)" + dat += "
" // End of DIV Q A A A A + dat += "
" // DIV Q A A A B + dat += "[quester_uid]" + dat += "
" // End of DIV Q A A A B + dat += "
" // End of DIV Q A A A + dat += "
" // DIV Q A A B + dat += "
" // DIV Q A A B A + dat += "Account Balance" + dat += "
" // End of DIV Q A A B A + dat += "
" // DIV Q A A B B + dat += "[SSeconomy.format_currency(saved_unclaimed_points, TRUE)]" + dat += "
" // End of DIV Q A A B B + dat += "
" // End of DIV Q A A B + dat += "
" // End of DIV Q A A + dat += "
" // End of DIV Q A + dat += "
" // End of DIV Q + + dat += "
" // DIV A + + dat += "
" // DIV A A + dat += "
" // DIV A A A + dat += "PDA Kind" + dat += "
" // End of DIV A A A + dat += PrefLink("[pda_skin]", PREFCMD_PDA_KIND, span = "SettingValueCol") + dat += "
" // End of DIV A A + + dat += "
" // DIV A B + dat += "
" // DIV A B A + dat += "PDA Ringtone" + dat += "
" // End of DIV A B A + dat += PrefLink("[pda_ringmessage]", PREFCMD_PDA_RINGTONE, span = "SettingValueCol") + dat += "
" // End of DIV A B + + dat += "
" // DIV A C + dat += "
" // DIV A C A + dat += "PDA Color" + dat += "
" // End of DIV A C A + + var/list/data = list(PREFDAT_COLKEY_IS_VAR = TRUE) + dat += ColorBox("pda_color", data = data) + dat += "
" // End of DIV A C + + dat += "
" // DIV A D + dat += "
" // DIV A D A + dat += "Backpack Kind" + dat += "
" // End of DIV A D A + dat += PrefLink("[backbag]", PREFCMD_BACKPACK_KIND, span = "SettingValueCol") + dat += "
" // End of DIV A D + + dat += "
" // DIV A E + dat += "
" // DIV A E A + dat += "Persistent Scars" + dat += "
" // DIV A E A A + dat += "
" // DIV A E A A A + dat += PrefLink("[persistent_scars]", PREFCMD_SCARS, span = "SettingValueCol") + dat += "
" // End of DIV A E A A A + dat += "
" // DIV A E A A B + dat += PrefLink("Clear them?", PREFCMD_SCARS_CLEAR, span = "SettingValueCol") + dat += "
" // End of DIV A E A A B + dat += "
" // End of DIV A E A A + dat += "
" // End of DIV A E A + dat += "
" // End of DIV A E + + dat += "
" // DIV A F + dat += "
" // DIV A F A + dat += "Attribute Stats (Affects Rolls)" + dat += "
" // End of DIV A F A + dat += "
" // DIV A F B + + dat += "
" // DIV A F B A + dat += "
" // DIV A F B A A + dat += "Strength" + dat += "
" // End of DIV A F B A A + var/list/statthing = list(PREFDAT_STAT = "strength") + dat += PrefLink("[special_s]", PREFCMD_STAT_CHANGE, statthing, span = "SettingValueCol") + dat += "
" // End of DIV A F B A + + dat += "
" // DIV A F B B + dat += "
" // DIV A F B B A + dat += "Perception" + dat += "
" // End of DIV A F B B A + statthing = list(PREFDAT_STAT = "perception") + dat += PrefLink("[special_p]", PREFCMD_STAT_CHANGE, statthing, span = "SettingValueCol") + dat += "
" // End of DIV A F B B + + dat += "
" // DIV A F B C + dat += "
" // DIV A F B C A + dat += "Endurance" + dat += "
" // End of DIV A F B C A + statthing = list(PREFDAT_STAT = "endurance") + dat += PrefLink("[special_e]", PREFCMD_STAT_CHANGE, statthing, span = "SettingValueCol") + dat += "
" // End of DIV A F B C + + dat += "
" // DIV A F B D + dat += "
" // DIV A F B D A + dat += "Charisma" + dat += "
" // End of DIV A F B D A + statthing = list(PREFDAT_STAT = "charisma") + dat += PrefLink("[special_c]", PREFCMD_STAT_CHANGE, statthing, span = "SettingValueCol") + dat += "
" // End of DIV A F B D + + dat += "
" // DIV A F B E + dat += "
" // DIV A F B E A + dat += "Intelligence" + dat += "
" // End of DIV A F B E A + statthing = list(PREFDAT_STAT = "intelligence") + dat += PrefLink("[special_i]", PREFCMD_STAT_CHANGE, statthing, span = "SettingValueCol") + dat += "
" // End of DIV A F B E + + dat += "
" // DIV A F B F + dat += "
" // DIV A F B F A + dat += "Agility" + dat += "
" // End of DIV A F B F A + statthing = list(PREFDAT_STAT = "agility") + dat += PrefLink("[special_a]", PREFCMD_STAT_CHANGE, statthing, span = "SettingValueCol") + dat += "
" // End of DIV A F B F + + dat += "
" // DIV A F B G + dat += "
" // DIV A F B G A + dat += "Luck" + dat += "
" // End of DIV A F B G A + statthing = list(PREFDAT_STAT = "luck") + dat += PrefLink("[special_l]", PREFCMD_STAT_CHANGE, statthing, span = "SettingValueCol") + dat += "
" // End of DIV A F B G + + dat += "
" // DIV A F B G + dat += "
" // DIV A F B G A + dat += "Total" + dat += "
" // End of DIV A F B G A + var/total = special_s + special_p + special_e + special_c + special_i + special_a + special_l + var/maximum = 40 + statthing = list(PREFDAT_STAT = "luck") + dat += "
" // DIV A F B G A + dat += "[total] / [maximum]" + dat += "
" // End of DIV A F B G A + dat += "
" // End of DIV A F B G + + dat += "
" // End of DIV A F B + dat += "
" // End of DIV A F + + dat += "
" // DIV A G + dat += "
" // DIV A G B + dat += RowifyQuirks() + dat += "
" // End of DIV A G B + dat += "
" // End of DIV A G + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/AppearanceMisc() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + dat += "
" // DIV A A A + dat += "Species Type:" + dat += "
" // End of DIV A A A + var/specname = pref_species.name + dat += PrefLink(specname, PREFCMD_SPECIES) + dat += "
" // DIV A A B + dat += "Body model:" + dat += "
" // End of DIV A A B + var/bmod = "N/A" + if(gender != NEUTER && pref_species.sexes) // oh yeah, my pref species sexes a lot + features["body_model"] = gender == MALE ? "Masculine" : "Feminine" + dat += PrefLink(bmod, PREFCMD_BODY_MODEL) + if(LAZYLEN(pref_species.allowed_limb_ids)) + if(!chosen_limb_id || !(chosen_limb_id in pref_species.allowed_limb_ids)) + chosen_limb_id = pref_species.limbs_id || pref_species.id + dat += "
" // DIV A A C + dat += "Body Sprite:" + dat += "
" // End of DIV A A C + dat += PrefLink("[chosen_limb_id]", PREFCMD_BODY_SPRITE) + if(LAZYLEN(pref_species.alt_prefixes)) + dat += "
" // DIV A A C + dat += "Alt Style:" + dat += "
" // End of DIV A A C + var/altfix = alt_appearance ? "[alt_appearance]" : "Select" + dat += PrefLink(altfix, PREFCMD_ALT_PREFIX) + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + dat += "
" // DIV B + dat += "
" // DIV B A + dat += "
" // DIV B A A + dat += "Species Name:" + dat += "
" // End of DIV B A A + var/spename = custom_species ? custom_species : pref_species.name + dat += PrefLink(spename, PREFCMD_SPECIES_NAME) + dat += "
" // DIV B A B + dat += "Blood Color:" + dat += "
" // End of DIV B A B + if(features["blood_color"] == "") + features["blood_color"] = "FF0000" // red + var/list/data = list(PREFDAT_COLKEY_IS_FEATURE = TRUE) + dat += ColorBox("blood_color", data = data) + dat += "
" // DIV B A C + dat += "Rainbow Blood?" + dat += "
" // End of DIV B A C + var/rbw = features["blood_color"] == "rainbow" ? "Yes" : "No" + dat += PrefLink("[rbw]", PREFCMD_RAINBOW_BLOOD) + dat += "
" // End of DIV B A + dat += "
" // End of DIV B + dat += "
" // DIV C + dat += "
" // DIV C A + dat += "
" // DIV C A A + dat += "Meat Type:" + dat += "
" // End of DIV C A A + var/meat = features["meat_type"] || "Meaty" + dat += PrefLink("[meat]", PREFCMD_MEAT_TYPE) + dat += "
" // DIV C A B + dat += "Taste:" + dat += "
" // End of DIV C A B + if(!features["taste"]) + features["taste"] = "something" + var/tasted = features["taste"] || "somthing" + dat += PrefLink(tasted, PREFCMD_TASTE) + dat += "
" // End of DIV C A + dat += "
" // End of DIV C + dat += "
" // DIV D + dat += "
" // DIV D A + dat += "
" // DIV D A A + dat += "Scale:" + dat += "
" // End of DIV D A A + var/bscale = features["body_size"]*100 + dat += PrefLink("[bscale]", PREFCMD_SCALE) + dat += "
" // DIV D A B + dat += "Width:" + dat += "
" // End of DIV D A B + var/bwidth = features["body_width"]*100 + dat += PrefLink(bwidth, PREFCMD_WIDTH) + dat += "
" // DIV D A C + dat += "Scaling" + dat += "
" // End of DIV D A C + var/fuzsharp = fuzzy ? "Fuzzy" : "Sharp" + dat += PrefLink(fuzsharp, PREFCMD_FUZZY) + dat += "
" // End of DIV D A + dat += "
" // End of DIV D + dat += "
" // DIV E + dat += "
" // DIV E A + dat += "
" // DIV E A A + dat += "Offset ⇅" + dat += "
" // End of DIV E A A + var/pye = features["pixel_y"] > 0 ? "+[features["pixel_y"]]" : "[features["pixel_y"]]" + dat += PrefLink(pye, PREFCMD_PIXEL_Y) + dat += "
" // DIV E A B + dat += "Offset ⇆" + dat += "
" // End of DIV E A B + var/pxe = features["pixel_x"] > 0 ? "+[features["pixel_x"]]" : "[features["pixel_x"]]" + dat += PrefLink(pxe, PREFCMD_PIXEL_X) + dat += "
" // DIV E A C + dat += "Legs:" + dat += "
" // End of DIV E A C + var/d_legs = features["legs"] + dat += PrefLink(d_legs, PREFCMD_LEGS) + dat += "
" // End of DIV E A + var/use_skintones = pref_species.use_skintones + if(use_skintones) // humans suck + dat += "
" // DIV E B + dat += "
" // DIV E B A + dat += "Skintone:" + dat += "
" // End of DIV E B A + if(use_custom_skin_tone) + data = list(PREFDAT_COLKEY_IS_VAR = TRUE) + dat += ColorBox("skin_tone", data = data) + else + dat += PrefLink("[skin_tone]", PREFCMD_SKIN_TONE) + dat += "
" // End of DIV E B + dat += "
" // End of DIV E + return dat.Join() + +/datum/preferences/proc/AppearanceHairEyes() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + // ^^ you might be wondering why theres two of these + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "Eyes" + dat += "
" // End of DIV A A A A + dat += "
" // DIV A A A B + dat += "
" // DIV A A A B A + dat += "Style:" + dat += "
" // End of DIV A A A B A + dat += PrefLink("<", PREFCMD_EYE_TYPE, list(PREFDAT_GO_PREV = TRUE), span = "SmolBox") + dat += PrefLink(">", PREFCMD_EYE_TYPE, list(PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + dat += PrefLink(capitalize("[eye_type]"), PREFCMD_EYE_TYPE) + dat += "
" // DIV A A A B B + dat += "Left Color:" + dat += "
" // End of DIV A A A B B + var/list/feat_data = list(PREFDAT_COLKEY_IS_FEATURE = TRUE) + var/list/var_data = list(PREFDAT_COLKEY_IS_VAR = TRUE) + dat += ColorBox("left_eye_color", data = var_data) + dat += "
" // DIV A A A B C + dat += "Right Color:" + dat += "
" // End of DIV A A A B C + dat += ColorBox("right_eye_color", data = var_data) + dat += "
" // End of DIV A A A B + dat += "
" // End of DIV A A A + + dat += "
" // DIV A A B + dat += "
" // DIV A A B A + dat += "Hairea 1" + dat += "
" // End of DIV A A B A + dat += "
" // DIV A A B B + dat += "
" // DIV A A B B A + dat += "Style:" + dat += "
" // End of DIV A A B B A + dat += PrefLink("<", PREFCMD_HAIR_STYLE_1, list(PREFDAT_GO_PREV = TRUE), span = "SmolBox") + dat += PrefLink(">", PREFCMD_HAIR_STYLE_1, list(PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + dat += PrefLink("[hair_style]", PREFCMD_HAIR_STYLE_1) + dat += "
" // DIV A A B B B + dat += "Color:" + dat += "
" // End of DIV A A B B B + dat += ColorBox("hair_color", data = var_data) + dat += "
" // End of DIV A A B B + dat += "
" // DIV A A B C + dat += "
" // DIV A A B C A + dat += "Gradient:" + dat += "
" // End of DIV A A B C A + dat += PrefLink("<", PREFCMD_HAIR_GRADIENT_1, list(PREFDAT_GO_PREV = TRUE), span = "SmolBox") + dat += PrefLink(">", PREFCMD_HAIR_GRADIENT_1, list(PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + dat += PrefLink("[features["grad_style"]]", PREFCMD_HAIR_GRADIENT_1) + dat += "
" // DIV A A B C B + dat += "Color:" + dat += "
" // End of DIV A A B C B + dat += ColorBox("hair_gradient_color_1", data = feat_data) + dat += "
" // End of DIV A A B C + dat += "
" // End of DIV A A B + dat += "
" // End of DIV A A + dat += "
" // DIV A B + dat += "
" // DIV A B A + dat += "
" // DIV A B A A + dat += "Hairea 2" + dat += "
" // End of DIV A B A A + dat += "
" // DIV A B A B + dat += "
" // DIV A B A B A + dat += "Style:" + dat += "
" // End of DIV A B A B A + dat += PrefLink("<", PREFCMD_HAIR_STYLE_2, list(PREFDAT_GO_PREV = TRUE), span = "SmolBox") + dat += PrefLink(">", PREFCMD_HAIR_STYLE_2, list(PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + dat += PrefLink("[features["hair_style_2"]]", PREFCMD_HAIR_STYLE_2) + dat += "
" // DIV A B A B B + dat += "Color:" + dat += "
" // End of DIV A B A B B + dat += ColorBox("hair_color_2", data = feat_data) + dat += "
" // End of DIV A B A B + dat += "
" // DIV A B A C + dat += "
" // DIV A B A C A + dat += "Gradient:" + dat += "
" // End of DIV A B A C A + dat += PrefLink("<", PREFCMD_HAIR_GRADIENT_2, list(PREFDAT_GO_PREV = TRUE), span = "SmolBox") + dat += PrefLink(">", PREFCMD_HAIR_GRADIENT_2, list(PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + dat += PrefLink("[features["grad_style_2"]]", PREFCMD_HAIR_GRADIENT_2) + dat += "
" // DIV A B A C B + dat += "Color:" + dat += "
" // End of DIV A B A C B + dat += ColorBox("grad_color_2", data = feat_data) + dat += "
" // End of DIV A B A C + dat += "
" // End of DIV A B A + dat += "
" // End of DIV A B + dat += "
" // DIV A C + dat += "
" // DIV A C A + dat += "
" // DIV A C A A + dat += "Facial Hair" + dat += "
" // End of DIV A C A A + dat += "
" // DIV A C A B + dat += "
" // DIV A C A B A + dat += "Style:" + dat += "
" // End of DIV A C A B A + dat += PrefLink("<", PREFCMD_FACIAL_HAIR_STYLE, list(PREFDAT_GO_PREV = TRUE), span = "SmolBox") + dat += PrefLink(">", PREFCMD_FACIAL_HAIR_STYLE, list(PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + dat += PrefLink("[facial_hair_style]", PREFCMD_FACIAL_HAIR_STYLE) + dat += "
" // DIV A C A B B + dat += "Color:" + dat += "
" // End of DIV A C A B B + dat += ColorBox("facial_hair_color", data = var_data) + dat += "
" // End of DIV A C A B + dat += "
" // End of DIV A C A + dat += "
" // End of DIV A C + dat += "
" // End of DIV A + // As am I + return dat.Join() + +/// Body parts, body parts, getting me erect +/datum/preferences/proc/AppearanceParts() + var/list/dat = list() + dat += "
" // DIV A + // dat += "
" // DIV A A + // dat += "
" // DIV A A A + // var/mismash = "Show Mismatched Parts" + // if(show_all_parts) + // mismash = "Show Only Recommended Parts" + // dat += PrefLink("[mismash]", PREFCMD_MISMATCHED_MARKINGS, span = "SmolBox") + // dat += "" + // dat += "
" // End of DIV A A A + // dat += "
" // End of DIV A A + dat += "
" // DIV A A + for(var/mutant_part in GLOB.all_mutant_parts) + if(mutant_part == "mam_body_markings") + continue // we'll get to this + if(!parent.can_have_part(mutant_part)) + continue + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "
" // DIV A A A A A + dat += "[GLOB.all_mutant_parts[mutant_part]]" + dat += "
" // End of DIV A A A A A + dat += "
" // DIV A A A A B + dat += "
" // DIV A A A A B A + dat += "Style:" + dat += "
" // End of DIV A A A A B A + dat += PrefLink("<", PREFCMD_CHANGE_PART, list(PREFDAT_PARTKIND = mutant_part, PREFDAT_GO_PREV = TRUE), span = "SmolBox") + dat += PrefLink(">", PREFCMD_CHANGE_PART, list(PREFDAT_PARTKIND = mutant_part, PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + dat += PrefLink("[features[mutant_part]]", PREFCMD_CHANGE_PART, list(PREFDAT_PARTKIND = mutant_part)) + dat += "
" // End of DIV A A A A B + /// now for the hell that is *colors* + dat += "
" // DIV A A A A C + var/color_type = GLOB.colored_mutant_parts[mutant_part] + var/list/feat_data = list(PREFDAT_COLKEY_IS_FEATURE = TRUE) + if(color_type) + dat += ColorBox(color_type, data = feat_data) + else // this is the hell + if(features["color_scheme"] != ADVANCED_CHARACTER_COLORING) + features["color_scheme"] = ADVANCED_CHARACTER_COLORING // screw you, use it + var/find_part = features[mutant_part] || pref_species.mutant_bodyparts[mutant_part] + var/find_part_list = GLOB.mutant_reference_list[mutant_part] + if(!find_part || find_part == "None" || !find_part_list) + continue + var/datum/sprite_accessory/accessory = find_part_list[find_part] + if(!accessory) + continue + // fuuck you POOJ + if(accessory.color_src != MATRIXED && \ + accessory.color_src != MUTCOLORS && \ + accessory.color_src != MUTCOLORS2 && \ + accessory.color_src != MUTCOLORS3) + continue // something something mutcolors are deprecated, not that it matters + var/mutant_string = accessory.mutant_part_string + var/primary_feature = "[mutant_string]_primary" + var/secondary_feature = "[mutant_string]_secondary" + var/tertiary_feature = "[mutant_string]_tertiary" + /// these just sanitize the colors, pay no attention!!! + if(!features[primary_feature]) + features[primary_feature] = features["mcolor"] + if(!features[secondary_feature]) + features[secondary_feature] = features["mcolor2"] + if(!features[tertiary_feature]) + features[tertiary_feature] = features["mcolor3"] + var/matrixed_sections = accessory.matrixed_sections + if(accessory.color_src == MATRIXED) + if(!matrixed_sections) + message_admins("Sprite Accessory Failure (customization): Accessory [accessory.type] is a matrixed item without any matrixed sections set!") + continue + // this part properly shuffles the colors around becausE THANKS POOJ + switch(matrixed_sections) + if(MATRIX_GREEN) //only composed of a green section + primary_feature = secondary_feature //swap primary for secondary, so it properly assigns the second colour, reserved for the green section + if(MATRIX_BLUE) + primary_feature = tertiary_feature //same as above, but the tertiary feature is for the blue section + if(MATRIX_RED_BLUE) //composed of a red and blue section + secondary_feature = tertiary_feature //swap secondary for tertiary, as blue should always be tertiary + if(MATRIX_GREEN_BLUE) //composed of a green and blue section + primary_feature = secondary_feature //swap primary for secondary, as first option is green, which is linked to the secondary + secondary_feature = tertiary_feature //swap secondary for tertiary, as second option is blue, which is linked to the tertiary + // BUT WHAT ABOUT FULL RGB well tahts already set up + /// NOW, the colors are all set up, display the color pickers + dat += ColorBox(primary_feature, data = feat_data) + if(accessory.ShouldHaveSecondaryColor()) + dat += ColorBox(secondary_feature, data = feat_data) + if(accessory.ShouldHaveTertiaryColor()) + dat += ColorBox(tertiary_feature, data = feat_data) // WAS THAT SO HARD, POOJ? + dat += "
" // End of DIV A A A A C + dat += "
" // End of DIV A A A + dat += "
" // End of DIV A A + /// robot parts + dat += "
" // DIV A B + dat += "
" // DIV A B A + dat += "
" // DIV A B A A + dat += "Limb Modifications" + for(var/modification in modified_limbs) + dat += "
" + dat += "
" + dat += "[modification]" + dat += "
" + dat += PrefLink("X", PREFCMD_REMOVE_LIMB, list(PREFDAT_REMOVE_LIMB_MOD = modification), span = "SmolBox") + var/toshow = modified_limbs[modification][1] + if(toshow == LOADOUT_LIMB_PROSTHETIC) + toshow = modified_limbs[modification][2] + dat += PrefLink(toshow, PREFCMD_MODIFY_LIMB, list(PREFDAT_MODIFY_LIMB_MOD = modification)) + dat += "
" + dat += "
" // DIV A B A B + dat += PrefLink("+ Add Something!", PREFCMD_ADD_LIMB) + dat += "
" // End of DIV A B A B + dat += "
" // End of DIV A B A + dat += "
" // End of DIV A B + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/AppearanceMarkings() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + dat += "
" // DIV A A A + dat += "Cool Markings" + dat += "
" // End of DIV A A A + if(!parent.can_have_part("mam_body_markings")) + dat += "
" // DIV A A A B + dat += "Oh no, you can't have any! Tough luck :(" + dat += "
" // End of DIV A A A B + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + // we use mam markings, ma'am + if(LAZYLEN(features["mam_body_markings"])) + var/list/markings = features["mam_body_markings"] + if(!islist(markings)) + markings = list() + // we're gonna group em turnwise by the limb they're on + /// FORMAT: list("Head" = list(HTML glonch)) + var/list/markings_by_part = list() + var/list/rev_markings = reverseList(markings) + for(var/list/mark in rev_markings) + var/limb_value = mark[MARKING_LIMB_INDEX_NUM] + var/limb_name = GLOB.bodypart_names[num2text(limb_value)] + if(!markings_by_part[limb_name]) + markings_by_part[limb_name] = list() + mark = SanitizeMarking(mark) + /// make the HTML glonch + var/m_uid = mark[MARKING_UID] + var/cm_dat = "" + cm_dat += "
" // DIV A A A B A + cm_dat += "
" // DIV A A A B A A + cm_dat += "[mark[MARKING_NAME]]" + cm_dat += "
" // End of DIV A A A B A A + cm_dat += MarkingPrefLink( + "X", + PREFCMD_MARKING_REMOVE, + m_uid, + span = "SmolBox" + ) + cm_dat += MarkingPrefLink( + "↑", + PREFCMD_MARKING_MOVE_UP, + m_uid, + span = "SmolBox" + ) + cm_dat += MarkingPrefLink( + "↓", + PREFCMD_MARKING_MOVE_DOWN, + m_uid, + span = "SmolBox" + ) + cm_dat += MarkingPrefLink( + "<", + PREFCMD_MARKING_PREV, + m_uid, + span = "SmolBox" + ) + cm_dat += MarkingPrefLink( + ">", + PREFCMD_MARKING_NEXT, + m_uid, + span = "SmolBox" + ) + cm_dat += MarkingPrefLink( + "[mark[MARKING_NAME]]", + PREFCMD_MARKING_EDIT, + m_uid + ) + cm_dat += "
" // End of DIV A A A B A + /// and here come the colors + cm_dat += "
" // DIV A A A B B + var/datum/sprite_accessory/mam_body_markings/S = GLOB.mam_body_markings_list[mark[2]] + if(S) + var/matrixed_sections = S.covered_limbs[limb_name] + if(matrixed_sections) + // if it has nothing initialize it to white + if(LAZYLEN(mark) == 2) + mark.len = 3 + var/first = "#FFFFFF" + var/second = "#FFFFFF" + var/third = "#FFFFFF" + if(features["mcolor"]) + first = "#[features["mcolor"]]" + if(features["mcolor2"]) + second = "#[features["mcolor2"]]" + if(features["mcolor3"]) + third = "#[features["mcolor3"]]" + mark[MARKING_COLOR_LIST] = list(first, second, third) // just assume its 3 colours if it isnt it doesnt matter we just wont use the other values + // index magic + var/primary_index = 1 + var/secondary_index = 2 + var/tertiary_index = 3 + switch(matrixed_sections) + if(MATRIX_GREEN) + primary_index = 2 + if(MATRIX_BLUE) + primary_index = 3 + if(MATRIX_RED_BLUE) + secondary_index = 2 + if(MATRIX_GREEN_BLUE) + primary_index = 2 + secondary_index = 3 + cm_dat += MarkingColorBox(mark, primary_index) + if(matrixed_sections == MATRIX_RED_BLUE || \ + matrixed_sections == MATRIX_GREEN_BLUE || \ + matrixed_sections == MATRIX_RED_GREEN || \ + matrixed_sections == MATRIX_ALL) + cm_dat += MarkingColorBox(mark, secondary_index) + if(matrixed_sections == MATRIX_ALL) + cm_dat += MarkingColorBox(mark, tertiary_index) + cm_dat += "
" // End of DIV A A A B B + /// just kidding, we're not sorting anything! + markings_by_part += cm_dat + /// now we display the markings + for(var/part in markings_by_part) + dat += "[part]" + dat += "
" // DIV A A B + dat += PrefLink("+ Add Something!", PREFCMD_MARKING_ADD) + dat += "
" // End of DIV A A B + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + + +/datum/preferences/proc/AppearanceUnderlyingUndies() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "
" // DIV A A A A A + dat += "
" // DIV A A A A A A + dat += "Topwear" + dat += "
" // End of DIV A A A A A A + dat += "
" // DIV A A A A A B + dat += "
" // DIV A A A A A B A + dat += "Style:" + dat += "
" // End of DIV A A A A A B A + dat += PrefLink("<", PREFCMD_UNDERSHIRT, list(PREFDAT_GO_PREV = TRUE), span = "SmolBox") + dat += PrefLink(">", PREFCMD_UNDERSHIRT, list(PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + dat += PrefLink("[undershirt]", PREFCMD_UNDERSHIRT) + var/whereisit = LAZYACCESS(GLOB.undie_position_strings, undershirt_overclothes + 1) + dat += PrefLink("[whereisit]", PREFCMD_UNDERSHIRT_OVERCLOTHES, span = "SmolBox") + dat += "
" // End of DIV A A A A A B + dat += "
" // DIV A A A A A C + dat += "
" // DIV A A A A A C A + dat += "Color:" + dat += "
" // End of DIV A A A A A C A + var/list/data = list(PREFDAT_COLKEY_IS_VAR = TRUE) + dat += ColorBox("undershirt_color", data = data) + dat += "
" // End of DIV A A A A A C + dat += "
" // End of DIV A A A A A + dat += "
" // End of DIV A A A + dat += "
" // DIV A A A B + dat += "
" // DIV A A A B A + dat += "
" // DIV A A A B A A + dat += "Underwear" + dat += "
" // End of DIV A A A B A A + dat += "
" // DIV A A A B A B + dat += "
" // DIV A A A B A B A + dat += "Style:" + dat += "
" // End of DIV A A A B A B A + dat += PrefLink("<", PREFCMD_UNDERWEAR, list(PREFDAT_GO_PREV = TRUE), span = "SmolBox") + dat += PrefLink(">", PREFCMD_UNDERWEAR, list(PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + dat += PrefLink("[underwear]", PREFCMD_UNDERWEAR) + var/underwear_position = LAZYACCESS(GLOB.undie_position_strings, undies_overclothes + 1) + dat += PrefLink("[underwear_position]", PREFCMD_UNDERWEAR_OVERCLOTHES, span = "SmolBox") + dat += "
" // End of DIV A A A B A B + dat += "
" // DIV A A A B A C + dat += "
" // DIV A A A B A C A + dat += "Color:" + dat += "
" // End of DIV A A A B A C A + dat += ColorBox("undie_color", data = data) + dat += "
" // End of DIV A A A B A C + dat += "
" // End of DIV A A A B A + dat += "
" // End of DIV A A A + dat += "
" // DIV A A A C + dat += "
" // DIV A A A C A + dat += "
" // DIV A A A C A A + dat += "Socks" + dat += "
" // End of DIV A A A C A A + dat += "
" // DIV A A A C A B + dat += "
" // DIV A A A C A B A + dat += "Style:" + dat += "
" // End of DIV A A A C A B A + dat += PrefLink("<", PREFCMD_SOCKS, list(PREFDAT_GO_PREV = TRUE), span = "SmolBox") + dat += PrefLink(">", PREFCMD_SOCKS, list(PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + dat += PrefLink("[socks]", PREFCMD_SOCKS) + var/socks_position = LAZYACCESS(GLOB.undie_position_strings, socks_overclothes + 1) + dat += PrefLink("[socks_position]", PREFCMD_SOCKS_OVERCLOTHES, span = "SmolBox") + dat += "
" // End of DIV A A A C A B + dat += "
" // DIV A A A C A C + dat += "
" // DIV A A A C A C A + dat += "Color:" + dat += "
" // End of DIV A A A C A C A + dat += ColorBox("socks_color", data = data) + dat += "
" // End of DIV A A A C A C + dat += "
" // End of DIV A A A C A + dat += "
" // End of DIV A A A + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/AppearanceUnderlyingLayering() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" + dat += PrefLink("Undo", PREFCMD_UNDO) + dat += "" + dat += PrefLink("Delete", PREFCMD_SLOT_DELETE) + dat += "
" // DIV A A + // header row + dat += "" // DIV A A A + dat += "" // End of DIV A A A A + dat += "" // End of DIV A A A B + dat += "" // End of DIV A A A C + dat += "" // End of DIV A A A D + dat += "" // End of DIV A A A E + dat += "" // End of DIV A A A F + dat += "" // End of DIV A A A + /// now the true fun begins + /// okay we've all ahd our fun with the c_string, time to use json like a real adult + var/list/cakestring = features["genital_order"] + cakestring = reverseList(cakestring) // so the order makes sense + //cakestring should have every genital known to man, so this should be fine + // first, filter out any non-visible parts + for(var/haz_donk in cakestring) + var/datum/genital_data/GD = GLOB.genital_data_system[haz_donk] + if(!(GD.genital_flags & GENITAL_CAN_HAVE)) + cakestring -= haz_donk + continue + if(!(GD.genital_flags & GENITAL_INTERNAL)) + cakestring -= haz_donk + continue + var/index = 1 + for(var/has_donk in cakestring) + var/datum/genital_data/GD = GLOB.genital_data_system[has_donk] + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + dat += "" + index += 1 + dat += "" + dat += "" + dat += "" + dat += "
" // DIV A A A A + dat += "Part" + dat += "" // DIV A A A B + dat += "Shift" + dat += "" // DIV A A A C + dat += "Hidden by..." + dat += "" // DIV A A A D + dat += "Override" + dat += "" // DIV A A A E + dat += "See on others" + dat += "" // DIV A A A F + dat += "Has" + dat += "
" + dat += "[GD.name]" + dat += "" + if(index > 1) // dir is flipped, because the list is reversed + dat += PrefLink("↑", PREFCMD_SHIFT_GENITAL, list(PREFDAT_GENITAL_HAS = has_donk, PREFDAT_GO_PREV = TRUE), span = "SmolBox") + else + dat += " " + dat += "" + if(index < LAZYLEN(cakestring)) + dat += PrefLink("↓", PREFCMD_SHIFT_GENITAL, list(PREFDAT_GENITAL_HAS = has_donk, PREFDAT_GO_NEXT = TRUE), span = "SmolBox") + else + dat += " " + dat += "" + var/undiehidspan + if(features[GD.vis_flags_key] & GENITAL_RESPECT_UNDERWEAR) + undiehidspan = "TabCellselected" + dat += PrefLink("Underwear", PREFCMD_HIDE_GENITAL, list(PREFDAT_GENITAL_HAS = has_donk, PREFDAT_HIDDEN_BY = "undies"), span = undiehidspan) + dat += "" + var/clotheshidspan + if(features[GD.vis_flags_key] & GENITAL_RESPECT_CLOTHING) + clotheshidspan = "TabCellselected" + dat += PrefLink("Clothes", PREFCMD_HIDE_GENITAL, list(PREFDAT_GENITAL_HAS = has_donk, PREFDAT_HIDDEN_BY = "clothes"), span = clotheshidspan) + dat += "" + var/peen_vis_override + if(CHECK_BITFIELD(features[GD.override_key], GENITAL_ALWAYS_HIDDEN)) + peen_vis_override = "Always Hidden" + else if(CHECK_BITFIELD(features[GD.override_key], GENITAL_ALWAYS_VISIBLE)) + peen_vis_override = "Always Visible" + else + peen_vis_override = "Check Coverage" + dat += PrefLink(peen_vis_override, PREFCMD_OVERRIDE_GENITAL, list(PREFDAT_GENITAL_HAS = has_donk), span = "SmolBox") + dat += "" + var/peen_see_span + if(!(features["genital_hide"] & GD.hide_flag)) + peen_see_span = "TabCellselected" + dat += PrefLink("Yes", PREFCMD_SEE_GENITAL, list(PREFDAT_GENITAL_HAS = has_donk), span = peen_see_span) + dat += "" + var/peen_has_span + var/peen_word = "No" + if(features[GD.has_key]) + peen_has_span = "TabCellselected" + peen_word = "Yes" + dat += PrefLink(peen_word, PREFCMD_TOGGLE_GENITAL, list(PREFDAT_GENITAL_HAS = has_donk), span = peen_has_span) + dat += "
" + dat += PrefLink("P-Hud Whitelisting", PREFCMD_PHUD_WHITELIST) + dat += "
" + dat += "
" + return dat.Join() + +// this one is built based on which genital sub sub tab is open +/datum/preferences/proc/AppearanceUnderlyingGenitals() + var/datum/genital_data/GD = GLOB.genital_data_system[current_sub_subtab] + if(!GD) + return "OH NO THERES A BUG HERE TELL DAN ERROR CODE: SQUISHY FOX BINGUS 2000" + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "Has one:" + dat += "
" // End of DIV A A A A + var/yesno = "No" + if(features[GD.has_key]) + yesno = "Yes" + dat += PrefLink(yesno, PREFCMD_TOGGLE_GENITAL, list(PREFDAT_GENITAL_HAS = current_sub_subtab)) + var/can_color = GD.genital_flags & GENITAL_CAN_RECOLOR + if(can_color) + var/list/feat_data = list(PREFDAT_COLKEY_IS_FEATURE = TRUE) + dat += ColorBox(GD.color_key, data = feat_data) + dat += "
" // End of DIV A A A + if(!(GD.genital_flags & GENITAL_INTERNAL)) + var/can_shape = GD.genital_flags & GENITAL_CAN_RESHAPE + var/can_size = GD.genital_flags & GENITAL_CAN_RESIZE + if(can_shape || can_size) + dat += "
" // DIV A A B + if(can_shape) + dat += "
" // DIV A A B A + dat += "Shape:" + dat += "
" // End of DIV A A B A + dat += PrefLink("[capitalize(features[GD.shape_key])]", PREFCMD_CHANGE_GENITAL_SHAPE, list(PREFDAT_GENITAL_HAS = current_sub_subtab)) + if(can_size) + dat += "
" // DIV A A B B + dat += "Size:" + dat += "
" // End of DIV A A B B + dat += PrefLink("[GD.SizeString(features[GD.size_key])]", PREFCMD_CHANGE_GENITAL_SIZE, list(PREFDAT_GENITAL_HAS = current_sub_subtab)) + dat += "
" // End of DIV A A B + var/hidden_by_clothes = GD.genital_flags & GENITAL_RESPECT_CLOTHING + var/hbc_span = "" + if(hidden_by_clothes) + hbc_span = "TabCellselected" + var/hidden_by_undies = GD.genital_flags & GENITAL_RESPECT_UNDERWEAR + var/hbu_span = "" + if(hidden_by_undies) + hbu_span = "TabCellselected" + dat += "
" // DIV A A C + dat += "
" // DIV A A C A + dat += "Hidden by:" + dat += "
" // End of DIV A A C A + dat += PrefLink("Clothes", PREFCMD_HIDE_GENITAL, list(PREFDAT_GENITAL_HAS = current_sub_subtab, PREFDAT_HIDDEN_BY = "clothes"), span = hbc_span) + dat += PrefLink("Underpants", PREFCMD_HIDE_GENITAL, list(PREFDAT_GENITAL_HAS = current_sub_subtab, PREFDAT_HIDDEN_BY = "undies"), span = hbu_span) + dat += "
" // End of DIV A A C + var/override = "Check Coverage" + if(CHECK_BITFIELD(features[GD.override_key], GENITAL_ALWAYS_HIDDEN)) + override = "Always Hidden" + else if(CHECK_BITFIELD(features[GD.override_key], GENITAL_ALWAYS_VISIBLE)) + override = "Always Visible" + dat += "
" // DIV A A D + dat += "
" // DIV A A D A + dat += "Override:" + dat += "
" // End of DIV A A D A + dat += PrefLink(override, PREFCMD_OVERRIDE_GENITAL, list(PREFDAT_GENITAL_HAS = current_sub_subtab)) + dat += "
" // End of DIV A A D + var/see_on_others = "No" + if(!(features["genital_hide"] & GD.hide_flag)) + see_on_others = "Yes" + dat += "
" // DIV A A E + dat += "
" // DIV A A E A + dat += "See on others:" + dat += "
" // End of DIV A A E A + dat += PrefLink(see_on_others, PREFCMD_SEE_GENITAL, list(PREFDAT_GENITAL_HAS = current_sub_subtab)) + dat += "
" // End of DIV A A E + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + +/// the unholy evil death bringer of the preferences tab +/datum/preferences/proc/Loadout() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + dat += "
" // DIV A A A + var/gear_points = CONFIG_GET(number/initial_gear_points) + var/list/chosen_gear = loadout_data["SAVE_[loadout_slot]"] + if(chosen_gear) + for(var/loadout_item in chosen_gear) + var/loadout_item_path = loadout_item[LOADOUT_ITEM] + if(loadout_item_path) + var/datum/gear/loadout_gear = text2path(loadout_item_path) + if(loadout_gear) + gear_points -= initial(loadout_gear.cost) + else + chosen_gear = list() + var/points_color = "#00FF00" + if(gear_points <= 0) + points_color = "#FF0000" + dat += "You have [gear_points] points!" + dat += "
" // End of DIV A A A + dat += PrefLink("Reset", PREFCMD_LOADOUT_RESET, list(PREFDAT_LOADOUT_SLOT = loadout_slot), span = "SmolBox") + dat += "" + dat += PrefLink("X", PREFCMD_LOADOUT_SEARCH_CLEAR, span = "SmolBox") + var/searchterm = loadout_search ? copytext(loadout_search, 1, 30) : "Search" + dat += PrefLink("[searchterm]", PREFCMD_LOADOUT_SEARCH, span = "SmolBox Wider100") + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + // now we need to build the actual gear list + // Categories! + if(!GLOB.loadout_categories[gear_category] && gear_category != GEAR_CAT_ALL_EQUIPPED) + gear_category = GLOB.loadout_categories[1] + dat += "
" // DIV A A + for(var/category in (list(GEAR_CAT_ALL_EQUIPPED = list()) | GLOB.loadout_categories)) + var/selspan = "" + if(category == gear_category) + selspan = "TabCellselected" + dat += PrefLink(category, PREFCMD_LOADOUT_CATEGORY, list(PREFDAT_LOADOUT_CATEGORY = html_encode(category)), span = selspan) + dat += "
" // End of DIV A A + dat += "
" // DIV A B End of DIV A B + // Subcategories! + var/list/subcategories = GLOB.loadout_categories[gear_category] + if(gear_category != GEAR_CAT_ALL_EQUIPPED && !subcategories.Find(gear_subcategory)) + gear_subcategory = subcategories[1] + if(!searchterm && gear_category != GEAR_CAT_ALL_EQUIPPED) + dat += "
" // DIV A C + for(var/subcategory in subcategories) + var/selspan = "" + if(subcategory == gear_subcategory) + selspan = "TabCellselected" + dat += PrefLink(subcategory, PREFCMD_LOADOUT_SUBCATEGORY, list(PREFDAT_LOADOUT_SUBCATEGORY = html_encode(subcategory)), span = selspan) + dat += "
" // End of DIV A C + dat += "
" // DIV A D End of DIV A D + // now we need to build the actual gear list + // first lets get all the gear + var/list/mystuff = list() + var/list/my_saved = loadout_data["SAVE_[loadout_slot]"] + for(var/loadout_gear in my_saved) + mystuff["[loadout_gear[LOADOUT_ITEM]]"] = TRUE // typecache! + var/list/flatlyss + if(loadout_search || gear_category == GEAR_CAT_ALL_EQUIPPED) + var/list/searchmine = list() + if(gear_category == GEAR_CAT_ALL_EQUIPPED) + searchmine = mystuff + else + searchmine = list() + flatlyss = GetGearFlatList(loadout_search, searchmine) + else + flatlyss = flatten_list(GLOB.loadout_items[gear_category][gear_subcategory]) + // now we need to display the gear + dat += "
" // DIV A E + dat += "
" // DIV A E A + for(var/datum/gear/gear in flatlyss) + var/donoritem = gear.donoritem + if(donoritem && !gear.donator_ckey_check(parent.ckey)) + continue + var/i_have_it = mystuff["[gear.type]"] + var/edited_name + var/edited_desc + var/edited_color = "FFFFFF" + if(i_have_it) + var/list/loadout_item = has_loadout_gear(loadout_slot, "[gear.name]") + if(loadout_item) + if(!loadout_item[LOADOUT_CUSTOM_COLOR]) + loadout_item[LOADOUT_CUSTOM_COLOR] = "FFFFFF" + edited_color = loadout_item[LOADOUT_CUSTOM_COLOR] + if(LAZYLEN(loadout_item[LOADOUT_CUSTOM_NAME])) + edited_name = loadout_item[LOADOUT_CUSTOM_NAME] + if(LAZYLEN(loadout_item[LOADOUT_CUSTOM_DESCRIPTION])) + edited_desc = loadout_item[LOADOUT_CUSTOM_DESCRIPTION] + dat += "
" // DIV A E A A + dat += "
" // DIV A E A A A + var/list/namespan = list() + if(i_have_it) + namespan += "TabCellselected" + namespan += "NotSoSmolBox" + if(edited_name) + namespan += "EditedEntry" + var/truenamespan = namespan.Join(" ") + var/namedisplay = edited_name ? edited_name : gear.name + dat += PrefLink(namedisplay, PREFCMD_LOADOUT_TOGGLE, list(PREFDAT_LOADOUT_GEAR_NAME = "[gear.type]"), span = truenamespan) + var/canafford = (gear_points - gear.cost) >= 0 + var/costspan = "SettingName SmolBox" + if(!canafford) + costspan += " CantAfford" + dat += "
" // DIV A E A A A B + dat += "[gear.cost] pts" + dat += "
" // End of DIV A E A A A B + var/descspan = "SettingValueSplit" + if(edited_desc) + descspan += " EditedEntry" + dat += "
" // End of DIV A E A A + dat += "
" // DIV A E A A A C + dat += "
" // DIV A E A A A C A + var/descdisplay = edited_desc ? edited_desc : gear.description + dat += descdisplay + dat += "
" // End of DIV A E A A A C A + dat += "
" // End of DIV A E A A A C + if(i_have_it) // show the customization things + dat += "
" // DIV A E A A A D + dat += GearColorBox(gear, edited_color) + dat += PrefLink("Edit
Name", PREFCMD_LOADOUT_RENAME, list(PREFDAT_GEAR_TYPE = "[gear.type]"), span = "SmolBox NotSoSmolBox") + dat += PrefLink("Edit
Desc", PREFCMD_LOADOUT_REDESC, list(PREFDAT_GEAR_TYPE = "[gear.type]"), span = "SmolBox NotSoSmolBox") + dat += "
" // End of DIV A E A A A D + dat += "
" // End of DIV A E A A + dat += "
" // End of DIV A E A + dat += "
" // End of DIV A E + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/GamePreferencesGeneral() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + // Widescreen + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "
" // DIV A A A A A + dat += "Widescreen" + dat += "
" // End of DIV A A A A A + var/showtext1 = "Disabled (15x15)" + if(widescreenpref) + showtext1 = "Enabled ([CONFIG_GET(string/default_view)])" + dat += PrefLink(showtext1, PREFCMD_WIDESCREEN_TOGGLE) + dat += "
" // End of DIV A A A A + dat += "
" // End of DIV A A A + // Auto Stand + dat += "
" // DIV A A B + dat += "
" // DIV A A B A + dat += "
" // DIV A A B A A + dat += "Auto Stand" + dat += "
" // End of DIV A A B A A + var/showtext2 = "Disabled" + if(autostand) + showtext2 = "Enabled" + dat += PrefLink(showtext2, PREFCMD_AUTOSTAND_TOGGLE) + dat += "
" // End of DIV A A B A + dat += "
" // End of DIV A A B + // Force Slot Storage HUD + dat += "
" // DIV A A C + dat += "
" // DIV A A C A + dat += "
" // DIV A A C A A + dat += "Force Slot Storage HUD" + dat += "
" // End of DIV A A C A A + var/showtext3 = "Disabled" + if(no_tetris_storage) + showtext3 = "Enabled" + dat += PrefLink(showtext3, PREFCMD_TETRIS_STORAGE_TOGGLE) + dat += "
" // End of DIV A A C A + dat += "
" // End of DIV A A C + // Gun Cursor + dat += "
" // DIV A A D + dat += "
" // DIV A A D A + dat += "
" // DIV A A D A A + dat += "Gun Cursor" + dat += "
" // End of DIV A A D A A + var/showtext4 = "Disabled" + if(cb_toggles & AIM_CURSOR_ON) + showtext4 = "Enabled" + dat += PrefLink(showtext4, PREFCMD_GUNCURSOR_TOGGLE) + dat += "
" // End of DIV A A D A + dat += "
" // End of DIV A A D + // Screen Shake + dat += "
" // DIV A A E + dat += "
" // DIV A A E A + dat += "
" // DIV A A E A A + dat += "Screen Shake" + dat += "
" // End of DIV A A E A A + var/showtext5 = "None" + if(screenshake == 100) + showtext5 = "Full" + else if(screenshake != 0) + showtext5 = "[screenshake]" + dat += PrefLink(showtext5, PREFCMD_SCREENSHAKE_TOGGLE) + dat += "
" // End of DIV A A E A + dat += "
" // End of DIV A A E + // Damage Screen Shake + dat += "
" // DIV A A F + dat += "
" // DIV A A F A + dat += "
" // DIV A A F A A + dat += "Damage Screen Shake" + dat += "
" // End of DIV A A F A A + var/showtext6 = "Only when down" + if(damagescreenshake == 1) + showtext6 = "On" + else if(damagescreenshake == 0) + showtext6 = "Off" + dat += PrefLink(showtext6, PREFCMD_DAMAGESCREENSHAKE_TOGGLE) + dat += "
" // End of DIV A A F A + dat += "
" // End of DIV A A F + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + dat += "" // End of DIV A + return dat.Join() + +/datum/preferences/proc/GamePreferencesUI() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + // UI Style + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "
" // DIV A A A A A + dat += "UI Style" + dat += "
" // End of DIV A A A A A + dat += PrefLink("[UI_style]", PREFCMD_UI_STYLE) + dat += "
" // End of DIV A A A A + dat += "
" // End of DIV A A A + // tgui Monitors + dat += "
" // DIV A A B + dat += "
" // DIV A A B A + dat += "
" // DIV A A B A A + dat += "tgui Monitors" + dat += "
" // End of DIV A A B A A + var/showtext1 = "All" + if(tgui_lock) + showtext1 = "Primary" + dat += PrefLink(showtext1, PREFCMD_TGUI_LOCK) + dat += "
" // End of DIV A A B A + dat += "
" // End of DIV A A B + // tgui Style + dat += "
" // DIV A A C + dat += "
" // DIV A A C A + dat += "
" // DIV A A C A A + dat += "tgui Style" + dat += "
" // End of DIV A A C A A + var/showtext2 = "No Frills" + if(tgui_fancy) + showtext2 = "Fancy" + dat += PrefLink(showtext2, PREFCMD_TGUI_FANCY) + dat += "
" // End of DIV A A C A + dat += "
" // End of DIV A A C + // Input Mode Hotkey + dat += "
" // DIV A A D + dat += "
" // DIV A A D A + dat += "
" // DIV A A D A A + dat += "Input Mode Hotkey" + dat += "
" // End of DIV A A D A A + dat += PrefLink("[input_mode_hotkey]", PREFCMD_INPUT_MODE_HOTKEY) + dat += "
" // End of DIV A A D A + dat += "
" // End of DIV A A D + // Action Buttons + dat += "
" // DIV A A E + dat += "
" // DIV A A E A + dat += "
" // DIV A A E A A + dat += "Action Buttons" + dat += "
" // End of DIV A A E A A + var/showtext3 = "Unlocked" + if(buttons_locked) + showtext3 = "Locked In Place" + dat += PrefLink(showtext3, PREFCMD_ACTION_BUTTONS) + dat += "
" // End of DIV A A E A + dat += "
" // End of DIV A A E + // Window Flashing + dat += "
" // DIV A A F + dat += "
" // DIV A A F A + dat += "
" // DIV A A F A A + dat += "Window Flashing" + dat += "
" // End of DIV A A F A A + var/showtext4 = "Disabled" + if(windowflashing) + showtext4 = "Enabled" + dat += PrefLink(showtext4, PREFCMD_WINFLASH) + dat += "
" // End of DIV A A F A + dat += "
" // End of DIV A A F + // Ambient Occlusion + dat += "
" // DIV A A G + dat += "
" // DIV A A G A + dat += "
" // DIV A A G A A + dat += "Ambient Occlusion" + dat += "
" // End of DIV A A G A A + var/showtext5 = "Disabled" + if(ambientocclusion) + showtext5 = "Enabled" + dat += PrefLink(showtext5, PREFCMD_AMBIENTOCCLUSION) + dat += "
" // End of DIV A A G A + dat += "
" // End of DIV A A G + // Fit Viewport + dat += "
" // DIV A A H + dat += "
" // DIV A A H A + dat += "
" // DIV A A H A A + dat += "Fit Viewport" + dat += "
" // End of DIV A A H A A + var/showtext6 = "Manual" + if(auto_fit_viewport) + showtext6 = "Auto" + dat += PrefLink(showtext6, PREFCMD_AUTO_FIT_VIEWPORT) + dat += "
" // End of DIV A A H A + dat += "
" // End of DIV A A H + // HUD Button Flashes + dat += "
" // DIV A A I + dat += "
" // DIV A A I A + dat += "
" // DIV A A I A A + dat += "HUD Button Flashes" + dat += "
" // End of DIV A A I A A + var/showtext7 = "Disabled" + if(hud_toggle_flash) + showtext7 = "Enabled" + dat += PrefLink(showtext7, PREFCMD_HUD_TOGGLE_FLASH) + dat += "
" // End of DIV A A I A + dat += "
" // End of DIV A A I + // HUD Button Flash Color + dat += "
" // DIV A A J + dat += "
" // DIV A A J A + dat += "
" // DIV A A J A A + dat += "HUD Button Flash Color" + dat += "
" // End of DIV A A J A A + dat += "
" // DIV A A J A B + dat += ColorBox("hud_toggle_color") + dat += "
" // End of DIV A A J A B + dat += "
" // End of DIV A A J A + dat += "
" // End of DIV A A J + // FPS + dat += "
" // DIV A A K + dat += "
" // DIV A A K A + dat += "
" // DIV A A K A A + dat += "FPS" + dat += "
" // End of DIV A A K A A + dat += PrefLink("[clientfps]", PREFCMD_CLIENTFPS) + dat += "
" // End of DIV A A K A + dat += "
" // End of DIV A A K + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + dat += "" // End of DIV A + return dat.Join() + +/datum/preferences/proc/GamePreferencesChat() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + // See Pull Requests + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "
" // DIV A A A A A + dat += "See Pull Requests" + dat += "
" // End of DIV A A A A A + var/showtext1 = "Disabled" + if(chat_toggles & CHAT_PULLR) + showtext1 = "Enabled" + dat += PrefLink(showtext1, PREFCMD_PULL_REQUESTS) + dat += "
" // End of DIV A A A A + dat += "
" // End of DIV A A A + // Show Health Smileys + dat += "
" // DIV A A B + dat += "
" // DIV A A B A + dat += "
" // DIV A A B A A + dat += "Show Health Smileys" + dat += "
" // End of DIV A A B A A + var/showtext2 = "Disabled" + if(show_health_smilies) + showtext2 = "Enabled" + dat += PrefLink(showtext2, PREFCMD_HEALTH_SMILEYS) + dat += "
" // End of DIV A A B A + dat += "
" // End of DIV A A B + // Max PFP Examine Image Height + dat += "
" // DIV A A C + dat += "
" // DIV A A C A + dat += "
" // DIV A A C A A + dat += "Max PFP Examine Image Height" + dat += "
" // End of DIV A A C A A + dat += PrefLink("[see_pfp_max_hight]px", PREFCMD_MAX_PFP_HEIGHT) + dat += "
" // End of DIV A A C A + dat += "
" // End of DIV A A C + // Max PFP Examine Image Width + dat += "
" // DIV A A D + dat += "
" // DIV A A D A + dat += "
" // DIV A A D A A + dat += "Max PFP Examine Image Width" + dat += "
" // End of DIV A A D A A + dat += PrefLink("[see_pfp_max_widht]%", PREFCMD_MAX_PFP_WIDTH) + dat += "
" // End of DIV A A D A + dat += "
" // End of DIV A A D + // Auto OOC + dat += "
" // DIV A A E + dat += "
" // DIV A A E A + dat += "
" // DIV A A E A A + dat += "Auto OOC" + dat += "
" // End of DIV A A E A A + var/showtext3 = "Disabled" + if(auto_ooc) + showtext3 = "Enabled" + dat += PrefLink(showtext3, PREFCMD_AUTO_OOC) + dat += "
" // End of DIV A A E A + dat += "
" // End of DIV A A E + // Income Updates + dat += "
" // DIV A A F + dat += "
" // DIV A A F A + dat += "
" // DIV A A F A A + dat += "Income Updates" + dat += "
" // End of DIV A A F A A + var/showtext4 = "Muted" + if(chat_toggles & CHAT_BANKCARD) + showtext4 = "Allowed" + dat += PrefLink(showtext4, PREFCMD_INCOME_UPDATES) + dat += "
" // End of DIV A A F A + dat += "
" // End of DIV A A F + // Hear Radio Static + dat += "
" // DIV A A G + dat += "
" // DIV A A G A + dat += "
" // DIV A A G A A + dat += "Hear Radio Static" + dat += "
" // End of DIV A A G A A + var/showtext5 = "Muted" + if(chat_toggles & CHAT_HEAR_RADIOSTATIC) + showtext5 = "Allowed" + dat += PrefLink(showtext5, PREFCMD_RADIO_STATIC) + dat += "
" // End of DIV A A G A + dat += "
" // End of DIV A A G + // Hear Radio Blurbles + dat += "
" // DIV A A H + dat += "
" // DIV A A H A + dat += "
" // DIV A A H A A + dat += "Hear Radio Blurbles" + dat += "
" // End of DIV A A H A A + var/showtext6 = "Muted" + if(chat_toggles & CHAT_HEAR_RADIOBLURBLES) + showtext6 = "Allowed" + dat += PrefLink(showtext6, PREFCMD_RADIO_BLURBLES) + dat += "
" // End of DIV A A H A + dat += "
" // End of DIV A A H + // BYOND Membership Publicity + if(usr.client) + if(unlock_content) + dat += "
" // DIV A A I + dat += "
" // DIV A A I A + dat += "
" // DIV A A I A A + dat += "BYOND Membership Publicity" + dat += "
" // End of DIV A A I A A + var/showtext7 = "Hidden" + if(toggles & MEMBER_PUBLIC) + showtext7 = "Public" + dat += PrefLink(showtext7, PREFCMD_BYOND_PUBLICITY) + dat += "
" // End of DIV A A I A + dat += "
" // End of DIV A A I + if(unlock_content || check_rights(R_ADMIN)) + // OOC Color + dat += "
" // DIV A A J + dat += "
" // DIV A A J A + dat += "
" // DIV A A J A A + dat += "OOC Color" + dat += "
" // End of DIV A A J A A + dat += "
" // DIV A A J A B + dat += ColorBox("ooccolor") + dat += "
" // End of DIV A A J A B + dat += "
" // End of DIV A A J A + dat += "
" // End of DIV A A J + // Antag OOC Color + // div += "
" // DIV A A K + // div += "
" // DIV A A K A + // div += "
" // DIV A A K A A + // div += "Antag OOC Color" + // div += "
" // End of DIV A A K A A + // div += "
" // DIV A A K A B + // div += ColorBox("aooccolor") + // div += "
" // End of DIV A A K A B + // div += "
" // End of DIV A A K A + // div += "
" // End of DIV A A K + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/GamePreferencesRunechat() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + // Show Runechat Chat Bubbles + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "
" // DIV A A A A A + dat += "Show Runechat Chat Bubbles" + dat += "
" // End of DIV A A A A A + var/showtext1 = "Disabled" + if(chat_on_map) + showtext1 = "Enabled" + dat += PrefLink(showtext1, PREFCMD_CHAT_ON_MAP) + dat += "
" // End of DIV A A A A + dat += "
" // End of DIV A A A + // Runechat message char limit + dat += "
" // DIV A A B + dat += "
" // DIV A A B A + dat += "
" // DIV A A B A A + dat += "Runechat message char limit" + dat += "
" // End of DIV A A B A A + dat += PrefLink("[max_chat_length]", PREFCMD_MAX_CHAT_LENGTH) + dat += "
" // End of DIV A A B A + dat += "
" // End of DIV A A B + // Runechat message width + dat += "
" // DIV A A C + dat += "
" // DIV A A C A + dat += "
" // DIV A A C A A + dat += "Runechat message width" + dat += "
" // End of DIV A A C A A + dat += PrefLink("[chat_width]", PREFCMD_CHAT_WIDTH) + dat += "
" // End of DIV A A C A + dat += "
" // End of DIV A A C + // Runechat off-screen + dat += "
" // DIV A A D + dat += "
" // DIV A A D A + dat += "
" // DIV A A D A A + dat += "Runechat off-screen" + dat += "
" // End of DIV A A D A A + var/showtext2 = "Disabled" + if(see_fancy_offscreen_runechat) + showtext2 = "Enabled" + dat += PrefLink(showtext2, PREFCMD_OFFSCREEN) + dat += "
" // End of DIV A A D A + dat += "
" // End of DIV A A D + // See Runechat for non-mobs + dat += "
" // DIV A A E + dat += "
" // DIV A A E A + dat += "
" // DIV A A E A A + dat += "See Runechat for non-mobs" + dat += "
" // End of DIV A A E A A + var/showtext3 = "Disabled" + if(see_chat_non_mob) + showtext3 = "Enabled" + dat += PrefLink(showtext3, PREFCMD_SEE_CHAT_NON_MOB) + dat += "
" // End of DIV A A E A + dat += "
" // End of DIV A A E + // See Runechat emotes + dat += "
" // DIV A A F + dat += "
" // DIV A A F A + dat += "
" // DIV A A F A A + dat += "See Runechat emotes" + dat += "
" // End of DIV A A F A A + var/showtext4 = "Disabled" + if(see_rc_emotes) + showtext4 = "Enabled" + dat += PrefLink(showtext4, PREFCMD_SEE_RC_EMOTES) + dat += "
" // End of DIV A A F A + dat += "
" // End of DIV A A F + // Use Runechat color in chat log + dat += "
" // DIV A A G + dat += "
" // DIV A A G A + dat += "
" // DIV A A G A A + dat += "Use Runechat color in chat log" + dat += "
" // End of DIV A A G A A + var/showtext5 = "Disabled" + if(color_chat_log) + showtext5 = "Enabled" + dat += PrefLink(showtext5, PREFCMD_COLOR_CHAT_LOG) + dat += "
" // End of DIV A A G A + dat += "
" // End of DIV A A G + // See Runechat / hear sounds above/below you + // dat += "
" // DIV A A H + // dat += "
" // DIV A A H A + // dat += "
" // DIV A A H A A + // dat += "See Runechat / hear sounds above/below you" + // dat += "
" // End of DIV A A H A A + // dat += PrefLink("[upperlowerfloor]", PREFCMD_UPPERLOWERFLOOR) + // dat += "
" // End of DIV A A H A + // dat += "
" // End of DIV A A H + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/GamePreferencesGhost() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + // Ghost Ears + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "
" // DIV A A A A A + dat += "Ghost Ears" + dat += "
" // End of DIV A A A A A + var/showtext1 = "Nearest Creatures" + if(chat_toggles & CHAT_GHOSTEARS) + showtext1 = "All Speech" + dat += PrefLink(showtext1, PREFCMD_GHOST_EARS) + dat += "
" // End of DIV A A A A + dat += "
" // End of DIV A A A + // Ghost Radio + dat += "
" // DIV A A B + dat += "
" // DIV A A B A + dat += "
" // DIV A A B A A + dat += "Ghost Radio" + dat += "
" // End of DIV A A B A A + var/showtext2 = "No Messages" + if(chat_toggles & CHAT_GHOSTRADIO) + showtext2 = "All Messages" + dat += PrefLink(showtext2, PREFCMD_GHOST_RADIO) + dat += "
" // End of DIV A A B A + dat += "
" // End of DIV A A B + // Ghost Sight + dat += "
" // DIV A A C + dat += "
" // DIV A A C A + dat += "
" // DIV A A C A A + dat += "Ghost Sight" + dat += "
" // End of DIV A A C A A + var/showtext3 = "Nearest Creatures" + if(chat_toggles & CHAT_GHOSTSIGHT) + showtext3 = "All Emotes" + dat += PrefLink(showtext3, PREFCMD_GHOST_SIGHT) + dat += "
" // End of DIV A A C A + dat += "
" // End of DIV A A C + // Ghost Whispers + dat += "
" // DIV A A D + dat += "
" // DIV A A D A + dat += "
" // DIV A A D A A + dat += "Ghost Whispers" + dat += "
" // End of DIV A A D A A + var/showtext4 = "Nearest Creatures" + if(chat_toggles & CHAT_GHOSTWHISPER) + showtext4 = "All Speech" + dat += PrefLink(showtext4, PREFCMD_GHOST_WHISPERS) + dat += "
" // End of DIV A A D A + dat += "
" // End of DIV A A D + // Ghost PDA + dat += "
" // DIV A A E + dat += "
" // DIV A A E A + dat += "
" // DIV A A E A A + dat += "Ghost PDA" + dat += "
" // End of DIV A A E A A + var/showtext500 = "Nearest Creatures" + if(chat_toggles & CHAT_GHOSTPDA) + showtext500 = "All Messages" + dat += PrefLink(showtext500, PREFCMD_GHOST_PDA) + dat += "
" // End of DIV A A E A + dat += "
" // End of DIV A A E + if(unlock_content || check_rights(R_ADMIN)) + // Ghost Form + dat += "
" // DIV A A F + dat += "
" // DIV A A F A + dat += "
" // DIV A A F A A + dat += "Ghost Form" + dat += "
" // End of DIV A A F A A + dat += PrefLink("[ghost_form]", PREFCMD_GHOST_FORM) + dat += "
" // End of DIV A A F A + dat += "
" // End of DIV A A F + // Ghost Orbit + dat += "
" // DIV A A G + dat += "
" // DIV A A G A + dat += "
" // DIV A A G A A + dat += "Ghost Orbit" + dat += "
" // End of DIV A A G A A + dat += PrefLink("[ghost_orbit]", PREFCMD_GHOST_ORBIT) + dat += "
" // End of DIV A A G A + dat += "
" // End of DIV A A G + var/showtext5 = "If you see this something went wrong." + switch(ghost_accs) + if(GHOST_ACCS_FULL) + showtext5 = GHOST_ACCS_FULL_NAME + if(GHOST_ACCS_DIR) + showtext5 = GHOST_ACCS_DIR_NAME + if(GHOST_ACCS_NONE) + showtext5 = GHOST_ACCS_NONE_NAME + // Ghost Accessories + dat += "
" // DIV A A H + dat += "
" // DIV A A H A + dat += "
" // DIV A A H A A + dat += "Ghost Accessories" + dat += "
" // End of DIV A A H A A + dat += PrefLink(showtext5, PREFCMD_GHOST_ACCS) + dat += "
" // End of DIV A A H A + dat += "
" // End of DIV A A H + var/showtext6 = "If you see this something went wrong." + switch(ghost_others) + if(GHOST_OTHERS_THEIR_SETTING) + showtext6 = GHOST_OTHERS_THEIR_SETTING_NAME + if(GHOST_OTHERS_DEFAULT_SPRITE) + showtext6 = GHOST_OTHERS_DEFAULT_SPRITE_NAME + if(GHOST_OTHERS_SIMPLE) + showtext6 = GHOST_OTHERS_SIMPLE_NAME + // Ghosts of Others + dat += "
" // DIV A A I + dat += "
" // DIV A A I A + dat += "
" // DIV A A I A A + dat += "Ghosts of Others" + dat += "
" // End of DIV A A I A A + dat += PrefLink(showtext6, PREFCMD_GHOST_OTHERS) + dat += "
" // End of DIV A A I A + dat += "
" // End of DIV A A I + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/GamePreferencesAudio() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + // Play Hunting Horn Sounds + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "
" // DIV A A A A A + dat += "Play Hunting Horn Sounds" + dat += "
" // End of DIV A A A A A + var/showtext1 = "Disabled" + if(toggles & SOUND_HUNTINGHORN) + showtext1 = "Enabled" + dat += PrefLink(showtext1, PREFCMD_HUNTINGHORN) + dat += "
" // End of DIV A A A A + dat += "
" // End of DIV A A A + // Sprint Depletion Sound + dat += "
" // DIV A A B + dat += "
" // DIV A A B A + dat += "
" // DIV A A B A A + dat += "Sprint Depletion Sound" + dat += "
" // End of DIV A A B A A + var/showtext2 = "Disabled" + if(toggles & SOUND_SPRINTBUFFER) + showtext2 = "Enabled" + dat += PrefLink(showtext2, PREFCMD_SPRINTBUFFER) + dat += "
" // End of DIV A A B A + dat += "
" // End of DIV A A B + // Play Admin MIDIs + dat += "
" // DIV A A C + dat += "
" // DIV A A C A + dat += "
" // DIV A A C A A + dat += "Play Admin MIDIs" + dat += "
" // End of DIV A A C A A + var/showtext3 = "Disabled" + if(toggles & SOUND_MIDI) + showtext3 = "Enabled" + dat += PrefLink(showtext3, PREFCMD_MIDIS) + dat += "
" // End of DIV A A C A + dat += "
" // End of DIV A A + // Play Lobby Music + dat += "
" // DIV A A D + dat += "
" // DIV A A D A + dat += "
" // DIV A A D A A + dat += "Play Lobby Music" + dat += "
" // End of DIV A A D A A + var/showtext4 = "Disabled" + if(toggles & SOUND_LOBBY) + showtext4 = "Enabled" + dat += PrefLink(showtext4, PREFCMD_LOBBY_MUSIC) + dat += "
" // End of DIV A A D A + dat += "
" // End of DIV A A D + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/GamePreferencesAdmin() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + // Adminhelp Sounds + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "
" // DIV A A A A A + dat += "Adminhelp Sounds" + dat += "
" // End of DIV A A A A A + var/showtext1 = "Disabled" + if(toggles & SOUND_ADMINHELP) + showtext1 = "Enabled" + dat += PrefLink(showtext1, PREFCMD_ADMINHELP) + dat += "
" // End of DIV A A A A + dat += "
" // End of DIV A A A + // Announce Login + dat += "
" // DIV A A B + dat += "
" // DIV A A B A + dat += "
" // DIV A A B A A + dat += "Announce Login" + dat += "
" // End of DIV A A B A A + var/showtext2 = "Disabled" + if(toggles & ANNOUNCE_LOGIN) + showtext2 = "Enabled" + dat += PrefLink(showtext2, PREFCMD_ANNOUNCE_LOGIN) + dat += "
" // End of DIV A A B A + dat += "
" // End of DIV A A B + // Combo HUD Lighting + dat += "
" // DIV A A C + dat += "
" // DIV A A C A + dat += "
" // DIV A A C A A + dat += "Combo HUD Lighting" + dat += "
" // End of DIV A A C A A + var/showtext3 = "No Change" + if(toggles & COMBOHUD_LIGHTING) + showtext3 = "Full-bright" + dat += PrefLink(showtext3, PREFCMD_COMBOHUD_LIGHTING) + dat += "
" // End of DIV A A C A + dat += "
" // End of DIV A A C + // Split Admin Tabs + dat += "
" // DIV A A D + dat += "
" // DIV A A D A + dat += "
" // DIV A A D A A + dat += "Split Admin Tabs" + dat += "
" // End of DIV A A D A A + var/showtext4 = "Disabled" + if(toggles & SPLIT_ADMIN_TABS) + showtext4 = "Enabled" + dat += PrefLink(showtext4, PREFCMD_SPLIT_ADMIN_TABS) + dat += "
" // End of DIV A A D A + dat += "
" // End of DIV A A D + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/GamePreferencesContent() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + // Arousal + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "
" // DIV A A A A A + dat += "Arousal" + dat += "
" // End of DIV A A A A A + var/showtext1 = "Disabled" + if(arousable) + showtext1 = "Enabled" + dat += PrefLink(showtext1, PREFCMD_AROUSABLE) + dat += "
" // End of DIV A A A A + dat += "
" // End of DIV A A A + // Genital examine text + dat += "
" // DIV A A B + dat += "
" // DIV A A B A + dat += "
" // DIV A A B A A + dat += "Genital examine text" + dat += "
" // End of DIV A A B A A + var/showtext2 = "Disabled" + if(cit_toggles & GENITAL_EXAMINE) + showtext2 = "Enabled" + dat += PrefLink(showtext2, PREFCMD_GENITAL_EXAMINE) + dat += "
" // End of DIV A A B A + dat += "
" // End of DIV A A B + // Butt Slapping + dat += "
" // DIV A A C + dat += "
" // DIV A A C A + dat += "
" // DIV A A C A A + dat += "Butt Slapping" + dat += "
" // End of DIV A A C A A + var/showtext3 = "Allowed" + if(cit_toggles & NO_BUTT_SLAP) + showtext3 = "Disallowed" + dat += PrefLink(showtext3, PREFCMD_BUTT_SLAP) + dat += "
" // End of DIV A A C A + dat += "
" // End of DIV A A + // Auto Wag + dat += "
" // DIV A A D + dat += "
" // DIV A A D A + dat += "
" // DIV A A D A A + dat += "Auto Wag" + dat += "
" // End of DIV A A D A A + var/showtext4 = "Enabled" + if(cit_toggles & NO_AUTO_WAG) + showtext4 = "Disabled" + dat += PrefLink(showtext4, PREFCMD_AUTO_WAG) + dat += "
" // End of DIV A A D A + dat += "
" // End of DIV A A + // Master Vore Toggle + dat += "
" // DIV A A E + dat += "
" // DIV A A E A + dat += "
" // DIV A A E A A + dat += "Master Vore Toggle" + dat += "
" // End of DIV A A E A A + var/showtext5 = "All Disabled" + if(master_vore_toggle) + showtext5 = "Per Preferences" + dat += PrefLink(showtext5, PREFCMD_MASTER_VORE_TOGGLE) + dat += "
" // End of DIV A A E A + dat += "
" // End of DIV A A E + // Being Prey + dat += "
" // DIV A A F + dat += "
" // DIV A A F A + dat += "
" // DIV A A F A A + dat += "Being Prey" + dat += "
" // End of DIV A A F A A + var/showtext6 = "Disallowed" + if(allow_being_prey) + showtext6 = "Allowed" + dat += PrefLink(showtext6, PREFCMD_ALLOW_BEING_PREY) + dat += "
" // End of DIV A A F A + dat += "
" // End of DIV A A F + // Being Fed Prey + dat += "
" // DIV A A G + dat += "
" // DIV A A G A + dat += "
" // DIV A A G A A + dat += "Being Fed Prey" + dat += "
" // End of DIV A A G A A + var/showtext7 = "Disallowed" + if(allow_being_fed_prey) + showtext7 = "Allowed" + dat += PrefLink(showtext7, PREFCMD_ALLOW_BEING_FED_PREY) + dat += "
" // End of DIV A A G A + dat += "
" // End of DIV A A G + // Digestion Damage + dat += "
" // DIV A A H + dat += "
" // DIV A A H A + dat += "
" // DIV A A H A A + dat += "Digestion Damage" + dat += "
" // End of DIV A A H A A + var/showtext8 = "Disallowed" + if(allow_digestion_damage) + showtext8 = "Allowed" + dat += PrefLink(showtext8, PREFCMD_ALLOW_DIGESTION_DAMAGE) + dat += "
" // End of DIV A A H A + dat += "
" // End of DIV A A H + // Digestion Death + dat += "
" // DIV A A I + dat += "
" // DIV A A I A + dat += "
" // DIV A A I A A + dat += "Digestion Death" + dat += "
" // End of DIV A A I A A + var/showtext9 = "Disallowed" + if(allow_digestion_death) + showtext9 = "Allowed" + dat += PrefLink(showtext9, PREFCMD_ALLOW_DIGESTION_DEATH) + dat += "
" // End of DIV A A I A + dat += "
" // End of DIV A A I + // Vore Messages + dat += "
" // DIV A A J + dat += "
" // DIV A A J A + dat += "
" // DIV A A J A A + dat += "Vore Messages" + dat += "
" // End of DIV A A J A A + var/showtext10 = "Hidden" + if(allow_vore_messages) + showtext10 = "Visible" + dat += PrefLink(showtext10, PREFCMD_ALLOW_VORE_MESSAGES) + dat += "
" // End of DIV A A J A + dat += "
" // End of DIV A A J + // Vore Trash Messages + dat += "
" // DIV A A K + dat += "
" // DIV A A K A + dat += "
" // DIV A A K A A + dat += "Vore Trash Messages" + dat += "
" // End of DIV A A K A A + var/showtext11 = "Hidden" + if(allow_trash_messages) + showtext11 = "Visible" + dat += PrefLink(showtext11, PREFCMD_ALLOW_TRASH_MESSAGES) + dat += "
" // End of DIV A A K A + dat += "
" // End of DIV A A K + // Vore Death Messages + dat += "
" // DIV A A L + dat += "
" // DIV A A L A + dat += "
" // DIV A A L A A + dat += "Vore Death Messages" + dat += "
" // End of DIV A A L A A + var/showtext12 = "Hidden" + if(allow_death_messages) + showtext12 = "Visible" + dat += PrefLink(showtext12, PREFCMD_ALLOW_DEATH_MESSAGES) + dat += "
" // End of DIV A A L A + dat += "
" // End of DIV A A L + // Vore Eating Sounds + dat += "
" // DIV A A M + dat += "
" // DIV A A M A + dat += "
" // DIV A A M A A + dat += "Vore Eating Sounds" + dat += "
" // End of DIV A A M A A + var/showtext13 = "Muted" + if(allow_eating_sounds) + showtext13 = "Audible" + dat += PrefLink(showtext13, PREFCMD_ALLOW_EATING_SOUNDS) + dat += "
" // End of DIV A A M A + dat += "
" // End of DIV A A M + // Digestion Sounds + dat += "
" // DIV A A N + dat += "
" // DIV A A N A + dat += "
" // DIV A A N A A + dat += "
" // End of DIV A A N A + dat += "
" // End of DIV A A N + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/Keybindings() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += "Keymode:" + dat += "
" // End of DIV A A A A + var/showtext1 = "Input" + if(hotkeys) + showtext1 = "Hotkeys" + dat += PrefLink(showtext1, PREFCMD_HOTKEYS) + dat += "" + var/showtext2 = "What's hotkeys / input mean?" + if(keybind_hotkey_helpmode) + showtext2 = "Oh cool, thanks! (Hide help)" + dat += PrefLink(showtext2, PREFCMD_HOTKEY_HELP) + dat += "
" // End of DIV A A A + dat += "
" // End of DIV A A + if(keybind_hotkey_helpmode) + dat += "
" // DIV A B + dat += "

Keybindings mode controls how the game behaves with tab and map/input focus." + dat += "

If it is on Hotkeys, the game will always attempt to force you to map focus, meaning keypresses are sent directly to the map instead of the input. You will still be able to use the command bar, but you need to tab to do it every time you click on the game map." + dat += "

If it is on Input, the game will not force focus away from the input bar, and you can switch focus using TAB between these two modes: If the input bar is pink, that means that you are in non-hotkey mode, sending all keypresses of the normal alphanumeric characters, punctuation, spacebar, backspace, enter, etc, typing keys into the input bar. If the input bar is white, you are in hotkey mode, meaning all keypresses go into the game's keybind handling system unless you manually click on the input bar to shift focus there." + dat += "

Input mode is the closest thing to the old input system." + dat += "

IMPORTANT: While in input mode's non hotkey setting (tab toggled), Ctrl + KEY will send KEY to the keybind system as the key itself, not as Ctrl + KEY. This means Ctrl + T/W/A/S/D/all your familiar stuff still works, but you won't be able to access any regular Ctrl binds." + dat += "

Modifier-Independent binding - This is a singular bind that works regardless of if Ctrl/Shift/Alt are held down. For example, if combat mode is bound to C in modifier-independent binds, it'll trigger regardless of if you are holding down shift for sprint. Each keybind can only have one independent binding, and each key can only have one keybind independently bound to it." + dat += "

" // End of DIV A B + // keybinds! + // Create an inverted list of keybindings -> key + var/list/user_binds = list() + var/list/user_modless_binds = list() + for (var/key in key_bindings) + for(var/kb_name in key_bindings[key]) + user_binds[kb_name] += list(key) + for (var/key in modless_key_bindings) + user_modless_binds[modless_key_bindings[key]] = key + var/list/kb_categories = list() + // Group keybinds by category + for (var/name in GLOB.keybindings_by_name) + var/datum/keybinding/kb = GLOB.keybindings_by_name[name] + kb_categories[kb.category] += list(kb) + for (var/category in kb_categories) + dat += "
" // DIV A A + dat += "
" // DIV A A A + var/arrowshow = ">" + if(keybind_cat_open[category]) + arrowshow = "v" + dat += PrefLink(arrowshow, PREFCMD_KEYBINDING_CATEGORY_TOGGLE, list(PREFDAT_CATEGORY = category)) + dat += "
" // DIV A A A A + dat += category + dat += "
" // End of DIV A A A A + dat += "
" // End of DIV A A A + dat += "
" // End of DIV A A + if(!keybind_cat_open[category]) + continue // Skip if the category is closed + for (var/i in kb_categories[category]) + var/datum/keybinding/kb = i + var/current_independent_binding = "Unbound" + if(user_modless_binds[kb.name]) + current_independent_binding = user_modless_binds[kb.name] + var/list/binds_for_entry = list() + for(var/j in 1 to MAX_KEYS_PER_KEYBIND) + binds_for_entry += "None!" + if(LAZYLEN(user_binds[kb.name])) // they have something set...? + for(var/bound_key_index in 1 to length(user_binds[kb.name])) + binds_for_entry[bound_key_index] = user_binds[kb.name][bound_key_index] + var/list/default_keys = hotkeys ? kb.classic_keys : kb.hotkey_keys + var/defkeys = "None!" + if(LAZYLEN(default_keys)) + defkeys = default_keys.Join(", ") + dat += "
" // DIV A A + dat += "
" // DIV A A A + dat += "
" // DIV A A A A + dat += kb.full_name + dat += "
" // End of DIV A A A A + var/indx = 1 + for(var/bind in binds_for_entry) + var/keydata = list( + PREFDAT_KEYBINDING = kb.name, + PREFDAT_OLD_KEY = bind + ) + var/keyclass = "KeyButton Key[indx]Text" + dat += PrefLink("[bind]", PREFCMD_KEYBINDING_CAPTURE, keydata, span = keyclass) + indx++ + dat += "
" // DIV A A A A + dat += defkeys + dat += "
" // End of DIV A A A A + /// then the special independent binding + if(!kb.special && !kb.clientside) + dat += "
" // DIV A A A A + dat += "Independent Binding: " + var/keydata = list( + PREFDAT_KEYBINDING = kb.name, + PREFDAT_OLD_KEY = current_independent_binding, + PREFDAT_INDEPENDENT = 1 + ) + dat += PrefLink(current_independent_binding, PREFCMD_KEYBINDING_CAPTURE, keydata, span = "KeyButton Key[indx]Text") + dat += "
" // End of DIV A A A A + dat += "
" // End of DIV A A A + dat += "
" // End of DIV A A + dat += "
" // End of DIV A A + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/GetGearFlatList(search, list/mystuff, mine) + var/list/flatlyss = list() + for(var/gitem in GLOB.flat_loadout_items) + var/datum/gear/gear = GLOB.flat_loadout_items[gitem] + if(gear) + if(mine) + if(!mystuff["[gear.type]"]) + continue + if(search) + if(!findtext(gitem, search)) + continue + flatlyss += gear + return flatlyss + +/datum/preferences/proc/GearColorBox(datum/gear/gear, edited_color) + var/list/datae = list( + PREFDAT_COLKEY_IS_COLOR = TRUE, + PREFDAT_IS_GEAR = TRUE, + PREFDAT_GEAR_NAME = "[html_encode(gear.name)]", + PREFDAT_GEAR_PATH = "[gear.type]", + PREFDAT_LOADOUT_SLOT = "[loadout_slot]" + ) + return ColorBox(edited_color, data = datae) + +/datum/preferences/proc/RowifyQuirks() + if(!LAZYLEN(char_quirks)) + return QuirkEntry("None!", "NEUTRAL") + var/list/goodquirks = list() + var/list/neutquirks = list() + var/list/badquirks = list() + for(var/quirk in char_quirks) + var/datum/quirk/Q = SSquirks.GetQuirk(quirk) + switch(Q.value) + if(-INFINITY to -1) + badquirks += Q + if(1 to INFINITY) + goodquirks += Q + else + neutquirks += Q + var/list/dat = list() + for(var/datum/quirk/Q in goodquirks) + dat += QuirkEntry(Q.name, "GOOD") + for(var/datum/quirk/Q in neutquirks) + dat += QuirkEntry(Q.name, "NEUTRAL") + for(var/datum/quirk/Q in badquirks) + dat += QuirkEntry(Q.name, "BAD") + return dat.Join() + +/datum/preferences/proc/QuirkEntry(q_name, quality) + var/list/dat = list() + dat += "
" // DIV A + var/q_span = "" + switch(quality) + if("GOOD") + q_span = "QuirkGood" + if("BAD") + q_span = "QuirkBad" + else + q_span = "QuirkNeutral" + dat += "[q_name]" + dat += "
" // End of DIV A + return dat.Join() + +/// Builds a cool toolbar for colorstuff +/// has two parts: a top and a bottom +/// the top has the Big Three mutant colors (and the undies button) +/// the bottom has a history of colors (up to, oh, 5?) +/datum/preferences/proc/ColorToolbar() + var/list/dat = list() + dat += "
" // DIV A + dat += "
" // DIV A A + var/list/data = list(PREFDAT_COLKEY_IS_FEATURE = TRUE) + dat += ColorBox("mcolor", data = data) + dat += ColorBox("mcolor2", data = data) + dat += ColorBox("mcolor3", data = data) + dat += "" + var/chundies = preview_hide_undies ? "Hiding Undies" : "Showing Undies" + dat += PrefLink("[chundies]", PREFDAT_TOGGLE_HIDE_UNDIES, span = "SettingName") + dat += "
" // End of DIV A A + /// History of colors + dat += "
" // DIV A B + CleanupColorHistory() + for(var/color in color_history) + dat += ColorBox(color, TRUE) + dat += "
" // End of DIV A B + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/ColorBox(colkey, history = FALSE, list/data = list()) + var/list/dat = list() + data[PREFDAT_COLOR_KEY] = colkey + dat += "
" // DIV A + var/col = "FFFFFF" + if(history) + col = colkey + data[PREFDAT_COLOR_HEX] = col + dat += "
" + dat += "[colkey]" + dat += "
" // End of DIV A A + else + if(data[PREFDAT_COLKEY_IS_COLOR]) + col = colkey + else + col = GetColor(colkey) + data[PREFDAT_COLOR_HEX] = col + dat += PrefLink("[col]", PREFCMD_COLOR_CHANGE, data, span = "ColorBoxxo", style = "background-color: #[col];") + var/cbut = "" + var/pbut = "" + dat += PrefLink("[cbut]", PREFCMD_COLOR_COPY, data, span = "SmolBox") + dat += PrefLink("[pbut]", PREFCMD_COLOR_PASTE, data, span = "SmolBox") + if(history) + dat += PrefLink("X", PREFCMD_COLOR_DEL, data, span = "SmolBox") + dat += "
" // End of DIV A + return dat.Join() + +/datum/preferences/proc/GetColor(colkey) + if(GLOB.features_that_are_colors[colkey]) + if(!is_color(features[colkey])) + features[colkey] = "FFFFFF" + return features[colkey] + /// because we have some colors in the features and SOME colors as hardvars + /// we need to suck this dikc + if(colkey in vars) + var/maybecolor = vars["[colkey]"] + if(is_color(maybecolor)) + return maybecolor + stack_trace("GetColor: Couldn't find color for [colkey]!") + return "FFFFFF" + +// pda_color +// undie_color +// shirt_color +// socks_color +// hair_color +// facial_hair_color +// left_eye_color +// right_eye_color +// personal_chat_color +// hud_toggle_color + +/datum/preferences/proc/MarkingColorBox(list/marking = list(), col_index) + var/truecolor = marking[MARKING_COLOR_LIST][col_index] + var/marking_uid = marking[MARKING_UID] + var/marking_slot = col_index + var/list/data = list( + PREFDAT_COLKEY_IS_COLOR = TRUE, + PREFDAT_IS_MARKING = TRUE, + PREFDAT_MARKING_UID = marking_uid, + PREFDAT_MARKING_SLOT = marking_slot + ) + return ColorBox(truecolor, data = data) + +/datum/preferences/proc/MarkingPrefLink(text, cmd, marking_uid, span) + var/command = PREFCMD_MARKING_EDIT + var/list/data = list(PREFDAT_MARKING_UID = marking_uid) + data[PREFDAT_MARKING_ACTION] = cmd + return PrefLink(text, command, data, span = span) + +/datum/preferences/proc/CoolDivider() + return "
" + + + diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 9bb2c6ae80..e3dbf48f81 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1,7 +1,3 @@ -#define MAX_FREE_PER_CAT 4 -#define HANDS_SLOT_AMT 2 -#define BACKPACK_SLOT_AMT 4 - #define DEFAULT_FEATURES list(\ "mcolor" = "CCCCCC",\ "mcolor2" = "EEEEEE",\ @@ -99,7 +95,14 @@ "body_size" = RESIZE_DEFAULT_SIZE,\ "body_width" = RESIZE_DEFAULT_WIDTH,\ "color_scheme" = ADVANCED_CHARACTER_COLORING,\ - "chat_color" = "whoopsie") + "chat_color" = "whoopsie",\ + "grad_color" = "FFFFFF",\ + "grad_style" = "None",\ + "grad_color_2" = "FFFFFF",\ + "grad_style_2" = "None",\ + "hair_color_2" = "FFFFFF",\ + "hair_style_2" = "Bald",\ + ) GLOBAL_LIST_EMPTY(preferences_datums) @@ -239,6 +242,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/backbag = DBACKPACK //backpack type var/jumpsuit_style = PREF_SUIT //suit/skirt var/hair_style = "Bald" //Hair type + /// unused -V var/hair_style_2 = "Bald" //Hair type var/hair_color = "000000" //Hair color var/facial_hair_style = "Shaved" //Face hair type @@ -252,7 +256,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/tbs = TBS_DEFAULT // turner broadcasting system var/kisser = KISS_DEFAULT // Kiss this / V \. /// which quester UID we're using ( | ). - var/quester_uid // (__________) (__________) + var/quester_uid // (___________|___________) var/dm_open = TRUE var/needs_a_friend = FALSE // for the quest var/list/blocked_from_dms = list() // list of quids @@ -366,7 +370,13 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/joblessrole = RETURNTOLOBBY //defaults to returning to lobby // 0 = character settings, 1 = game preferences - var/current_tab = SETTINGS_TAB + var/current_tab = PPT_CHARCTER_PROPERTIES + + // 0 = character settings, 1 = game preferences + var/current_subtab = PPT_CHARCTER_PROPERTIES_INFO + + // 0 = character settings, 1 = game preferences + var/current_sub_subtab = PPT_CHARCTER_APPEARANCE_UNDERLYING_UNDIES // If in the ERP tab, are we rearranging genitals var/erp_tab_page = ERP_TAB_HOME @@ -406,6 +416,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/list/bgstate_options = list("000", "midgrey", "FFF", "white", "steel", "techmaint", "dark", "plating", "reinforced") var/show_mismatched_markings = TRUE //determines whether or not the markings lists should show markings that don't match the currently selected species. Intentionally left unsaved. + var/show_all_parts = FALSE //determines whether or not the markings lists should show markings that don't match the currently selected species. Intentionally left unsaved. var/no_tetris_storage = FALSE @@ -483,9 +494,17 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/show_this_many = 30 var/names_per_row = 6 + var/charlist_hidden = FALSE var/hear_people_on_other_zs = TRUE + var/list/color_history = list() + var/current_color + + var/list/keybind_cat_open = list() + var/keybind_hotkey_helpmode = FALSE + var/loadout_search + /datum/preferences/New(client/C) parent = C @@ -522,1313 +541,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) menuoptions = list() return -#define APPEARANCE_CATEGORY_COLUMN "" -#define ERP_CATEGORY_ROW "" -#define MAX_MUTANT_ROWS 5 - -/datum/preferences/proc/ShowChoices(mob/user) - if(!user || !user.client) - return - - if(CONFIG_GET(flag/use_role_whitelist)) - user.client.set_job_whitelist_from_db() - - update_preview_icon(current_tab) - var/list/dat = list("
") - - dat += "Character Settings" - dat += "Character Appearance" - dat += "Character Info" - dat += "Underlying Appearance" - dat += "Loadout" - dat += "Game Preferences" - dat += "Adult Preferences" - dat += "Keybindings" - - if(!path) - dat += "
Please create an account to save your preferences
" - - dat += "
" - - dat += "
" - - switch(current_tab) - if(SETTINGS_TAB) // Character Settings# - if(path) - var/savefile/S = new /savefile(path) - if(S) - dat += "
" - dat += "" - var/name - var/unspaced_slots = 0 - for(var/i=1, i<=min(max_save_slots, show_this_many), i++) - unspaced_slots++ - if(unspaced_slots > names_per_row) - dat += "" - dat += "" - unspaced_slots = 1 - dat += "" - dat += "
" - S.cd = "/character[i]" - S["real_name"] >> name - if(!name) - name = "Character[i]" - dat += "[name] " - dat += "
" - dat += "
" - dat += "Copy | Paste" - dat += " | Showing [show_this_many] characters, [names_per_row] per row" - if(copyslot) - dat += "
Copying FROM: [copyslot] ([copyname])" - - dat += "

Quest Board UID

" - dat += "[quester_uid]
" - var/cash_change = SSeconomy.player_login(src) - var/list/llogin_msg = list() - llogin_msg += "
Last Login: [time2text(last_quest_login)]" - llogin_msg += " Banked Cash: [SSeconomy.format_currency(saved_unclaimed_points, TRUE)]" - if(cash_change > 0) - llogin_msg += " ([span_green("[SSeconomy.format_currency(cash_change, TRUE)]")] activity bonus)" - else if(cash_change < 0) - llogin_msg += " ([span_alert("[SSeconomy.format_currency(cash_change, TRUE)]")] inactivity tax)" - llogin_msg += "
" - dat += llogin_msg.Join() - if(CONFIG_GET(flag/roundstart_traits)) - dat += "
" - if(SSquirks.initialized && !(PMC_QUIRK_OVERHAUL_2K23 in current_version)) - dat += "CLICK HERE to migrate your old quirks to the new system!" - dat += "" - dat += "

Configure Quirks


" - dat += "" - dat += "
Current Quirks: [get_my_quirks()]
" - dat += "

S.P.E.C.I.A.L.

" - dat += "Allocate Points
" - //Left Column - dat += "" -/* //Middle Column - dat +="" -*/ - //Right column - dat +="" - /* - dat += "Special Names:
" - var/old_group - for(var/custom_name_id in GLOB.preferences_custom_names) - var/namedata = GLOB.preferences_custom_names[custom_name_id] - if(!old_group) - old_group = namedata["group"] - else if(old_group != namedata["group"]) - old_group = namedata["group"] - dat += "
" - dat += "[namedata["pref_name"]]: [custom_names[custom_name_id]] " - dat += "

" - - Records disabled until a use for them is found - dat += "Custom job preferences:
" - dat += "Preferred AI Core Display: [preferred_ai_core_display]
" - dat += "Preferred Security Department: [prefered_security_department]
" - dat += "
Records
" - dat += "
Security Records
" - if(length_char(security_records) <= 40) - if(!length(security_records)) - dat += "\[...\]" - else - dat += "[security_records]" - else - dat += "[TextPreview(security_records)]...
" - - dat += "
Medical Records
" - if(length_char(medical_records) <= 40) - if(!length(medical_records)) - dat += "\[...\]
" - else - dat += "[medical_records]" - else - dat += "[TextPreview(medical_records)]...
" - dat += "
Hide ckey: [hide_ckey ? "Enabled" : "Disabled"]
" - */ - dat += "
" - dat += "

Identity

" - if(jobban_isbanned(user, "appearance")) - dat += "You are banned from using custom names and appearances. You can continue to adjust your characters, but you will be randomised once you join the game.
" - - dat += "Configure VisualChat / Profile Pictures!
" - dat += "Name: " - dat += "[real_name]
" - - dat += "Gender: [gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" - dat += "Age: [age]
" - dat += "Top/Bottom/Switch: [tbs || "Set me!"]
" - dat += "Orientation: [kisser || "Set me!"]
" - dat += "When you despawn, all your equipment... [stash_equipment_on_logout?"will be left where you despawn":"will be deleted"]
" - dat += "Your equipment, if left behind... [lock_equipment_on_logout?"will be locked (only you can open it)":"will be open for everyone"]
" - dat += "
" - dat += "

Matchmaking preferences:

" - if(SSmatchmaking.initialized) - for(var/datum/matchmaking_pref/match_pref as anything in SSmatchmaking.all_match_types) - var/max_matches = initial(match_pref.max_matches) - if(!max_matches) - continue // Disabled. - var/current_value = clamp((matchmaking_prefs[match_pref] || 0), 0, max_matches) - var/set_name = !current_value ? "Disabled" : (max_matches == 1 ? "Enabled" : "[current_value]") - dat += "[initial(match_pref.pref_text)]: [set_name]
" - else - dat += "Loading matchmaking preferences...
" - dat += "Refresh once the game has finished setting up...
" - dat += "
" - dat += "Configure VisualChat / Profile Pictures!
" - // dat += "

Profile Picture ([pfphost]):


" - var/pfplink = SSchat.GetPicForMode(user, MODE_PROFILE_PIC) - dat += "Picture: [pfplink ? "" : "Upload a picture!"]
" - dat += "
" - - - //Character Appearance - if(APPEARANCE_TAB) - if(path) - var/savefile/S = new /savefile(path) - if(S) - dat += "
" - var/name - var/unspaced_slots = 0 - for(var/i=1, i<=max_save_slots, i++) - unspaced_slots++ - if(unspaced_slots > 8) - dat += "
" - unspaced_slots = 0 - S.cd = "/character[i]" - S["real_name"] >> name - if(!name) - name = "Character[i]" - dat += "[name] " - dat += "
" - dat += "" - dat += APPEARANCE_CATEGORY_COLUMN - var/use_skintones = pref_species.use_skintones - var/mutant_colors - if((MUTCOLORS in pref_species.species_traits) || (MUTCOLORS_PARTSONLY in pref_species.species_traits)) - if(!use_skintones) - dat += "Primary Color:
" - dat += "   Change
" - - dat += "Secondary Color:
" - dat += "   Change
" - - dat += "Tertiary Color:
" - dat += "   Change
" - mutant_colors = TRUE - - if(use_skintones) - dat += "

Skin Tone

" - dat += "[use_custom_skin_tone ? "custom:    " : skin_tone]
" - - if (CONFIG_GET(number/body_size_min) != CONFIG_GET(number/body_size_max)) - dat += "Sprite Size:[features["body_size"]*100]%
" - if (CONFIG_GET(number/body_width_min) != CONFIG_GET(number/body_width_max)) - dat += "Sprite Width:[features["body_width"]*100]%
" - dat += "Scaling:[fuzzy ? "Fuzzy" : "Sharp"]
" - - dat += "Limb Modification:
" - dat += "Modify Limbs
" - for(var/modification in modified_limbs) - if(modified_limbs[modification][1] == LOADOUT_LIMB_PROSTHETIC) - dat += "[modification]: [modified_limbs[modification][2]]
" - else - dat += "[modification]: [modified_limbs[modification][1]]
" - - dat += "" - // END COLUMN 1 - // START COLUMN 2 - dat += APPEARANCE_CATEGORY_COLUMN - if(!(NOEYES in pref_species.species_traits)) - dat += "

Eyes

" - dat += "[eye_type]" - if((EYECOLOR in pref_species.species_traits)) - if(!use_skintones && !mutant_colors) - dat += APPEARANCE_CATEGORY_COLUMN - if(left_eye_color != right_eye_color) - split_eye_colors = TRUE - dat += "[eye_over_hair ? "Over Hair" : "Under Hair"]" - dat += "Heterochromia
" - dat += "[split_eye_colors ? "Enabled" : "Disabled"]" - if(!split_eye_colors) - dat += "Eye Color
" - dat += "   Change
" - else - dat += "Left Color
" - dat += "   Change
" - dat += "Right Color
" - dat += "   Change
" - // END COLUMN 2 - dat += APPEARANCE_CATEGORY_COLUMN - if(HAIR in pref_species.species_traits) - dat += "

Hair

" - dat += "Style Up:
" - dat += "[hair_style]
" - dat += "
<>
" - dat += "   Change

" - - // Coyote ADD: Hair gradients - dat += "Gradient Up:
" - dat += "[features_override["grad_style"]]" - dat += "   Change

" - // Coyote ADD: End - - dat += "Style Down:
" - dat += "[features_override["hair_style_2"]]" - dat += "<>
" - dat += "   Change

" - - dat += "Gradient Down:
" - dat += "[features_override["grad_style_2"]]" - dat += "   Change

" - - dat += "Facial Style:
" - dat += "[facial_hair_style]
" - dat += "
<>
" - dat += "   Change

" - - dat += "Show/hide Undies:
" - dat += "[preview_hide_undies ? "Hidden" : "Visible"]
" - - dat += "" - - //end column 3 or something - //start column 4 - dat += APPEARANCE_CATEGORY_COLUMN - //Waddling - dat += "

Waddling

" - dat += "Waddle Amount:
[waddle_amount]
" - if(waddle_amount > 0) - dat += "↔ Speed:[up_waddle_time]
" - dat += "↕ Speed:[side_waddle_time]
" - - - dat += "

Misc

" - dat += "Custom Taste:[features["taste"] ? features["taste"] : "something"]
" - dat += "Runechat Color:#[features["chat_color"]]
" - dat += "Blood Color:#[features["blood_color"]]
" - dat += "Reset Blood Color
" - dat += "Rainbow Blood Color
" - dat += "Background:[bgstate]
" - dat += "Pixel Offsets
" - var/px = custom_pixel_x > 0 ? "+[custom_pixel_x]" : "[custom_pixel_x]" - var/py = custom_pixel_y > 0 ? "+[custom_pixel_y]" : "[custom_pixel_y]" - dat += "↔[px]
" - dat += "↕[py]
" - - dat += "" - //Mutant stuff - var/mutant_category = 0 - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) //just in case someone sets the max rows to 1 or something dumb like that - dat += "" - mutant_category = 0 - - // rp marking selection - // assume you can only have mam markings or regular markings or none, never both - var/marking_type - dat += APPEARANCE_CATEGORY_COLUMN - if(parent.can_have_part("mam_body_markings")) - marking_type = "mam_body_markings" - if(marking_type) - dat += "

[GLOB.all_mutant_parts[marking_type]]

" // give it the appropriate title for the type of marking - dat += "Add marking" - // list out the current markings you have - if(length(features[marking_type])) - dat += "
" - - // START COLUMN 1 - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Body

" - - dat += "Species:[pref_species.name]
" - - if(LAZYLEN(pref_species.alt_prefixes)) - dat += "Alt Appearance:[alt_appearance ? alt_appearance : "Select"]
" - - dat += "Custom Species Name:[custom_species ? custom_species : "None"]
" - - dat += "Gender:[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" - - if(gender != NEUTER && pref_species.sexes) - dat += "Body Model:[features["body_model"] == MALE ? "Masculine" : "Feminine"]
" - - if(length(pref_species.allowed_limb_ids)) - if(!chosen_limb_id || !(chosen_limb_id in pref_species.allowed_limb_ids)) - chosen_limb_id = pref_species.limbs_id || pref_species.id - dat += "Body Sprite:[chosen_limb_id]
" - dat += "
" - var/list/markings = features[marking_type] - if(!islist(markings)) - // something went terribly wrong - markings = list() - var/list/reverse_markings = reverseList(markings) - for(var/list/marking_list in reverse_markings) - var/marking_index = markings.Find(marking_list) // consider changing loop to go through indexes over lists instead of using Find here - var/limb_value = marking_list[1] - var/actual_name = GLOB.bodypart_names[num2text(limb_value)] // get the actual name from the bitflag representing the part the marking is applied to - var/color_marking_dat = "" - var/number_colors = 1 - var/datum/sprite_accessory/mam_body_markings/S = GLOB.mam_body_markings_list[marking_list[2]] - var/matrixed_sections = S.covered_limbs[actual_name] - if(S && matrixed_sections) - // if it has nothing initialize it to white - if(length(marking_list) == 2) - var/first = "#FFFFFF" - var/second = "#FFFFFF" - var/third = "#FFFFFF" - if(features["mcolor"]) - first = "#[features["mcolor"]]" - if(features["mcolor2"]) - second = "#[features["mcolor2"]]" - if(features["mcolor3"]) - third = "#[features["mcolor3"]]" - marking_list += list(list(first, second, third)) // just assume its 3 colours if it isnt it doesnt matter we just wont use the other values - // index magic - var/primary_index = 1 - var/secondary_index = 2 - var/tertiary_index = 3 - switch(matrixed_sections) - if(MATRIX_GREEN) - primary_index = 2 - if(MATRIX_BLUE) - primary_index = 3 - if(MATRIX_RED_BLUE) - secondary_index = 2 - if(MATRIX_GREEN_BLUE) - primary_index = 2 - secondary_index = 3 - - // we know it has one matrixed section at minimum - color_marking_dat += "   " - // if it has a second section, add it - if(matrixed_sections == MATRIX_RED_BLUE || matrixed_sections == MATRIX_GREEN_BLUE || matrixed_sections == MATRIX_RED_GREEN || matrixed_sections == MATRIX_ALL) - color_marking_dat += "   " - number_colors = 2 - // if it has a third section, add it - if(matrixed_sections == MATRIX_ALL) - color_marking_dat += "   " - number_colors = 3 - color_marking_dat += " Change
" - dat += "" - dat += "
[marking_list[2]] - [actual_name] ˄ ˅ X [color_marking_dat]
" - - for(var/mutant_part in GLOB.all_mutant_parts) - if(mutant_part == "mam_body_markings") - continue - if(parent.can_have_part(mutant_part)) - if(!mutant_category) - dat += APPEARANCE_CATEGORY_COLUMN - dat += "

[GLOB.all_mutant_parts[mutant_part]]

" - dat += "[features[mutant_part]]" - var/color_type = GLOB.colored_mutant_parts[mutant_part] //if it can be coloured, show the appropriate button - if(color_type) - dat += "    Change
" - else - if(features["color_scheme"] == ADVANCED_CHARACTER_COLORING) //advanced individual part colouring system - //is it matrixed or does it have extra parts to be coloured? - var/find_part = features[mutant_part] || pref_species.mutant_bodyparts[mutant_part] - var/find_part_list = GLOB.mutant_reference_list[mutant_part] - if(find_part && find_part != "None" && find_part_list) - var/datum/sprite_accessory/accessory = find_part_list[find_part] - if(accessory) - if(accessory.color_src == MATRIXED || accessory.color_src == MUTCOLORS || accessory.color_src == MUTCOLORS2 || accessory.color_src == MUTCOLORS3) //mutcolors1-3 are deprecated now, please don't rely on these in the future - var/mutant_string = accessory.mutant_part_string - var/primary_feature = "[mutant_string]_primary" - var/secondary_feature = "[mutant_string]_secondary" - var/tertiary_feature = "[mutant_string]_tertiary" - if(!features[primary_feature]) - features[primary_feature] = features["mcolor"] - if(!features[secondary_feature]) - features[secondary_feature] = features["mcolor2"] - if(!features[tertiary_feature]) - features[tertiary_feature] = features["mcolor3"] - - var/matrixed_sections = accessory.matrixed_sections - if(accessory.color_src == MATRIXED && !matrixed_sections) - message_admins("Sprite Accessory Failure (customization): Accessory [accessory.type] is a matrixed item without any matrixed sections set!") - continue - else if(accessory.color_src == MATRIXED) - switch(matrixed_sections) - if(MATRIX_GREEN) //only composed of a green section - primary_feature = secondary_feature //swap primary for secondary, so it properly assigns the second colour, reserved for the green section - if(MATRIX_BLUE) - primary_feature = tertiary_feature //same as above, but the tertiary feature is for the blue section - if(MATRIX_RED_BLUE) //composed of a red and blue section - secondary_feature = tertiary_feature //swap secondary for tertiary, as blue should always be tertiary - if(MATRIX_GREEN_BLUE) //composed of a green and blue section - primary_feature = secondary_feature //swap primary for secondary, as first option is green, which is linked to the secondary - secondary_feature = tertiary_feature //swap secondary for tertiary, as second option is blue, which is linked to the tertiary - dat += "Primary Color
" - dat += "    Change
" - if((accessory.color_src == MATRIXED && (matrixed_sections == MATRIX_RED_BLUE || matrixed_sections == MATRIX_GREEN_BLUE || matrixed_sections == MATRIX_RED_GREEN || matrixed_sections == MATRIX_ALL)) || (accessory.extra && (accessory.extra_color_src == MUTCOLORS || accessory.extra_color_src == MUTCOLORS2 || accessory.extra_color_src == MUTCOLORS3))) - dat += "Secondary Color
" - dat += "    Change
" - if((accessory.color_src == MATRIXED && matrixed_sections == MATRIX_ALL) || (accessory.extra2 && (accessory.extra2_color_src == MUTCOLORS || accessory.extra2_color_src == MUTCOLORS2 || accessory.extra2_color_src == MUTCOLORS3))) - dat += "Tertiary Color
" - dat += "    Change
" - - mutant_category++ - if(mutant_category >= MAX_MUTANT_ROWS) - dat += "" - mutant_category = 0 - - if(mutant_category) - dat += "" - mutant_category = 0 - - dat += "" - - dat += "" - - dat += "" - /*Uplink choice disabled since not implemented, pointless button - dat += "Uplink Location:[uplink_spawn_loc]" - dat += ""*/ - - /// HA HA! I HAVE DELETED YOUR PRECIOUS NAUGHTY PARTS, YOU HORNY ANIMALS! - /* dat +="" // - if(NOGENITALS in pref_species.species_traits) - dat += "Your species ([pref_species.name]) does not support genitals!
" - else - dat += "

Penis

" - dat += "[features["has_cock"] == TRUE ? "Yes" : "No"]" - if(features["has_cock"]) - if(!pref_species.use_skintones) - dat += "Penis Color:
" - dat += "    Change
" - var/tauric_shape = FALSE - if(features["cock_taur"]) - var/datum/sprite_accessory/penis/P = GLOB.cock_shapes_list[features["cock_shape"]] - if(P.taur_icon && parent.can_have_part("taur")) - var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]] - if(T.taur_mode & P.accepted_taurs) - tauric_shape = TRUE - dat += "Penis Shape: [features["cock_shape"]][tauric_shape ? " (Taur)" : ""]" - dat += "Penis Length: [features["cock_length"]] inch(es)" - dat += "Penis Visibility:[features["cock_visibility"]]" - dat += "Has Testicles:[features["has_balls"] == TRUE ? "Yes" : "No"]" - if(features["has_balls"]) - if(!pref_species.use_skintones) - dat += "Testicles Type: [features["balls_shape"]]" - dat += "Testicles Color:
" - dat += "    Change
" - dat += "Testicles Visibility:[features["balls_visibility"]]" - dat += APPEARANCE_CATEGORY_COLUMN - dat += "

Vagina

" - dat += "[features["has_vag"] == TRUE ? "Yes": "No" ]" - if(features["has_vag"]) - dat += "Vagina Type: [features["vag_shape"]]" - if(!pref_species.use_skintones) - dat += "Vagina Color:
" - dat += "    Change
" - dat += "Vagina Visibility:[features["vag_visibility"]]" - dat += "Has Womb:[features["has_womb"] == TRUE ? "Yes" : "No"]" - dat += "" - dat += APPEARANCE_CATEGORY_COLUMN - dat += "

Breasts

" - dat += "[features["has_breasts"] == TRUE ? "Yes" : "No" ]" - if(features["has_breasts"]) - if(!pref_species.use_skintones) - dat += "Color:
" - dat += "    Change
" - dat += "Cup Size:[features["breasts_size"]]" - dat += "Breasts Shape:[features["breasts_shape"]]" - dat += "Breasts Visibility:[features["breasts_visibility"]]" - dat += "Lactates:[features["breasts_producing"] == TRUE ? "Yes" : "No"]" - dat += "" - dat += APPEARANCE_CATEGORY_COLUMN - dat += "

Belly

" - dat += "[features["has_belly"] == TRUE ? "Yes" : "No" ]" - if(features["has_belly"]) - if(!pref_species.use_skintones) - dat += "Color:
" - dat += "    Change
" - dat += "Belly Size:[features["belly_size"]]" - dat += "Belly Shape:[features["belly_shape"]]" - dat += "Belly Visibility:[features["belly_visibility"]]" - dat += "" - dat += APPEARANCE_CATEGORY_COLUMN - dat += "

Butt

" - dat += "[features["has_butt"] == TRUE ? "Yes" : "No"]" - if(features["has_butt"]) - if(!pref_species.use_skintones) - dat += "Color:
" - dat += "    Change
" - dat += "Butt Size:[features["butt_size"]]" - dat += "Butt Visibility:[features["butt_visibility"]]" - dat += "" - dat += "" - dat += ""*/ - - if(CHAR_INFO_TAB) - if(path) - var/savefile/S = new /savefile(path) - if(S) - dat += "
" - var/name - var/unspaced_slots = 0 - for(var/i=1, i<=max_save_slots, i++) - unspaced_slots++ - if(unspaced_slots > 8) - dat += "
" - unspaced_slots = 0 - S.cd = "/character[i]" - S["real_name"] >> name - if(!name) - name = "Character[i]" - dat += "[name] " - dat += "
" - dat += "" - dat += APPEARANCE_CATEGORY_COLUMN - - - - dat += "" - dat += APPEARANCE_CATEGORY_COLUMN - - dat += "

Voice

" - - // Coyote ADD: Blurbleblurhs - dat += "Voice Sound:[features_speech["typing_indicator_sound"]]
" - dat += "Voice When:[features_speech["typing_indicator_sound_play"]]
" - dat += "[features_speech["typing_indicator_speed"]]
" - dat += "[features_speech["typing_indicator_pitch"]]
" - dat += "[features_speech["typing_indicator_variance"]]
" - dat += "[features_speech["typing_indicator_volume"]]
" - dat += "[features_speech["typing_indicator_max_words_spoken"]]
" - dat += "" - - dat += APPEARANCE_CATEGORY_COLUMN - dat += "

Custom Say Verbs

" - dat += "Says" - dat += "
Whispers" - dat += "
Asks" - dat += "
Exclaims" - dat += "
Yells" - dat += "
Sings" - //dat += "
Preview Sound Indicator
" - dat += "" - // Coyote ADD: End - /// just kidding I moved it down here lol - if(ERP_TAB) // hoo haw preferences - if(path) - var/savefile/S = new /savefile(path) - if(S) - dat += "
" - var/name - var/unspaced_slots = 0 - for(var/i=1, i<=max_save_slots, i++) - unspaced_slots++ - if(unspaced_slots > 8) - dat += "
" - unspaced_slots = 0 - S.cd = "/character[i]" - S["real_name"] >> name - if(!name) - name = "Character[i]" - dat += "[name] " - dat += "

" - if(!path) - dat += "
Please create an account to save your preferences
" - if(NOGENITALS in pref_species.species_traits) - dat += "
Your species ([pref_species.name]) does not support genitals! These won't apply to your species!


" - dat += {" - Layering and Visibility - "} - dat += {" - Underwear and Socks - "} - dat += "
" - // here be gonads - for(var/dic in PREFS_ALL_HAS_GENITALS) - dat += {" - [GLOB.hasgenital2genital[dic]] - "} - dat += "
" - dat += "
" - - switch(erp_tab_page) - if(ERP_TAB_REARRANGE) - var/list/all_genitals = decode_cockstring() // i made it i can call it whatever I want - var/list/genitals_we_have = list() - dat += "
" - dat += APPEARANCE_CATEGORY_COLUMN - dat += "

Flavor Text

" - dat += "Set Examine Text
" - dat += "Configure VisualChat / Profile Pictures!
" - if(length(features["flavor_text"]) <= 40) - if(!length(features["flavor_text"])) - dat += "\[...\]" - else - dat += "[features["flavor_text"]]" - else - dat += "[TextPreview(features["flavor_text"])]...
" - dat += "

Silicon Flavor Text

" - dat += "Set Silicon Examine Text
" - if(length(features["silicon_flavor_text"]) <= 40) - if(!length(features["silicon_flavor_text"])) - dat += "\[...\]" - else - dat += "[features["silicon_flavor_text"]]" - else - dat += "[TextPreview(features["silicon_flavor_text"])]...
" - dat += "

OOC notes

" - dat += "Set OOC notes
" - var/ooc_notes_len = length(features["ooc_notes"]) - if(ooc_notes_len <= 40) - if(!ooc_notes_len) - dat += "\[...\]
" - else - dat += "[features["ooc_notes"]]
" - else - dat += "[TextPreview(features["ooc_notes"])]...
" - - // dat += "Set Background Info Notes
" - // var/background_info_notes_len = length(features["background_info_notes"]) - // if(background_info_notes_len <= 40) - // if(!background_info_notes_len) - // dat += "\[...\]
" - // else - // dat += "[features["background_info_notes"]]
" - // else - // dat += "[TextPreview(features["background_info_notes"])]...
" - - //outside link stuff - dat += "

Outer hyper-links settings

" - dat += "Set F-list link
" - var/flist_len = length(features["flist"]) - if(flist_len <= 40) - if(!flist_len) - dat += "\[...\]" - else - dat += "[features["flist"]]" - else - dat += "[TextPreview(features["flist"])]...
" - - dat += "
" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - - for(var/nad in all_genitals) - genitals_we_have += nad - if(LAZYLEN(all_genitals)) - for(var/i in 1 to LAZYLEN(genitals_we_have)) - dat += add_genital_layer_piece(genitals_we_have[i], i, LAZYLEN(genitals_we_have)) - else - dat += "I dont seem to have any movable genitals!" - dat += "" - dat += "" - /* var/genital_shirtlayer - if(CHECK_BITFIELD(features["genital_visibility_flags"], GENITAL_ABOVE_UNDERWEAR)) - genital_shirtlayer = "Over Underwear" - else if(CHECK_BITFIELD(features["genital_visibility_flags"], GENITAL_ABOVE_CLOTHING)) - genital_shirtlayer = "Over Clothes" - else - genital_shirtlayer = "Under Underwear" */ - dat += {""} - - dat += {""} - dat += {""} - dat += "
ShiftHidden by...OverrideSee on others?
Hide Undies In Preview - - [preview_hide_undies ? "Hidden" : "Visible"] - - - Over Clothes - - - Whitelisted Names - -
" - if(ERP_TAB_HOME)/// UNDERWEAR GOES HERE - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += {"" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - dat += "
" - dat += "

Clothing & Equipment

" - dat += "
" - dat += "
Topwear
" - dat += {" - [undershirt] - "} - dat += {" - \t#[shirt_color] - "} - dat += {" - [LAZYACCESS(GLOB.undie_position_strings, undershirt_overclothes + 1)] - "} - dat += "
" - dat += "
Bottomwear
" - dat += {" - [underwear] - "} - dat += {" - \t#[undie_color] - "} - dat += {" - [LAZYACCESS(GLOB.undie_position_strings, undies_overclothes + 1)] - "} - dat += "
-
Legwear
- - [socks] - "} - dat += {" - \t#[socks_color] - "} - dat += {" - [LAZYACCESS(GLOB.undie_position_strings, socks_overclothes + 1)] - "} - dat += "
" - dat += "
Backpack
" - dat += {" - [backbag] - "} - dat += "" - dat += "
" - dat += "
Persistent Scars
" - dat += {" - [persistent_scars ? "Enabled" : "Disabled"] - "} - dat += {" - \tClear them? - "} - dat += "
" - dat += "
Underwear Settings
" - dat += {" - Layered [underwear_overhands ? "OVER" : "UNDER"] hands - "} - dat += {" - Cuteness: 100% - "} - dat += "
" - dat += "
Hide Undies In Preview
" - dat += {" - [preview_hide_undies ? "Hidden" : "Visible"] - "} - dat += "
" - dat += "
PDA Style
" - dat += {" - [pda_skin] - "} - dat += "
" - dat += "
PDA Ringmessage
" - dat += {" - [pda_ringmessage] - "} - dat += "
" - if(PREFS_ALL_HAS_GENITALS_SET) // fuck it - dat += build_genital_setup() - - - if(GAME_PREFERENCES_TAB) // Game Preferences - dat += "" - if(user.client.holder) - dat +="" - - dat +="" - dat += "
" - dat += "

General Settings

" - dat += "Input Mode Hotkey: [input_mode_hotkey]
" - dat += "UI Style: [UI_style]
" - dat += "tgui Monitors: [(tgui_lock) ? "Primary" : "All"]
" - dat += "tgui Style: [(tgui_fancy) ? "Fancy" : "No Frills"]
" - dat += "Show Runechat Chat Bubbles: [chat_on_map ? "Enabled" : "Disabled"]
" - dat += "Runechat message char limit: [max_chat_length]
" - dat += "Runechat message width: [chat_width]
" - dat += "Runechat off-screen: [see_fancy_offscreen_runechat ? "Enabled" : "Disabled"]
" - dat += "See Runechat for non-mobs: [see_chat_non_mob ? "Enabled" : "Disabled"]
" - dat += "See Runechat emotes: [see_rc_emotes ? "Enabled" : "Disabled"]
" - dat += "Use Runechat color in chat log: [color_chat_log ? "Enabled" : "Disabled"]
" - dat += "
" - dat += "See Runechat / hear sounds above/below you: [hear_people_on_other_zs ? "Enabled" : "Disabled"]
" - dat += "
" - dat += "Action Buttons: [(buttons_locked) ? "Locked In Place" : "Unlocked"]
" - dat += "
" - dat += "PDA Color:     Change
" - //dat += "PDA Style: [pda_style]
" - //dat += "PDA Reskin: [pda_skin]
" - dat += "
" - dat += "Ghost Ears: [(chat_toggles & CHAT_GHOSTEARS) ? "All Speech":"Nearest Creatures"]
" - dat += "Ghost Radio: [(chat_toggles & CHAT_GHOSTRADIO) ? "All Messages":"No Messages"]
" - dat += "Ghost Sight: [(chat_toggles & CHAT_GHOSTSIGHT) ? "All Emotes":"Nearest Creatures" ]
" - dat += "Ghost Whispers: [(chat_toggles & CHAT_GHOSTWHISPER) ? "All Speech":"Nearest Creatures"]
" - dat += "Ghost PDA: [(chat_toggles & CHAT_GHOSTPDA) ? "All Messages" : "Nearest Creatures"]
" - //dat += "Window Flashing: [(windowflashing) ? "Enabled":"Disabled"]
" - dat += "
" - dat += "Play Hunting Horn Sounds: [(toggles & SOUND_HUNTINGHORN) ? "Enabled":"Disabled"]
" - dat += "Sprint Depletion Sound: [(toggles & SOUND_SPRINTBUFFER) ? "Enabled":"Disabled"]
" - dat += "Play Admin MIDIs: [(toggles & SOUND_MIDI) ? "Enabled":"Disabled"]
" - dat += "Play Lobby Music: [(toggles & SOUND_LOBBY) ? "Enabled":"Disabled"]
" - dat += "See Pull Requests: [(chat_toggles & CHAT_PULLR) ? "Enabled":"Disabled"]
" - dat += "
" - if(user.client) - if(unlock_content) - dat += "BYOND Membership Publicity: [(toggles & MEMBER_PUBLIC) ? "Public" : "Hidden"]
" - if(unlock_content || check_rights_for(user.client, R_ADMIN)) - dat += "OOC Color:     Change
" - dat += "Antag OOC Color:     Change
" - - dat += "
" - dat += "

Admin Settings

" - dat += "Adminhelp Sounds: [(toggles & SOUND_ADMINHELP)?"Enabled":"Disabled"]
" - dat += "Announce Login: [(toggles & ANNOUNCE_LOGIN)?"Enabled":"Disabled"]
" - dat += "
" - dat += "Combo HUD Lighting: [(toggles & COMBOHUD_LIGHTING)?"Full-bright":"No Change"]
" - dat += "Split Admin Tabs: [(toggles & SPLIT_ADMIN_TABS)?"Enabled":"Disabled"]
" - dat += "
" - dat += "

Preferences

" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe. - dat += "End of round deathmatch: [end_of_round_deathmatch ? "Enabled" : "Disabled"]
" - dat += "

Citadel Preferences

" //Because fuck me if preferences can't be fucking modularized and expected to update in a reasonable timeframe. - dat += "Widescreen: [widescreenpref ? "Enabled ([CONFIG_GET(string/default_view)])" : "Disabled (15x15)"]
" - dat += "Auto stand: [autostand ? "Enabled" : "Disabled"]
" - dat += "Auto OOC: [auto_ooc ? "Disabled" : "Enabled" ]
" - dat += "Force Slot Storage HUD: [no_tetris_storage ? "Enabled" : "Disabled"]
" - dat += "Gun Cursor: [(cb_toggles & AIM_CURSOR_ON) ? "Enabled" : "Disabled"]
" - dat += "Screen Shake: [(screenshake==100) ? "Full" : ((screenshake==0) ? "None" : "[screenshake]")]
" - if (user && user.client && !user.client.prefs.screenshake==0) - dat += "Damage Screen Shake: [(damagescreenshake==1) ? "On" : ((damagescreenshake==0) ? "Off" : "Only when down")]
" - - dat += "Show Health Smileys: [show_health_smilies ? "Enabled" : "Disabled"]
" - dat += "
" - dat += "Max PFP Examine Image Height px: [see_pfp_max_hight]px
" - dat += "Max PFP Examine Image Width %: [see_pfp_max_widht]%
" - dat += "
" - if(unlock_content) - dat += "Ghost Form: [ghost_form]
" - dat += "Ghost Orbit: [ghost_orbit]
" - var/button_name = "If you see this something went wrong." - switch(ghost_accs) - if(GHOST_ACCS_FULL) - button_name = GHOST_ACCS_FULL_NAME - if(GHOST_ACCS_DIR) - button_name = GHOST_ACCS_DIR_NAME - if(GHOST_ACCS_NONE) - button_name = GHOST_ACCS_NONE_NAME - - dat += "Ghost Accessories: [button_name]
" - switch(ghost_others) - if(GHOST_OTHERS_THEIR_SETTING) - button_name = GHOST_OTHERS_THEIR_SETTING_NAME - if(GHOST_OTHERS_DEFAULT_SPRITE) - button_name = GHOST_OTHERS_DEFAULT_SPRITE_NAME - if(GHOST_OTHERS_SIMPLE) - button_name = GHOST_OTHERS_SIMPLE_NAME - - dat += "Ghosts of Others: [button_name]
" - dat += "
" - - dat += "FPS: [clientfps]
" - - dat += "Income Updates: [(chat_toggles & CHAT_BANKCARD) ? "Allowed" : "Muted"]
" - dat += "Hear Radio Static: [(chat_toggles & CHAT_HEAR_RADIOSTATIC) ? "Allowed" : "Muted"]
" - dat += "Hear Radio Blurbles: [(chat_toggles & CHAT_HEAR_RADIOBLURBLES) ? "Allowed" : "Muted"]
" - dat += "
" - - dat += "Parallax (Fancy Space): " - switch (parallax) - if (PARALLAX_LOW) - dat += "Low" - if (PARALLAX_MED) - dat += "Medium" - if (PARALLAX_INSANE) - dat += "Insane" - if (PARALLAX_DISABLE) - dat += "Disabled" - else - dat += "High" - dat += "
" - dat += "Ambient Occlusion: [ambientocclusion ? "Enabled" : "Disabled"]
" - dat += "Fit Viewport: [auto_fit_viewport ? "Auto" : "Manual"]
" - dat += "HUD Button Flashes: [hud_toggle_flash ? "Enabled" : "Disabled"]
" - dat += "HUD Button Flash Color:     Change
" - - if (CONFIG_GET(flag/maprotation) && CONFIG_GET(flag/tgstyle_maprotation)) - var/p_map = preferred_map - if (!p_map) - p_map = "Default" - if (config.defaultmap) - p_map += " ([config.defaultmap.map_name])" - else - if (p_map in config.maplist) - var/datum/map_config/VM = config.maplist[p_map] - if (!VM) - p_map += " (No longer exists)" - else - p_map = VM.map_name - else - p_map += " (No longer exists)" - if(CONFIG_GET(flag/allow_map_voting)) - dat += "Preferred Map: [p_map]
" - - dat += "" - - /*dat += "

Special Role Settings

" - if(jobban_isbanned(user, ROLE_SYNDICATE)) - dat += "You are banned from antagonist roles." - src.be_special = list() - - - for (var/i in GLOB.special_roles) - if(jobban_isbanned(user, i)) - dat += "Be [capitalize(i)]: BANNED
" - else - var/days_remaining = null - if(ispath(GLOB.special_roles[i]) && CONFIG_GET(flag/use_age_restriction_for_jobs)) //If it's a game mode antag, check if the player meets the minimum age - var/mode_path = GLOB.special_roles[i] - var/datum/game_mode/temp_mode = new mode_path - days_remaining = temp_mode.get_remaining_days(user.client) - - if(days_remaining) - dat += "Be [capitalize(i)]: \[IN [days_remaining] DAYS]
" - else - dat += "Be [capitalize(i)]: [(i in be_special) ? "Enabled" : "Disabled"]
" - dat += "Midround Antagonist: [(toggles & MIDROUND_ANTAG) ? "Enabled" : "Disabled"]
" - - dat += "
" - */ - if(LOADOUT_TAB) - //calculate your gear points from the chosen item - gear_points = CONFIG_GET(number/initial_gear_points) - var/list/chosen_gear = loadout_data["SAVE_[loadout_slot]"] - if(chosen_gear) - for(var/loadout_item in chosen_gear) - var/loadout_item_path = loadout_item[LOADOUT_ITEM] - if(loadout_item_path) - var/datum/gear/loadout_gear = text2path(loadout_item_path) - if(loadout_gear) - gear_points -= initial(loadout_gear.cost) - else - chosen_gear = list() - - dat += "" - dat += "" - dat += "" - dat += "" - dat += "" - - dat += "" - - dat += "" - dat += "" - dat += "" - dat += "" - for(var/name in GLOB.loadout_items[gear_category][gear_subcategory]) - var/datum/gear/gear = GLOB.loadout_items[gear_category][gear_subcategory][name] - var/donoritem = gear.donoritem - if(donoritem && !gear.donator_ckey_check(user.ckey)) - continue - var/class_link = "" - var/list/loadout_item = has_loadout_gear(loadout_slot, "[gear.type]") - var/extra_loadout_data = "" - if(loadout_item) - class_link = "style='white-space:normal;' class='linkOn' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=0'" - if(gear.loadout_flags & LOADOUT_CAN_NAME) - extra_loadout_data += "
Name [loadout_item[LOADOUT_CUSTOM_NAME] ? loadout_item[LOADOUT_CUSTOM_NAME] : "N/A"]" - if(gear.loadout_flags & LOADOUT_CAN_DESCRIPTION) - extra_loadout_data += "
Description" - if(gear.loadout_flags & LOADOUT_CAN_COLOR) - extra_loadout_data += "
Color   " - else if((gear_points - gear.cost) < 0) - class_link = "style='white-space:normal;' class='linkOff'" - else if(donoritem) - class_link = "style='white-space:normal;background:#ebc42e;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'" - else - class_link = "style='white-space:normal;' href='?_src_=prefs;preference=gear;toggle_gear_path=[html_encode(name)];toggle_gear=1'" - dat += "" - dat += "" - - dat += "
[gear_points] loadout points remaining. \[Clear Loadout\]
You can choose up to [MAX_FREE_PER_CAT] free items per category.
" - - if(!length(GLOB.loadout_items)) - dat += "
ERROR: No loadout categories - something is horribly wrong!" - else - if(!GLOB.loadout_categories[gear_category]) - gear_category = GLOB.loadout_categories[1] - var/firstcat = TRUE - for(var/category in GLOB.loadout_categories) - if(firstcat) - firstcat = FALSE - else - dat += " |" - if(category == gear_category) - dat += " [category] " - else - dat += " [category] " - - dat += "

" - - if(!length(GLOB.loadout_categories[gear_category])) - dat += "No subcategories detected. Something is horribly wrong!" - else - var/list/subcategories = GLOB.loadout_categories[gear_category] - if(!subcategories.Find(gear_subcategory)) - gear_subcategory = subcategories[1] - - var/firstsubcat = TRUE - for(var/subcategory in subcategories) - if(firstsubcat) - firstsubcat = FALSE - else - dat += " |" - if(gear_subcategory == subcategory) - dat += " [subcategory] " - else - dat += " [subcategory] " - dat += "
NameCostRestrictionsDescription
[name][extra_loadout_data][gear.cost]" - if(islist(gear.restricted_roles)) - if(gear.restricted_roles.len) - if(gear.restricted_desc) - dat += "" - dat += gear.restricted_desc - dat += "" - else - dat += "" - dat += gear.restricted_roles.Join(";") - dat += "" - // the below line essentially means "if the loadout item is picked by the user and has a custom description, give it the custom description, otherwise give it the default description" - //This would normally be part if an if else but because we dont have unlockable loadout items it's not - dat += "[loadout_item ? (loadout_item[LOADOUT_CUSTOM_DESCRIPTION] ? loadout_item[LOADOUT_CUSTOM_DESCRIPTION] : gear.description) : gear.description]
" - if(CONTENT_PREFERENCES_TAB) - dat += "
" - dat += "

Adult content prefs

" - dat += "Arousal:[arousable == TRUE ? "Enabled" : "Disabled"]
" - dat += "Genital examine text:[(cit_toggles & GENITAL_EXAMINE) ? "Enabled" : "Disabled"]
" - dat += "Ass Slapping: [(cit_toggles & NO_ASS_SLAP) ? "Disallowed" : "Allowed"]
" - dat += "

Vore prefs

" - dat += "Master Vore Toggle: [(master_vore_toggle) ? "Per Preferences" : "All Disabled"]
" - if(master_vore_toggle) - dat += "Being Prey: [(allow_being_prey) ? "Allowed" : "Disallowed"]
" - dat += "Being Fed Prey: [(allow_being_fed_prey) ? "Allowed" : "Disallowed"]
" - dat += "Digestion Damage: [(allow_digestion_damage) ? "Allowed" : "Disallowed"]
" - dat += "Digestion Death: [(allow_digestion_death) ? "Allowed" : "Disallowed"]
" - dat += "Vore Messages: [(allow_vore_messages) ? "Visible" : "Hidden"]
" - dat += "Vore Trash Messages: [(allow_trash_messages) ? "Visible" : "Hidden"]
" - dat += "Vore Death Messages: [(allow_death_messages) ? "Visible" : "Hidden"]
" - dat += "Vore Eating Sounds: [(allow_eating_sounds) ? "Audible" : "Muted"]
" - dat += "Digestion Sounds: [(allow_digestion_sounds) ? "Audible" : "Muted"]
" - dat += "
" - dat += "
" - - if(KEYBINDINGS_TAB) // Custom keybindings - dat += "Keybindings: [(hotkeys) ? "Hotkeys" : "Input"]
" - dat += "Keybindings mode controls how the game behaves with tab and map/input focus.
If it is on Hotkeys, the game will always attempt to force you to map focus, meaning keypresses are sent \ - directly to the map instead of the input. You will still be able to use the command bar, but you need to tab to do it every time you click on the game map.
\ - If it is on Input, the game will not force focus away from the input bar, and you can switch focus using TAB between these two modes: If the input bar is pink, that means that you are in non-hotkey mode, sending all keypresses of the normal \ - alphanumeric characters, punctuation, spacebar, backspace, enter, etc, typing keys into the input bar. If the input bar is white, you are in hotkey mode, meaning all keypresses go into the game's keybind handling system unless you \ - manually click on the input bar to shift focus there.
\ - Input mode is the closest thing to the old input system.
\ - IMPORTANT: While in input mode's non hotkey setting (tab toggled), Ctrl + KEY will send KEY to the keybind system as the key itself, not as Ctrl + KEY. This means Ctrl + T/W/A/S/D/all your familiar stuff still works, but you \ - won't be able to access any regular Ctrl binds.
" - dat += "
Modifier-Independent binding - This is a singular bind that works regardless of if Ctrl/Shift/Alt are held down. For example, if combat mode is bound to C in modifier-independent binds, it'll trigger regardless of if you are \ - holding down shift for sprint. Each keybind can only have one independent binding, and each key can only have one keybind independently bound to it." - // Create an inverted list of keybindings -> key - var/list/user_binds = list() - var/list/user_modless_binds = list() - for (var/key in key_bindings) - for(var/kb_name in key_bindings[key]) - user_binds[kb_name] += list(key) - for (var/key in modless_key_bindings) - user_modless_binds[modless_key_bindings[key]] = key - - var/list/kb_categories = list() - // Group keybinds by category - for (var/name in GLOB.keybindings_by_name) - var/datum/keybinding/kb = GLOB.keybindings_by_name[name] - kb_categories[kb.category] += list(kb) - - dat += {" - - "} - - for (var/category in kb_categories) - dat += "

[category]

" - for (var/i in kb_categories[category]) - var/datum/keybinding/kb = i - var/current_independent_binding = user_modless_binds[kb.name] || "Unbound" - if(!length(user_binds[kb.name])) - dat += "[kb.full_name]Unbound" - var/list/default_keys = hotkeys ? kb.hotkey_keys : kb.classic_keys - if(LAZYLEN(default_keys)) - dat += "| Default: [default_keys.Join(", ")]" - dat += "" - if(!kb.special && !kb.clientside) - dat += "Independent Binding: [current_independent_binding]" - dat += "
" - else - var/bound_key = user_binds[kb.name][1] - dat += "[kb.full_name][bound_key]" - for(var/bound_key_index in 2 to length(user_binds[kb.name])) - bound_key = user_binds[kb.name][bound_key_index] - dat += " | [bound_key]" - if(length(user_binds[kb.name]) < MAX_KEYS_PER_KEYBIND) - dat += "| Add Secondary" - var/list/default_keys = hotkeys ? kb.classic_keys : kb.hotkey_keys - if(LAZYLEN(default_keys)) - dat += "| Default: [default_keys.Join(", ")]" - dat += "" - if(!kb.special && !kb.clientside) - dat += "Independent Binding: [current_independent_binding]" - dat += "
" - - dat += "

" - dat += "\[Reset to default\]" - dat += "" - - - dat += "
" - - if(!IsGuestKey(user.key)) - dat += "Delete " - dat += "Undo " - dat += "Save Setup " - - dat += "Reset Setup" - dat += "
" - - winset(user, "preferences_window", "is-visible=1;focus=0;") - var/datum/browser/popup = new(user, "preferences_browser", "
Character Setup
", 640, 770) - popup.set_content(dat.Join()) - popup.open(FALSE) - onclose(user, "preferences_window", src) - -#undef APPEARANCE_CATEGORY_COLUMN -#undef MAX_MUTANT_ROWS /// takes in whatever's at features["genital_order"] and spits out a list in order of what's present /// reverses it cus its more intuitive that way (for everyone but me) @@ -2156,30 +869,30 @@ GLOBAL_LIST_EMPTY(preferences_datums) our_genitals = reverseList(our_genitals) encode_cockstring(our_genitals) // post it! -/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, old_key, independent = FALSE, special = FALSE) - var/HTML = {" -
Keybinding: [kb.full_name]
[kb.description]

Press any key to change
Press ESC to clear
- - "} - winshow(user, "capturekeypress", TRUE) - var/datum/browser/popup = new(user, "capturekeypress", "
Keybindings
", 350, 300) - popup.set_content(HTML) - popup.open(FALSE) - onclose(user, "capturekeypress", src) +// /datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, old_key, independent = FALSE, special = FALSE) +// var/HTML = {" +//
Keybinding: [kb.full_name]
[kb.description]

Press any key to change
Press ESC to clear
+// +// "} +// winshow(user, "capturekeypress", TRUE) +// var/datum/browser/popup = new(user, "capturekeypress", "
Keybindings
", 350, 300) +// popup.set_content(HTML) +// popup.open(FALSE) +// onclose(user, "capturekeypress", src) /datum/preferences/proc/SetChoices(mob/user, limit = 17, list/splitJobs = list("Chief Engineer"), widthPerColumn = 295, height = 620) if(!SSjob) @@ -2471,18 +1184,18 @@ GLOBAL_LIST_EMPTY(preferences_datums) popup.set_content(dat.Join()) popup.open(0) return - -// /datum/preferences/proc/GetQuirkBalance() -// var/bal = 100 -// for(var/V in char_quirks) -// var/datum/quirk/T = SSquirks.quirks[V] -// bal -= initial(T.value) -// for(var/modification in modified_limbs) -// if(modified_limbs[modification][1] == LOADOUT_LIMB_PROSTHETIC) -// return bal + 33 //max 33 point regardless of how many prosthetics -// return bal - -/datum/preferences/proc/update_genital_whitelist() +/* +/datum/preferences/proc/GetQuirkBalance() + var/bal = 100 + for(var/V in char_quirks) + var/datum/quirk/T = SSquirks.quirks[V] + bal -= initial(T.value) + for(var/modification in modified_limbs) + if(modified_limbs[modification][1] == LOADOUT_LIMB_PROSTHETIC) + return bal + 33 //max 33 point regardless of how many prosthetics + return bal + +/datum/preferences/proc/ChangePHUDWhitelist() var/new_genital_whitelist = stripped_multiline_input_or_reflect( parent, "Which people are you okay with seeing their genitals when exposed? If a humanlike mob has a name containing \ @@ -2501,18 +1214,10 @@ GLOBAL_LIST_EMPTY(preferences_datums) return genital_whitelist = new_genital_whitelist to_chat(parent, span_notice("Updated your genital whitelist! It should kick in soon!")) - save_preferences() + save_preferences() */ -/datum/preferences/Topic(href, href_list, hsrc) //yeah, gotta do this I guess.. - if(lockdown) - return - . = ..() - if(href_list["close"]) - var/client/C = usr.client - if(C) - C.clear_character_previews() -/datum/preferences/proc/process_link(mob/user, list/href_list) +/datum/preferences/proc/process_link_old(mob/user, list/href_list) if(lockdown) return if(href_list["jobbancheck"]) @@ -2543,7 +1248,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(href_list["preference"] == "change_genital_order") shift_genital_order(href_list["which"], (href_list["direction"]=="up")) if(href_list["preference"] == "change_genital_whitelist") - update_genital_whitelist() + ChangePHUDWhitelist() if(href_list["preference"] == "change_genital_clothing") var/list/genital_overrides = GENITAL_CLOTHING_FLAG_LIST var/new_visibility = input(user, "When your genitals are visible, how should they appear in relation to your clothes/underwear?", "Character Preference", href_list["nadflag"]) as null|anything in GENITAL_CLOTHING_FLAG_LIST @@ -2556,27 +1261,27 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(href_list["preference"] == "toggle_undie_preview") TOGGLE_VAR(preview_hide_undies) - if(href_list["preference"] == "choose_pda_skin") - var/pickedPDASkin = input(user, "Choose your DataPal appearance. (You can change this in-game by ctrl-shift-clicking the DataPal!)", "Character Preference", pda_skin) as null|anything in GLOB.pda_skins - if(pickedPDASkin) - pda_skin = pickedPDASkin - - if(href_list["preference"] == "choose_pda_message") - var/new_message = stripped_multiline_input_or_reflect( - user, - "What message would you like to display when someone rings your DataPal? (Leave blank to disable)", - "DataPal Ring Message", - pda_ringmessage, - 30) - if(!isnull(new_message)) - if(new_message) - pda_ringmessage = new_message - else - pda_ringmessage = "beep-boop" + // if(href_list["preference"] == "choose_pda_skin") + // var/pickedPDASkin = input(user, "Choose your DataPal appearance. (You can change this in-game by ctrl-shift-clicking the DataPal!)", "Character Preference", pda_skin) as null|anything in GLOB.pda_skins + // if(pickedPDASkin) + // pda_skin = pickedPDASkin + + // if(href_list["preference"] == "choose_pda_message") + // var/new_message = stripped_multiline_input_or_reflect( + // user, + // "What message would you like to display when someone rings your DataPal? (Leave blank to disable)", + // "DataPal Ring Message", + // pda_ringmessage, + // 30) + // if(!isnull(new_message)) + // if(new_message) + // pda_ringmessage = new_message + // else + // pda_ringmessage = "beep-boop" - if(href_list["preference"] == "genital_hide") - var/hideit = text2num(href_list["hideflag"]) - TOGGLE_BITFIELD(features["genital_hide"], hideit) + // if(href_list["preference"] == "genital_hide") + // var/hideit = text2num(href_list["hideflag"]) + // TOGGLE_BITFIELD(features["genital_hide"], hideit) if(href_list["preference"] == "job") switch(href_list["task"]) @@ -2702,107 +1407,107 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(href_list["preference"] in GLOB.preferences_custom_names) ask_for_custom_name(user,href_list["preference"]) switch(href_list["preference"]) - if("max_pfp_hight") - var/newhight = input(user, "How many pixels tall should profile examine images be when you see em?", "tall") as num|null - if(newhight) - see_pfp_max_hight = newhight - else - to_chat("Okay!") - return 1 - if("max_pfp_with") - var/newhight = input(user, "How many pixels wide should profile examine images be when you see em?", "wide") as num|null - if(newhight) - see_pfp_max_widht = newhight - else - to_chat("Okay!") - return 1 - if("show_health_smilies") - TOGGLE_VAR(show_health_smilies) - return 1 - if("special_s") - var/new_point = input(user, "Choose Amount(1-9)", "Strength") as num|null - if(new_point) - special_s = max(min(round(text2num(new_point)), 9),1) - SetSpecial(user) - return 1 - if("special_p") - var/new_point = input(user, "Choose Amount(1-9)", "Perception") as num|null - if(new_point) - special_p = max(min(round(text2num(new_point)), 9),1) - SetSpecial(user) - return 1 - if("special_e") - var/new_point = input(user, "Choose Amount(1-9)", "Endurance") as num|null - if(new_point) - special_e = max(min(round(text2num(new_point)), 9),1) - SetSpecial(user) - return 1 - if("special_c") - var/new_point = input(user, "Choose Amount(1-9)", "Charisma") as num|null - if(new_point) - special_c = max(min(round(text2num(new_point)), 9),1) - SetSpecial(user) - return 1 - if("special_i") - var/new_point = input(user, "Choose Amount(1-9)", "Intelligence") as num|null - if(new_point) - special_i = max(min(round(text2num(new_point)), 9),1) - SetSpecial(user) - return 1 - if("special_a") - var/new_point = input(user, "Choose Amount(1-9)", "Agility") as num|null - if(new_point) - special_a = max(min(round(text2num(new_point)), 9),1) - SetSpecial(user) - return 1 - if("special_l") - var/new_point = input(user, "Choose Amount(1-9)", "Luck") as num|null - if(new_point) - special_l = max(min(round(text2num(new_point)), 9),1) - SetSpecial(user) - return 1 - if("ghostform") - if(unlock_content) - var/new_form = input(user, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in GLOB.ghost_forms - if(new_form) - ghost_form = new_form - if("ghostorbit") - if(unlock_content) - var/new_orbit = input(user, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND", null) as null|anything in GLOB.ghost_orbits - if(new_orbit) - ghost_orbit = new_orbit - - if("ghostaccs") - var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,GHOST_ACCS_FULL_NAME, GHOST_ACCS_DIR_NAME, GHOST_ACCS_NONE_NAME) - switch(new_ghost_accs) - if(GHOST_ACCS_FULL_NAME) - ghost_accs = GHOST_ACCS_FULL - if(GHOST_ACCS_DIR_NAME) - ghost_accs = GHOST_ACCS_DIR - if(GHOST_ACCS_NONE_NAME) - ghost_accs = GHOST_ACCS_NONE - - if("ghostothers") - var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,GHOST_OTHERS_THEIR_SETTING_NAME, GHOST_OTHERS_DEFAULT_SPRITE_NAME, GHOST_OTHERS_SIMPLE_NAME) - switch(new_ghost_others) - if(GHOST_OTHERS_THEIR_SETTING_NAME) - ghost_others = GHOST_OTHERS_THEIR_SETTING - if(GHOST_OTHERS_DEFAULT_SPRITE_NAME) - ghost_others = GHOST_OTHERS_DEFAULT_SPRITE - if(GHOST_OTHERS_SIMPLE_NAME) - ghost_others = GHOST_OTHERS_SIMPLE - - if("name") - var/new_name = input(user, "Choose your character's name:", "Character Preference") as text|null - if(new_name) - new_name = reject_bad_name(new_name) - if(new_name) - real_name = new_name - if(isnewplayer(parent.mob)) // Update the player panel with the new name. - var/mob/dead/new_player/player_mob = parent.mob - player_mob.new_player_panel() - else - to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .") + // if("max_pfp_hight") + // var/newhight = input(user, "How many pixels tall should profile examine images be when you see em?", "tall") as num|null + // if(newhight) + // see_pfp_max_hight = newhight + // else + // to_chat("Okay!") + // return 1 + // if("max_pfp_with") + // var/newhight = input(user, "How many pixels wide should profile examine images be when you see em?", "wide") as num|null + // if(newhight) + // see_pfp_max_widht = newhight + // else + // to_chat("Okay!") + // return 1 + // if("show_health_smilies") + // TOGGLE_VAR(show_health_smilies) + // return 1 + // if("special_s") + // var/new_point = input(user, "Choose Amount(1-9)", "Strength") as num|null + // if(new_point) + // special_s = max(min(round(text2num(new_point)), 9),1) + // SetSpecial(user) + // return 1 + // if("special_p") + // var/new_point = input(user, "Choose Amount(1-9)", "Perception") as num|null + // if(new_point) + // special_p = max(min(round(text2num(new_point)), 9),1) + // SetSpecial(user) + // return 1 + // if("special_e") + // var/new_point = input(user, "Choose Amount(1-9)", "Endurance") as num|null + // if(new_point) + // special_e = max(min(round(text2num(new_point)), 9),1) + // SetSpecial(user) + // return 1 + // if("special_c") + // var/new_point = input(user, "Choose Amount(1-9)", "Charisma") as num|null + // if(new_point) + // special_c = max(min(round(text2num(new_point)), 9),1) + // SetSpecial(user) + // return 1 + // if("special_i") + // var/new_point = input(user, "Choose Amount(1-9)", "Intelligence") as num|null + // if(new_point) + // special_i = max(min(round(text2num(new_point)), 9),1) + // SetSpecial(user) + // return 1 + // if("special_a") + // var/new_point = input(user, "Choose Amount(1-9)", "Agility") as num|null + // if(new_point) + // special_a = max(min(round(text2num(new_point)), 9),1) + // SetSpecial(user) + // return 1 + // if("special_l") + // var/new_point = input(user, "Choose Amount(1-9)", "Luck") as num|null + // if(new_point) + // special_l = max(min(round(text2num(new_point)), 9),1) + // SetSpecial(user) + // return 1 + // if("ghostform") + // if(unlock_content) + // var/new_form = input(user, "Thanks for supporting BYOND - Choose your ghostly form:","Thanks for supporting BYOND",null) as null|anything in GLOB.ghost_forms + // if(new_form) + // ghost_form = new_form + // if("ghostorbit") + // if(unlock_content) + // var/new_orbit = input(user, "Thanks for supporting BYOND - Choose your ghostly orbit:","Thanks for supporting BYOND", null) as null|anything in GLOB.ghost_orbits + // if(new_orbit) + // ghost_orbit = new_orbit + + // if("ghostaccs") + // var/new_ghost_accs = alert("Do you want your ghost to show full accessories where possible, hide accessories but still use the directional sprites where possible, or also ignore the directions and stick to the default sprites?",,GHOST_ACCS_FULL_NAME, GHOST_ACCS_DIR_NAME, GHOST_ACCS_NONE_NAME) + // switch(new_ghost_accs) + // if(GHOST_ACCS_FULL_NAME) + // ghost_accs = GHOST_ACCS_FULL + // if(GHOST_ACCS_DIR_NAME) + // ghost_accs = GHOST_ACCS_DIR + // if(GHOST_ACCS_NONE_NAME) + // ghost_accs = GHOST_ACCS_NONE + + // if("ghostothers") + // var/new_ghost_others = alert("Do you want the ghosts of others to show up as their own setting, as their default sprites or always as the default white ghost?",,GHOST_OTHERS_THEIR_SETTING_NAME, GHOST_OTHERS_DEFAULT_SPRITE_NAME, GHOST_OTHERS_SIMPLE_NAME) + // switch(new_ghost_others) + // if(GHOST_OTHERS_THEIR_SETTING_NAME) + // ghost_others = GHOST_OTHERS_THEIR_SETTING + // if(GHOST_OTHERS_DEFAULT_SPRITE_NAME) + // ghost_others = GHOST_OTHERS_DEFAULT_SPRITE + // if(GHOST_OTHERS_SIMPLE_NAME) + // ghost_others = GHOST_OTHERS_SIMPLE + + // if("name") + // var/new_name = input(user, "Choose your character's name:", "Character Preference") as text|null + // if(new_name) + // new_name = reject_bad_name(new_name) + // if(new_name) + // real_name = new_name + // if(isnewplayer(parent.mob)) // Update the player panel with the new name. + // var/mob/dead/new_player/player_mob = parent.mob + // player_mob.new_player_panel() + // else + // to_chat(user, "Invalid name. Your name should be at least 2 and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .") if("creature_name") var/new_name = input(user, "Choose your creature character's name:", "Character Preference") as text|null if(new_name) @@ -2838,77 +1543,77 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(!isnull(msg)) creature_ooc = msg - if("tbs") - var/new_tbs = input(user, "Are you a top, bottom, or switch? (or none of the above)", "Character Preference") as null|anything in TBS_LIST - if(new_tbs) - tbs = new_tbs - if("kisser") - var/newkiss = input(user, "What sort of person do you like to kisser?", "Character Preference") as null|anything in KISS_LIST - if(newkiss) - kisser = newkiss + // if("tbs") + // var/new_tbs = input(user, "Are you a top, bottom, or switch? (or none of the above)", "Character Preference") as null|anything in TBS_LIST + // if(new_tbs) + // tbs = new_tbs + // if("kisser") + // var/newkiss = input(user, "What sort of person do you like to kisser?", "Character Preference") as null|anything in KISS_LIST + // if(newkiss) + // kisser = newkiss if("stash_equipment_on_logout") TOGGLE_VAR(stash_equipment_on_logout) if("lock_equipment_on_logout") TOGGLE_VAR(lock_equipment_on_logout) - if("age") - var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null - if(new_age) - age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) - if("pixel_x") - var/newx = input(user, "A new left/right pixel offset:\n([PIXELSHIFT_MAX] - [PIXELSHIFT_MIN])", "Character Preference", custom_pixel_x) as num|null - if(newx) - custom_pixel_x = round(clamp(newx, PIXELSHIFT_MIN, PIXELSHIFT_MAX), 1) - else - custom_pixel_x = 0 - if("pixel_y") - var/newy = input(user, "A new up/down pixel offset:\n([PIXELSHIFT_MAX] - [PIXELSHIFT_MIN])", "Character Preference", custom_pixel_y) as num|null - if(newy) - custom_pixel_y = round(clamp(newy, PIXELSHIFT_MIN, PIXELSHIFT_MAX), 1) - else - custom_pixel_y = 0 - if("custom_say") - var/verb_type = href_list["verbtype"] - var/lastvalue = "" - if(length(features[verb_type])) - lastvalue = jointext(features[verb_type],",") - var/msg = input(usr, "Give a custom set of verbs for this character's [verb_type]. Separate them with a single comma and nothing else.", "Custom [verb_type]", lastvalue) as message|null - if(!isnull(msg)) - features[verb_type] = splittext(msg,",") + // if("age") + // var/new_age = input(user, "Choose your character's age:\n([AGE_MIN]-[AGE_MAX])", "Character Preference") as num|null + // if(new_age) + // age = max(min( round(text2num(new_age)), AGE_MAX),AGE_MIN) + // if("pixel_x") + // var/newx = input(user, "A new left/right pixel offset:\n([PIXELSHIFT_MAX] - [PIXELSHIFT_MIN])", "Character Preference", custom_pixel_x) as num|null + // if(newx) + // custom_pixel_x = round(clamp(newx, PIXELSHIFT_MIN, PIXELSHIFT_MAX), 1) + // else + // custom_pixel_x = 0 + // if("pixel_y") + // var/newy = input(user, "A new up/down pixel offset:\n([PIXELSHIFT_MAX] - [PIXELSHIFT_MIN])", "Character Preference", custom_pixel_y) as num|null + // if(newy) + // custom_pixel_y = round(clamp(newy, PIXELSHIFT_MIN, PIXELSHIFT_MAX), 1) + // else + // custom_pixel_y = 0 + // if("custom_say") + // var/verb_type = href_list["verbtype"] + // var/lastvalue = "" + // if(length(features[verb_type])) + // lastvalue = jointext(features[verb_type],",") + // var/msg = input(usr, "Give a custom set of verbs for this character's [verb_type]. Separate them with a single comma and nothing else.", "Custom [verb_type]", lastvalue) as message|null + // if(!isnull(msg)) + // features[verb_type] = splittext(msg,",") ////////////////// VORE STUFF / - if("master_vore_toggle") - TOGGLE_VAR(master_vore_toggle) - if("allow_being_prey") - TOGGLE_VAR(allow_being_prey) - if("allow_being_fed_prey") - TOGGLE_VAR(allow_being_fed_prey) - if("allow_digestion_damage") - TOGGLE_VAR(allow_digestion_damage) - if("allow_digestion_death") - TOGGLE_VAR(allow_digestion_death) - if("allow_trash_messages") - TOGGLE_VAR(allow_trash_messages) - if("allow_vore_messages") - TOGGLE_VAR(allow_vore_messages) - if("allow_death_messages") - TOGGLE_VAR(allow_death_messages) - if("allow_eating_sounds") - TOGGLE_VAR(allow_eating_sounds) - if("allow_digestion_sounds") - TOGGLE_VAR(allow_digestion_sounds) - if("flavor_text") - var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", html_decode(features["flavor_text"]), MAX_FLAVOR_LEN, TRUE) - if(!isnull(msg)) - features["flavor_text"] = msg + // if("master_vore_toggle") + // TOGGLE_VAR(master_vore_toggle) + // if("allow_being_prey") + // TOGGLE_VAR(allow_being_prey) + // if("allow_being_fed_prey") + // TOGGLE_VAR(allow_being_fed_prey) + // if("allow_digestion_damage") + // TOGGLE_VAR(allow_digestion_damage) + // if("allow_digestion_death") + // TOGGLE_VAR(allow_digestion_death) + // if("allow_trash_messages") + // TOGGLE_VAR(allow_trash_messages) + // if("allow_vore_messages") + // TOGGLE_VAR(allow_vore_messages) + // if("allow_death_messages") + // TOGGLE_VAR(allow_death_messages) + // if("allow_eating_sounds") + // TOGGLE_VAR(allow_eating_sounds) + // if("allow_digestion_sounds") + // TOGGLE_VAR(allow_digestion_sounds) + // if("flavor_text") + // var/msg = stripped_multiline_input(usr, "Set the flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Flavor Text", html_decode(features["flavor_text"]), MAX_FLAVOR_LEN, TRUE) + // if(!isnull(msg)) + // features["flavor_text"] = msg if("silicon_flavor_text") var/msg = stripped_multiline_input(usr, "Set the silicon flavor text in your 'examine' verb. This can also be used for OOC notes and preferences!", "Silicon Flavor Text", html_decode(features["silicon_flavor_text"]), MAX_FLAVOR_LEN, TRUE) if(!isnull(msg)) features["silicon_flavor_text"] = msg - if("ooc_notes") - var/msg = stripped_multiline_input(usr, "Set always-visible OOC notes related to content preferences. THIS IS NOT FOR CHARACTER DESCRIPTIONS!", "OOC notes", html_decode(features["ooc_notes"]), MAX_FLAVOR_LEN, TRUE) - if(!isnull(msg)) - features["ooc_notes"] = msg + // if("ooc_notes") + // var/msg = stripped_multiline_input(usr, "Set always-visible OOC notes related to content preferences. THIS IS NOT FOR CHARACTER DESCRIPTIONS!", "OOC notes", html_decode(features["ooc_notes"]), MAX_FLAVOR_LEN, TRUE) + // if(!isnull(msg)) + // features["ooc_notes"] = msg if("background_info_notes") var/msg = stripped_multiline_input(usr, "Set always-visible character's background!", "Background Info Notes", html_decode(features["background_info_notes"]), MAX_FLAVOR_LEN, TRUE) @@ -2931,134 +1636,134 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(user) user.mind?.hide_ckey = hide_ckey - if("hair") - var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null - if(new_hair) - hair_color = sanitize_hexcolor(new_hair, 6) + // if("hair") + // var/new_hair = input(user, "Choose your character's hair colour:", "Character Preference","#"+hair_color) as color|null + // if(new_hair) + // hair_color = sanitize_hexcolor(new_hair, 6) - if("hair_style") - var/new_hair_style - new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.hair_styles_list - if(new_hair_style) - hair_style = new_hair_style + // if("hair_style") + // var/new_hair_style + // new_hair_style = input(user, "Choose your character's hair style:", "Character Preference") as null|anything in GLOB.hair_styles_list + // if(new_hair_style) + // hair_style = new_hair_style - if("next_hair_style") - hair_style = next_list_item(hair_style, GLOB.hair_styles_list) + // if("next_hair_style") + // hair_style = next_list_item(hair_style, GLOB.hair_styles_list) - if("previous_hair_style") - hair_style = previous_list_item(hair_style, GLOB.hair_styles_list) + // if("previous_hair_style") + // hair_style = previous_list_item(hair_style, GLOB.hair_styles_list) - if("facial") - var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference","#"+facial_hair_color) as color|null - if(new_facial) - facial_hair_color = sanitize_hexcolor(new_facial, 6) + // if("facial") + // var/new_facial = input(user, "Choose your character's facial-hair colour:", "Character Preference","#"+facial_hair_color) as color|null + // if(new_facial) + // facial_hair_color = sanitize_hexcolor(new_facial, 6) - if("facial_hair_style") - var/new_facial_hair_style - new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in GLOB.facial_hair_styles_list - if(new_facial_hair_style) - facial_hair_style = new_facial_hair_style + // if("facial_hair_style") + // var/new_facial_hair_style + // new_facial_hair_style = input(user, "Choose your character's facial-hair style:", "Character Preference") as null|anything in GLOB.facial_hair_styles_list + // if(new_facial_hair_style) + // facial_hair_style = new_facial_hair_style - if("next_facehair_style") - facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_list) + // if("next_facehair_style") + // facial_hair_style = next_list_item(facial_hair_style, GLOB.facial_hair_styles_list) - if("previous_facehair_style") - facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_list) + // if("previous_facehair_style") + // facial_hair_style = previous_list_item(facial_hair_style, GLOB.facial_hair_styles_list) if("cycle_bg") bgstate = next_list_item(bgstate, bgstate_options) - if("modify_limbs") - var/limb_type = input(user, "Choose the limb to modify:", "Character Preference") as null|anything in LOADOUT_ALLOWED_LIMB_TARGETS - if(!limb_type) - return - var/modification_type = input(user, "Choose the modification to the limb:", "Character Preference") as null|anything in LOADOUT_LIMBS - if(!modification_type) - return - if(modification_type == LOADOUT_LIMB_PROSTHETIC) - var/prosthetic_type = input(user, "Choose the type of prosthetic", "Character Preference") as null|anything in (list("prosthetic") + GLOB.prosthetic_limb_types) - if(!prosthetic_type) - return - var/number_of_prosthetics = 0 - for(var/modified_limb in modified_limbs) - if(modified_limbs[modified_limb][1] == LOADOUT_LIMB_PROSTHETIC && modified_limb != limb_type) - number_of_prosthetics += 1 - if(number_of_prosthetics > MAXIMUM_LOADOUT_PROSTHETICS) - to_chat(user, span_danger("I can only have up to two prosthetic limbs!")) - else - //save the actual prosthetic data - modified_limbs[limb_type] = list(modification_type, prosthetic_type) - else - if(modification_type == LOADOUT_LIMB_NORMAL) - modified_limbs -= limb_type - else - modified_limbs[limb_type] = list(modification_type) - - if("underwear") - var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_list - if(new_underwear) - underwear = new_underwear - - if("undie_color") - var/n_undie_color = input(user, "Choose your underwear's color.", "Character Preference", "#[undie_color]") as color|null - if(n_undie_color) - undie_color = sanitize_hexcolor(n_undie_color, 6) - - if("undershirt") - var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_list - if(new_undershirt) - undershirt = new_undershirt - - if("shirt_color") - var/n_shirt_color = input(user, "Choose your undershirt's color.", "Character Preference", "#[shirt_color]") as color|null - if(n_shirt_color) - shirt_color = sanitize_hexcolor(n_shirt_color, 6) - - if("socks") - var/new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list - if(new_socks) - socks = new_socks - - if("socks_color") - var/n_socks_color = input(user, "Choose your socks' color.", "Character Preference", "#[socks_color]") as color|null - if(n_socks_color) - socks_color = sanitize_hexcolor(n_socks_color, 6) - - if("undershirt_overclothes") - undershirt_overclothes = undershirt_overclothes+1 - if(undershirt_overclothes > UNDERWEAR_OVER_EVERYTHING) - undershirt_overclothes = UNDERWEAR_UNDER_CLOTHES - - if("undies_overclothes") - undies_overclothes = undies_overclothes+1 - if(undies_overclothes > UNDERWEAR_OVER_EVERYTHING) - undies_overclothes = UNDERWEAR_UNDER_CLOTHES - - if("socks_overclothes") - socks_overclothes = socks_overclothes+1 - if(socks_overclothes > UNDERWEAR_OVER_EVERYTHING) - socks_overclothes = UNDERWEAR_UNDER_CLOTHES - - if("eyes") - var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+left_eye_color) as color|null - if(new_eyes) - left_eye_color = sanitize_hexcolor(new_eyes, 6) - right_eye_color = sanitize_hexcolor(new_eyes, 6) - - if("eye_left") - var/new_eyes = input(user, "Choose your character's left eye colour:", "Character Preference","#"+left_eye_color) as color|null - if(new_eyes) - left_eye_color = sanitize_hexcolor(new_eyes, 6) - - if("eye_right") - var/new_eyes = input(user, "Choose your character's right eye colour:", "Character Preference","#"+right_eye_color) as color|null - if(new_eyes) - right_eye_color = sanitize_hexcolor(new_eyes, 6) - - if("eye_type") - var/new_eye_type = input(user, "Choose your character's eye type.", "Character Preference") as null|anything in GLOB.eye_types - if(new_eye_type) - eye_type = new_eye_type + // if("modify_limbs") + // var/limb_type = input(user, "Choose the limb to modify:", "Character Preference") as null|anything in LOADOUT_ALLOWED_LIMB_TARGETS + // if(!limb_type) + // return + // var/modification_type = input(user, "Choose the modification to the limb:", "Character Preference") as null|anything in LOADOUT_LIMBS + // if(!modification_type) + // return + // if(modification_type == LOADOUT_LIMB_PROSTHETIC) + // var/prosthetic_type = input(user, "Choose the type of prosthetic", "Character Preference") as null|anything in (list("prosthetic") + GLOB.prosthetic_limb_types) + // if(!prosthetic_type) + // return + // var/number_of_prosthetics = 0 + // for(var/modified_limb in modified_limbs) + // if(modified_limbs[modified_limb][1] == LOADOUT_LIMB_PROSTHETIC && modified_limb != limb_type) + // number_of_prosthetics += 1 + // if(number_of_prosthetics > MAXIMUM_LOADOUT_PROSTHETICS) + // to_chat(user, span_danger("I can only have up to two prosthetic limbs!")) + // else + // //save the actual prosthetic data + // modified_limbs[limb_type] = list(modification_type, prosthetic_type) + // else + // if(modification_type == LOADOUT_LIMB_NORMAL) + // modified_limbs -= limb_type + // else + // modified_limbs[limb_type] = list(modification_type) + + // if("underwear") + // var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_list + // if(new_underwear) + // underwear = new_underwear + + // if("undie_color") + // var/n_undie_color = input(user, "Choose your underwear's color.", "Character Preference", "#[undie_color]") as color|null + // if(n_undie_color) + // undie_color = sanitize_hexcolor(n_undie_color, 6) + + // if("undershirt") + // var/new_undershirt = input(user, "Choose your character's undershirt:", "Character Preference") as null|anything in GLOB.undershirt_list + // if(new_undershirt) + // undershirt = new_undershirt + + // if("shirt_color") + // var/n_shirt_color = input(user, "Choose your undershirt's color.", "Character Preference", "#[shirt_color]") as color|null + // if(n_shirt_color) + // shirt_color = sanitize_hexcolor(n_shirt_color, 6) + + // if("socks") + // var/new_socks = input(user, "Choose your character's socks:", "Character Preference") as null|anything in GLOB.socks_list + // if(new_socks) + // socks = new_socks + + // if("socks_color") + // var/n_socks_color = input(user, "Choose your socks' color.", "Character Preference", "#[socks_color]") as color|null + // if(n_socks_color) + // socks_color = sanitize_hexcolor(n_socks_color, 6) + + // if("undershirt_overclothes") + // undershirt_overclothes = undershirt_overclothes+1 + // if(undershirt_overclothes > UNDERWEAR_OVER_EVERYTHING) + // undershirt_overclothes = UNDERWEAR_UNDER_CLOTHES + + // if("undies_overclothes") + // undies_overclothes = undies_overclothes+1 + // if(undies_overclothes > UNDERWEAR_OVER_EVERYTHING) + // undies_overclothes = UNDERWEAR_UNDER_CLOTHES + + // if("socks_overclothes") + // socks_overclothes = socks_overclothes+1 + // if(socks_overclothes > UNDERWEAR_OVER_EVERYTHING) + // socks_overclothes = UNDERWEAR_UNDER_CLOTHES + + // if("eyes") + // var/new_eyes = input(user, "Choose your character's eye colour:", "Character Preference","#"+left_eye_color) as color|null + // if(new_eyes) + // left_eye_color = sanitize_hexcolor(new_eyes, 6) + // right_eye_color = sanitize_hexcolor(new_eyes, 6) + + // if("eye_left") + // var/new_eyes = input(user, "Choose your character's left eye colour:", "Character Preference","#"+left_eye_color) as color|null + // if(new_eyes) + // left_eye_color = sanitize_hexcolor(new_eyes, 6) + + // if("eye_right") + // var/new_eyes = input(user, "Choose your character's right eye colour:", "Character Preference","#"+right_eye_color) as color|null + // if(new_eyes) + // right_eye_color = sanitize_hexcolor(new_eyes, 6) + + // if("eye_type") + // var/new_eye_type = input(user, "Choose your character's eye type.", "Character Preference") as null|anything in GLOB.eye_types + // if(new_eye_type) + // eye_type = new_eye_type if("toggle_split_eyes") split_eye_colors = !split_eye_colors @@ -3067,666 +1772,632 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("toggle_eye_over_hair") TOGGLE_VAR(eye_over_hair) - if("species") - var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_race_names - if(result) - var/newtype = GLOB.species_list[GLOB.roundstart_race_names[result]] - pref_species = new newtype() - //let's ensure that no weird shit happens on species swapping. - custom_species = null - if(!parent.can_have_part("mam_body_markings")) - features["mam_body_markings"] = list() - if(parent.can_have_part("mam_body_markings")) - if(features["mam_body_markings"] == "None") - features["mam_body_markings"] = list() - if(parent.can_have_part("tail_lizard")) - features["tail_lizard"] = "Smooth" - if(pref_species.id == "felinid") - features["mam_tail"] = "Cat" - features["mam_ears"] = "Cat" - - //Now that we changed our species, we must verify that the mutant colour is still allowed. - var/temp_hsv = RGBtoHSV(features["mcolor"]) - if(features["mcolor"] == "#000000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) - features["mcolor"] = pref_species.default_color - if(features["mcolor2"] == "#000000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) - features["mcolor2"] = pref_species.default_color - if(features["mcolor3"] == "#000000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) - features["mcolor3"] = pref_species.default_color - - //switch to the type of eyes the species uses - eye_type = pref_species.eye_type - if("species_alt_prefix") - if(LAZYLEN(pref_species.alt_prefixes))//if there are alt sprites to even pick from - var/list/pickfrom = list("Default" = "") - pickfrom |= pref_species.alt_prefixes - var/result = input(user, "Select an alternate species appearance or press cancel to clear it.", "Alternate Appearance") as null|anything in pickfrom - if(isnull(result) || result == "") - alt_appearance = "Default" - else - alt_appearance = result - else //this species has none so I'm not sure how you clicked this button but clear it anyway - alt_appearance = "Default" - if("custom_species") - var/new_species = reject_bad_name(input(user, "Choose your species subtype, if unique. This will show up on examinations and health scans. Do not abuse this:", "Character Preference", custom_species) as null|text) - if(new_species) - custom_species = new_species - else - custom_species = null - - if("taste") - var/new_taste = reject_bad_name(input(user, "What do you taste like?", "Character Preference", features["taste"]) as null|text) - if(new_taste) - features["taste"] = new_taste - else - features["taste"] = "something" - - if("chat_color") - var/new_runecolor = input(user, "Choose your character's runechat color:", "Character Preference","#"+features["chat_color"]) as color|null - if(new_runecolor) - features["chat_color"] = sanitize_hexcolor(new_runecolor, 6) - - if("mutant_color") - var/new_mutantcolor = input(user, "Choose your character's alien/mutant color:", "Character Preference","#"+features["mcolor"]) as color|null - if(new_mutantcolor) - var/temp_hsv = RGBtoHSV(new_mutantcolor) - if(new_mutantcolor == "#000000") - features["mcolor"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright, but only if they affect the skin - features["mcolor"] = sanitize_hexcolor(new_mutantcolor, 6) - else - to_chat(user, span_danger("Invalid color. Your color is not bright enough.")) - - if("mutant_color2") - var/new_mutantcolor = input(user, "Choose your character's secondary alien/mutant color:", "Character Preference","#"+features["mcolor2"]) as color|null - if(new_mutantcolor) - var/temp_hsv = RGBtoHSV(new_mutantcolor) - if(new_mutantcolor == "#000000") - features["mcolor2"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright, but only if they affect the skin - features["mcolor2"] = sanitize_hexcolor(new_mutantcolor, 6) - else - to_chat(user, span_danger("Invalid color. Your color is not bright enough.")) - - if("mutant_color3") - var/new_mutantcolor = input(user, "Choose your character's tertiary alien/mutant color:", "Character Preference","#"+features["mcolor3"]) as color|null - if(new_mutantcolor) - var/temp_hsv = RGBtoHSV(new_mutantcolor) - if(new_mutantcolor == "#000000") - features["mcolor3"] = pref_species.default_color - else if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright, but only if they affect the skin - features["mcolor3"] = sanitize_hexcolor(new_mutantcolor, 6) - else - to_chat(user, span_danger("Invalid color. Your color is not bright enough.")) - - if("mismatched_markings") - show_mismatched_markings = !show_mismatched_markings - - if("ipc_screen") - var/new_ipc_screen - new_ipc_screen = input(user, "Choose your character's screen:", "Character Preference") as null|anything in GLOB.ipc_screens_list - if(new_ipc_screen) - features["ipc_screen"] = new_ipc_screen - - if("ipc_antenna") - var/list/snowflake_antenna_list = list() - //Potential todo: turn all of THIS into a define to reduce copypasta. - for(var/path in GLOB.ipc_antennas_list) - var/datum/sprite_accessory/antenna/instance = GLOB.ipc_antennas_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) - continue - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_antenna_list[S.name] = path - var/new_ipc_antenna - new_ipc_antenna = input(user, "Choose your character's antenna:", "Character Preference") as null|anything in snowflake_antenna_list - if(new_ipc_antenna) - features["ipc_antenna"] = new_ipc_antenna - - if("tail_lizard") - var/new_tail - new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.tails_list_lizard - if(new_tail) - features["tail_lizard"] = new_tail - if(new_tail != "None") - features["taur"] = "None" - features["tail_human"] = "None" - features["mam_tail"] = "None" - - if("tail_human") - var/list/snowflake_tails_list = list() - for(var/path in GLOB.tails_list_human) - var/datum/sprite_accessory/tails/human/instance = GLOB.tails_list_human[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) - continue - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_tails_list[S.name] = path - var/new_tail - new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list - if(new_tail) - features["tail_human"] = new_tail - if(new_tail != "None") - features["taur"] = "None" - features["tail_lizard"] = "None" - features["mam_tail"] = "None" - - if("mam_tail") - var/list/snowflake_tails_list = list() - for(var/path in GLOB.mam_tails_list) - var/datum/sprite_accessory/tails/mam_tails/instance = GLOB.mam_tails_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) - continue - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_tails_list[S.name] = path - var/new_tail - new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list - if(new_tail) - features["mam_tail"] = new_tail - if(new_tail != "None") - features["taur"] = "None" - features["tail_human"] = "None" - features["tail_lizard"] = "None" - - if("meat_type") - var/new_meat - new_meat = input(user, "Choose your character's meat type:", "Character Preference") as null|anything in GLOB.meat_types - if(new_meat) - features["meat_type"] = new_meat - - if("snout") - var/list/snowflake_snouts_list = list() - for(var/path in GLOB.snouts_list) - var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.snouts_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) - continue - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_snouts_list[S.name] = path - var/new_snout - new_snout = input(user, "Choose your character's snout:", "Character Preference") as null|anything in snowflake_snouts_list - if(new_snout) - features["snout"] = new_snout - features["mam_snouts"] = "None" - - - if("mam_snouts") - var/list/snowflake_mam_snouts_list = list() - for(var/path in GLOB.mam_snouts_list) - var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.mam_snouts_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) - continue - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_mam_snouts_list[S.name] = path - var/new_mam_snouts - new_mam_snouts = input(user, "Choose your character's snout:", "Character Preference") as null|anything in snowflake_mam_snouts_list - if(new_mam_snouts) - features["mam_snouts"] = new_mam_snouts - features["snout"] = "None" - - if("horns") - var/new_horns - new_horns = input(user, "Choose your character's horns:", "Character Preference") as null|anything in GLOB.horns_list - if(new_horns) - features["horns"] = new_horns - - if("horns_color") - var/new_horn_color = input(user, "Choose your character's horn colour:", "Character Preference","#"+features["horns_color"]) as color|null - if(new_horn_color) - if (new_horn_color == "#000000") - features["horns_color"] = "85615A" - else - features["horns_color"] = sanitize_hexcolor(new_horn_color, 6) - - if("blood_color") - var/new_color - new_color = input(user, "Choose your character's blood color", "#"+features["blood_color"]) as color|null - if(!isnull(new_color)) - features["blood_color"] = sanitize_hexcolor(new_color, 6) - //else - //var/rainbow = alert(user, "Do you want rainbow blood?", "Hi!", "Yes", "No") - //if(rainbow == "Yes") - // features["blood_color"] = "rainbow" - if("reset_blood_color") - features["blood_color"] = "" - if("rainbow_blood_color") - features["blood_color"] = "rainbow" - if("wings") - var/new_wings - new_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.r_wings_list - if(new_wings) - features["wings"] = new_wings - - if("wings_color") - var/new_wing_color = input(user, "Choose your character's wing colour:", "Character Preference","#"+features["wings_color"]) as color|null - if(new_wing_color) - if (new_wing_color == "#000000") - features["wings_color"] = "#FFFFFF" - else - features["wings_color"] = sanitize_hexcolor(new_wing_color, 6) - - if("frills") - var/new_frills - new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in GLOB.frills_list - if(new_frills) - features["frills"] = new_frills - - if("spines") - var/new_spines - new_spines = input(user, "Choose your character's spines:", "Character Preference") as null|anything in GLOB.spines_list - if(new_spines) - features["spines"] = new_spines - - if("legs") - var/new_legs - new_legs = input(user, "Choose your character's legs:", "Character Preference") as null|anything in GLOB.legs_list - if(new_legs) - features["legs"] = new_legs - - if("insect_wings") - var/new_insect_wings - new_insect_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_wings_list - if(new_insect_wings) - features["insect_wings"] = new_insect_wings - - if("deco_wings") - var/new_deco_wings - new_deco_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.deco_wings_list - if(new_deco_wings) - features["deco_wings"] = new_deco_wings - - if("insect_fluff") - var/new_insect_fluff - new_insect_fluff = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_fluffs_list - if(new_insect_fluff) - features["insect_fluff"] = new_insect_fluff - - if("insect_markings") - var/new_insect_markings - new_insect_markings = input(user, "Choose your character's markings:", "Character Preference") as null|anything in GLOB.insect_markings_list - if(new_insect_markings) - features["insect_markings"] = new_insect_markings - - if("s_tone") - var/list/choices = GLOB.skin_tones - GLOB.nonstandard_skin_tones - if(CONFIG_GET(flag/allow_custom_skintones)) - choices += "custom" - var/new_s_tone = input(user, "Choose your character's skin tone:", "Character Preference") as null|anything in choices - if(new_s_tone) - if(new_s_tone == "custom") - var/default = use_custom_skin_tone ? skin_tone : null - var/custom_tone = input(user, "Choose your custom skin tone:", "Character Preference", default) as color|null - if(custom_tone) - var/temp_hsv = RGBtoHSV(custom_tone) - if(ReadHSV(temp_hsv)[3] < ReadHSV("#333333")[3]) // rgb(50,50,50) - to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) - else - use_custom_skin_tone = TRUE - skin_tone = custom_tone - else - use_custom_skin_tone = FALSE - skin_tone = new_s_tone - - if("taur") - var/list/snowflake_taur_list = list() - for(var/path in GLOB.taur_list) - var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) - continue - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_taur_list[S.name] = path - var/new_taur - new_taur = input(user, "Choose your character's tauric body:", "Character Preference") as null|anything in snowflake_taur_list - if(new_taur) - features["taur"] = new_taur - if(new_taur != "None") - features["mam_tail"] = "None" - features["xenotail"] = "None" - features["tail_human"] = "None" - features["tail_lizard"] = "None" - - if("ears") - var/list/snowflake_ears_list = list() - for(var/path in GLOB.ears_list) - var/datum/sprite_accessory/ears/instance = GLOB.ears_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) - continue - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_ears_list[S.name] = path - var/new_ears - new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list - if(new_ears) - features["ears"] = new_ears - - if("mam_ears") - var/list/snowflake_ears_list = list() - for(var/path in GLOB.mam_ears_list) - var/datum/sprite_accessory/ears/mam_ears/instance = GLOB.mam_ears_list[path] - if(istype(instance, /datum/sprite_accessory)) - var/datum/sprite_accessory/S = instance - if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) - continue - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_ears_list[S.name] = path - var/new_ears - new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list - if(new_ears) - features["mam_ears"] = new_ears - - //Xeno Bodyparts - if("xenohead")//Head or caste type - var/new_head - new_head = input(user, "Choose your character's caste:", "Character Preference") as null|anything in GLOB.xeno_head_list - if(new_head) - features["xenohead"] = new_head - - if("xenotail")//Currently one one type, more maybe later if someone sprites them. Might include animated variants in the future. - var/new_tail - new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.xeno_tail_list - if(new_tail) - features["xenotail"] = new_tail - if(new_tail != "None") - features["mam_tail"] = "None" - features["taur"] = "None" - features["tail_human"] = "None" - features["tail_lizard"] = "None" - - if("xenodorsal") - var/new_dors - new_dors = input(user, "Choose your character's dorsal tube type:", "Character Preference") as null|anything in GLOB.xeno_dorsal_list - if(new_dors) - features["xenodorsal"] = new_dors - - //Dragon Bodyparts - if("derg_body") //dragon main body - var/new_body - new_body = input(user, "Choose your character's body type:", "Character Preference") as null|anything in GLOB.derg_body_list - if(new_body) - features["derg_body"] = new_body - - if("derg_belly") //dragon underside - var/new_belly - new_belly = input(user, "Choose your character's belly type:", "Character Preference") as null|anything in GLOB.derg_belly_list - if(new_belly) - features["derg_belly"] = new_belly - - if("derg_horns") - var/new_horn - new_horn = input(user, "Choose your character's horn type:", "Character Preference") as null|anything in GLOB.derg_horn_list - if(new_horn) - features["derg_horns"] = new_horn - - if("derg_ears") - var/new_ears - new_ears = input(user, "Choose your character's ear type:", "Character Preference") as null|anything in GLOB.derg_ear_list - if(new_ears) - features["derg_ears"] = new_ears - - if("derg_mane") - var/new_mane - new_mane = input(user, "Choose your character's mane type:", "Character Preference") as null|anything in GLOB.derg_mane_list - if(new_mane) - features["derg_mane"] = new_mane - - if("derg_eyes") - var/new_eye - new_eye = input(user, "Choose your character's eye type:", "Character Preference") as null|anything in GLOB.derg_eye_list - if(new_eye) - features["derg_eyes"] = new_eye + // if("species") + // var/result = input(user, "Select a species", "Species Selection") as null|anything in GLOB.roundstart_race_names + // if(result) + // var/newtype = GLOB.species_list[GLOB.roundstart_race_names[result]] + // pref_species = new newtype() + // //let's ensure that no weird shit happens on species swapping. + // custom_species = null + // if(!parent.can_have_part("mam_body_markings")) + // features["mam_body_markings"] = list() + // if(parent.can_have_part("mam_body_markings")) + // if(features["mam_body_markings"] == "None") + // features["mam_body_markings"] = list() + // if(parent.can_have_part("tail_lizard")) + // features["tail_lizard"] = "Smooth" + // if(pref_species.id == "felinid") + // features["mam_tail"] = "Cat" + // features["mam_ears"] = "Cat" + + // //Now that we changed our species, we must verify that the mutant colour is still allowed. + // var/temp_hsv = RGBtoHSV(features["mcolor"]) + // if(features["mcolor"] == "#000000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) + // features["mcolor"] = pref_species.default_color + // if(features["mcolor2"] == "#000000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) + // features["mcolor2"] = pref_species.default_color + // if(features["mcolor3"] == "#000000" || (!(MUTCOLORS_PARTSONLY in pref_species.species_traits) && ReadHSV(temp_hsv)[3] < ReadHSV("#202020")[3])) + // features["mcolor3"] = pref_species.default_color + + // //switch to the type of eyes the species uses + // eye_type = pref_species.eye_type + // if("species_alt_prefix") + // if(LAZYLEN(pref_species.alt_prefixes))//if there are alt sprites to even pick from + // var/list/pickfrom = list("Default" = "") + // pickfrom |= pref_species.alt_prefixes + // var/result = input(user, "Select an alternate species appearance or press cancel to clear it.", "Alternate Appearance") as null|anything in pickfrom + // if(isnull(result) || result == "") + // alt_appearance = "Default" + // else + // alt_appearance = result + // else //this species has none so I'm not sure how you clicked this button but clear it anyway + // alt_appearance = "Default" + // if("custom_species") + // var/new_species = reject_bad_name(input(user, "Choose your species subtype, if unique. This will show up on examinations and health scans. Do not abuse this:", "Character Preference", custom_species) as null|text) + // if(new_species) + // custom_species = new_species + // else + // custom_species = null + + // if("taste") + // var/new_taste = reject_bad_name(input(user, "What do you taste like?", "Character Preference", features["taste"]) as null|text) + // if(new_taste) + // features["taste"] = new_taste + // else + // features["taste"] = "something" + + // if("chat_color") + // var/new_runecolor = input(user, "Choose your character's runechat color:", "Character Preference","#"+features["chat_color"]) as color|null + // if(new_runecolor) + // features["chat_color"] = sanitize_hexcolor(new_runecolor, 6) + + + // if("mismatched_markings") + // show_mismatched_markings = !show_mismatched_markings + + // if("ipc_screen") + // var/new_ipc_screen + // new_ipc_screen = input(user, "Choose your character's screen:", "Character Preference") as null|anything in GLOB.ipc_screens_list + // if(new_ipc_screen) + // features["ipc_screen"] = new_ipc_screen + + // if("ipc_antenna") + // var/list/snowflake_antenna_list = list() + // //Potential todo: turn all of THIS into a define to reduce copypasta. + // for(var/path in GLOB.ipc_antennas_list) + // var/datum/sprite_accessory/antenna/instance = GLOB.ipc_antennas_list[path] + // if(istype(instance, /datum/sprite_accessory)) + // var/datum/sprite_accessory/S = instance + // if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) + // continue + // if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + // snowflake_antenna_list[S.name] = path + // var/new_ipc_antenna + // new_ipc_antenna = input(user, "Choose your character's antenna:", "Character Preference") as null|anything in snowflake_antenna_list + // if(new_ipc_antenna) + // features["ipc_antenna"] = new_ipc_antenna + + // if("tail_lizard") + // var/new_tail + // new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.tails_list_lizard + // if(new_tail) + // features["tail_lizard"] = new_tail + // if(new_tail != "None") + // features["taur"] = "None" + // features["tail_human"] = "None" + // features["mam_tail"] = "None" + + // if("tail_human") + // var/list/snowflake_tails_list = list() + // for(var/path in GLOB.tails_list_human) + // var/datum/sprite_accessory/tails/human/instance = GLOB.tails_list_human[path] + // if(istype(instance, /datum/sprite_accessory)) + // var/datum/sprite_accessory/S = instance + // if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) + // continue + // if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + // snowflake_tails_list[S.name] = path + // var/new_tail + // new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list + // if(new_tail) + // features["tail_human"] = new_tail + // if(new_tail != "None") + // features["taur"] = "None" + // features["tail_lizard"] = "None" + // features["mam_tail"] = "None" + + // if("mam_tail") + // var/list/snowflake_tails_list = list() + // for(var/path in GLOB.mam_tails_list) + // var/datum/sprite_accessory/tails/mam_tails/instance = GLOB.mam_tails_list[path] + // if(istype(instance, /datum/sprite_accessory)) + // var/datum/sprite_accessory/S = instance + // if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) + // continue + // if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + // snowflake_tails_list[S.name] = path + // var/new_tail + // new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in snowflake_tails_list + // if(new_tail) + // features["mam_tail"] = new_tail + // if(new_tail != "None") + // features["taur"] = "None" + // features["tail_human"] = "None" + // features["tail_lizard"] = "None" + + // if("meat_type") + // var/new_meat + // new_meat = input(user, "Choose your character's meat type:", "Character Preference") as null|anything in GLOB.meat_types + // if(new_meat) + // features["meat_type"] = new_meat + + // if("snout") + // var/list/snowflake_snouts_list = list() + // for(var/path in GLOB.snouts_list) + // var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.snouts_list[path] + // if(istype(instance, /datum/sprite_accessory)) + // var/datum/sprite_accessory/S = instance + // if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) + // continue + // if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + // snowflake_snouts_list[S.name] = path + // var/new_snout + // new_snout = input(user, "Choose your character's snout:", "Character Preference") as null|anything in snowflake_snouts_list + // if(new_snout) + // features["snout"] = new_snout + // features["mam_snouts"] = "None" + + + // if("mam_snouts") + // var/list/snowflake_mam_snouts_list = list() + // for(var/path in GLOB.mam_snouts_list) + // var/datum/sprite_accessory/snouts/mam_snouts/instance = GLOB.mam_snouts_list[path] + // if(istype(instance, /datum/sprite_accessory)) + // var/datum/sprite_accessory/S = instance + // if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) + // continue + // if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + // snowflake_mam_snouts_list[S.name] = path + // var/new_mam_snouts + // new_mam_snouts = input(user, "Choose your character's snout:", "Character Preference") as null|anything in snowflake_mam_snouts_list + // if(new_mam_snouts) + // features["mam_snouts"] = new_mam_snouts + // features["snout"] = "None" + + // if("horns") + // var/new_horns + // new_horns = input(user, "Choose your character's horns:", "Character Preference") as null|anything in GLOB.horns_list + // if(new_horns) + // features["horns"] = new_horns + + // if("horns_color") + // var/new_horn_color = input(user, "Choose your character's horn colour:", "Character Preference","#"+features["horns_color"]) as color|null + // if(new_horn_color) + // if (new_horn_color == "#000000") + // features["horns_color"] = "85615A" + // else + // features["horns_color"] = sanitize_hexcolor(new_horn_color, 6) + + // if("blood_color") + // var/new_color + // new_color = input(user, "Choose your character's blood color", "#"+features["blood_color"]) as color|null + // if(!isnull(new_color)) + // features["blood_color"] = sanitize_hexcolor(new_color, 6) + // //else + // //var/rainbow = alert(user, "Do you want rainbow blood?", "Hi!", "Yes", "No") + // //if(rainbow == "Yes") + // // features["blood_color"] = "rainbow" + // if("reset_blood_color") + // features["blood_color"] = "" + // if("rainbow_blood_color") + // features["blood_color"] = "rainbow" + // if("wings") + // var/new_wings + // new_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.r_wings_list + // if(new_wings) + // features["wings"] = new_wings + + // if("wings_color") + // var/new_wing_color = input(user, "Choose your character's wing colour:", "Character Preference","#"+features["wings_color"]) as color|null + // if(new_wing_color) + // if (new_wing_color == "#000000") + // features["wings_color"] = "#FFFFFF" + // else + // features["wings_color"] = sanitize_hexcolor(new_wing_color, 6) + + // if("frills") + // var/new_frills + // new_frills = input(user, "Choose your character's frills:", "Character Preference") as null|anything in GLOB.frills_list + // if(new_frills) + // features["frills"] = new_frills + + // if("spines") + // var/new_spines + // new_spines = input(user, "Choose your character's spines:", "Character Preference") as null|anything in GLOB.spines_list + // if(new_spines) + // features["spines"] = new_spines + + // if("legs") + // var/new_legs + // new_legs = input(user, "Choose your character's legs:", "Character Preference") as null|anything in GLOB.legs_list + // if(new_legs) + // features["legs"] = new_legs + + // if("insect_wings") + // var/new_insect_wings + // new_insect_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_wings_list + // if(new_insect_wings) + // features["insect_wings"] = new_insect_wings + + // if("deco_wings") + // var/new_deco_wings + // new_deco_wings = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.deco_wings_list + // if(new_deco_wings) + // features["deco_wings"] = new_deco_wings + + // if("insect_fluff") + // var/new_insect_fluff + // new_insect_fluff = input(user, "Choose your character's wings:", "Character Preference") as null|anything in GLOB.insect_fluffs_list + // if(new_insect_fluff) + // features["insect_fluff"] = new_insect_fluff + + // if("insect_markings") + // var/new_insect_markings + // new_insect_markings = input(user, "Choose your character's markings:", "Character Preference") as null|anything in GLOB.insect_markings_list + // if(new_insect_markings) + // features["insect_markings"] = new_insect_markings + + // if("s_tone") + // var/list/choices = GLOB.skin_tones - GLOB.nonstandard_skin_tones + // if(CONFIG_GET(flag/allow_custom_skintones)) + // choices += "custom" + // var/new_s_tone = input(user, "Choose your character's skin tone:", "Character Preference") as null|anything in choices + // if(new_s_tone) + // if(new_s_tone == "custom") + // var/default = use_custom_skin_tone ? skin_tone : null + // var/custom_tone = input(user, "Choose your custom skin tone:", "Character Preference", default) as color|null + // if(custom_tone) + // var/temp_hsv = RGBtoHSV(custom_tone) + // if(ReadHSV(temp_hsv)[3] < ReadHSV("#333333")[3]) // rgb(50,50,50) + // to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) + // else + // use_custom_skin_tone = TRUE + // skin_tone = custom_tone + // else + // use_custom_skin_tone = FALSE + // skin_tone = new_s_tone + + // if("taur") + // var/list/snowflake_taur_list = list() + // for(var/path in GLOB.taur_list) + // var/datum/sprite_accessory/taur/instance = GLOB.taur_list[path] + // if(istype(instance, /datum/sprite_accessory)) + // var/datum/sprite_accessory/S = instance + // if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) + // continue + // if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + // snowflake_taur_list[S.name] = path + // var/new_taur + // new_taur = input(user, "Choose your character's tauric body:", "Character Preference") as null|anything in snowflake_taur_list + // if(new_taur) + // features["taur"] = new_taur + // if(new_taur != "None") + // features["mam_tail"] = "None" + // features["xenotail"] = "None" + // features["tail_human"] = "None" + // features["tail_lizard"] = "None" + + // if("ears") + // var/list/snowflake_ears_list = list() + // for(var/path in GLOB.ears_list) + // var/datum/sprite_accessory/ears/instance = GLOB.ears_list[path] + // if(istype(instance, /datum/sprite_accessory)) + // var/datum/sprite_accessory/S = instance + // if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) + // continue + // if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + // snowflake_ears_list[S.name] = path + // var/new_ears + // new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list + // if(new_ears) + // features["ears"] = new_ears + + // if("mam_ears") + // var/list/snowflake_ears_list = list() + // for(var/path in GLOB.mam_ears_list) + // var/datum/sprite_accessory/ears/mam_ears/instance = GLOB.mam_ears_list[path] + // if(istype(instance, /datum/sprite_accessory)) + // var/datum/sprite_accessory/S = instance + // if(!show_mismatched_markings && S.recommended_species && !S.recommended_species.Find(pref_species.id)) + // continue + // if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + // snowflake_ears_list[S.name] = path + // var/new_ears + // new_ears = input(user, "Choose your character's ears:", "Character Preference") as null|anything in snowflake_ears_list + // if(new_ears) + // features["mam_ears"] = new_ears + + // if("xenohead")//Head or caste type + // var/new_head + // new_head = input(user, "Choose your character's caste:", "Character Preference") as null|anything in GLOB.xeno_head_list + // if(new_head) + // features["xenohead"] = new_head + + // if("xenotail")//Currently one one type, more maybe later if someone sprites them. Might include animated variants in the future. + // var/new_tail + // new_tail = input(user, "Choose your character's tail:", "Character Preference") as null|anything in GLOB.xeno_tail_list + // if(new_tail) + // features["xenotail"] = new_tail + // if(new_tail != "None") + // features["mam_tail"] = "None" + // features["taur"] = "None" + // features["tail_human"] = "None" + // features["tail_lizard"] = "None" + + // if("xenodorsal") + // var/new_dors + // new_dors = input(user, "Choose your character's dorsal tube type:", "Character Preference") as null|anything in GLOB.xeno_dorsal_list + // if(new_dors) + // features["xenodorsal"] = new_dors + + // if("derg_body") //dragon main body + // var/new_body + // new_body = input(user, "Choose your character's body type:", "Character Preference") as null|anything in GLOB.derg_body_list + // if(new_body) + // features["derg_body"] = new_body + + // if("derg_belly") //dragon underside + // var/new_belly + // new_belly = input(user, "Choose your character's belly type:", "Character Preference") as null|anything in GLOB.derg_belly_list + // if(new_belly) + // features["derg_belly"] = new_belly + + // if("derg_horns") + // var/new_horn + // new_horn = input(user, "Choose your character's horn type:", "Character Preference") as null|anything in GLOB.derg_horn_list + // if(new_horn) + // features["derg_horns"] = new_horn + + // if("derg_ears") + // var/new_ears + // new_ears = input(user, "Choose your character's ear type:", "Character Preference") as null|anything in GLOB.derg_ear_list + // if(new_ears) + // features["derg_ears"] = new_ears + + // if("derg_mane") + // var/new_mane + // new_mane = input(user, "Choose your character's mane type:", "Character Preference") as null|anything in GLOB.derg_mane_list + // if(new_mane) + // features["derg_mane"] = new_mane + + // if("derg_eyes") + // var/new_eye + // new_eye = input(user, "Choose your character's eye type:", "Character Preference") as null|anything in GLOB.derg_eye_list + // if(new_eye) + // features["derg_eyes"] = new_eye //every single primary/secondary/tertiary colouring done at once - if( - "derg_body_primary","derg_body_secondary","derg_body_tertiary", - "derg_belly_primary","derg_belly_secondary","derg_belly_tertiary", - "derg_horns_primary","derg_horns_secondary","derg_horns_tertiary", - "derg_ears_primary","derg_ears_secondary","derg_ears_tertiary", - "derg_mane_primary","derg_mane_secondary","derg_mane_tertiary", - "derg_eyes_primary","derg_eyes_secondary","derg_eyes_tertiary", - "xenodorsal_primary","xenodorsal_secondary","xenodorsal_tertiary", - "xhead_primary","xhead_secondary","xhead_tertiary", - "tail_primary","tail_secondary","tail_tertiary", - "insect_markings_primary","insect_markings_secondary","insect_markings_tertiary", - "insect_fluff_primary","insect_fluff_secondary","insect_fluff_tertiary", - "ears_primary","ears_secondary","ears_tertiary", - "frills_primary","frills_secondary","frills_tertiary", - "ipc_antenna_primary","ipc_antenna_secondary","ipc_antenna_tertiary", - "taur_primary","taur_secondary","taur_tertiary", - "snout_primary","snout_secondary","snout_tertiary", - "spines_primary","spines_secondary","spines_tertiary", - "mam_body_markings_primary", "mam_body_markings_secondary", "mam_body_markings_tertiary") - var/the_feature = features[href_list["preference"]] - if(!the_feature) - features[href_list["preference"]] = "FFFFFF" - the_feature = "FFFFFF" - var/new_feature_color = input(user, "Choose your character's mutant part colour:", "Character Preference","#"+features[href_list["preference"]]) as color|null - if(new_feature_color) - var/temp_hsv = RGBtoHSV(new_feature_color) - if(new_feature_color == "#000000") - features[href_list["preference"]] = pref_species.default_color - else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) - features[href_list["preference"]] = sanitize_hexcolor(new_feature_color, 6) - else - to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) + // if( + // "derg_body_primary","derg_body_secondary","derg_body_tertiary", + // "derg_belly_primary","derg_belly_secondary","derg_belly_tertiary", + // "derg_horns_primary","derg_horns_secondary","derg_horns_tertiary", + // "derg_ears_primary","derg_ears_secondary","derg_ears_tertiary", + // "derg_mane_primary","derg_mane_secondary","derg_mane_tertiary", + // "derg_eyes_primary","derg_eyes_secondary","derg_eyes_tertiary", + // "xenodorsal_primary","xenodorsal_secondary","xenodorsal_tertiary", + // "xhead_primary","xhead_secondary","xhead_tertiary", + // "tail_primary","tail_secondary","tail_tertiary", + // "insect_markings_primary","insect_markings_secondary","insect_markings_tertiary", + // "insect_fluff_primary","insect_fluff_secondary","insect_fluff_tertiary", + // "ears_primary","ears_secondary","ears_tertiary", + // "frills_primary","frills_secondary","frills_tertiary", + // "ipc_antenna_primary","ipc_antenna_secondary","ipc_antenna_tertiary", + // "taur_primary","taur_secondary","taur_tertiary", + // "snout_primary","snout_secondary","snout_tertiary", + // "spines_primary","spines_secondary","spines_tertiary", + // "mam_body_markings_primary", "mam_body_markings_secondary", "mam_body_markings_tertiary") + // var/the_feature = features[href_list["preference"]] + // if(!the_feature) + // features[href_list["preference"]] = "FFFFFF" + // the_feature = "FFFFFF" + // var/new_feature_color = input(user, "Choose your character's mutant part colour:", "Character Preference","#"+features[href_list["preference"]]) as color|null + // if(new_feature_color) + // var/temp_hsv = RGBtoHSV(new_feature_color) + // if(new_feature_color == "#000000") + // features[href_list["preference"]] = pref_species.default_color + // else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) + // features[href_list["preference"]] = sanitize_hexcolor(new_feature_color, 6) + // else + // to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) //advanced color mode toggle - if("color_scheme") - if(features["color_scheme"] == ADVANCED_CHARACTER_COLORING) - features["color_scheme"] = OLD_CHARACTER_COLORING - else - features["color_scheme"] = ADVANCED_CHARACTER_COLORING + // if("color_scheme") + // if(features["color_scheme"] == ADVANCED_CHARACTER_COLORING) + // features["color_scheme"] = OLD_CHARACTER_COLORING + // else + // features["color_scheme"] = ADVANCED_CHARACTER_COLORING //Genital code // visibility stuff~ - if(GENITAL_VIS_OVERRIDE_SET) - var/list/genital_overrides = GENITAL_VIS_FLAG_LIST - var/new_visibility = input(user, "Set a visibility override! If set, this part will always be visible/hidden, regardless of how covered it is.", "Character Preference", href_list["genital_flag"]) as null|anything in genital_overrides - if(new_visibility) - var/new_bit = genital_overrides[new_visibility] - var/which_gunt = GENITAL_VIS_OVERRIDE2FLAGS_LIST[href_list["preference"]] - DISABLE_BITFIELD(features[which_gunt], GENITAL_ALWAYS_HIDDEN | GENITAL_ALWAYS_VISIBLE) - ENABLE_BITFIELD(features[which_gunt], new_bit) - - if(GENITAL_VIS_FLAGS_SET) - var/which_gunt = href_list["preference"] - var/dicflag = text2num(href_list["genital_flag"]) // it gets something like "2" - TOGGLE_BITFIELD(features[which_gunt], dicflag) - - if("cock_color") - var/new_cockcolor = input(user, "Penis color:", "Character Preference","#"+features["cock_color"]) as color|null - if(new_cockcolor) - var/temp_hsv = RGBtoHSV(new_cockcolor) - if(new_cockcolor == "#000000") - features["cock_color"] = pref_species.default_color - else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) - features["cock_color"] = sanitize_hexcolor(new_cockcolor, 6) - else - to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) - - if("cock_size") - var/min_D = CONFIG_GET(number/penis_min_inches_prefs) - var/max_D = CONFIG_GET(number/penis_max_inches_prefs) - var/new_length = input(user, "Penis length in inches:\n([min_D]-[max_D])", "Character Preference") as num|null - if(new_length) - features["cock_size"] = clamp(round(new_length), min_D, max_D) - - if("cock_shape") - var/new_shape - var/list/hockeys = list() - if(parent.can_have_part("taur")) - var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]] - for(var/A in GLOB.cock_shapes_list) - var/datum/sprite_accessory/penis/P = GLOB.cock_shapes_list[A] - if(P.taur_icon && T.taur_mode & P.accepted_taurs) - LAZYSET(hockeys, "[A] (Taur)", A) - new_shape = input(user, "Penis shape:", "Character Preference") as null|anything in (GLOB.cock_shapes_list + hockeys) - if(new_shape) - features["cock_taur"] = FALSE - if(hockeys[new_shape]) - new_shape = hockeys[new_shape] - features["cock_taur"] = TRUE - features["cock_shape"] = new_shape - - if("cock_visibility") - var/n_vis = input(user, "Penis Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) - if(n_vis) - features["cock_visibility"] = n_vis - - if("balls_color") - var/new_ballscolor = input(user, "Testicles Color:", "Character Preference","#"+features["balls_color"]) as color|null - if(new_ballscolor) - var/temp_hsv = RGBtoHSV(new_ballscolor) - if(new_ballscolor == "#000000") - features["balls_color"] = pref_species.default_color - else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) - features["balls_color"] = sanitize_hexcolor(new_ballscolor, 6) - else - to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) - - if("balls_shape") - var/new_shape - new_shape = input(user, "Balls Shape", "Character Preference") as null|anything in GLOB.balls_shapes_list - if(new_shape) - features["balls_shape"] = new_shape - - if("balls_size") - var/min_B = 1 - var/max_B = BALLS_SIZE_MAX - var/new_length = input(user, "Testicle size in decigrundles:\n([min_B]-[max_B])", "Character Preference") as num|null - if(new_length) - features["balls_size"] = clamp(round(new_length), min_B, max_B) - - if("balls_visibility") - var/n_vis = input(user, "Testicles Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) - if(n_vis) - features["balls_visibility"] = n_vis - - if("breasts_size") - var/new_size = input(user, "Breast Size", "Character Preference") as null|anything in CONFIG_GET(keyed_list/breasts_cups_prefs) - if(new_size) - features["breasts_size"] = new_size - - if("breasts_shape") - var/new_shape - new_shape = input(user, "Breast Shape", "Character Preference") as null|anything in GLOB.breasts_shapes_list - if(new_shape) - features["breasts_shape"] = new_shape - - if("breasts_color") - var/new_breasts_color = input(user, "Breast Color:", "Character Preference","#"+features["breasts_color"]) as color|null - if(new_breasts_color) - var/temp_hsv = RGBtoHSV(new_breasts_color) - if(new_breasts_color == "#000000") - features["breasts_color"] = pref_species.default_color - else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) - features["breasts_color"] = sanitize_hexcolor(new_breasts_color, 6) - else - to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) - - if("breasts_visibility") - var/n_vis = input(user, "Breasts Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) - if(n_vis) - features["breasts_visibility"] = n_vis - - if("belly_size") - var/min_B = CONFIG_GET(number/belly_min_size_prefs) - var/max_B = CONFIG_GET(number/belly_max_size_prefs) - var/new_length = input(user, "Belly size:\n([min_B]-[max_B])", "Character Preference") as num|null - if(new_length) - features["belly_size"] = clamp(round(new_length), min_B, max_B) - - if("belly_shape") - var/new_shape - new_shape = input(user, "Belly Shape", "Character Preference") as null|anything in GLOB.belly_shapes_list - if(new_shape) - features["belly_shape"] = new_shape - - if("belly_color") - var/new_belly_color = input(user, "Belly Color:", "Character Preference","#"+features["belly_color"]) as color|null - if(new_belly_color) - var/temp_hsv = RGBtoHSV(new_belly_color) - if(new_belly_color == "#000000") - features["belly_color"] = pref_species.default_color - else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) - features["belly_color"] = sanitize_hexcolor(new_belly_color, 6) - else - to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) - - if("belly_visibility") - var/n_vis = input(user, "Belly Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) - if(n_vis) - features["belly_visibility"] = n_vis - - if("vag_shape") - var/new_shape - new_shape = input(user, "Vagina Type", "Character Preference") as null|anything in GLOB.vagina_shapes_list - if(new_shape) - features["vag_shape"] = new_shape - - if("vag_color") - var/new_vagcolor = input(user, "Vagina color:", "Character Preference","#"+features["vag_color"]) as color|null - if(new_vagcolor) - var/temp_hsv = RGBtoHSV(new_vagcolor) - if(new_vagcolor == "#000000") - features["vag_color"] = pref_species.default_color - else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) - features["vag_color"] = sanitize_hexcolor(new_vagcolor, 6) - else - to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) - - if("vag_visibility") - var/n_vis = input(user, "Vagina Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) - if(n_vis) - features["vag_visibility"] = n_vis - - if("butt_color") - var/new_buttcolor = input(user, "Butt color:", "Character Preference","#"+features["butt_color"]) as color|null - if(new_buttcolor) - var/temp_hsv = RGBtoHSV(new_buttcolor) - if(new_buttcolor == "#000000") - features["butt_color"] = pref_species.default_color - else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) - features["butt_color"] = sanitize_hexcolor(new_buttcolor, 6) - else - to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) - - if("butt_size") - var/min_B = CONFIG_GET(number/butt_min_size_prefs) - var/max_B = CONFIG_GET(number/butt_max_size_prefs) - var/new_length = input(user, "Butt size:\n([min_B]-[max_B])", "Character Preference") as num|null - if(new_length) - features["butt_size"] = clamp(round(new_length), min_B, max_B) - - if("butt_visibility") - var/n_vis = input(user, "Butt Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) - if(n_vis) - features["butt_visibility"] = n_vis - - if("ooccolor") - var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference",ooccolor) as color|null - if(new_ooccolor) - ooccolor = new_ooccolor - - if("aooccolor") - var/new_aooccolor = input(user, "Choose your Antag OOC colour:", "Game Preference",ooccolor) as color|null - if(new_aooccolor) - aooccolor = new_aooccolor - - if("bag") - var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in GLOB.backbaglist - if(new_backbag) - backbag = new_backbag + // if(GENITAL_VIS_OVERRIDE_SET) + // var/list/genital_overrides = GENITAL_VIS_FLAG_LIST + // var/new_visibility = input(user, "Set a visibility override! If set, this part will always be visible/hidden, regardless of how covered it is.", "Character Preference", href_list["genital_flag"]) as null|anything in genital_overrides + // if(new_visibility) + // var/new_bit = genital_overrides[new_visibility] + // var/which_gunt = GENITAL_VIS_OVERRIDE2FLAGS_LIST[href_list["preference"]] + // DISABLE_BITFIELD(features[which_gunt], GENITAL_ALWAYS_HIDDEN | GENITAL_ALWAYS_VISIBLE) + // ENABLE_BITFIELD(features[which_gunt], new_bit) + + // if(GENITAL_VIS_FLAGS_SET) + // var/which_gunt = href_list["preference"] + // var/dicflag = text2num(href_list["genital_flag"]) // it gets something like "2" + // TOGGLE_BITFIELD(features[which_gunt], dicflag) + + // if("cock_color") + // var/new_cockcolor = input(user, "Penis color:", "Character Preference","#"+features["cock_color"]) as color|null + // if(new_cockcolor) + // var/temp_hsv = RGBtoHSV(new_cockcolor) + // if(new_cockcolor == "#000000") + // features["cock_color"] = pref_species.default_color + // else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) + // features["cock_color"] = sanitize_hexcolor(new_cockcolor, 6) + // else + // to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) + + // if("cock_size") + // var/min_D = CONFIG_GET(number/penis_min_inches_prefs) + // var/max_D = CONFIG_GET(number/penis_max_inches_prefs) + // var/new_length = input(user, "Penis length in inches:\n([min_D]-[max_D])", "Character Preference") as num|null + // if(new_length) + // features["cock_size"] = clamp(round(new_length), min_D, max_D) + + // if("cock_shape") + // var/new_shape + // var/list/hockeys = list() + // if(parent.can_have_part("taur")) + // var/datum/sprite_accessory/taur/T = GLOB.taur_list[features["taur"]] + // for(var/A in GLOB.cock_shapes_list) + // var/datum/sprite_accessory/penis/P = GLOB.cock_shapes_list[A] + // if(P.taur_icon && T.taur_mode & P.accepted_taurs) + // LAZYSET(hockeys, "[A] (Taur)", A) + // new_shape = input(user, "Penis shape:", "Character Preference") as null|anything in (GLOB.cock_shapes_list + hockeys) + // if(new_shape) + // features["cock_taur"] = FALSE + // if(hockeys[new_shape]) + // new_shape = hockeys[new_shape] + // features["cock_taur"] = TRUE + // features["cock_shape"] = new_shape + + // if("cock_visibility") + // var/n_vis = input(user, "Penis Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) + // if(n_vis) + // features["cock_visibility"] = n_vis + + // if("balls_color") + // var/new_ballscolor = input(user, "Testicles Color:", "Character Preference","#"+features["balls_color"]) as color|null + // if(new_ballscolor) + // var/temp_hsv = RGBtoHSV(new_ballscolor) + // if(new_ballscolor == "#000000") + // features["balls_color"] = pref_species.default_color + // else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) + // features["balls_color"] = sanitize_hexcolor(new_ballscolor, 6) + // else + // to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) + + // if("balls_shape") + // var/new_shape + // new_shape = input(user, "Balls Shape", "Character Preference") as null|anything in GLOB.balls_shapes_list + // if(new_shape) + // features["balls_shape"] = new_shape + + // if("balls_size") + // var/min_B = 1 + // var/max_B = BALLS_SIZE_MAX + // var/new_length = input(user, "Testicle size in decigrundles:\n([min_B]-[max_B])", "Character Preference") as num|null + // if(new_length) + // features["balls_size"] = clamp(round(new_length), min_B, max_B) + + // if("balls_visibility") + // var/n_vis = input(user, "Testicles Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) + // if(n_vis) + // features["balls_visibility"] = n_vis + + // if("breasts_size") + // var/new_size = input(user, "Breast Size", "Character Preference") as null|anything in CONFIG_GET(keyed_list/breasts_cups_prefs) + // if(new_size) + // features["breasts_size"] = new_size + + // if("breasts_shape") + // var/new_shape + // new_shape = input(user, "Breast Shape", "Character Preference") as null|anything in GLOB.breasts_shapes_list + // if(new_shape) + // features["breasts_shape"] = new_shape + + // if("breasts_color") + // var/new_breasts_color = input(user, "Breast Color:", "Character Preference","#"+features["breasts_color"]) as color|null + // if(new_breasts_color) + // var/temp_hsv = RGBtoHSV(new_breasts_color) + // if(new_breasts_color == "#000000") + // features["breasts_color"] = pref_species.default_color + // else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) + // features["breasts_color"] = sanitize_hexcolor(new_breasts_color, 6) + // else + // to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) + + // if("breasts_visibility") + // var/n_vis = input(user, "Breasts Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) + // if(n_vis) + // features["breasts_visibility"] = n_vis + + // if("belly_size") + // var/min_B = CONFIG_GET(number/belly_min_size_prefs) + // var/max_B = CONFIG_GET(number/belly_max_size_prefs) + // var/new_length = input(user, "Belly size:\n([min_B]-[max_B])", "Character Preference") as num|null + // if(new_length) + // features["belly_size"] = clamp(round(new_length), min_B, max_B) + + // if("belly_shape") + // var/new_shape + // new_shape = input(user, "Belly Shape", "Character Preference") as null|anything in GLOB.belly_shapes_list + // if(new_shape) + // features["belly_shape"] = new_shape + + // if("belly_color") + // var/new_belly_color = input(user, "Belly Color:", "Character Preference","#"+features["belly_color"]) as color|null + // if(new_belly_color) + // var/temp_hsv = RGBtoHSV(new_belly_color) + // if(new_belly_color == "#000000") + // features["belly_color"] = pref_species.default_color + // else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) + // features["belly_color"] = sanitize_hexcolor(new_belly_color, 6) + // else + // to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) + + // if("belly_visibility") + // var/n_vis = input(user, "Belly Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) + // if(n_vis) + // features["belly_visibility"] = n_vis + + // if("vag_shape") + // var/new_shape + // new_shape = input(user, "Vagina Type", "Character Preference") as null|anything in GLOB.vagina_shapes_list + // if(new_shape) + // features["vag_shape"] = new_shape + + // if("vag_color") + // var/new_vagcolor = input(user, "Vagina color:", "Character Preference","#"+features["vag_color"]) as color|null + // if(new_vagcolor) + // var/temp_hsv = RGBtoHSV(new_vagcolor) + // if(new_vagcolor == "#000000") + // features["vag_color"] = pref_species.default_color + // else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) + // features["vag_color"] = sanitize_hexcolor(new_vagcolor, 6) + // else + // to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) + + // if("vag_visibility") + // var/n_vis = input(user, "Vagina Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) + // if(n_vis) + // features["vag_visibility"] = n_vis + + // if("butt_color") + // var/new_buttcolor = input(user, "Butt color:", "Character Preference","#"+features["butt_color"]) as color|null + // if(new_buttcolor) + // var/temp_hsv = RGBtoHSV(new_buttcolor) + // if(new_buttcolor == "#000000") + // features["butt_color"] = pref_species.default_color + // else if(ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) + // features["butt_color"] = sanitize_hexcolor(new_buttcolor, 6) + // else + // to_chat(user,span_danger("Invalid color. Your color is not bright enough.")) + + // if("butt_size") + // var/min_B = CONFIG_GET(number/butt_min_size_prefs) + // var/max_B = CONFIG_GET(number/butt_max_size_prefs) + // var/new_length = input(user, "Butt size:\n([min_B]-[max_B])", "Character Preference") as num|null + // if(new_length) + // features["butt_size"] = clamp(round(new_length), min_B, max_B) + + // if("butt_visibility") + // var/n_vis = input(user, "Butt Visibility", "Character Preference") as null|anything in CONFIG_GET(keyed_list/safe_visibility_toggles) + // if(n_vis) + // features["butt_visibility"] = n_vis + + // if("ooccolor") + // var/new_ooccolor = input(user, "Choose your OOC colour:", "Game Preference",ooccolor) as color|null + // if(new_ooccolor) + // ooccolor = new_ooccolor + + // if("aooccolor") + // var/new_aooccolor = input(user, "Choose your Antag OOC colour:", "Game Preference",ooccolor) as color|null + // if(new_aooccolor) + // aooccolor = new_aooccolor + + // if("bag") + // var/new_backbag = input(user, "Choose your character's style of bag:", "Character Preference") as null|anything in GLOB.backbaglist + // if(new_backbag) + // backbag = new_backbag if("suit") if(jumpsuit_style == PREF_SUIT) @@ -3763,90 +2434,90 @@ GLOBAL_LIST_EMPTY(preferences_datums) if (!isnull(desiredfps)) clientfps = desiredfps parent.fps = desiredfps - if("input_mode_hotkey") - if(input_mode_hotkey == "Tab") - input_mode_hotkey = "Ctrl+Tab" - else - input_mode_hotkey = "Tab" - parent.change_input_toggle_key(input_mode_hotkey, send_chat = TRUE) + // if("input_mode_hotkey") + // if(input_mode_hotkey == "Tab") + // input_mode_hotkey = "Ctrl+Tab" + // else + // input_mode_hotkey = "Tab" + // parent.change_input_toggle_key(input_mode_hotkey, send_chat = TRUE) - if("ui") - var/pickedui = input(user, "Choose your UI style.", "Character Preference", UI_style) as null|anything in GLOB.available_ui_styles - if(pickedui) - UI_style = pickedui - if (parent && parent.mob && parent.mob.hud_used) - parent.mob.hud_used.update_ui_style(ui_style2icon(UI_style)) - if("pda_style") - var/pickedPDAStyle = input(user, "Choose your PDA style.", "Character Preference", pda_style) as null|anything in GLOB.pda_styles - if(pickedPDAStyle) - pda_style = pickedPDAStyle - if("pda_color") - var/pickedPDAColor = input(user, "Choose your PDA Interface color.", "Character Preference",pda_color) as color|null - if(pickedPDAColor) - pda_color = pickedPDAColor - if ("max_chat_length") - var/desiredlength = input(user, "Choose the max character length of shown Runechat messages. Valid range is 1 to [CHAT_MESSAGE_MAX_LENGTH] (default: [initial(max_chat_length)]))", "Character Preference", max_chat_length) as null|num - if (!isnull(desiredlength)) - max_chat_length = clamp(desiredlength, 1, CHAT_MESSAGE_MAX_LENGTH) - - if ("chat_width") - var/desiredlength = input(user, "Choose the max character length of shown Runechat messages. Valid range is 1 to [CHAT_MESSAGE_MAX_LENGTH] (default: [initial(max_chat_length)]))", "Character Preference", max_chat_length) as null|num - if (!isnull(desiredlength)) - chat_width = clamp(desiredlength, 1, CHAT_MESSAGE_MAX_WIDTH) + // if("ui") + // var/pickedui = input(user, "Choose your UI style.", "Character Preference", UI_style) as null|anything in GLOB.available_ui_styles + // if(pickedui) + // UI_style = pickedui + // if (parent && parent.mob && parent.mob.hud_used) + // parent.mob.hud_used.update_ui_style(ui_style2icon(UI_style)) + // if("pda_style") + // var/pickedPDAStyle = input(user, "Choose your PDA style.", "Character Preference", pda_style) as null|anything in GLOB.pda_styles + // if(pickedPDAStyle) + // pda_style = pickedPDAStyle + // if("pda_color") + // var/pickedPDAColor = input(user, "Choose your PDA Interface color.", "Character Preference",pda_color) as color|null + // if(pickedPDAColor) + // pda_color = pickedPDAColor + // if ("max_chat_length") + // var/desiredlength = input(user, "Choose the max character length of shown Runechat messages. Valid range is 1 to [CHAT_MESSAGE_MAX_LENGTH] (default: [initial(max_chat_length)]))", "Character Preference", max_chat_length) as null|num + // if (!isnull(desiredlength)) + // max_chat_length = clamp(desiredlength, 1, CHAT_MESSAGE_MAX_LENGTH) + + // if ("chat_width") + // var/desiredlength = input(user, "Choose the max character length of shown Runechat messages. Valid range is 1 to [CHAT_MESSAGE_MAX_LENGTH] (default: [initial(max_chat_length)]))", "Character Preference", max_chat_length) as null|num + // if (!isnull(desiredlength)) + // chat_width = clamp(desiredlength, 1, CHAT_MESSAGE_MAX_WIDTH) - if("offscreen") - TOGGLE_VAR(see_hidden_runechat) - - if("hud_toggle_color") - var/new_toggle_color = input(user, "Choose your HUD toggle flash color:", "Game Preference",hud_toggle_color) as color|null - if(new_toggle_color) - hud_toggle_color = new_toggle_color - - if("setup_hornychat") - SSchat.HornyPreferences(user) - - if("gender") - var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) as null|anything in list(MALE,FEMALE,"nonbinary","object") - if(!chosengender) - return - switch(chosengender) - if("nonbinary") - chosengender = PLURAL - features["body_model"] = pick(MALE, FEMALE) - if("object") - chosengender = NEUTER - features["body_model"] = MALE - else - features["body_model"] = chosengender - gender = chosengender - - if("body_size") - var/min = CONFIG_GET(number/body_size_min) - var/max = CONFIG_GET(number/body_size_max) - var/danger = CONFIG_GET(number/threshold_body_size_slowdown) - var/new_body_size = input(user, "Choose your desired sprite size: ([min*100]%-[max*100]%)\nWarning: This may make your character look distorted[danger > min ? "! Additionally, a proportional movement speed penalty will be applied to characters smaller than [danger*100]%." : "!"]", "Character Preference", features["body_size"]*100) as num|null - if (new_body_size) - new_body_size = clamp(new_body_size * 0.01, min, max) - var/dorfy - if((new_body_size + 0.01) < danger) // Adding 0.01 as a dumb fix to prevent the warning message from appearing when exactly at threshold... Not sure why that happens in the first place. - dorfy = alert(user, "I have chosen a size below the slowdown threshold of [danger*100]%. For balancing purposes, the further you go below this percentage, the slower your character will be. Do you wish to keep this size?", "Speed Penalty Alert", "Yes", "Move it to the threshold", "No") - if(dorfy == "Move it to the threshold") - new_body_size = danger - if(!dorfy) //Aborts if this var is somehow empty - return - if(dorfy != "No") - features["body_size"] = new_body_size - - if("toggle_fuzzy") - fuzzy = !fuzzy - - if("body_width") - var/min = CONFIG_GET(number/body_width_min) - var/max = CONFIG_GET(number/body_width_max) - var/new_body_width = input(user, "Choose your desired sprite size: ([min*100]%-[max*100]%)\nWarning: This may make your character look distorted", "Character Preference", features["body_width"]*100) as num|null - if (new_body_width) - new_body_width = clamp(new_body_width * 0.01, min, max) - features["body_width"] = new_body_width + // if("offscreen") + // TOGGLE_VAR(see_hidden_runechat) + + // if("hud_toggle_color") + // var/new_toggle_color = input(user, "Choose your HUD toggle flash color:", "Game Preference",hud_toggle_color) as color|null + // if(new_toggle_color) + // hud_toggle_color = new_toggle_color + + // if("setup_hornychat") + // SSchat.HornyPreferences(user) + + // if("gender") + // var/chosengender = input(user, "Select your character's gender.", "Gender Selection", gender) as null|anything in list(MALE,FEMALE,"nonbinary","object") + // if(!chosengender) + // return + // switch(chosengender) + // if("nonbinary") + // chosengender = PLURAL + // features["body_model"] = pick(MALE, FEMALE) + // if("object") + // chosengender = NEUTER + // features["body_model"] = MALE + // else + // features["body_model"] = chosengender + // gender = chosengender + + // if("body_size") + // var/min = CONFIG_GET(number/body_size_min) + // var/max = CONFIG_GET(number/body_size_max) + // var/danger = CONFIG_GET(number/threshold_body_size_slowdown) + // var/new_body_size = input(user, "Choose your desired sprite size: ([min*100]%-[max*100]%)\nWarning: This may make your character look distorted[danger > min ? "! Additionally, a proportional movement speed penalty will be applied to characters smaller than [danger*100]%." : "!"]", "Character Preference", features["body_size"]*100) as num|null + // if (new_body_size) + // new_body_size = clamp(new_body_size * 0.01, min, max) + // var/dorfy + // if((new_body_size + 0.01) < danger) // Adding 0.01 as a dumb fix to prevent the warning message from appearing when exactly at threshold... Not sure why that happens in the first place. + // dorfy = alert(user, "I have chosen a size below the slowdown threshold of [danger*100]%. For balancing purposes, the further you go below this percentage, the slower your character will be. Do you wish to keep this size?", "Speed Penalty Alert", "Yes", "Move it to the threshold", "No") + // if(dorfy == "Move it to the threshold") + // new_body_size = danger + // if(!dorfy) //Aborts if this var is somehow empty + // return + // if(dorfy != "No") + // features["body_size"] = new_body_size + + // if("toggle_fuzzy") + // fuzzy = !fuzzy + + // if("body_width") + // var/min = CONFIG_GET(number/body_width_min) + // var/max = CONFIG_GET(number/body_width_max) + // var/new_body_width = input(user, "Choose your desired sprite size: ([min*100]%-[max*100]%)\nWarning: This may make your character look distorted", "Character Preference", features["body_width"]*100) as num|null + // if (new_body_width) + // new_body_width = clamp(new_body_width * 0.01, min, max) + // features["body_width"] = new_body_width if("waddle_amount") var/new_waddle_amount = input(user, "Choose how many pixels you want to move when walking(4 Recommended): ([WADDLE_MIN]-[WADDLE_MAX])", "Character Preference", waddle_amount) as num|null @@ -3888,138 +2559,138 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(selected_custom_speech_verb) custom_speech_verb = selected_custom_speech_verb - if("bodysprite") - var/selected_body_sprite = input(user, "Choose your desired body sprite", "Character Preference") as null|anything in pref_species.allowed_limb_ids - if(selected_body_sprite) - chosen_limb_id = selected_body_sprite //this gets sanitized before loading - - if("marking_down") - // move the specified marking down - var/index = text2num(href_list["marking_index"]) - var/marking_type = href_list["marking_type"] - if(index && marking_type && features[marking_type] && index != length(features[marking_type])) - var/index_down = index + 1 - var/markings = features[marking_type] - var/first_marking = markings[index] - var/second_marking = markings[index_down] - markings[index] = second_marking - markings[index_down] = first_marking - - if("marking_up") - // move the specified marking up - var/index = text2num(href_list["marking_index"]) - var/marking_type = href_list["marking_type"] - if(index && marking_type && features[marking_type] && index != 1) - var/index_up = index - 1 - var/markings = features[marking_type] - var/first_marking = markings[index] - var/second_marking = markings[index_up] - markings[index] = second_marking - markings[index_up] = first_marking - - if("marking_remove") - // move the specified marking up - var/index = text2num(href_list["marking_index"]) - var/marking_type = href_list["marking_type"] - if(index && marking_type && features[marking_type]) - // because linters are just absolutely awful: - var/list/L = features[marking_type] - L.Cut(index, index + 1) - - if("marking_add") - // add a marking - var/marking_type = href_list["marking_type"] - if(marking_type && features[marking_type]) - var/selected_limb = input(user, "Choose the limb to apply to.", "Character Preference") as null|anything in list("Head", "Chest", "Left Arm", "Right Arm", "Left Leg", "Right Leg", "All") - if(selected_limb) - var/list/marking_list = GLOB.mam_body_markings_list - var/list/snowflake_markings_list = list() - for(var/path in marking_list) - var/datum/sprite_accessory/S = marking_list[path] - if(istype(S)) - if(istype(S, /datum/sprite_accessory/mam_body_markings)) - var/datum/sprite_accessory/mam_body_markings/marking = S - if(!(selected_limb in marking.covered_limbs) && selected_limb != "All") - continue - - if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) - snowflake_markings_list[S.name] = path - - var/selected_marking = input(user, "Select the marking to apply to the limb.") as null|anything in snowflake_markings_list - if(selected_marking) - if(selected_limb != "All") - var/limb_value = text2num(GLOB.bodypart_values[selected_limb]) - features[marking_type] += list(list(limb_value, selected_marking)) - else - var/datum/sprite_accessory/mam_body_markings/S = marking_list[selected_marking] - for(var/limb in S.covered_limbs) - var/limb_value = text2num(GLOB.bodypart_values[limb]) - features[marking_type] += list(list(limb_value, selected_marking)) - - if("marking_color") - var/index = text2num(href_list["marking_index"]) - var/marking_type = href_list["marking_type"] - if(index && marking_type && features[marking_type]) - // work out the input options to show the user - var/list/options = list("Primary") - var/number_colors = text2num(href_list["number_colors"]) - var/color_number = 1 // 1-3 which color are we editing - if(number_colors >= 2) - options += "Secondary" - if(number_colors == 3) - options += "Tertiary" - var/color_option = input(user, "Select the colour you wish to edit") as null|anything in options - if(color_option) - if(color_option == "Secondary") color_number = 2 - if(color_option == "Tertiary") color_number = 3 - // perform some magic on the color number - var/list/marking_list = features[marking_type][index] - var/datum/sprite_accessory/mam_body_markings/S = GLOB.mam_body_markings_list[marking_list[2]] - var/matrixed_sections = S.covered_limbs[GLOB.bodypart_names[num2text(marking_list[1])]] - if(color_number == 1) - switch(matrixed_sections) - if(MATRIX_GREEN) - color_number = 2 - if(MATRIX_BLUE) - color_number = 3 - else if(color_number == 2) - switch(matrixed_sections) - if(MATRIX_RED_BLUE) - color_number = 3 - if(MATRIX_GREEN_BLUE) - color_number = 3 - - var/color_list = features[marking_type][index][3] - var/new_marking_color = input(user, "Choose your character's marking color:", "Character Preference","#"+color_list[color_number]) as color|null - if(new_marking_color) - var/temp_hsv = RGBtoHSV(new_marking_color) - if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright, but only if they affect the skin - color_list[color_number] = "#[sanitize_hexcolor(new_marking_color, 6)]" - else - to_chat(user, span_danger("Invalid color. Your color is not bright enough.")) + // if("bodysprite") + // var/selected_body_sprite = input(user, "Choose your desired body sprite", "Character Preference") as null|anything in pref_species.allowed_limb_ids + // if(selected_body_sprite) + // chosen_limb_id = selected_body_sprite //this gets sanitized before loading + + // if("marking_down") + // // move the specified marking down + // var/index = text2num(href_list["marking_index"]) + // var/marking_type = href_list["marking_type"] + // if(index && marking_type && features[marking_type] && index != length(features[marking_type])) + // var/index_down = index + 1 + // var/markings = features[marking_type] + // var/first_marking = markings[index] + // var/second_marking = markings[index_down] + // markings[index] = second_marking + // markings[index_down] = first_marking + + // if("marking_up") + // // move the specified marking up + // var/index = text2num(href_list["marking_index"]) + // var/marking_type = href_list["marking_type"] + // if(index && marking_type && features[marking_type] && index != 1) + // var/index_up = index - 1 + // var/markings = features[marking_type] + // var/first_marking = markings[index] + // var/second_marking = markings[index_up] + // markings[index] = second_marking + // markings[index_up] = first_marking + + // if("marking_remove") + // // move the specified marking up + // var/index = text2num(href_list["marking_index"]) + // var/marking_type = href_list["marking_type"] + // if(index && marking_type && features[marking_type]) + // // because linters are just absolutely awful: + // var/list/L = features[marking_type] + // L.Cut(index, index + 1) + + // if("marking_add") + // // add a marking + // var/marking_type = href_list["marking_type"] + // if(marking_type && features[marking_type]) + // var/selected_limb = input(user, "Choose the limb to apply to.", "Character Preference") as null|anything in list("Head", "Chest", "Left Arm", "Right Arm", "Left Leg", "Right Leg", "All") + // if(selected_limb) + // var/list/marking_list = GLOB.mam_body_markings_list + // var/list/snowflake_markings_list = list() + // for(var/path in marking_list) + // var/datum/sprite_accessory/S = marking_list[path] + // if(istype(S)) + // if(istype(S, /datum/sprite_accessory/mam_body_markings)) + // var/datum/sprite_accessory/mam_body_markings/marking = S + // if(!(selected_limb in marking.covered_limbs) && selected_limb != "All") + // continue + + // if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + // snowflake_markings_list[S.name] = path + + // var/selected_marking = input(user, "Select the marking to apply to the limb.") as null|anything in snowflake_markings_list + // if(selected_marking) + // if(selected_limb != "All") + // var/limb_value = text2num(GLOB.bodypart_values[selected_limb]) + // features[marking_type] += list(list(limb_value, selected_marking)) + // else + // var/datum/sprite_accessory/mam_body_markings/S = marking_list[selected_marking] + // for(var/limb in S.covered_limbs) + // var/limb_value = text2num(GLOB.bodypart_values[limb]) + // features[marking_type] += list(list(limb_value, selected_marking)) + + // if("marking_color") + // var/index = text2num(href_list["marking_index"]) + // var/marking_type = href_list["marking_type"] + // if(index && marking_type && features[marking_type]) + // // work out the input options to show the user + // var/list/options = list("Primary") + // var/number_colors = text2num(href_list["number_colors"]) + // var/color_number = 1 // 1-3 which color are we editing + // if(number_colors >= 2) + // options += "Secondary" + // if(number_colors == 3) + // options += "Tertiary" + // var/color_option = input(user, "Select the colour you wish to edit") as null|anything in options + // if(color_option) + // if(color_option == "Secondary") color_number = 2 + // if(color_option == "Tertiary") color_number = 3 + // // perform some magic on the color number + // var/list/marking_list = features[marking_type][index] + // var/datum/sprite_accessory/mam_body_markings/S = GLOB.mam_body_markings_list[marking_list[2]] + // var/matrixed_sections = S.covered_limbs[GLOB.bodypart_names[num2text(marking_list[1])]] + // if(color_number == 1) + // switch(matrixed_sections) + // if(MATRIX_GREEN) + // color_number = 2 + // if(MATRIX_BLUE) + // color_number = 3 + // else if(color_number == 2) + // switch(matrixed_sections) + // if(MATRIX_RED_BLUE) + // color_number = 3 + // if(MATRIX_GREEN_BLUE) + // color_number = 3 + + // var/color_list = features[marking_type][index][3] + // var/new_marking_color = input(user, "Choose your character's marking color:", "Character Preference","#"+color_list[color_number]) as color|null + // if(new_marking_color) + // var/temp_hsv = RGBtoHSV(new_marking_color) + // if((MUTCOLORS_PARTSONLY in pref_species.species_traits) || ReadHSV(temp_hsv)[3] >= ReadHSV(MINIMUM_MUTANT_COLOR)[3]) // mutantcolors must be bright, but only if they affect the skin + // color_list[color_number] = "#[sanitize_hexcolor(new_marking_color, 6)]" + // else + // to_chat(user, span_danger("Invalid color. Your color is not bright enough.")) else switch(href_list["preference"]) //CITADEL PREFERENCES EDIT - I can't figure out how to modularize these, so they have to go here. :c -Pooj - if("arousable") - arousable = !arousable - if("has_cock") - features["has_cock"] = !features["has_cock"] - if("has_balls") - features["has_balls"] = !features["has_balls"] - if("has_breasts") - features["has_breasts"] = !features["has_breasts"] - if(features["has_breasts"] == FALSE) - features["breasts_producing"] = FALSE - if("breasts_producing") - features["breasts_producing"] = !features["breasts_producing"] - if("has_vag") - features["has_vag"] = !features["has_vag"] - if("has_womb") - features["has_womb"] = !features["has_womb"] - if("has_butt") - features["has_butt"] = !features["has_butt"] - if("has_belly") - features["has_belly"] = !features["has_belly"] + // if("arousable") + // // arousable = !arousable + // if("has_cock") + // features["has_cock"] = !features["has_cock"] + // if("has_balls") + // features["has_balls"] = !features["has_balls"] + // if("has_breasts") + // features["has_breasts"] = !features["has_breasts"] + // if(features["has_breasts"] == FALSE) + // features["breasts_producing"] = FALSE + // if("breasts_producing") + // features["breasts_producing"] = !features["breasts_producing"] + // if("has_vag") + // features["has_vag"] = !features["has_vag"] + // if("has_womb") + // features["has_womb"] = !features["has_womb"] + // if("has_butt") + // features["has_butt"] = !features["has_butt"] + // if("has_belly") + // features["has_belly"] = !features["has_belly"] if("widescreenpref") TOGGLE_VAR(widescreenpref) user.client.change_view(CONFIG_GET(string/default_view)) @@ -4042,106 +2713,106 @@ GLOBAL_LIST_EMPTY(preferences_datums) matchmaking_prefs -= matchmake_type else matchmaking_prefs[matchmake_type] = clamp(desired_matches, 1, max_matches) - if("autostand") - autostand = !autostand - if("auto_ooc") - auto_ooc = !auto_ooc + // if("autostand") + // autostand = !autostand + // if("auto_ooc") + // auto_ooc = !auto_ooc if("no_tetris_storage") no_tetris_storage = !no_tetris_storage - if("guncursor") - cb_toggles ^= AIM_CURSOR_ON + // if("guncursor") + // cb_toggles ^= AIM_CURSOR_ON if ("screenshake") var/desiredshake = input(user, "Set the amount of screenshake you want. \n(0 = disabled, 100 = full, 200 = maximum.)", "Character Preference", screenshake) as null|num if (!isnull(desiredshake)) screenshake = desiredshake - if("damagescreenshake") - switch(damagescreenshake) - if(0) - damagescreenshake = 1 - if(1) - damagescreenshake = 2 - if(2) - damagescreenshake = 0 - else - damagescreenshake = 1 + // if("damagescreenshake") + // switch(damagescreenshake) + // if(0) + // damagescreenshake = 1 + // if(1) + // damagescreenshake = 2 + // if(2) + // damagescreenshake = 0 + // else + // damagescreenshake = 1 //END CITADEL EDIT - if("publicity") - if(unlock_content) - toggles ^= MEMBER_PUBLIC - - if("body_model") - features["body_model"] = features["body_model"] == MALE ? FEMALE : MALE - - if("hotkeys") - hotkeys = !hotkeys - user.client.ensure_keys_set(src) - - if("keybindings_capture") - var/datum/keybinding/kb = GLOB.keybindings_by_name[href_list["keybinding"]] - CaptureKeybinding(user, kb, href_list["old_key"], text2num(href_list["independent"]), kb.special || kb.clientside) - return - - if("keybindings_set") - var/kb_name = href_list["keybinding"] - if(!kb_name) - user << browse(null, "window=capturekeypress") - ShowChoices(user) - return - - var/independent = href_list["independent"] - - var/clear_key = text2num(href_list["clear_key"]) - var/old_key = href_list["old_key"] - if(clear_key) - if(independent) - modless_key_bindings -= old_key - else - if(key_bindings[old_key]) - key_bindings[old_key] -= kb_name - LAZYADD(key_bindings["Unbound"], kb_name) - if(!length(key_bindings[old_key])) - key_bindings -= old_key - user << browse(null, "window=capturekeypress") - if(href_list["special"]) // special keys need a full reset - user.client.ensure_keys_set(src) - save_preferences() - ShowChoices(user) - return - - var/new_key = uppertext(href_list["key"]) - var/AltMod = text2num(href_list["alt"]) ? "Alt" : "" - var/CtrlMod = text2num(href_list["ctrl"]) ? "Ctrl" : "" - var/ShiftMod = text2num(href_list["shift"]) ? "Shift" : "" - var/numpad = text2num(href_list["numpad"]) ? "Numpad" : "" - // var/key_code = text2num(href_list["key_code"]) - - if(GLOB._kbMap[new_key]) - new_key = GLOB._kbMap[new_key] - - var/full_key - switch(new_key) - if("Alt") - full_key = "[new_key][CtrlMod][ShiftMod]" - if("Ctrl") - full_key = "[AltMod][new_key][ShiftMod]" - if("Shift") - full_key = "[AltMod][CtrlMod][new_key]" - else - full_key = "[AltMod][CtrlMod][ShiftMod][numpad][new_key]" - if(independent) - modless_key_bindings -= old_key - modless_key_bindings[full_key] = kb_name - else - if(key_bindings[old_key]) - key_bindings[old_key] -= kb_name - if(!length(key_bindings[old_key])) - key_bindings -= old_key - key_bindings[full_key] += list(kb_name) - key_bindings[full_key] = sortList(key_bindings[full_key]) - if(href_list["special"]) // special keys need a full reset - user.client.ensure_keys_set(src) - user << browse(null, "window=capturekeypress") - save_preferences() + // if("publicity") + // if(unlock_content) + // toggles ^= MEMBER_PUBLIC + + // if("body_model") + // features["body_model"] = features["body_model"] == MALE ? FEMALE : MALE + + // if("hotkeys") + // hotkeys = !hotkeys + // user.client.ensure_keys_set(src) + + // if("keybindings_capture") + // var/datum/keybinding/kb = GLOB.keybindings_by_name[href_list["keybinding"]] + // CaptureKeybinding(user, kb, href_list["old_key"], text2num(href_list["independent"]), kb.special || kb.clientside) + // return + + // if("keybindings_set") + // var/kb_name = href_list["keybinding"] + // if(!kb_name) + // user << browse(null, "window=capturekeypress") + // ShowChoices(user) + // return + + // var/independent = href_list["independent"] + + // var/clear_key = text2num(href_list["clear_key"]) + // var/old_key = href_list["old_key"] + // if(clear_key) + // if(independent) + // modless_key_bindings -= old_key + // else + // if(key_bindings[old_key]) + // key_bindings[old_key] -= kb_name + // LAZYADD(key_bindings["Unbound"], kb_name) + // if(!length(key_bindings[old_key])) + // key_bindings -= old_key + // user << browse(null, "window=capturekeypress") + // if(href_list["special"]) // special keys need a full reset + // user.client.ensure_keys_set(src) + // save_preferences() + // ShowChoices(user) + // return + + // var/new_key = uppertext(href_list["key"]) + // var/AltMod = text2num(href_list["alt"]) ? "Alt" : "" + // var/CtrlMod = text2num(href_list["ctrl"]) ? "Ctrl" : "" + // var/ShiftMod = text2num(href_list["shift"]) ? "Shift" : "" + // var/numpad = text2num(href_list["numpad"]) ? "Numpad" : "" + // // var/key_code = text2num(href_list["key_code"]) + + // if(GLOB._kbMap[new_key]) + // new_key = GLOB._kbMap[new_key] + + // var/full_key + // switch(new_key) + // if("Alt") + // full_key = "[new_key][CtrlMod][ShiftMod]" + // if("Ctrl") + // full_key = "[AltMod][new_key][ShiftMod]" + // if("Shift") + // full_key = "[AltMod][CtrlMod][new_key]" + // else + // full_key = "[AltMod][CtrlMod][ShiftMod][numpad][new_key]" + // if(independent) + // modless_key_bindings -= old_key + // modless_key_bindings[full_key] = kb_name + // else + // if(key_bindings[old_key]) + // key_bindings[old_key] -= kb_name + // if(!length(key_bindings[old_key])) + // key_bindings -= old_key + // key_bindings[full_key] += list(kb_name) + // key_bindings[full_key] = sortList(key_bindings[full_key]) + // if(href_list["special"]) // special keys need a full reset + // user.client.ensure_keys_set(src) + // user << browse(null, "window=capturekeypress") + // save_preferences() if("keybindings_reset") var/choice = tgalert(user, "Would you prefer 'hotkey' or 'classic' defaults?", "Setup keybindings", "Hotkey", "Classic", "Cancel") @@ -4153,31 +2824,31 @@ GLOBAL_LIST_EMPTY(preferences_datums) modless_key_bindings = list() user.client.ensure_keys_set(src) - if("chat_on_map") - chat_on_map = !chat_on_map - if("see_chat_non_mob") - see_chat_non_mob = !see_chat_non_mob - if("see_rc_emotes") - see_rc_emotes = !see_rc_emotes - if("color_chat_log") - color_chat_log = !color_chat_log - - if("action_buttons") - buttons_locked = !buttons_locked + // if("chat_on_map") + // chat_on_map = !chat_on_map + // if("see_chat_non_mob") + // see_chat_non_mob = !see_chat_non_mob + // if("see_rc_emotes") + // see_rc_emotes = !see_rc_emotes + // if("color_chat_log") + // color_chat_log = !color_chat_log + + // if("action_buttons") + // buttons_locked = !buttons_locked if("tgui_fancy") tgui_fancy = !tgui_fancy if("tgui_lock") tgui_lock = !tgui_lock if("winflash") windowflashing = !windowflashing - if("hear_adminhelps") - toggles ^= SOUND_ADMINHELP - if("announce_login") - toggles ^= ANNOUNCE_LOGIN - if("combohud_lighting") - toggles ^= COMBOHUD_LIGHTING - if("toggle_split_admin_tabs") - toggles ^= SPLIT_ADMIN_TABS + // if("hear_adminhelps") + // toggles ^= SOUND_ADMINHELP + // if("announce_login") + // toggles ^= ANNOUNCE_LOGIN + // if("combohud_lighting") + // toggles ^= COMBOHUD_LIGHTING + // if("toggle_split_admin_tabs") + // toggles ^= SPLIT_ADMIN_TABS if("be_special") var/be_special_type = href_list["be_special_type"] @@ -4195,62 +2866,62 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("all") be_random_body = !be_random_body - if("hear_hunting_horns") - toggles ^= SOUND_HUNTINGHORN + // if("hear_hunting_horns") + // toggles ^= SOUND_HUNTINGHORN - if("hear_sprint_buffer") - toggles ^= SOUND_SPRINTBUFFER + // if("hear_sprint_buffer") + // toggles ^= SOUND_SPRINTBUFFER - if("hear_midis") - toggles ^= SOUND_MIDI + // if("hear_midis") + // toggles ^= SOUND_MIDI - if("persistent_scars") - persistent_scars = !persistent_scars + // if("persistent_scars") + // persistent_scars = !persistent_scars if("underwear_hands") TOGGLE_VAR(underwear_overhands) - if("clear_scars") - to_chat(user, span_notice("All scar slots cleared. Please save character to confirm.")) - scars_list["1"] = "" - scars_list["2"] = "" - scars_list["3"] = "" - scars_list["4"] = "" - scars_list["5"] = "" - - if("lobby_music") - toggles ^= SOUND_LOBBY - if((toggles & SOUND_LOBBY) && user.client && isnewplayer(user)) - user.client.playtitlemusic() - else - user.stop_sound_channel(CHANNEL_LOBBYMUSIC) + // if("clear_scars") + // to_chat(user, span_notice("All scar slots cleared. Please save character to confirm.")) + // scars_list["1"] = "" + // scars_list["2"] = "" + // scars_list["3"] = "" + // scars_list["4"] = "" + // scars_list["5"] = "" + + // if("lobby_music") + // toggles ^= SOUND_LOBBY + // if((toggles & SOUND_LOBBY) && user.client && isnewplayer(user)) + // user.client.playtitlemusic() + // else + // user.stop_sound_channel(CHANNEL_LOBBYMUSIC) - if("ghost_ears") - chat_toggles ^= CHAT_GHOSTEARS + // if("ghost_ears") + // chat_toggles ^= CHAT_GHOSTEARS - if("ghost_sight") - chat_toggles ^= CHAT_GHOSTSIGHT + // if("ghost_sight") + // chat_toggles ^= CHAT_GHOSTSIGHT - if("ghost_whispers") - chat_toggles ^= CHAT_GHOSTWHISPER + // if("ghost_whispers") + // chat_toggles ^= CHAT_GHOSTWHISPER - if("ghost_radio") - chat_toggles ^= CHAT_GHOSTRADIO + // if("ghost_radio") + // chat_toggles ^= CHAT_GHOSTRADIO - if("ghost_pda") - chat_toggles ^= CHAT_GHOSTPDA + // if("ghost_pda") + // chat_toggles ^= CHAT_GHOSTPDA - if("income_pings") - chat_toggles ^= CHAT_BANKCARD + // if("income_pings") + // chat_toggles ^= CHAT_BANKCARD - if("static_blurble") - chat_toggles ^= CHAT_HEAR_RADIOBLURBLES + // if("static_blurble") + // chat_toggles ^= CHAT_HEAR_RADIOBLURBLES - if("static_radio") - chat_toggles ^= CHAT_HEAR_RADIOSTATIC + // if("static_radio") + // chat_toggles ^= CHAT_HEAR_RADIOSTATIC - if("pull_requests") - chat_toggles ^= CHAT_PULLR + // if("pull_requests") + // chat_toggles ^= CHAT_PULLR if("allow_midround_antag") toggles ^= MIDROUND_ANTAG @@ -4297,183 +2968,183 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("aphro") cit_toggles ^= NO_APHRO - if("ass_slap") - cit_toggles ^= NO_ASS_SLAP + // if("ass_slap") + // cit_toggles ^= NO_BUTT_SLAP if("bimbo") cit_toggles ^= BIMBOFICATION - if("auto_wag") - cit_toggles ^= NO_AUTO_WAG + // if("auto_wag") + // cit_toggles ^= NO_AUTO_WAG //END CITADEL EDIT - if("ambientocclusion") - ambientocclusion = !ambientocclusion - if(parent && parent.screen && parent.screen.len) - var/atom/movable/screen/plane_master/game_world/G = parent.mob.hud_used.plane_masters["[GAME_PLANE]"] - var/atom/movable/screen/plane_master/objitem/OI = parent.mob.hud_used.plane_masters["[OBJITEM_PLANE]"] - var/atom/movable/screen/plane_master/mob/M = parent.mob.hud_used.plane_masters["[MOB_PLANE]"] - var/atom/movable/screen/plane_master/above_wall/A = parent.mob.hud_used.plane_masters["[ABOVE_WALL_PLANE]"] - var/atom/movable/screen/plane_master/wall/W = parent.mob.hud_used.plane_masters["[WALL_PLANE]"] - G.backdrop(parent.mob) - OI.backdrop(parent.mob) - M.backdrop(parent.mob) - A.backdrop(parent.mob) - W.backdrop(parent.mob) - - if("auto_fit_viewport") - auto_fit_viewport = !auto_fit_viewport - if(auto_fit_viewport && parent) - parent.fit_viewport() - - if("hud_toggle_flash") - hud_toggle_flash = !hud_toggle_flash - - if("save") - save_preferences() - save_character() - - if("load") - load_preferences() - load_character() - - if("delete_character") - run_deletion_song_and_dance() - - if("copyslot") - set_copyslot() + // if("ambientocclusion") + // ambientocclusion = !ambientocclusion + // if(parent && parent.screen && parent.screen.len) + // var/atom/movable/screen/plane_master/game_world/G = parent.mob.hud_used.plane_masters["[GAME_PLANE]"] + // var/atom/movable/screen/plane_master/objitem/OI = parent.mob.hud_used.plane_masters["[OBJITEM_PLANE]"] + // var/atom/movable/screen/plane_master/mob/M = parent.mob.hud_used.plane_masters["[MOB_PLANE]"] + // var/atom/movable/screen/plane_master/above_wall/A = parent.mob.hud_used.plane_masters["[ABOVE_WALL_PLANE]"] + // var/atom/movable/screen/plane_master/wall/W = parent.mob.hud_used.plane_masters["[WALL_PLANE]"] + // G.backdrop(parent.mob) + // OI.backdrop(parent.mob) + // M.backdrop(parent.mob) + // A.backdrop(parent.mob) + // W.backdrop(parent.mob) + + // if("auto_fit_viewport") + // auto_fit_viewport = !auto_fit_viewport + // if(auto_fit_viewport && parent) + // parent.fit_viewport() + + // if("hud_toggle_flash") + // hud_toggle_flash = !hud_toggle_flash + + // if("save") + // save_preferences() + // save_character() + + // if("load") + // load_preferences() + // load_character() + + // if("delete_character") + // run_deletion_song_and_dance() + + // if("copyslot") + // set_copyslot() - if("paste") - run_paste_song_and_dance() - - if("show_this_many") - var/s_howmany = input( - user, - "How many character slots do you want to be able to see? This will just \ - hide the rest, they'll still be there when you change this back later. \ - (1-[max_save_slots])", - "Hide The Unused", - show_this_many - ) as null|num - if(s_howmany) - show_this_many = clamp(s_howmany, 1, max_save_slots) - to_chat(user, span_notice("You will now see [show_this_many] character slots! Any characters in the hidden slots will be inaccessible until you change this back. If there aren't any characters there, then, good, all is well!")) - - if("names_per_row") - var/narow = input( - user, - "How many character names do you want to see per row? (1-10)", - "Character Preference", - names_per_row - ) as null|num - if(narow) - names_per_row = clamp(narow, 1, 10) - to_chat(user, span_notice("You will now see [names_per_row] character names per row!")) - - if("changeslot") - if(!load_character(text2num(href_list["num"]))) - initialize_preferences() // just so we dont carry over literally everything from the last character - random_character() - real_name = random_unique_name(gender) - save_character() - if(isnewplayer(parent.mob)) // Update the player panel with the new name. - var/mob/dead/new_player/player_mob = parent.mob - player_mob.new_player_panel() - - if("tab") - if(href_list["tab"]) - current_tab = text2num(href_list["tab"]) - if("erp_tab") - if(href_list["newtab"]) - if(href_list["nonumber"]) - erp_tab_page = href_list["newtab"] - else - erp_tab_page = text2num(href_list["newtab"]) + // if("paste") + // run_paste_song_and_dance() + + // if("show_this_many") + // var/s_howmany = input( + // user, + // "How many character slots do you want to be able to see? This will just + // hide the rest, they'll still be there when you change this back later. + // (1-[max_save_slots])", + // "Hide The Unused", + // show_this_many + // ) as null|num + // if(s_howmany) + // show_this_many = clamp(s_howmany, 1, max_save_slots) + // to_chat(user, span_notice("You will now see [show_this_many] character slots! Any characters in the hidden slots will be inaccessible until you change this back. If there aren't any characters there, then, good, all is well!")) + + // if("names_per_row") + // var/narow = input( + // user, + // "How many character names do you want to see per row? (1-10)", + // "Character Preference", + // names_per_row + // ) as null|num + // if(narow) + // names_per_row = clamp(narow, 1, 10) + // to_chat(user, span_notice("You will now see [names_per_row] character names per row!")) + + // if("changeslot") + // if(!load_character(text2num(href_list["num"]))) + // initialize_preferences() // just so we dont carry over literally everything from the last character + // random_character() + // real_name = random_unique_name(gender) + // save_character() + // if(isnewplayer(parent.mob)) // Update the player panel with the new name. + // var/mob/dead/new_player/player_mob = parent.mob + // player_mob.new_player_panel() + + // if("tab") + // if(href_list["tab"]) + // current_tab = text2num(href_list["tab"]) + // if("erp_tab") + // if(href_list["newtab"]) + // if(href_list["nonumber"]) + // erp_tab_page = href_list["newtab"] + // else + // erp_tab_page = text2num(href_list["newtab"]) chat_toggles |= CHAT_LOOC // the LOOC stays on during sex - if(href_list["preference"] == "gear") - if(href_list["clear_loadout"]) - loadout_data["SAVE_[loadout_slot]"] = list() - - save_preferences() - if(href_list["select_category"]) - gear_category = html_decode(href_list["select_category"]) - gear_subcategory = GLOB.loadout_categories[gear_category][1] - if(href_list["select_subcategory"]) - gear_subcategory = html_decode(href_list["select_subcategory"]) - if(href_list["toggle_gear_path"]) - var/name = html_decode(href_list["toggle_gear_path"]) - var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name] - if(!G) - return - var/toggle = text2num(href_list["toggle_gear"]) - if(!toggle && has_loadout_gear(loadout_slot, "[G.type]"))//toggling off and the item effectively is in chosen gear) - remove_gear_from_loadout(loadout_slot, "[G.type]") - else if(toggle && !(has_loadout_gear(loadout_slot, "[G.type]"))) + // if(href_list["preference"] == "gear") + // if(href_list["clear_loadout"]) + // loadout_data["SAVE_[loadout_slot]"] = list() + + // save_preferences() + // if(href_list["select_category"]) + // gear_category = html_decode(href_list["select_category"]) + // gear_subcategory = GLOB.loadout_categories[gear_category][1] + // if(href_list["select_subcategory"]) + // gear_subcategory = html_decode(href_list["select_subcategory"]) + // if(href_list["toggle_gear_path"]) + // var/name = html_decode(href_list["toggle_gear_path"]) + // var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name] + // if(!G) + // return + // var/toggle = text2num(href_list["toggle_gear"]) + // if(!toggle && has_loadout_gear(loadout_slot, "[G.type]"))//toggling off and the item effectively is in chosen gear) + // RemoveGearFromLoadout(loadout_slot, "[G.type]") + // else if(toggle && !(has_loadout_gear(loadout_slot, "[G.type]"))) - if(!is_loadout_slot_available(G.category, G.cost)) - to_chat(user, span_danger("I can only take [MAX_FREE_PER_CAT] free items from this category!")) - return + // if(!is_loadout_slot_available(G.category, G.cost)) + // to_chat(user, span_danger("I can only take [MAX_FREE_PER_CAT] free items from this category!")) + // return - if(G.donoritem && !G.donator_ckey_check(user.ckey)) - to_chat(user, span_danger("This is an item intended for donator use only. You are not authorized to use this item.")) - return - if(gear_points >= initial(G.cost)) - var/list/new_loadout_data = list(LOADOUT_ITEM = "[G.type]") - if(loadout_data["SAVE_[loadout_slot]"]) - loadout_data["SAVE_[loadout_slot]"] += list(new_loadout_data) //double packed because it does the union of the CONTENTS of the lists - else - loadout_data["SAVE_[loadout_slot]"] = list(new_loadout_data) //double packed because you somehow had no save slot in your loadout? - - if(href_list["loadout_color"] || href_list["loadout_rename"] || href_list["loadout_redescribe"] || href_list["loadout_recolor"]) - //if the gear doesn't exist, or they don't have it, ignore the request - var/name = html_decode(href_list["loadout_gear_name"]) - var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name] - if(!G) - return - var/user_gear = has_loadout_gear(loadout_slot, "[G.type]") - if(!user_gear) - return - - //possible requests: rename, redescribe (recolor/recolor polychrom not ported) - //always make sure the gear allows said request before proceeding - - //both renaming and redescribing strip the input to stop html injection - - //renaming is only allowed if it has the flag for it - if(href_list["loadout_rename"] && (G.loadout_flags & LOADOUT_CAN_NAME)) - var/new_name = stripped_input(user, "Enter new name for item. Maximum [MAX_NAME_LEN] characters.", "Loadout Item Naming", null, MAX_NAME_LEN) - if(new_name) - user_gear[LOADOUT_CUSTOM_NAME] = new_name - - //redescribing is only allowed if it has the flag for it - if(href_list["loadout_redescribe"] && (G.loadout_flags & LOADOUT_CAN_DESCRIPTION)) //redescribe isnt a real word but i can't think of the right term to use - var/new_description = stripped_input(user, "Enter new description for item. Maximum 500 characters.", "Loadout Item Redescribing", null, 500) - if(new_description) - user_gear[LOADOUT_CUSTOM_DESCRIPTION] = new_description - - if(href_list["loadout_recolor"] && (G.loadout_flags & LOADOUT_CAN_COLOR)) - // var/enter_the_matrix = alert( - // user, - // "Use the simple Color Picker to choose a solid color, or use the more advanced (and convoluted) Color Matrix editor to recolor this?", - // "Colorize, Quick or Advanced?", - // "Color Picker", - // "Matrix Editor", - // "Cancel", - // ) - // if(enter_the_matrix == "Color Picker") - var/new_color = input( - user, - "Pick a cool new color for your [G.name]! =3", - "Recolor Your Thing", - user_gear[LOADOUT_CUSTOM_COLOR] || "#FFFFFF", - ) as color|null - if(new_color) - user_gear[LOADOUT_CUSTOM_COLOR] = "#[sanitize_hexcolor(new_color, 6)]" - to_chat(user, span_notice("Your [G.name] has been recolored to [user_gear[LOADOUT_CUSTOM_COLOR]]!")) - // else if(enter_the_matrix == "Matrix Editor") - // gear_color_matrix_setup_thing(user, user_gear, G) + // if(G.donoritem && !G.donator_ckey_check(user.ckey)) + // to_chat(user, span_danger("This is an item intended for donator use only. You are not authorized to use this item.")) + // return + // if(gear_points >= initial(G.cost)) + // var/list/new_loadout_data = list(LOADOUT_ITEM = "[G.type]") + // if(loadout_data["SAVE_[loadout_slot]"]) + // loadout_data["SAVE_[loadout_slot]"] += list(new_loadout_data) //double packed because it does the union of the CONTENTS of the lists + // else + // loadout_data["SAVE_[loadout_slot]"] = list(new_loadout_data) //double packed because you somehow had no save slot in your loadout? + + // if(href_list["loadout_color"] || href_list["loadout_rename"] || href_list["loadout_redescribe"] || href_list["loadout_recolor"]) + // //if the gear doesn't exist, or they don't have it, ignore the request + // var/name = html_decode(href_list["loadout_gear_name"]) + // var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name] + // if(!G) + // return + // var/user_gear = has_loadout_gear(loadout_slot, "[G.type]") + // if(!user_gear) + // return + + // //possible requests: rename, redescribe (recolor/recolor polychrom not ported) + // //always make sure the gear allows said request before proceeding + + // //both renaming and redescribing strip the input to stop html injection + + // //renaming is only allowed if it has the flag for it + // if(href_list["loadout_rename"] && (G.loadout_flags & LOADOUT_CAN_NAME)) + // var/new_name = stripped_input(user, "Enter new name for item. Maximum [MAX_NAME_LEN] characters.", "Loadout Item Naming", null, MAX_NAME_LEN) + // if(new_name) + // user_gear[LOADOUT_CUSTOM_NAME] = new_name + + // //redescribing is only allowed if it has the flag for it + // if(href_list["loadout_redescribe"] && (G.loadout_flags & LOADOUT_CAN_DESCRIPTION)) //redescribe isnt a real word but i can't think of the right term to use + // var/new_description = stripped_input(user, "Enter new description for item. Maximum 500 characters.", "Loadout Item Redescribing", null, 500) + // if(new_description) + // user_gear[LOADOUT_CUSTOM_DESCRIPTION] = new_description + + // if(href_list["loadout_recolor"] && (G.loadout_flags & LOADOUT_CAN_COLOR)) + // // var/enter_the_matrix = alert( + // // user, + // // "Use the simple Color Picker to choose a solid color, or use the more advanced (and convoluted) Color Matrix editor to recolor this?", + // // "Colorize, Quick or Advanced?", + // // "Color Picker", + // // "Matrix Editor", + // // "Cancel", + // // ) + // // if(enter_the_matrix == "Color Picker") + // var/new_color = input( + // user, + // "Pick a cool new color for your [G.name]! =3", + // "Recolor Your Thing", + // user_gear[LOADOUT_CUSTOM_COLOR] || "#FFFFFF", + // ) as color|null + // if(new_color) + // user_gear[LOADOUT_CUSTOM_COLOR] = "#[sanitize_hexcolor(new_color, 6)]" + // to_chat(user, span_notice("Your [G.name] has been recolored to [user_gear[LOADOUT_CUSTOM_COLOR]]!")) + // // else if(enter_the_matrix == "Matrix Editor") + // // gear_color_matrix_setup_thing(user, user_gear, G) ShowChoices(user) return 1 @@ -4708,34 +3379,34 @@ GLOBAL_LIST_EMPTY(preferences_datums) key_bindings[key] = oldkeys[key] parent?.ensure_keys_set(src) -/datum/preferences/proc/is_loadout_slot_available(category, cost) - if(cost) - return TRUE - var/list/L - LAZYINITLIST(L) - for(var/i in loadout_data["SAVE_[loadout_slot]"]) - var/loadie = i[LOADOUT_ITEM] - var/datum/gear/G = text2path(loadie) - if(initial(G.cost) > 0) // oh right, these are uninitialized, mb - continue // non-free items are self limiting - if(initial(G.category) != category) - continue - var/occupied_slots = L[initial(G.category)] ? L[initial(G.category)] + 1 : 1 - LAZYSET(L, initial(G.category), occupied_slots) - for(var/things_got in L) - if(L[things_got] > MAX_FREE_PER_CAT) - return FALSE - return TRUE - /* switch(slot) - if(SLOT_IN_BACKPACK) - if(L[LOADOUT_CATEGORY_BACKPACK] < BACKPACK_SLOT_AMT) - return TRUE - if(SLOT_HANDS) - if(L[LOADOUT_CATEGORY_HANDS] < HANDS_SLOT_AMT) - return TRUE - else - if(L[slot] < MAX_FREE_PER_CAT) - return TRUE */ +// /datum/preferences/proc/is_loadout_slot_available(category, cost) +// if(cost) +// return TRUE +// var/list/L +// LAZYINITLIST(L) +// for(var/i in loadout_data["SAVE_[loadout_slot]"]) +// var/loadie = i[LOADOUT_ITEM] +// var/datum/gear/G = text2path(loadie) +// if(initial(G.cost) > 0) // oh right, these are uninitialized, mb +// continue // non-free items are self limiting +// if(initial(G.category) != category) +// continue +// var/occupied_slots = L[initial(G.category)] ? L[initial(G.category)] + 1 : 1 +// LAZYSET(L, initial(G.category), occupied_slots) +// for(var/things_got in L) +// if(L[things_got] > MAX_FREE_PER_CAT) +// return FALSE +// return TRUE +// /* switch(slot) +// if(SLOT_IN_BACKPACK) +// if(L[LOADOUT_CATEGORY_BACKPACK] < BACKPACK_SLOT_AMT) +// return TRUE +// if(SLOT_HANDS) +// if(L[LOADOUT_CATEGORY_HANDS] < HANDS_SLOT_AMT) +// return TRUE +// else +// if(L[slot] < MAX_FREE_PER_CAT) +// return TRUE */ /datum/preferences/proc/generate_quester_id() var/list/new_quid = list() @@ -4756,10 +3427,10 @@ GLOBAL_LIST_EMPTY(preferences_datums) return loadout_gear return FALSE -/datum/preferences/proc/remove_gear_from_loadout(save_slot, gear_type) - var/find_gear = has_loadout_gear(save_slot, gear_type) - if(find_gear) - loadout_data["SAVE_[save_slot]"] -= list(find_gear) +// /datum/preferences/proc/RemoveGearFromLoadout(save_slot, gear_type) +// var/find_gear = has_loadout_gear(save_slot, gear_type) +// if(find_gear) +// loadout_data["SAVE_[save_slot]"] -= list(find_gear) /// sux0rs I gotta do this, but hey, I love to sux0r my cox0r /datum/preferences/proc/initialize_preferences() @@ -4887,8 +3558,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) input_mode_hotkey = initial(input_mode_hotkey) pref_species = new /datum/species/mammal() quester_uid = generate_quester_id() - -/datum/preferences/proc/run_deletion_song_and_dance() +/* +/datum/preferences/proc/run_deletion_s ong_and_dance() lockdown = TRUE /// stage one, ask if they are sure, and detail the fact that this will delete the character forever /// with no chance of retrieval @@ -4929,7 +3600,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) to_chat(usr, span_danger("So be it. Deleting [real_name]...")) delete_character(default_slot, real_name) to_chat(usr, span_danger("Character deletion complete. They are gone, forever.")) - lockdown = FALSE + lockdown = FALSE */ /datum/preferences/proc/get_my_quirks() if(!LAZYLEN(char_quirks)) @@ -4962,7 +3633,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "" return dat.Join() -/datum/preferences/proc/set_copyslot() +/* /datum/preferences/proc/set_copyslot() copyslot = default_slot copyname = real_name to_chat(usr, span_notice("Copied [real_name] to the clipboard.")) @@ -4996,8 +3667,5 @@ GLOBAL_LIST_EMPTY(preferences_datums) return load_character(copyslot, TRUE) save_character() - to_chat(usr, span_notice("Character pasted successfully!")) + to_chat(usr, span_notice("Character pasted successfully!")) */ -#undef MAX_FREE_PER_CAT -#undef HANDS_SLOT_AMT -#undef BACKPACK_SLOT_AMT diff --git a/code/modules/client/preferences_actions.dm b/code/modules/client/preferences_actions.dm new file mode 100644 index 0000000000..f55d04fc2b --- /dev/null +++ b/code/modules/client/preferences_actions.dm @@ -0,0 +1,2757 @@ +/* + * File: preferences_actions.dm + * Author: Awesome Possum (https://tgstation13.org/phpBB/memberlist.php?mode=viewprofile&u=244) + * Date: 2019-12-10 + * License: WWW.PLAYAPOCALYPSE.COM + * + * This thing takes in an action from the prefs thing and does the thing + * */ + +#define MAX_FREE_PER_CAT 4 +#define HANDS_SLOT_AMT 2 +#define BACKPACK_SLOT_AMT 4 + + +/datum/preferences/Topic(href, href_list, hsrc) //yeah, gotta do this I guess.. + if(lockdown) + return + . = ..() + if(href_list["close"]) + var/client/C = usr.client + if(C) + C.clear_character_previews() + +/datum/preferences/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) + . = ..() + var/mob/user = parent.client + if(lockdown) + return + var/list/hreflist = list() + hreflist["preference"] = action + hreflist |= params + if(user) + process_link(user, hreflist) + +/datum/preferences/proc/process_link(mob/user, list/href_list) + if(lockdown) + return + var/what_did + var/do_vis_update = FALSE + var/command = href_list["preference"] + switch(command) + // Set whether or not the action buttons are locked + if(PREFCMD_ACTION_BUTTONS) + TOGGLE_VAR(buttons_locked) + what_did = PRACT_TOGGLE_INV(buttons_locked) + // Change your limbs to be prosthetic, amputated, or normal + if(PREFCMD_ADD_LIMB) + what_did = AddLimbMod(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle whether or not the adminhelp sound plays (mainly just for admins) + if(PREFCMD_ADMINHELP) + TOGGLE_BITFIELD(toggles, SOUND_ADMINHELP) + what_did = PRACT_TOGGLE(toggles & SOUND_ADMINHELP) + // vore prefs + // Toggle whether or not you can be fed prey + if(PREFCMD_ALLOW_BEING_FED_PREY) + TOGGLE_VAR(allow_being_fed_prey) + what_did = PRACT_TOGGLE(allow_being_fed_prey) + // Toggle whether or not you can be prey + if(PREFCMD_ALLOW_BEING_PREY) + TOGGLE_VAR(allow_being_prey) + what_did = PRACT_TOGGLE(allow_being_prey) + // Toggle whether or not you see messages about vore death + if(PREFCMD_ALLOW_DEATH_MESSAGES) + TOGGLE_VAR(allow_death_messages) + what_did = PRACT_TOGGLE(allow_death_messages) + // Toggle whether or not you take damage from digestion + if(PREFCMD_ALLOW_DIGESTION_DAMAGE) + TOGGLE_VAR(allow_digestion_damage) + what_did = PRACT_TOGGLE(allow_digestion_damage) + // Toggle whether or not you can die from digestion + if(PREFCMD_ALLOW_DIGESTION_DEATH) + TOGGLE_VAR(allow_digestion_death) + what_did = PRACT_TOGGLE(allow_digestion_death) + // Toggle whether or not you can hear digestion sounds + if(PREFCMD_ALLOW_DIGESTION_SOUNDS) + TOGGLE_VAR(allow_digestion_sounds) + what_did = PRACT_TOGGLE(allow_digestion_sounds) + // Toggle whether or not you can hear vore eating sounds + if(PREFCMD_ALLOW_EATING_SOUNDS) + TOGGLE_VAR(allow_eating_sounds) + what_did = PRACT_TOGGLE(allow_eating_sounds) + // Toggle whether or not you see trash messages ?? + if(PREFCMD_ALLOW_TRASH_MESSAGES) + TOGGLE_VAR(allow_trash_messages) + what_did = PRACT_TOGGLE(allow_trash_messages) + // Toggle whether or not you can see vore messages in general + if(PREFCMD_ALLOW_VORE_MESSAGES) + TOGGLE_VAR(allow_vore_messages) + what_did = PRACT_TOGGLE(allow_vore_messages) + // Change the appearance of your alternate species (for pokemon, make em shiny or something) + if(PREFCMD_ALT_PREFIX) + do_vis_update = TRUE + what_did = ChangeAltPrefix(user, href_list) + // Toggle whether or not you can see the ambient occlusion + if(PREFCMD_AMBIENTOCCLUSION) + TOGGLE_VAR(ambientocclusion) + if(parent && parent.screen && parent.screen.len) + var/atom/movable/screen/plane_master/game_world/G = parent.mob.hud_used.plane_masters["[GAME_PLANE]"] + var/atom/movable/screen/plane_master/objitem/OI = parent.mob.hud_used.plane_masters["[OBJITEM_PLANE]"] + var/atom/movable/screen/plane_master/mob/M = parent.mob.hud_used.plane_masters["[MOB_PLANE]"] + var/atom/movable/screen/plane_master/above_wall/A = parent.mob.hud_used.plane_masters["[ABOVE_WALL_PLANE]"] + var/atom/movable/screen/plane_master/wall/W = parent.mob.hud_used.plane_masters["[WALL_PLANE]"] + G.backdrop(parent.mob) + OI.backdrop(parent.mob) + M.backdrop(parent.mob) + A.backdrop(parent.mob) + W.backdrop(parent.mob) + what_did = PRACT_TOGGLE(ambientocclusion) + // If you're an admin, toggle whether or not you tell the rest of the admins you're logging in + if(PREFCMD_ANNOUNCE_LOGIN) + TOGGLE_BITFIELD(toggles, ANNOUNCE_LOGIN) + what_did = PRACT_TOGGLE(toggles & ANNOUNCE_LOGIN) + // Toggle whether or not you're arrousable + if(PREFCMD_AROUSABLE) + TOGGLE_VAR(arousable) + what_did = PRACT_TOGGLE(arousable) + // Toggle whether or not the viewport will auto-resize to fit the screen occasionally + if(PREFCMD_AUTO_FIT_VIEWPORT) + TOGGLE_VAR(auto_fit_viewport) + if(auto_fit_viewport && parent) + parent.fit_viewport() + what_did = PRACT_TOGGLE(auto_fit_viewport) + // Toggle whether or not your OOC turns on after the round? unclear + if(PREFCMD_AUTO_OOC) + TOGGLE_VAR(auto_ooc) + what_did = PRACT_TOGGLE(auto_ooc) + // Toggle whether or not you wag your tail automatically when someone pats you and calls you a good puppy + if(PREFCMD_AUTO_WAG) + TOGGLE_BITFIELD(cit_toggles, NO_AUTO_WAG) + what_did = PRACT_TOGGLE_INV(cit_toggles & NO_AUTO_WAG) + // Toggle whether or not you stand up automatically when you're downed + if(PREFCMD_AUTOSTAND_TOGGLE) + TOGGLE_VAR(autostand) + what_did = PRACT_TOGGLE(autostand) + // Change the kind of backpack you have + if(PREFCMD_BACKPACK_KIND) + what_did = ChangeBackpackKind(user, href_list) + // Change the maximum number of words you'll blurble + if(PREFCMD_BLURBLE_MAX_WORDS) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_input = input( + user, + "When you speak, a sound will be played for every word you say. \ + How many words should be the maximum before the sound stops playing? \ + Note that this only really works if the sound behavior is set to \ + Animal Crossing!", + "Sound Indicator" + ) as null|anything in GLOB.typing_indicator_max_words_spoken_list + if(new_input) + what_did = PRACT_DIALOG_ACCEPT + to_chat(user, span_green("You have set the maximum words spoken to [new_input]!")) + features_speech["typing_indicator_max_words_spoken"] = new_input + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change the pitch of the blurble sound + if(PREFCMD_BLURBLE_PITCH) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_input = input( + user, + "When you speak, a sound will be played for every word you say. \ + What pitch should the sound be?", + "Sound Indicator" + ) as null|anything in GLOB.typing_indicator_pitches + if(new_input) + what_did = PRACT_DIALOG_ACCEPT + to_chat(user, span_green("You have set the pitch to [new_input]!")) + features_speech["typing_indicator_pitch"] = new_input + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change your blurble sound + if(PREFCMD_BLURBLE_SOUND) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_input = input( + user, + "When you speak, a sound will be played for every word you say. \ + What sound should be played?", + "Sound Indicator" + ) as null|anything in GLOB.typing_sounds + if(new_input) + what_did = PRACT_DIALOG_ACCEPT + to_chat(user, span_green("You have set the sound to [new_input]!")) + features_speech["typing_indicator_sound"] = new_input + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change the speed of the blurble sound + if(PREFCMD_BLURBLE_SPEED) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_input = input( + user, + "When you speak, a sound will be played for every word you say. \ + How rapidly should the sound be played?", + "Sound Indicator" + ) as null|anything in GLOB.typing_indicator_speeds + if(new_input) + what_did = PRACT_DIALOG_ACCEPT + to_chat(user, span_green("You have set the speed to [new_input]!")) + features_speech["typing_indicator_speed"] = new_input + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change the trigger for the blurble sound + if(PREFCMD_BLURBLE_TRIGGER) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_input = input( + user, + "When you speak, a sound will be played for every word you say. \ + What should trigger the sound?", + "Sound Indicator" + ) as null|anything in GLOB.play_methods + if(new_input) + what_did = PRACT_DIALOG_ACCEPT + to_chat(user, span_green("You have set the trigger to [new_input]!")) + features_speech["typing_indicator_trigger"] = new_input + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change how much the blurble sound varies + if(PREFCMD_BLURBLE_VARY) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_input = input( + user, + "When you speak, a sound will be played for every word you say. \ + How much should the sound vary?", + "Sound Indicator" + ) as null|anything in GLOB.typing_indicator_variances + if(new_input) + what_did = PRACT_DIALOG_ACCEPT + to_chat(user, span_green("You have set the variance to [new_input]!")) + features_speech["typing_indicator_variance"] = new_input + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change the volume of the blurble sound + if(PREFCMD_BLURBLE_VOLUME) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_input = input( + user, + "When you speak, a sound will be played for every word you say. \ + How loud should the sound be?", + "Sound Indicator" + ) as null|anything in GLOB.typing_indicator_volumes + if(new_input) + what_did = PRACT_DIALOG_ACCEPT + to_chat(user, span_green("You have set the volume to [new_input]!")) + features_speech["typing_indicator_volume"] = new_input + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change the model of your body, mainly for removing two (2) pixels from the sprite + if(PREFCMD_BODY_MODEL) + do_vis_update = TRUE + features["body_model"] = features["body_model"] == MALE ? FEMALE : MALE + what_did = PRACT_TOGGLE(features["body_model"] == FEMALE) // sure, female is on + // Change the sprite of your body + if(PREFCMD_BODY_SPRITE) + do_vis_update = TRUE + PlayBoop(user, BOOP_MENU_OPEN) + var/selbodspr = input( + user, + "You can change what the base sprite of your character looks like! \ + Note that if you use markings, they'll probably hide this sprite. \ + However it does make a really cool looking shadekin!", + "Body Sprite", + ) as null|anything in pref_species.allowed_limb_ids + if(selbodspr) + what_did = PRACT_DIALOG_ACCEPT + to_chat(user, span_green("You have set your body sprite to [selbodspr]!")) + chosen_limb_id = selbodspr + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Toggle whether or not people can slap ur butt + if(PREFCMD_BUTT_SLAP) + TOGGLE_BITFIELD(cit_toggles, NO_BUTT_SLAP) + what_did = PRACT_TOGGLE_INV(cit_toggles & NO_BUTT_SLAP) + // Toggle whether or not you want people to know you paid for BYOND (its a good thing to do so! support the dev!) + if(PREFCMD_BYOND_PUBLICITY) + if(!unlock_content) + what_did = PRACT_DIALOG_DENIED + else + TOGGLE_BITFIELD(toggles, MEMBER_PUBLIC) + what_did = PRACT_TOGGLE(toggles & MEMBER_PUBLIC) + // Change your age + if(PREFCMD_CHANGE_AGE) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_age = input( + user, + "How old is your character?\n\ + ([AGE_MIN] - [AGE_MAX])", + "Character Preference" + ) as num|null + if(new_age) + age = clamp(numberfy(new_age), AGE_MIN, AGE_MAX) + what_did = PRACT_DIALOG_ACCEPT + to_chat(user, span_green("You have set your age to [age]!")) + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change your flavor text + if(PREFCMD_CHANGE_FLAVOR_TEXT) + PlayBoop(user, BOOP_BIG_MENU_OPEN) + var/numessage = stripped_multiline_input( + user, + "Set your flavor text! This is where you can describe your character's appearance, personality, \ + or anything else you want to share about them. Feel free to get juicy with it!", + "Flavor Text", + html_decode(features["flavor_text"]), + MAX_FLAVOR_LEN, + TRUE + ) + if(!isnull(numessage)) + if(numessage == "") + PlayBoop(user, BOOP_SUB_PROMPT) + var/usure = alert( + user, + "Are you sure you want to clear your flavor text?", + "Character Preference", + "Yes clear it", + "No keep it" + ) + if(usure != "Yes clear it") + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + features["flavor_text"] = numessage + what_did = PRACT_DIALOG_ACCEPT_BIG + to_chat(user, span_green("You have set your flavor text!")) + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change your gender + if(PREFCMD_CHANGE_GENDER) + PlayBoop(user, BOOP_MENU_OPEN) + var/chosengender = input( + user, + "Select a gender for your character!", + "Gender Selection", + gender, + ) as null|anything in list(MALE,FEMALE,"nonbinary","object") + if(!chosengender) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + var/bm_b4 = features["body_model"] + switch(chosengender) + if("nonbinary") + chosengender = PLURAL + features["body_model"] = pick(MALE, FEMALE) + if("object") + chosengender = NEUTER + features["body_model"] = MALE + else + features["body_model"] = chosengender + if(bm_b4 != features["body_model"]) + do_vis_update = TRUE + to_chat(user, span_green("You have set your gender to [chosengender]!")) + gender = chosengender + what_did = PRACT_DIALOG_ACCEPT + // Change the shape of your genitals (circle, square, etc) + if(PREFCMD_CHANGE_GENITAL_SHAPE) + what_did = ChangeGenitalShape(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the size of your genitals + if(PREFCMD_CHANGE_GENITAL_SIZE) + what_did = ChangeGenitalSize(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change who you like to kiss uwu kissu + if(PREFCMD_CHANGE_KISSER) + PlayBoop(user, BOOP_MENU_OPEN) + var/newkiss = input( + user, + "What sort of person do you like to kiss?", + "Character Preference" + ) as null|anything in KISS_LIST + if(newkiss) + kisser = newkiss + to_chat(user, span_green("[newkiss]!")) + what_did = PRACT_DIALOG_ACCEPT + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change your name + if(PREFCMD_CHANGE_NAME) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_name = input( + user, + "What's your character's name?", + "Character Preference" + ) as null|text + if(isnull(new_name)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + new_name = reject_bad_name(new_name) + if(!new_name) + to_chat(user, span_warning("Oh no! That name is invalid! Please have a name that is at least 2 characters long and at most [MAX_NAME_LEN] characters long. It may only contain the characters A-Z, a-z, -, ' and .")) + what_did = PRACT_DIALOG_DENIED + else + real_name = new_name + if(isnewplayer(parent.mob)) + var/mob/dead/new_player/player_mob = parent.mob + player_mob.new_player_panel() + what_did = PRACT_DIALOG_ACCEPT + to_chat(user, span_green("Hi, [new_name]!")) + // Change your OOC notes + if(PREFCMD_CHANGE_OOC_NOTES) + PlayBoop(user, BOOP_BIG_MENU_OPEN) + var/numessage = stripped_multiline_input( + user, + "Set your OOC notes! This is where you describe anything you want others to know about yourself or your character \ + that isn't covered by the flavor text. This is a great place to list things like your preferences, limits, or \ + anything else you want to share!", + "OOC Notes", + html_decode(features["ooc_notes"]), + MAX_FLAVOR_LEN, + TRUE + ) + if(!isnull(numessage)) + PlayBoop(user, BOOP_SUB_PROMPT) + if(numessage == "") + var/usure = alert( + user, + "Are you sure you want to clear your OOC notes?", + "Character Preference", + "Yes clear it", + "No keep it" + ) + if(usure != "Yes clear it") + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + features["ooc_notes"] = numessage + what_did = PRACT_DIALOG_ACCEPT_BIG + to_chat(user, span_green("You have set your OOC notes!")) + else + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + // Change one of your parts (horns, tails, etc) + if(PREFCMD_CHANGE_PART) + what_did = ChangePart(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the current slot + if(PREFCMD_CHANGE_SLOT) + what_did = ChangeSlot(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the current TBS + if(PREFCMD_CHANGE_TBS) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_tbs = input( + user, + "Are you a top, bottom, or switch? (or none of the above)", + "Character Preference" + ) as null|anything in TBS_LIST + if(new_tbs) + tbs = new_tbs + to_chat(user, span_green("You are a [new_tbs]!")) + what_did = PRACT_DIALOG_ACCEPT + else + to_chat(user, span_warning("Okay nevermind[prob(1)? ", bottom" : ""]!!")) + what_did = PRACT_DIALOG_CANCEL + // Apply some kind of color to somewhere + if(PREFCMD_COLOR_CHANGE) + what_did = ChangeColor(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Use runechat color in the chat log + if(PREFCMD_COLOR_CHAT_LOG) + TOGGLE_VAR(color_chat_log) + what_did = PRACT_TOGGLE(color_chat_log) + // Copy a color from somewhere + if(PREFCMD_COLOR_COPY) + what_did = CopyColor(user, href_list) + // Delete a color from somewhere + if(PREFCMD_COLOR_DEL) + what_did = DeleteColor(user, href_list) + // Paste a color to somewhere + if(PREFCMD_COLOR_PASTE) + what_did = PasteColor(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle whether or not the combo HUD uses lighting (i dont know what this does) + if(PREFCMD_COMBOHUD_LIGHTING) + TOGGLE_BITFIELD(toggles, COMBOHUD_LIGHTING) + what_did = PRACT_TOGGLE(toggles & COMBOHUD_LIGHTING) + // Change how much if at all the screen shakes when you take damage + if(PREFCMD_DAMAGESCREENSHAKE_TOGGLE) + switch(damagescreenshake) + if(0) + damagescreenshake = 1 + if(1) + damagescreenshake = 2 + if(2) + damagescreenshake = 0 + else + damagescreenshake = 1 + what_did = PRACT_TOGGLE(damagescreenshake) + // Edit the current eye type + if(PREFCMD_EYE_TYPE) + what_did = ChangeEyeType(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the style of facial hair you have + if(PREFCMD_FACIAL_HAIR_STYLE) + what_did = ChangeFacialHairStyle(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle whether or not you have a fuzzy body + if(PREFCMD_FUZZY) + TOGGLE_VAR(fuzzy) + what_did = PRACT_TOGGLE(fuzzy) + // Toggle whether or not you can see peoples genitals when you look at them (the player, not the genitals) + if(PREFCMD_GENITAL_EXAMINE) + TOGGLE_BITFIELD(cit_toggles, GENITAL_EXAMINE) + what_did = PRACT_TOGGLE(cit_toggles & GENITAL_EXAMINE) + // Toggle whether or not you can see ghost accessories + if(PREFCMD_GHOST_ACCS) + var/new_ghost_accs = alert( + user, + "Do you want your ghost to show full accessories where possible, \ + hide accessories but still use the directional sprites where possible, \ + or also ignore the directions and stick to the default sprites?", + "Boob Yeah", + GHOST_ACCS_FULL_NAME, + GHOST_ACCS_DIR_NAME, + GHOST_ACCS_NONE_NAME + ) + switch(new_ghost_accs) + if(GHOST_ACCS_FULL_NAME) + ghost_accs = GHOST_ACCS_FULL + if(GHOST_ACCS_DIR_NAME) + ghost_accs = GHOST_ACCS_DIR + if(GHOST_ACCS_NONE_NAME) + ghost_accs = GHOST_ACCS_NONE + else + ghost_accs = GHOST_ACCS_FULL + what_did = PRACT_DIALOG_ACCEPT + // Toggle whether or not you can hear people with your ghost ears + if(PREFCMD_GHOST_EARS) + TOGGLE_BITFIELD(chat_toggles, CHAT_GHOSTEARS) + what_did = PRACT_TOGGLE(chat_toggles & CHAT_GHOSTEARS) + // Change the form of your ghost + if(PREFCMD_GHOST_FORM) + if(!unlock_content) + what_did = PRACT_DIALOG_DENIED + to_chat(user, span_warning("You need to support BYOND to change your ghost form! It's a good thing to do!")) + else + var/new_form = input( + user, + "Choose your ghostly form!", + "Thanks for supporting BYOND", + ghost_form, + ) as null|anything in GLOB.ghost_forms + if(isnull(new_form)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + ghost_form = new_form + what_did = PRACT_DIALOG_ACCEPT + // Change how your ghost orbits + if(PREFCMD_GHOST_ORBIT) + if(!unlock_content) + what_did = PRACT_DIALOG_DENIED + to_chat(user, span_warning("You need to support BYOND to change your ghostly orbit! It's a good thing to do!")) + else + var/new_orbit = input( + user, + "Choose your ghostly orbit!", + "Thanks for supporting BYOND", + ghost_orbit, + ) as null|anything in GLOB.ghost_orbits + if(isnull(new_orbit)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + ghost_orbit = new_orbit + what_did = PRACT_DIALOG_ACCEPT + // Change how you see other ghosts + if(PREFCMD_GHOST_OTHERS) + var/new_ghost_others = alert( + user, + "Do you want the ghosts of others to show up as their own setting, \ + as their default sprites, or always as the default white ghost?", + "Boob Yeah", + GHOST_OTHERS_THEIR_SETTING_NAME, + GHOST_OTHERS_DEFAULT_SPRITE_NAME, + GHOST_OTHERS_SIMPLE_NAME + ) + switch(new_ghost_others) + if(GHOST_OTHERS_THEIR_SETTING_NAME) + ghost_others = GHOST_OTHERS_THEIR_SETTING + if(GHOST_OTHERS_DEFAULT_SPRITE_NAME) + ghost_others = GHOST_OTHERS_DEFAULT_SPRITE + if(GHOST_OTHERS_SIMPLE_NAME) + ghost_others = GHOST_OTHERS_SIMPLE + else + ghost_others = GHOST_OTHERS_THEIR_SETTING + what_did = PRACT_DIALOG_ACCEPT + // Toggle whether or not you can see PDAs as a ghost + if(PREFCMD_GHOST_PDA) + TOGGLE_BITFIELD(chat_toggles, CHAT_GHOSTPDA) + what_did = PRACT_TOGGLE(chat_toggles & CHAT_GHOSTPDA) + // Toggle whether or not you can hear the radio as a ghost + if(PREFCMD_GHOST_RADIO) + TOGGLE_BITFIELD(chat_toggles, CHAT_GHOSTRADIO) + what_did = PRACT_TOGGLE(chat_toggles & CHAT_GHOSTRADIO) + // Toggle whether or not you can see actions as a ghost + if(PREFCMD_GHOST_SIGHT) + TOGGLE_BITFIELD(chat_toggles, CHAT_GHOSTSIGHT) + what_did = PRACT_TOGGLE(chat_toggles & CHAT_GHOSTSIGHT) + // Toggle whether or not you can hear whispers as a ghost + if(PREFCMD_GHOST_WHISPERS) + TOGGLE_BITFIELD(chat_toggles, CHAT_GHOSTWHISPER) + what_did = PRACT_TOGGLE(chat_toggles & CHAT_GHOSTWHISPER) + // Toggle whether or not you can see the gun cursor + if(PREFCMD_GUNCURSOR_TOGGLE) + TOGGLE_BITFIELD(cb_toggles, AIM_CURSOR_ON) + what_did = PRACT_TOGGLE(cb_toggles & AIM_CURSOR_ON) + // Change the first gradient of your hair + if(PREFCMD_HAIR_GRADIENT_1) + what_did = ChangeHairGradient(user, href_list, 1) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the second gradient of your hair + if(PREFCMD_HAIR_GRADIENT_2) + what_did = ChangeHairGradient(user, href_list, 2) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the style of your hair + if(PREFCMD_HAIR_STYLE_1) + what_did = ChangeHairStyle(user, href_list, 1) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the second style of your hair + if(PREFCMD_HAIR_STYLE_2) + what_did = ChangeHairStyle(user, href_list, 2) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle whether or not you see smileys in the health bar + if(PREFCMD_HEALTH_SMILEYS) + TOGGLE_VAR(show_health_smilies) + what_did = PRACT_TOGGLE(show_health_smilies) + // Toggle if a genital is hidden by clothes and or by undies + if(PREFCMD_HIDE_GENITAL) + what_did = ToggleGenitalHide(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle whether or not you can see the hotkey help + if(PREFCMD_HOTKEY_HELP) + TOGGLE_VAR(keybind_hotkey_helpmode) + what_did = PRACT_TOGGLE(keybind_hotkey_helpmode) + // Toggle hotkey mode! + if(PREFCMD_HOTKEYS) + TOGGLE_VAR(hotkeys) + user.client.ensure_keys_set(src) + what_did = PRACT_TOGGLE(hotkeys) + // Toggle whether or not the HUD flashes whenever it feels like it + if(PREFCMD_HUD_TOGGLE_FLASH) + TOGGLE_VAR(hud_toggle_flash) + what_did = PRACT_TOGGLE(hud_toggle_flash) + // Toggle whether or not you can hear people spam the hunting horn + if(PREFCMD_HUNTINGHORN) + TOGGLE_BITFIELD(toggles, SOUND_HUNTINGHORN) + what_did = PRACT_TOGGLE(toggles & SOUND_HUNTINGHORN) + // Toggle whether or not you see income updates + if(PREFCMD_INCOME_UPDATES) + TOGGLE_BITFIELD(chat_toggles, CHAT_BANKCARD) + what_did = PRACT_TOGGLE(chat_toggles & CHAT_BANKCARD) + // Change which key turns on the loser bar + if(PREFCMD_INPUT_MODE_HOTKEY) + if(input_mode_hotkey == "Tab") + input_mode_hotkey = "Ctrl+Tab" + else + input_mode_hotkey = "Tab" + parent.change_input_toggle_key(input_mode_hotkey, send_chat = TRUE) + what_did = PRACT_TOGGLE(input_mode_hotkey == "Tab") + // The game wants to record a keypress! + if(PREFCMD_KEYBINDING_CAPTURE) + CaptureKeybinding(user, href_list) + // Actually record the keypress + if(PREFCMD_KEYBINDING_SET) + what_did = KeybindingSet(user, href_list) + // Toggle whether or not you can see the category of a keybinding + if(PREFCMD_KEYBINDING_CATEGORY_TOGGLE) + what_did = ToggleKeybindingCategory(user, href_list) + // Change the legs of your character + if(PREFCMD_LEGS) + what_did = ChangeLegs(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the category of your loadout + if(PREFCMD_LOADOUT_CATEGORY) + what_did = ChangeLoadoutCategory(user, href_list) + // Change the description of your loadout + if(PREFCMD_LOADOUT_REDESC) + what_did = ChangeLoadoutDescription(user, href_list) + // Change the name of your loadout + if(PREFCMD_LOADOUT_RENAME) + what_did = ChangeLoadoutName(user, href_list) + // Reset your loadout + if(PREFCMD_LOADOUT_RESET) + what_did = ResetLoadout(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Ask for something to set the search to + if(PREFCMD_LOADOUT_SEARCH) + what_did = EnterSearchTerm(user, href_list) + // Clear the search term for your loadout + if(PREFCMD_LOADOUT_SEARCH_CLEAR) + what_did = ClearLoadoutSearch(user, href_list) + // Change the subcategory of your loadout + if(PREFCMD_LOADOUT_SUBCATEGORY) + what_did = ChangeLoadoutSubcategory(user, href_list) + // (De)select something for your loadout! + if(PREFCMD_LOADOUT_TOGGLE) + what_did = ToggleLoadoutItem(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle if you can hear the lobby music + if(PREFCMD_LOBBY_MUSIC) + TOGGLE_BITFIELD(toggles, SOUND_LOBBY) + what_did = PRACT_TOGGLE(toggles & SOUND_LOBBY) + // Add a marking to your character + if(PREFCMD_MARKING_ADD) + what_did = AddMarking(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Edit a marking on your character + if(PREFCMD_MARKING_EDIT) + what_did = EditMarking(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Move a marking down on your character + if(PREFCMD_MARKING_MOVE_DOWN) + what_did = ShiftMarking(user, href_list, "down") + if(WasAccept(what_did)) + do_vis_update = TRUE + // Move a marking up on your character + if(PREFCMD_MARKING_MOVE_UP) + what_did = ShiftMarking(user, href_list, "up") + if(WasAccept(what_did)) + do_vis_update = TRUE + // Move to the next marking on your character + if(PREFCMD_MARKING_NEXT) + href_list[PREFDAT_GO_NEXT] = TRUE + what_did = EditMarking(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Move to the previous marking on your character + if(PREFCMD_MARKING_PREV) + href_list[PREFDAT_GO_PREV] = TRUE + what_did = EditMarking(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Remove a marking from your character + if(PREFCMD_MARKING_REMOVE) + what_did = RemoveMarking(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle the master vore switch + if(PREFCMD_MASTER_VORE_TOGGLE) + TOGGLE_VAR(master_vore_toggle) + what_did = PRACT_TOGGLE(master_vore_toggle) + // Change the maximum length of a runechat message + if(PREFCMD_MAX_CHAT_LENGTH) + PlayBoop(user, BOOP_MENU_OPEN) + var/desiredlength = input( + user, + "Runechat is a system that shows big blocks of text on screen whenever something speaks or emotes. \ + When one is shown, how many characters maximum should it be? \ + (Valid range is 1 to [CHAT_MESSAGE_MAX_LENGTH] (default: [initial(max_chat_length)]))", + "Character Preference", + max_chat_length + ) as null|num + if(isnull(desiredlength)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + max_chat_length = clamp(desiredlength, 1, CHAT_MESSAGE_MAX_LENGTH) + to_chat(user, span_green("You have set the maximum runechat length to [max_chat_length]!")) + what_did = PRACT_DIALOG_ACCEPT + // Change the maximum height of a PFP + if(PREFCMD_MAX_PFP_HEIGHT) + PlayBoop(user, BOOP_MENU_OPEN) + var/newhight = input( + user, + "When you examine other players, a profile image is typically shown. \ + These images can be quite big, so they are scaled down to a maximum height. \ + How many pixels tall should profile examine images be when you see them?", + "Character Preference", + see_pfp_max_hight + ) as null|num + if(isnull(newhight)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + see_pfp_max_hight = newhight + to_chat(user, span_green("You have set the maximum profile image height to [see_pfp_max_hight]!")) + what_did = PRACT_DIALOG_ACCEPT + // Change the maximum width percent of a PFP + if(PREFCMD_MAX_PFP_WIDTH) + PlayBoop(user, BOOP_MENU_OPEN) + var/newhight = input( + user, + "When you examine other players, a profile image is typically shown. \ + These images can be quite big, so they are scaled down to a maximum width. \ + This width is measured as a percentage of the chat window. \ + How many percent wide should profile examine images be when you see them?", + "Character Preference", + see_pfp_max_widht + ) as null|num + if(isnull(newhight)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + see_pfp_max_widht = newhight + to_chat(user, span_green("You have set the maximum profile image width percent to [see_pfp_max_widht]!")) + what_did = PRACT_DIALOG_ACCEPT + // Change the type of meat you are + if(PREFCMD_MEAT_TYPE) + PlayBoop(user, BOOP_MENU_OPEN) + var/newmeat = input( + user, + "What kind of meat are you?", + "Character Preference", + features["meat_type"] + ) as null|anything in GLOB.meat_types + if(isnull(newmeat)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + features["meat_type"] = newmeat + to_chat(user, span_green("You are [features["meat_type"]] meat!")) + what_did = PRACT_DIALOG_ACCEPT + // Change the MIDI that plays when you die + if(PREFCMD_MIDIS) + TOGGLE_BITFIELD(toggles, SOUND_MIDI) + what_did = PRACT_TOGGLE(toggles & SOUND_MIDI) + // Toggle whether or not you see mismatched markings + if(PREFCMD_MISMATCHED_MARKINGS) + TOGGLE_VAR(show_mismatched_markings) + what_did = PRACT_TOGGLE(show_mismatched_markings) + // Modify a limb + if(PREFCMD_MODIFY_LIMB) + what_did = ModifyLimbMod(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Remove a limb modification + if(PREFCMD_REMOVE_LIMB) + what_did = RemoveLimbMod(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle whether or not you can see offscreen runechats + if(PREFCMD_OFFSCREEN) + TOGGLE_VAR(see_fancy_offscreen_runechat) + what_did = PRACT_TOGGLE(see_fancy_offscreen_runechat) + // Change whether or not the genital is always show, never show, or show when unclothered + if(PREFCMD_OVERRIDE_GENITAL) + what_did = OverrideGenital(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the kind of PDA you have + if(PREFCMD_PDA_KIND) + what_did = ChangePDAKind(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the ringtone of your PDA + if(PREFCMD_PDA_RINGTONE) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_ringtone = stripped_input( + user, + "When someone sends a message to your DataPal, it'll say something! \ + What would you like it to say?", + "Character Preference", + pda_ringmessage, + 30 + ) + if(isnull(new_ringtone)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else if(trim(new_ringtone) == "") + pda_ringmessage = initial(pda_ringmessage) + to_chat(user, span_green("You have set your DataPal ringtone to [pda_ringmessage]!")) + what_did = PRACT_DIALOG_ACCEPT + // Change the whitelist for the PHUD + if(PREFCMD_PHUD_WHITELIST) + what_did = ChangePHUDWhitelist(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change your default X pixel offset + if(PREFCMD_PIXEL_X) + PlayBoop(user, BOOP_MENU_OPEN) + var/newx = input( + user, + "You can have your character be, by default, offset to the left or right by a certain number of pixels. \ + How many pixels would you like to offset your character? \ + Positive numbers move your character to the right, negative numbers move your character to the left. \ + (Valid range is [PIXELSHIFT_MIN] to [PIXELSHIFT_MAX] )", + "Character Preference", + custom_pixel_x + ) as null|num + if(isnull(newx)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + custom_pixel_x = round(clamp(newx, PIXELSHIFT_MIN, PIXELSHIFT_MAX), 1) + to_chat(user, span_green("You have set your default left/right pixel offset to [custom_pixel_x]!")) + what_did = PRACT_DIALOG_ACCEPT + // Change your default Y pixel offset + if(PREFCMD_PIXEL_Y) + PlayBoop(user, BOOP_MENU_OPEN) + var/newy = input( + user, + "You can have your character be, by default, offset up or down by a certain number of pixels. \ + How many pixels would you like to offset your character? \ + Positive numbers move your character up, negative numbers move your character down. \ + (Valid range is [PIXELSHIFT_MIN] to [PIXELSHIFT_MAX] )", + "Character Preference", + custom_pixel_y + ) as null|num + if(isnull(newy)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + custom_pixel_y = round(clamp(newy, PIXELSHIFT_MIN, PIXELSHIFT_MAX), 1) + to_chat(user, span_green("You have set your default up/down pixel offset to [custom_pixel_y]!")) + what_did = PRACT_DIALOG_ACCEPT + // Toggle whether or not you can see pull requests + if(PREFCMD_PULL_REQUESTS) + TOGGLE_BITFIELD(chat_toggles, CHAT_PULLR) + what_did = PRACT_TOGGLE(chat_toggles & CHAT_PULLR) + // Toggle whether or not you can hear radio blurbles + if(PREFCMD_RADIO_BLURBLES) + TOGGLE_BITFIELD(chat_toggles, CHAT_HEAR_RADIOBLURBLES) + what_did = PRACT_TOGGLE(chat_toggles & CHAT_HEAR_RADIOBLURBLES) + // Toggle whether or not you can hear radio static + if(PREFCMD_RADIO_STATIC) + TOGGLE_BITFIELD(chat_toggles, CHAT_HEAR_RADIOSTATIC) + what_did = PRACT_TOGGLE(chat_toggles & CHAT_HEAR_RADIOSTATIC) + // Toggle whether or not you gots rainbow blood + if(PREFCMD_RAINBOW_BLOOD) + if(features["blood_color"] != "rainbow") + features["blood_color"] = "rainbow" + to_chat(user, span_green("You have rainbow blood!")) + what_did = PRACT_TOGGLE(TRUE) + else + features["blood_color"] = "FFFFFF" + to_chat(user, span_green("You have normal blood!")) + what_did = PRACT_TOGGLE(FALSE) + // Save your preferences + if(PREFCMD_SAVE) + if(!save_preferences()) + alert( + user, + "OH NO! Something went wrong while saving your preferences! \ + Something seriously wrong happened, maybe! Please, close the game and \ + contact a staff member to help you out! Error code: THAT ONE DJ PONY'S BUTT", + "Character Preference", + "Okay", + "Oh no!" + ) + else if(!save_character()) + alert( + user, + "OH NO! Something went wrong while saving your character! \ + Something seriously wrong happened, maybe! Please, close the game and \ + contact a staff member to help you out! Error code: THE PONY WITH THE WIERD EYES' BUTT", + "Character Preference", + "Okay", + "Oh no!" + ) + else + to_chat(user, span_green("SAVE OK!")) + what_did = PRACT_DIALOG_ACCEPT + // Change the scale of your character + if(PREFCMD_SCALE) + what_did = ChangeScale(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle whether or not you get permascars + if(PREFCMD_SCARS) + TOGGLE_VAR(persistent_scars) + what_did = PRACT_TOGGLE(persistent_scars) + // Clear all your permascars + if(PREFCMD_SCARS_CLEAR) + scars_list["1"] = "" + scars_list["2"] = "" + scars_list["3"] = "" + scars_list["4"] = "" + scars_list["5"] = "" + to_chat(user, span_notice("You have cleared all of your permanent scars!")) + what_did = PRACT_DIALOG_ACCEPT + // Toggle whether or not you can see runechat from non-mobs + if(PREFCMD_SEE_CHAT_NON_MOB) + TOGGLE_VAR(see_chat_non_mob) + what_did = PRACT_TOGGLE(see_chat_non_mob) + // Toggle whether or not you can see certain genitals + if(PREFCMD_SEE_GENITAL) + what_did = ToggleGenitalCanSee(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle whether or not you can see RC emotes + if(PREFCMD_SEE_RC_EMOTES) + TOGGLE_VAR(see_rc_emotes) + what_did = PRACT_TOGGLE(see_rc_emotes) + // Change the subsubcategory of the prefs menu + if(PREFCMD_SET_SUBSUBTAB) + what_did = SetSubSubTab(user, href_list) + // Change the subcategory of the prefs menu + if(PREFCMD_SET_SUBTAB) + what_did = SetSubTab(user, href_list) + // Change the category of the prefs menu + if(PREFCMD_SET_TAB) + what_did = SetMainTab(user, href_list) + // Shift the genital + if(PREFCMD_SHIFT_GENITAL) + what_did = ShiftGenital(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Show this many characters in the character list + if(PREFCMD_SHOW_THIS_MANY_CHARS) + PlayBoop(user, BOOP_MENU_OPEN) + var/newchars = input( + user, + "How many character slots do you want to be able to see? This will just \ + hide the rest, they'll still be there when you change this back later. \ + (1-[max_save_slots])", + "Character Preference", + show_this_many + ) as null|num + if(isnull(newchars)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + show_this_many = clamp(newchars, 1, max_save_slots) + to_chat(user, span_green("You will now see [show_this_many] character slots!")) + what_did = PRACT_DIALOG_ACCEPT + // Change the skin tone of your character + if(PREFCMD_SKIN_TONE) + what_did = ChangeSkinTone(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Copy a character slot to your clopboard uwu princess plotlestia + if(PREFCMD_SLOT_COPY) + what_did = CopySlot(user, href_list) + // Delete a character slot + if(PREFCMD_SLOT_DELETE) + what_did = DeleteSlot(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Paste a character slot from your clopboard uwu princess poona + if(PREFCMD_SLOT_PASTE) + what_did = PasteSlot(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change your socks! + if(PREFCMD_SOCKS) + what_did = ChangeSocks(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Set if your socks are over your clothes or something + if(PREFCMD_SOCKS_OVERCLOTHES) + socks_overclothes++ + if(socks_overclothes > UNDERWEAR_OVER_EVERYTHING) + socks_overclothes = UNDERWEAR_UNDER_CLOTHES + what_did = PRACT_TOGGLE(TRUE) + do_vis_update = TRUE + // Change the species of your character + if(PREFCMD_SPECIES) + what_did = ChangeSpecies(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the name of your species + if(PREFCMD_SPECIES_NAME) + var/spename = input( + user, + "What is your character's species called?", + "Character Preference", + custom_species + ) as null|text + if(isnull(spename)) + to_chat(user, span_warning("Okay nevermind!!")) + spename = reject_bad_name(spename) + if(spename) + custom_species = spename + to_chat(user, span_green("Your species is now called [custom_species]!")) + else + custom_species = null + to_chat(user, span_green("Your species name is the default!")) + what_did = PRACT_DIALOG_ACCEPT + // Split the admin tabs + if(PREFCMD_SPLIT_ADMIN_TABS) + TOGGLE_BITFIELD(toggles, SPLIT_ADMIN_TABS) + what_did = PRACT_TOGGLE(toggles & SPLIT_ADMIN_TABS) + // Toggle the sprint buffer + if(PREFCMD_SPRINTBUFFER) + TOGGLE_BITFIELD(toggles, SOUND_SPRINTBUFFER) + what_did = PRACT_TOGGLE(toggles & SOUND_SPRINTBUFFER) + // Change the stat of ur character + if(PREFCMD_STAT_CHANGE) + what_did = ChangeStats(user, href_list) + // Change the taste of your character + if(PREFCMD_TASTE) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_taste = input( + user, + "What does your character taste like?", + "Character Preference", + features["taste"] + ) as null|text + if(isnull(new_taste)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + new_taste = reject_bad_name(new_taste) + if(new_taste) + features["taste"] = new_taste + to_chat(user, span_green("Your character tastes like [features["taste"]]!")) + else + features["taste"] = "something" + to_chat(user, span_green("Your character tastes like something!")) + what_did = PRACT_DIALOG_ACCEPT + // Toggle the tetris storage + if(PREFCMD_TETRIS_STORAGE_TOGGLE) + TOGGLE_VAR(no_tetris_storage) + what_did = PRACT_TOGGLE_INV(no_tetris_storage) + // Toggle the fancy TGUI + if(PREFCMD_TGUI_FANCY) + TOGGLE_VAR(tgui_fancy) + what_did = PRACT_TOGGLE(tgui_fancy) + // Toggle the lock on the TGUI + if(PREFCMD_TGUI_LOCK) + TOGGLE_VAR(tgui_lock) + what_did = PRACT_TOGGLE(tgui_lock) + // Toggle whether or not you have a certain genital + if(PREFCMD_TOGGLE_GENITAL) + what_did = ToggleGenital(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle whether or not you can see the character list + if(PREFCMD_TOGGLE_SHOW_CHARACTER_LIST) + TOGGLE_VAR(charlist_hidden) + what_did = PRACT_TOGGLE(charlist_hidden) + // Change the style of the UI + if(PREFCMD_UI_STYLE) + PlayBoop(user, BOOP_MENU_OPEN) + var/pickedui = input( + user, + "What kind of UI would you like?", + "Character Preference", + UI_style + ) as null|anything in GLOB.available_ui_styles + if(isnull(pickedui)) + to_chat(user, span_warning("Okay nevermind!!")) + what_did = PRACT_DIALOG_CANCEL + else + UI_style = pickedui + if(parent && parent.mob && parent.mob.hud_used) + parent.mob.hud_used.update_ui_style(ui_style2icon(UI_style)) + what_did = PRACT_DIALOG_ACCEPT + // Change the undershirt of your character + if(PREFCMD_UNDERSHIRT) + what_did = ChangeUndershirt(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the undershirt of your character + if(PREFCMD_UNDERSHIRT_OVERCLOTHES) + undershirt_overclothes++ + if(undershirt_overclothes > UNDERWEAR_OVER_EVERYTHING) + undershirt_overclothes = UNDERWEAR_UNDER_CLOTHES + what_did = PRACT_TOGGLE(TRUE) + do_vis_update = TRUE + // Change the underwear of your character + if(PREFCMD_UNDERWEAR) + what_did = ChangeUnderwear(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Change the underwear of your character + if(PREFCMD_UNDERWEAR_OVERCLOTHES) + undies_overclothes++ + if(undies_overclothes > UNDERWEAR_OVER_EVERYTHING) + undies_overclothes = UNDERWEAR_UNDER_CLOTHES + what_did = PRACT_TOGGLE(TRUE) + do_vis_update = TRUE + // Undo the last thing you did + if(PREFCMD_UNDO) + load_preferences() + load_character() + to_chat(user, span_green("You have undone your changes!")) + what_did = PRACT_DIALOG_ACCEPT + // Change the whether you can hear sounds and runechats on floors above or below you + // if(PREFCMD_UPPERLOWERFLOOR) + // TOGGLE_VAR(upperlowerfloor) + // what_did = PRACT_TOGGLE(upperlowerfloor) + // do_vis_update = TRUE + // Open the VChat window + if(PREFCMD_VCHAT) + PlayBoop(user, BOOP_MENU_OPEN) + SSchat.HornyPreferences(user) + what_did = PRACT_DIALOG_ACCEPT + // Toggle widescreen mode + if(PREFCMD_WIDESCREEN_TOGGLE) + TOGGLE_VAR(widescreenpref) + user.client.change_view(CONFIG_GET(string/default_view)) + what_did = PRACT_TOGGLE(widescreenpref) + // Change the width of your character + if(PREFCMD_WIDTH) + what_did = ChangeWidth(user, href_list) + if(WasAccept(what_did)) + do_vis_update = TRUE + // Toggle Winflash! + if(PREFCMD_WINFLASH) + TOGGLE_VAR(windowflashing) + what_did = PRACT_TOGGLE(windowflashing) + + var/boob + switch(what_did) // play some sounds! + if(PRACT_DIALOG_ACCEPT) + boob = BOOP_ACCEPT + if(PRACT_DIALOG_ACCEPT_BIG) + boob = BOOP_ACCEPT_BIG + if(PRACT_DIALOG_ACCEPT_SMOL) + boob = BOOP_ACCEPT_SMOL + if(PRACT_DIALOG_CANCEL) + boob = BOOP_CANCEL + if(PRACT_DIALOG_DENIED) + boob = BOOP_DENIED + if(PRACT_DIALOG_ERROR) + boob = BOOP_ERROR + if(boob) + PlayBoop(user, boob) + // post stuff do + ShowChoices(user, do_vis_update) + +/// Try to let the player add a limb modification to their character +/datum/preferences/proc/AddLimbMod(mob/user, list/href_list) + var/list/moddable_limbs = LOADOUT_ALLOWED_LIMB_TARGETS + for(var/limb in modified_limbs) + moddable_limbs -= limb + if(LAZYLEN(moddable_limbs) <= 0) + to_chat(user, span_warning("All of your limbs are already modified!")) + return PRACT_DIALOG_DENIED + PlayBoop(user, BOOP_MENU_OPEN) + // make the moddable limbs have actual names + var/limb_names = list() + for(var/limb_key in moddable_limbs) + var/thename = GLOB.main_body_parts2words[limb_key] + thename = capitalize_all(thename) + limb_names[thename] = limb_key + + var/which_limb = input( + user, + "Which limb would you like to modify?", + "Character Preference" + ) as null|anything in limb_names + if(!which_limb) + return PRACT_DIALOG_CANCEL + PlayBoop(user, BOOP_SUB_PROMPT) + var/mod_type = input( + user, + "What would you like to do with your [which_limb]?", + "Character Preference" + ) as null|anything in LOADOUT_LIMBS + if(!mod_type) + return PRACT_DIALOG_CANCEL + switch(mod_type) + if(LOADOUT_LIMB_PROSTHETIC) + PlayBoop(user, BOOP_SUB_PROMPT) + return AddProsthetic(user, which_limb, mod_type) + if(LOADOUT_LIMB_AMPUTATED) + modified_limbs[which_limb] = list(mod_type) + to_chat(user, span_green("You have amputated your [which_limb]!")) + return PRACT_DIALOG_ACCEPT + if(LOADOUT_LIMB_NORMAL) + modified_limbs -= which_limb + to_chat(user, span_green("You have restored your [which_limb]!")) + return PRACT_DIALOG_ACCEPT + return PRACT_DIALOG_CANCEL + +/// Try to let the player add a prosthetic to their character +/datum/preferences/proc/AddProsthetic(mob/user, which_limb, mod_type) + var/prosthetic_type = input( + user, + "Choose the type of prosthetic for your [which_limb]", + "Character Preference" + ) as null|anything in (list("prosthetic") + GLOB.prosthetic_limb_types) + if(!prosthetic_type) + return PRACT_DIALOG_CANCEL + // var/prosthetic_count = 0 + // for(var/modified_limb in modified_limbs) + // if(modified_limbs[modified_limb][1] == LOADOUT_LIMB_PROSTHETIC && modified_limb != which_limb) + // prosthetic_count += 1 + // if(prosthetic_count > MAXIMUM_LOADOUT_PROSTHETICS) + // to_chat(user, span_danger("You can only have up to two prosthetic limbs!")) + // return PRACT_DIALOG_DENIED + // else + //save the actual prosthetic data + modified_limbs[which_limb] = list(mod_type, prosthetic_type) + to_chat(user, span_green("You have added a prosthetic [which_limb]!")) + return PRACT_DIALOG_ACCEPT + +/// Modify a limb +/datum/preferences/proc/ModifyLimbMod(mob/user, list/href_list) + var/list/modified_limbs = features["modified_limbs"] + if(LAZYLEN(modified_limbs) <= 0) + to_chat(user, span_warning("You have no modified limbs to change!")) + return PRACT_DIALOG_DENIED + PlayBoop(user, BOOP_MENU_OPEN) + var/which = href_list[PREFDAT_MODIFY_LIMB_MOD] + var/list/modded_limb = modified_limbs[which] + if(!modded_limb) + to_chat(user, span_warning("That limb isn't modified!")) + return PRACT_DIALOG_DENIED + if(modded_limb[1] == LOADOUT_LIMB_AMPUTATED) + to_chat(user, span_warning("There isn't much to modify about an amputated limb! Try removing it (which is to say, restore it) instead!")) + return PRACT_DIALOG_DENIED + return AddLimbMod(user, href_list) // it'll remove it for us + +/// Remove a limb modification +/datum/preferences/proc/RemoveLimbMod(mob/user, list/href_list) + var/list/modified_limbs = features["modified_limbs"] + if(LAZYLEN(modified_limbs) <= 0) + to_chat(user, span_warning("You have no modified limbs to remove!")) + return PRACT_DIALOG_DENIED + PlayBoop(user, BOOP_MENU_OPEN) + var/which = href_list[PREFDAT_REMOVE_LIMB_MOD] + var/list/modded_limb = modified_limbs[which] + if(!modded_limb) + to_chat(user, span_warning("That limb isn't modified!")) + return PRACT_DIALOG_DENIED + modified_limbs -= which + to_chat(user, span_green("Your [which] is back to normal!")) + return PRACT_DIALOG_ACCEPT + +/// Change the alt prefix of the user +/datum/preferences/proc/ChangeAltPrefix(mob/user, list/href_list) + if(!LAZYLEN(pref_species.alt_prefixes)) + alt_appearance = "Default" + to_chat(user, span_warning("You have no alternate appearances to choose from!")) + return PRACT_DIALOG_DENIED + var/pickfrom = list("Default" = "") + pickfrom |= pref_species.alt_prefixes + PlayBoop(user, BOOP_MENU_OPEN) + var/result = input( + user, + "Select an alternate species appearance! Or press cancel to clear it.", + "Character Preference" + ) as null|anything in pickfrom + if(isnull(result) || result == "") + alt_appearance = "Default" + to_chat(user, span_green("You have cleared your alternate appearance!")) + return PRACT_DIALOG_ACCEPT + alt_appearance = result + to_chat(user, span_green("You have set your alternate appearance to [result]!")) + return PRACT_DIALOG_ACCEPT + +/// Change the backpack kind of the user +/datum/preferences/proc/ChangeBackpackKind(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/backbag = input( + user, + "Choose the kind of backpack you'd like to use!", + "Character Preference" + ) as null|anything in GLOB.backbaglist + if(isnull(backbag)) + return PRACT_DIALOG_CANCEL + to_chat(user, span_green("You have set your backpack to [backbag]!")) + return PRACT_DIALOG_ACCEPT + +/// Change the shape of the user's genitals +/datum/preferences/proc/ChangeGenitalShape(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/haspart = href_list[PREFDAT_GENITAL_HAS] + var/datum/genital_data/GD = GLOB.genital_data_system[haspart] + if(!GD) + to_chat(user, span_warning("That's not a valid genital! something went wrong :( error code: FLUTTERSHY'S BUTT")) + return PRACT_DIALOG_ERROR + if(!CHECK_BITFIELD(GD.genital_flags, GENITAL_CAN_RESHAPE)) + to_chat(user, span_warning("[GD.name] can't be reshaped! :(")) + return PRACT_DIALOG_DENIED + var/list/shape_list = GD.shapelist + if(!LAZYLEN(shape_list)) + to_chat(user, span_warning("This genital is set to be reshapable, but there arent any shapes! something went wrong :( error code: RARITY'S BUTT")) + return PRACT_DIALOG_ERROR + var/new_shape = input( + user, + "How would you like your [GD.name] to look?", + "Character Preference" + ) as null|anything in shape_list + if(isnull(new_shape)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + // save the new shape + features[GD.shape_key] = new_shape + to_chat(user, span_green("Congratulations! Your [GD.name] looks like \a [new_shape] now!")) + return PRACT_DIALOG_ACCEPT + +/// Change the size of the user's genitals +/datum/preferences/proc/ChangeGenitalSize(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/haspart = href_list[PREFDAT_GENITAL_HAS] + var/datum/genital_data/GD = GLOB.genital_data_system[haspart] + if(!GD) + to_chat(user, span_warning("That's not a valid genital! something went wrong :( error code: RAINBOW DASH'S BUTT")) + return PRACT_DIALOG_ERROR + if(!CHECK_BITFIELD(GD.genital_flags, GENITAL_CAN_RESIZE)) + to_chat(user, span_warning("[GD.name] can't be resized! :(")) + return PRACT_DIALOG_DENIED + // now this can be either a number range or a list (thanks boobs) + var/size_list = GD.sizelist + var/new_size + if(LAZYLEN(size_list)) + new_size = input( + user, + "How big would you like your [GD.name] to be? (in [GD.size_units])", + "Character Preference" + ) as null|anything in size_list + else if(GD.size_min && GD.size_max) + new_size = input( + user, + "How big would you like your [GD.name] to be? ([GD.size_min] - [GD.size_max] [GD.size_units])", + "Character Preference" + ) as null|num + if(new_size) + new_size = clamp(new_size, GD.size_min, GD.size_max) + if(isnull(new_size)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + // save the new size + features[GD.size_key] = new_size + to_chat(user, span_green("Congratulations! Your [GD.name] is now \a [GD.SizeString(new_size)]!")) + return PRACT_DIALOG_ACCEPT + +/// Change the slot! +/datum/preferences/proc/ChangeSlot(mob/user, list/href_list) + var/new_slot = numberfy(href_list[PREFDAT_SLOT]) + if(new_slot == default_slot) + return PRACT_DIALOG_CANCEL + var/haz_character = load_character(new_slot) + if(!haz_character) + initialize_preferences() + random_character() + real_name = random_unique_name(gender) + save_character() + to_chat(user, span_green("Welcome to life, [real_name]!")) + if(isnewplayer(parent.mob)) + var/mob/dead/new_player/player_mob = parent.mob + player_mob.new_player_panel() + return PRACT_DIALOG_ACCEPT + +/// Change a part of the user +/datum/preferences/proc/ChangePart(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/partkind = href_list[PREFDAT_PARTKIND] + var/list/optionslist + var/list/blank_others + var/blank_with + var/specialy + var/kindname + /// now for everyone's favorite: look up tables! + switch(partkind) + if(BPART_DECO_WINGS) + optionslist = GLOB.deco_wings_list + kindname = "decorative wings" + if(BPART_DERG_BELLY) + optionslist = GLOB.derg_belly_list + kindname = "dragon belly style" + if(BPART_DERG_BODY) + optionslist = GLOB.derg_body_list + kindname = "dragon body style" + if(BPART_DERG_EARS) + optionslist = GLOB.derg_ear_list + kindname = "dragon ears" + if(BPART_DERG_EYES) + optionslist = GLOB.derg_eye_list + kindname = "dragon eyes" + if(BPART_DERG_HORNS) + optionslist = GLOB.derg_horn_list + kindname = "dragon horns" + if(BPART_DERG_MANE) + optionslist = GLOB.derg_mane_list + kindname = "dragon mane" + if(BPART_EARS) + optionslist = GLOB.ears_list + kindname = "ears" + specialy = TRUE + if(BPART_FRILLS) + optionslist = GLOB.frills_list + kindname = "frills" + if(BPART_HORNS) + optionslist = GLOB.horns_list + kindname = "horns" + if(BPART_INSECT_FLUFF) + optionslist = GLOB.insect_fluffs_list + kindname = "bug fluff" + if(BPART_INSECT_MARKINGS) + optionslist = GLOB.insect_markings_list + kindname = "bug markings" + if(BPART_INSECT_WINGS) + optionslist = GLOB.insect_wings_list + kindname = "bug wings" + if(BPART_IPC_ANTENNA) + optionslist = GLOB.ipc_antennas_list + kindname = "robot antenna" + specialy = TRUE + if(BPART_IPC_SCREEN) + optionslist = GLOB.ipc_screens_list + kindname = "robot screen" + if(BPART_MAM_EARS) + optionslist = GLOB.mam_ears_list + kindname = "furry ears" + specialy = TRUE + if(BPART_MAM_SNOUTS) + optionslist = GLOB.mam_snouts_list + kindname = "furry snouts" + specialy = TRUE + blank_others = list("snout") + blank_with = "None" + if(BPART_MAM_TAIL) + optionslist = GLOB.mam_tails_list + kindname = "furry tails" + specialy = TRUE + blank_others = list("taur", "tail_human", "tail_lizard", "xenotail") + blank_with = "None" + if(BPART_SNOUT) + optionslist = GLOB.snouts_list + kindname = "snouts" + specialy = TRUE + blank_others = list("mam_snouts") + blank_with = "None" + if(BPART_SPINES) + optionslist = GLOB.spines_list + kindname = "spines" + if(BPART_TAIL_HUMAN) + optionslist = GLOB.tails_list_human + kindname = "human tails" + specialy = TRUE + blank_others = list("taur", "tail_lizard", "mam_tail", "xenotail") + blank_with = "None" + if(BPART_TAIL_LIZARD) + optionslist = GLOB.tails_list_lizard + kindname = "lizard tails" + blank_others = list("taur", "tail_human", "mam_tail", "xenotail") + blank_with = "None" + if(BPART_TAUR) + optionslist = GLOB.taur_list + kindname = "tauric body" + specialy = TRUE + blank_others = list("mam_tail", "xenotail", "tail_human", "tail_lizard") + blank_with = "None" + if(BPART_WINGS) + optionslist = GLOB.wings_list + kindname = "wings" + if(BPART_XENODORSAL) + optionslist = GLOB.xeno_dorsal_list + kindname = "alien dorsal" + if(BPART_XENOHEAD) + optionslist = GLOB.xeno_head_list + kindname = "alien head" + if(BPART_XENOTAIL) + optionslist = GLOB.xeno_tail_list + kindname = "alien tail" + specialy = TRUE + blank_others = list("mam_tail", "taur", "tail_human", "tail_lizard") + blank_with = "None" + // now we have the options list, let's get the user to pick one + // just kidding, we need to do special stuff to special stuff first + if(specialy) + var/list/newlist = list() + for(var/path in optionslist) + var/datum/sprite_accessory/instance = optionslist[path] + if(istype(instance, /datum/sprite_accessory)) + var/datum/sprite_accessory/S = instance + if(!(S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + newlist[path] = S.name + optionslist = newlist + if(LAZYLEN(optionslist) <= 0) + to_chat(user, span_warning("There don't seem to be any options for [kindname]! Huh.")) + return PRACT_DIALOG_DENIED + // now we can actually get the user to pick one + // just kidding, we need to handle the previous and next buttons first + var/first_try = ShiftAdjustment(user, optionslist, features[partkind], href_list) + if(first_try) + features[partkind] = first_try + return PRACT_DIALOG_ACCEPT_SMOL + var/new_thing = input( + user, + "Choose your character's [kindname]!", + "Character Preference" + ) as null|anything in optionslist + if(isnull(new_thing)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + features[partkind] = new_thing + if(blank_others) + for(var/other in blank_others) + features[other] = blank_with + to_chat(user, span_green("You have set your [kindname] to [new_thing]!")) + return PRACT_DIALOG_ACCEPT + +/// Change the color of something on the user +/datum/preferences/proc/ChangeColor(mob/user, list/href_list = list()) + PlayBoop(user, BOOP_MENU_OPEN) + // this proc is a bit more complicated than the others + // first, get us a color, we'll figure out where it goes later + var/new_color = input( + user, + "Choose a color!", + "Character Preference" + ) as null|color + // easy part's done, now we need to-- + if(isnull(new_color)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + // --figure out where it goes + // first, check if the color is for a marking or gear item + if(href_list[PREFDAT_IS_MARKING]) + // find the marking by its uid + var/muid = href_list[PREFDAT_MARKING_UID] + for(var/list/mark in features["mam_body_markings"]) + if(LAZYLEN(mark) < MARKING_LIST_LENGTH) + mark = SanitizeMarking(mark) + if(mark[MARKING_UID] == muid) + var/slott = numberfy(href_list[PREFDAT_MARKING_SLOT]) + mark[MARKING_COLOR_LIST][slott] = new_color + to_chat(user, span_green("You have set the color of your marking to [new_color]!")) + return PRACT_DIALOG_ACCEPT + to_chat(user, span_warning("Couldn't find the marking you wanted to color! Something went wrong :( error code: PRINCESS LUNA'S BUTT")) + return PRACT_DIALOG_ERROR + // if it's not a marking, maybe it's a gear item + if(href_list[PREFDAT_IS_GEAR]) + var/load_slot = numberfy(href_list[PREFDAT_LOADOUT_SLOT]) + var/geartype = href_list[PREFDAT_GEAR_TYPE] // who lives in a pineapple under the sea + var/list/loadoutgear = has_loadout_gear(load_slot, geartype) + loadoutgear[LOADOUT_CUSTOM_COLOR] = new_color + to_chat(user, span_green("You have set the color of your [geartype] to [new_color]!")) + return PRACT_DIALOG_ACCEPT + // The easy part is done, and now we know its probably a pref color feature thing, so let's find out which one + if(href_list[PREFDAT_COLKEY_IS_FEATURE]) + var/colkey = href_list[PREFDAT_COLOR_KEY] + features[colkey] = new_color + to_chat(user, span_green("You have set the color of your [colkey] to [new_color]!")) + return PRACT_DIALOG_ACCEPT + // Or maybe its some kind of hard variable, which complicates things (for future coders, not me =3) + if(href_list[PREFDAT_COLKEY_IS_VAR]) + var/colkey = href_list[PREFDAT_COLOR_KEY] + if(!(colkey in vars)) + to_chat(user, span_warning("Couldn't find the variable you wanted to color! Something went wrong :( error code: PRINCESS CELESTIA'S BUTT")) + return PRACT_DIALOG_ERROR + vars[colkey] = new_color // warning, it doesnt actually know if this var is a color or not, so make sure you know what you're doing + to_chat(user, span_green("You have set the color of your [colkey] to [new_color]!")) + return PRACT_DIALOG_ACCEPT + // if we got here, something went wrong + to_chat(user, span_warning("Couldn't find the color you wanted to change! Something went wrong :( error code: PINKIE PIE'S BUTT")) + return PRACT_DIALOG_ERROR + +/// Let the player copy a color from somewhere +/datum/preferences/proc/CopyColor(mob/user, list/href_list) + // considerably less upsettingly guntcitory than the other color proc + // Who loves his brainwashing and always wants more? | + var/thecolor = href_list[PREFDAT_COLOR_HEX] // <-------/ + if(!is_color(thecolor)) + to_chat(user, span_warning("That's not a valid color!")) + return PRACT_DIALOG_DENIED + color_history -= thecolor + color_history.Insert(1, thecolor) + current_color = thecolor + CleanupColorHistory() + if(!href_list[PREFDAT_SUPPRESS_MESSAGE]) + to_chat(user, span_green("You have copied the color [thecolor]!")) + return PRACT_DIALOG_ACCEPT + +/// Let the player delete a color from somewhere +/datum/preferences/proc/DeleteColor(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/thecolor = href_list[PREFDAT_COLOR_HEX] + if(!is_color(thecolor)) + to_chat(user, span_warning("That's not a valid color!")) + return PRACT_DIALOG_DENIED + color_history -= thecolor + CleanupColorHistory() + to_chat(user, span_green("You have removed the color [thecolor]!")) + return PRACT_DIALOG_ACCEPT + +/// Let the player paste a color to somewhere +/datum/preferences/proc/PasteColor(mob/user, list/href_list) + if(!is_color(current_color)) + to_chat(user, span_warning("You haven't copied a color yet!")) + return PRACT_DIALOG_DENIED + // now heres the guntic part + href_list[PREFDAT_COLOR_HEX] = current_color + href_list[PREFDAT_SUPPRESS_MESSAGE] = TRUE + . = ChangeColor(user, href_list) + if(. == PRACT_DIALOG_ACCEPT) + CopyColor(user, href_list) // move it to the top of the list, just like the real world + +/datum/preferences/proc/CleanupColorHistory() + if(!islist(color_history)) + color_history = list() + if(!LAZYLEN(color_history)) + return + color_history.len = min(5, color_history.len) + +/// Let the player change the type of eyes they have +/datum/preferences/proc/ChangeEyeType(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/first_try = ShiftAdjustment(user, GLOB.eye_types, eye_type, href_list) + if(first_try) + eye_type = first_try + return PRACT_DIALOG_ACCEPT_SMOL + var/new_eye_type = input( + user, + "What's your character's eyes look like?", + "Character Preference" + ) as null|anything in GLOB.eye_types + if(isnull(new_eye_type)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + eye_type = new_eye_type + to_chat(user, span_green("You have set your eye type to [new_eye_type]!")) + return PRACT_DIALOG_ACCEPT + +/// Let the player change the style of facial hair they have +/datum/preferences/proc/ChangeFacialHairStyle(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/first_try = ShiftAdjustment(user, GLOB.facial_hair_styles_list, facial_hair_style, href_list) + if(first_try) + facial_hair_style = first_try + return PRACT_DIALOG_ACCEPT_SMOL + var/new_facial_hair_style = input( + user, + "How does your character's facial hair look?", + "Character Preference" + ) as null|anything in GLOB.facial_hair_styles_list + if(isnull(new_facial_hair_style)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + facial_hair_style = new_facial_hair_style + to_chat(user, span_green("You have set your facial hair style to [new_facial_hair_style]!")) + return PRACT_DIALOG_ACCEPT + +/// Change the gradient of the user's hair, either the first or second +/datum/preferences/proc/ChangeHairGradient(mob/user, list/href_list, which) + PlayBoop(user, BOOP_MENU_OPEN) + var/hair = which == 1 ? "grad_style" : "grad_style_2" + var/first_try = ShiftAdjustment(user, GLOB.hair_gradients, features[hair], href_list) + if(first_try) + features[hair] = first_try + return PRACT_DIALOG_ACCEPT_SMOL + var/new_gradient = input( + user, + "How does the [which ? "first" : "second"] gradient style of your character's hair look?", + "Character Preference" + ) as null|anything in GLOB.hair_gradients + if(isnull(new_gradient)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + features[hair] = new_gradient + to_chat(user, span_green("You have set the [which ? "first" : "second"] gradient style of your hair to [new_gradient]!")) + return PRACT_DIALOG_ACCEPT + +/// Change the style of the user's hair, either the first or second +/// the first is a var, and the second is a f&*king feature +/datum/preferences/proc/ChangeHairStyle(mob/user, list/href_list, which) + PlayBoop(user, BOOP_MENU_OPEN) + var/first_try + if(which == 1) + first_try = ShiftAdjustment(user, GLOB.hair_styles_list, hair_style, href_list) + if(first_try) + hair_style = first_try + return PRACT_DIALOG_ACCEPT_SMOL + else if(which == 2) + first_try = ShiftAdjustment(user, GLOB.hair_styles_list, features["hair_style_2"], href_list) + if(first_try) + features["hair_style_2"] = first_try + return PRACT_DIALOG_ACCEPT_SMOL + var/new_hair_style = input( + user, + "How does the [which ? "first" : "second"] style of your character's hair look?", + "Character Preference" + ) as null|anything in GLOB.hair_styles_list + if(isnull(new_hair_style)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + if(which == 1) + hair_style = new_hair_style + else if(which == 2) + features["hair_style_2"] = new_hair_style + to_chat(user, span_green("You have set the [which ? "first" : "second"] style of your hair to [new_hair_style]!")) + return PRACT_DIALOG_ACCEPT + +/// Change which genitals you wont see +/datum/preferences/proc/ToggleGenitalCanSee(mob/user, list/href_list) + var/which = href_list[PREFDAT_GENITAL_HAS] + var/datum/genital_data/GD = GLOB.genital_data_system[which] + if(!GD) + to_chat(user, span_warning("That's not a valid genital! something went wrong :( error code: APPLEJACK'S BUTT")) + return PRACT_DIALOG_ERROR + TOGGLE_BITFIELD(features["genital_hide"], GD.hide_flag) + var/seesee = CHECK_BITFIELD(features["genital_hide"], GD.hide_flag) ? "no longer see" : "now be able to see" + to_chat(user, span_green("You will [seesee] others' [GD.name]!")) + return PRACT_TOGGLE_INV(CHECK_BITFIELD(features["genital_hide"], GD.hide_flag)) + +/// Let the player capture a keypress for a keybinding +/datum/preferences/proc/CaptureKeybinding(mob/user, datum/keybinding/kb, old_key, independent = FALSE, special = FALSE) + PlayBoop(user, BOOP_MENU_OPEN) + var/HTML = {" +
Keybinding: [kb.full_name]
[kb.description]

Press any key to change
Press ESC to clear
+ + "} + winshow(user, "capturekeypress", TRUE) + var/datum/browser/popup = new(user, "capturekeypress", "
Keybindings
", 350, 300) + popup.set_content(HTML) + popup.open(FALSE) + onclose(user, "capturekeypress", src) + +/// Actually set the keybinding +/datum/preferences/proc/KeybindingSet(mob/user, list/href_list) + var/kb_name = href_list["keybinding"] + if(!kb_name) + user << browse(null, "window=capturekeypress") + ShowChoices(user) + return PRACT_DIALOG_CANCEL + var/independent = href_list["independent"] + var/clear_key = text2num(href_list["clear_key"]) + var/old_key = href_list["old_key"] + if(clear_key) + if(independent) + modless_key_bindings -= old_key + else + if(key_bindings[old_key]) + key_bindings[old_key] -= kb_name + LAZYADD(key_bindings["Unbound"], kb_name) + if(!length(key_bindings[old_key])) + key_bindings -= old_key + user << browse(null, "window=capturekeypress") + if(href_list["special"]) // special keys need a full reset + user.client.ensure_keys_set(src) + save_preferences() + ShowChoices(user) + return PRACT_DIALOG_ACCEPT + + var/new_key = uppertext(href_list["key"]) + var/AltMod = text2num(href_list["alt"]) ? "Alt" : "" + var/CtrlMod = text2num(href_list["ctrl"]) ? "Ctrl" : "" + var/ShiftMod = text2num(href_list["shift"]) ? "Shift" : "" + var/numpad = text2num(href_list["numpad"]) ? "Numpad" : "" + // var/key_code = text2num(href_list["key_code"]) + if(GLOB._kbMap[new_key]) + new_key = GLOB._kbMap[new_key] + var/full_key + switch(new_key) + if("Alt") + full_key = "[new_key][CtrlMod][ShiftMod]" + if("Ctrl") + full_key = "[AltMod][new_key][ShiftMod]" + if("Shift") + full_key = "[AltMod][CtrlMod][new_key]" + else + full_key = "[AltMod][CtrlMod][ShiftMod][numpad][new_key]" + if(independent) + modless_key_bindings -= old_key + modless_key_bindings[full_key] = kb_name + else + if(key_bindings[old_key]) + key_bindings[old_key] -= kb_name + if(!length(key_bindings[old_key])) + key_bindings -= old_key + key_bindings[full_key] += list(kb_name) + key_bindings[full_key] = sortList(key_bindings[full_key]) + if(href_list["special"]) // special keys need a full reset + user.client.ensure_keys_set(src) + user << browse(null, "window=capturekeypress") + return PRACT_DIALOG_ACCEPT + +/// Toggle the category of a keybinding +/datum/preferences/proc/ToggleKeybindingCategory(mob/user, list/href_list) + var/cat = href_list[PREFDAT_CATEGORY] + if(!cat) + return PRACT_DIALOG_CANCEL + if(!islist(keybind_cat_open)) + keybind_cat_open = list() + keybind_cat_open[cat] = keybind_cat_open[cat] ? FALSE : TRUE + return PRACT_DIALOG_ACCEPT + +/// Change your legs +/datum/preferences/proc/ChangeLegs(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/first_try = ShiftAdjustment(user, GLOB.legs_list, features["legs"], href_list) + if(first_try) + features["legs"] = first_try + return PRACT_DIALOG_ACCEPT_SMOL + var/new_legs = input( + user, + "Choose your character's legs!", + "Character Preference" + ) as null|anything in GLOB.legs_list + if(isnull(new_legs)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + features["legs"] = new_legs + to_chat(user, span_green("You have set your legs to [new_legs]!")) + return PRACT_DIALOG_ACCEPT + +/// Change your loadout category! +/datum/preferences/proc/ChangeLoadoutCategory(mob/user, list/href_list) + var/cat = html_decode(href_list[PREFDAT_LOADOUT_CATEGORY]) + if(!cat) + return PRACT_DIALOG_CANCEL + ClearLoadoutSearch(user, href_list) + gear_category = cat + if(cat != GEAR_CAT_ALL_EQUIPPED) + gear_subcategory = GLOB.loadout_categories[cat][1] + return PRACT_DIALOG_ACCEPT + +/// Change your loadout subcategory! +/datum/preferences/proc/ChangeLoadoutSubcategory(mob/user, list/href_list) + var/subcat = html_decode(href_list[PREFDAT_LOADOUT_SUBCATEGORY]) + if(!subcat) + return PRACT_DIALOG_CANCEL + ClearLoadoutSearch(user, href_list) + gear_subcategory = subcat + return PRACT_DIALOG_ACCEPT + +/// Change the description of a loadout thing! +/datum/preferences/proc/ChangeLoadoutDescription(mob/user, list/href_list) + var/list/usergear = GetLoadoutList(user, href_list) + if(!usergear) + return PRACT_DIALOG_CANCEL + var/new_description = stripped_multiline_input_or_reflect( + user, + "What should this thing's description be? (max 500 characters)", + "Loadout Description", + usergear[LOADOUT_CUSTOM_DESCRIPTION] || "", + 500 + ) + if(isnull(new_description)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + if(trim(new_description) == "") + var/usure = alert( + user, + "Are you sure you want to clear this item's description?", + "Clear Description?", + "Yes, clear it", + "No, leave it", + ) + if(usure != "Yes, clear it") + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + usergear[LOADOUT_CUSTOM_DESCRIPTION] = null + return PRACT_DIALOG_ACCEPT + else + usergear[LOADOUT_CUSTOM_DESCRIPTION] = new_description + to_chat(user, span_green("You have set the description of your [usergear[LOADOUT_CUSTOM_NAME]] to [new_description]!")) + return PRACT_DIALOG_ACCEPT + +/// Change the name of a loadout thing! +/datum/preferences/proc/ChangeLoadoutName(mob/user, list/href_list) + var/list/usergear = GetLoadoutList(user, href_list) + if(!usergear) + return PRACT_DIALOG_CANCEL + var/new_name = stripped_input( + user, + "What should this thing's name be? (max [MAX_NAME_LEN] characters)", + "Loadout Name", + usergear[LOADOUT_CUSTOM_NAME] || "", + MAX_NAME_LEN, + ) + if(isnull(new_name)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + if(trim(new_name) == "") + var/usure = alert( + user, + "Are you sure you want to clear this item's name?", + "Clear Name?", + "Yes, clear it", + "No, leave it", + ) + if(usure != "Yes, clear it") + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + usergear[LOADOUT_CUSTOM_NAME] = null + return PRACT_DIALOG_ACCEPT + else + usergear[LOADOUT_CUSTOM_NAME] = new_name + to_chat(user, span_green("You have set the name of your [usergear[LOADOUT_CUSTOM_NAME]] to [new_name]!")) + return PRACT_DIALOG_ACCEPT + +/// Reset your loadout! +/datum/preferences/proc/ResetLoadout(mob/user, list/href_list) + var/usure = alert( + user, + "Are you sure you want to reset your loadout?", + "Reset Loadout?", + "Yes, reset it", + "No, leave it", + ) + if(usure != "Yes, reset it") + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + loadout_data["SAVE_[loadout_slot]"] = list() + to_chat(user, span_green("You have reset your loadout!")) + return PRACT_DIALOG_ACCEPT + +/// Ask for a search term for the loadout +/datum/preferences/proc/EnterSearchTerm(mob/user, list/href_list) + var/search = input( + user, + "What would you like to search for?", + "Character Preference" + ) as null|text + if(isnull(search)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + SetLoadoutSearch(user, search) + loadout_search = search + return PRACT_DIALOG_ACCEPT + +/// Set the search term for the loadout +/datum/preferences/proc/SetLoadoutSearch(mob/user, search_term) + if(!search_term) + ClearLoadoutSearch(user) + return PRACT_DIALOG_CANCEL + loadout_search = search_term + return PRACT_DIALOG_ACCEPT + +/// Clear the search term for the loadout +/datum/preferences/proc/ClearLoadoutSearch(mob/user, list/href_list) + loadout_search = null + return PRACT_DIALOG_ACCEPT + +/// Toggle having something in your loadout! +/datum/preferences/proc/ToggleLoadoutItem(mob/user, list/href_list) + var/gearname = html_decode(href_list[PREFDAT_LOADOUT_GEAR_NAME]) + var/datum/gear/G = GLOB.flat_loadout_items[gearname] + if(!G) + return PRACT_DIALOG_ERROR + var/loadout_slot = numberfy(href_list[PREFDAT_LOADOUT_SLOT]) + var/has_it = has_loadout_gear(loadout_slot, "[G.type]") + if(has_it) + RemoveGearFromLoadout(loadout_slot, "[G.type]") + to_chat(user, span_green("You have removed the [G.name] from your loadout!")) + return PRACT_TOGGLE(FALSE) + else + if(!CanAffordLoadoutItem(user, G)) + to_chat(user, span_danger("You can't afford that item!")) + return PRACT_DIALOG_DENIED + if(!HasSlotForLoadoutItem(user, G)) + to_chat(user, span_danger("You can only have a total of [MAX_FREE_PER_CAT] things from this category!")) + return PRACT_DIALOG_DENIED + if(G.donoritem && !G.donator_ckey_check(user.ckey)) + to_chat(user, span_danger("Sorry, this item is special for a certain person! You probably shouldnt be seeing this, so, error code: PRINCESS CADANCE'S BUTT")) + return PRACT_DIALOG_ERROR + AddGearToLoadout(loadout_slot, G) + to_chat(user, span_green("You have added the [G.name] to your loadout!")) + return PRACT_TOGGLE(TRUE) + +// Add a marking to the user! MAM MARKINGS ONLY!!!!! +/datum/preferences/proc/AddMarking(mob/user, list/href_list) + var/which_part = input( + user, + "Where will this marking go?", + "Character Preference" + ) as null|anything in list("Head", "Chest", "Left Arm", "Right Arm", "Left Leg", "Right Leg", "All") + if(isnull(which_part)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + var/list/lame_markings = GLOB.mam_body_markings_list + var/list/cool_markings = GetAppropriateMamMarkings(user, lame_markings, which_part) + if(!LAZYLEN(cool_markings)) + to_chat(user, span_warning("There don't seem to be any markings for that part! Huh.")) + return PRACT_DIALOG_DENIED + var/new_marking = input( + user, + "What marking will you add?", + "Character Preference" + ) as null|anything in cool_markings + if(isnull(new_marking)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + var/list/locations = list() + if(which_part != "All") + locations = list(which_part) + else + locations = list("Head", "Chest", "Left Arm", "Right Arm", "Left Leg", "Right Leg") + for(var/spot in locations) + var/list/newmarking = list() + newmarking.len = MARKING_LIST_LENGTH + newmarking[MARKING_LIMB_INDEX_NUM] = text2num(GLOB.bodypart_values[spot]) + newmarking[MARKING_NAME] = new_marking + newmarking[MARKING_COLOR_LIST] = GetDefaultMarkingColors() + newmarking[MARKING_UID] = GenerateMarkingUID() + features["mam_body_markings"] += list(newmarking) + to_chat(user, span_green("You have added the [new_marking] to your character!")) + return PRACT_DIALOG_ACCEPT + +// change a marking from one style to another! MAM MARKINGS ONLY!!!!! +/datum/preferences/proc/EditMarking(mob/user, list/href_list) + var/muid = href_list[PREFDAT_MARKING_UID] + if(!muid) + return PRACT_DIALOG_CANCEL + var/list/mark = GetMarkingByUID(user, muid) + if(!mark) + to_chat(user, span_warning("Couldn't find the marking you wanted to edit! Something went wrong :( error code: MINUETTE'S BUTT")) + return PRACT_DIALOG_ERROR + var/place = text2num(mark[MARKING_LIMB_INDEX_NUM]) + var/which_part = GLOB.bodypart_names[place] + var/list/lame_markings = GLOB.mam_body_markings_list + var/list/cool_markings = GetAppropriateMamMarkings(user, lame_markings, which_part) + if(!LAZYLEN(cool_markings)) + to_chat(user, span_warning("There don't seem to be any markings for that part! Huh.")) + return PRACT_DIALOG_DENIED + var/first_try = ShiftAdjustment(user, cool_markings, mark[MARKING_NAME], href_list) + if(first_try) + mark[MARKING_NAME] = first_try + return PRACT_DIALOG_ACCEPT_SMOL + var/new_marking = input( + user, + "What marking will you change it to?", + "Character Preference" + ) as null|anything in cool_markings + if(isnull(new_marking)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + mark[MARKING_NAME] = new_marking + to_chat(user, span_green("You have changed the marking to [new_marking]!")) + return PRACT_DIALOG_ACCEPT + +// remove a marking from the user! MAM MARKINGS ONLY!!!!! +/datum/preferences/proc/RemoveMarking(mob/user, list/href_list) + var/muid = href_list[PREFDAT_MARKING_UID] + if(!muid) + return PRACT_DIALOG_CANCEL + var/mark = GetMarkingByUID(user, muid) + if(!mark) + to_chat(user, span_warning("Couldn't find the marking you wanted to remove! Something went wrong :( error code: LYRA'S BUTT")) + return PRACT_DIALOG_ERROR + features["mam_body_markings"] -= list(mark) + to_chat(user, span_green("You have removed the marking!")) + return PRACT_DIALOG_ACCEPT + +// Change the ordering of a marking in the list +/datum/preferences/proc/ShiftMarking(mob/user, list/href_list, whichdir) + var/muid = href_list[PREFDAT_MARKING_UID] + if(!muid) + return PRACT_DIALOG_CANCEL + var/mark = GetMarkingByUID(user, muid) + if(!mark) + to_chat(user, span_warning("Couldn't find the marking you wanted to move! Something went wrong :( error code: RARITY'S BUTT")) + return PRACT_DIALOG_ERROR + var/list/mymarkings = features["mam_body_markings"] + var/wheredex = mymarkings.Find(mark) + if(wheredex == LAZYLEN(mymarkings) && whichdir == "down") + to_chat(user, span_warning("That marking is already at the bottom of the list!")) + return PRACT_DIALOG_DENIED + if(wheredex == 1 && whichdir == "up") + to_chat(user, span_warning("That marking is already at the top of the list!")) + return PRACT_DIALOG_DENIED + var/swapdex = whichdir == "up" ? wheredex - 1 : wheredex + 1 + mymarkings.Swap(wheredex, swapdex) + to_chat(user, span_green("You have moved the marking [whichdir]!")) + return PRACT_DIALOG_ACCEPT + +// OverrideGenital +/datum/preferences/proc/OverrideGenital(mob/user, list/href_list) + var/which = href_list[PREFDAT_GENITAL_HAS] + var/datum/genital_data/GD = GLOB.genital_data_system[which] + if(!GD) + to_chat(user, span_warning("That's not a valid genital! something went wrong :( error code: APPLEJACK'S BUTT")) + return PRACT_DIALOG_ERROR + var/list/options = list( + "Always Visible" = GENITAL_ALWAYS_VISIBLE, + "Always Hidden" = GENITAL_ALWAYS_HIDDEN, + "Check Coverage" = 0 + ) + var/overkey = GD.override_key + var/newvis = input( + user, + "Set a visibility override! If set, this part will always be visible/hidden, regardless of how covered it is.", + "Character Preference", + options + ) as null|anything in options + if(isnull(newvis)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + var/it_to_bit = options[newvis] + DISABLE_BITFIELD(features[overkey], GENITAL_ALWAYS_HIDDEN | GENITAL_ALWAYS_VISIBLE) + ENABLE_BITFIELD(features[overkey], it_to_bit) + to_chat(user, span_green("You have set the visibility of your [GD.name] to [newvis]!")) + return PRACT_DIALOG_ACCEPT + +// Change the PDA skin! +/datum/preferences/proc/ChangePDAKind(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/picked_pda = input( + user, + "What kind of DataPal do you want? \ + You can change this in-game by ctrl-shift-clicking the DataPal ingame!", + "Character Preference", + pda_skin + ) as null|anything in GLOB.pda_skins + if(isnull(picked_pda)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + pda_skin = picked_pda + to_chat(user, span_green("You have set your DataPal to [picked_pda]!")) + return PRACT_DIALOG_ACCEPT + +// Change the p-hud whtielist +/datum/preferences/proc/ChangePHUDWhitelist(mob/user, list/href_list, savetoo) + PlayBoop(user, BOOP_MENU_OPEN) + var/new_genital_whitelist = stripped_multiline_input_or_reflect( + user, + "Which people are you okay with seeing their genitals when exposed? If a humanlike mob has a name containing \ + any of the following, if their genitals are showing, you will be able to see them, regardless of your \ + content settings. Partial names are accepted, case is not important, please no punctuation (except ','). \ + Separate your entries with a comma!", + "Genital Whitelist", + genital_whitelist) + if(isnull(new_genital_whitelist)) + to_chat(user, "Never mind!!") + return PRACT_DIALOG_CANCEL + if(trim(new_genital_whitelist) == "" && trim(genital_whitelist) != "") + var/whoa = alert(user, "Are you sure you want to clear your genital whitelist?", "Clear Genital Whitelist", "Yes", "No") + if(whoa == "No") + to_chat(user, "Never mind!!") + return PRACT_DIALOG_CANCEL + genital_whitelist = new_genital_whitelist + to_chat(user, span_notice("Updated your genital whitelist! It should kick in soon!")) + if(savetoo) + save_preferences() + return PRACT_DIALOG_ACCEPT + +// Change your size +/datum/preferences/proc/ChangeScale(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/min = CONFIG_GET(number/body_size_min) + var/max = CONFIG_GET(number/body_size_max) + var/donger = CONFIG_GET(number/threshold_body_size_slowdown) + var/new_size = input( + user, + "How big is your character? (from [min*100]% to [max*100]%)\n\ + Just a heads up, this might make your character look a little distorted!\ + [donger > min ? " Also, if you go below [donger*100]%, you'll have a slower movement speed!" : ""]", + "Character Preference", + features["body_size"]*100 + ) as null|num + if(isnull(new_size)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + new_size = clamp(new_size * 0.01, min, max) + if((new_size + 0.01) < donger) + var/dorfy = alert( + user, + "Your character is smaller than the threshold of [donger*100]%. \ + This will make them move slower. Do you want to keep this size?", + "Speed Penalty Alert", + "Yes", + "Move it to the threshold", + "No" + ) + if(dorfy == "Move it to the threshold") + new_size = donger + if(dorfy == "No" || !dorfy) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + features["body_size"] = new_size + to_chat(user, span_green("You have set your size to [new_size*100]%!")) + return PRACT_DIALOG_ACCEPT + +// Change your width +/datum/preferences/proc/ChangeWidth(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/min = CONFIG_GET(number/body_width_min) + var/max = CONFIG_GET(number/body_width_max) + var/new_width = input( + user, + "How wide is your character? (from [min*100]% to [max*100]%)", + "Character Preference", + features["body_width"]*100 + ) as null|num + if(isnull(new_width)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + new_width = clamp(new_width * 0.01, min, max) + features["body_width"] = new_width + to_chat(user, span_green("You have set your width to [new_width*100]%!")) + return PRACT_DIALOG_ACCEPT + +// Change your ToggleGenitalHide +/datum/preferences/proc/ToggleGenitalHide(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/which = href_list[PREFDAT_GENITAL_HAS] + var/datum/genital_data/GD = GLOB.genital_data_system[which] + if(!GD) + to_chat(user, span_warning("That's not a valid genital! something went wrong :( error code: OCTAVIA'S BUTT")) + return PRACT_DIALOG_ERROR + var/bittu = features[GD.vis_flags_key] + if(href_list[PREFDAT_HIDDEN_BY] == "undies") + TOGGLE_BITFIELD(bittu, GENITAL_RESPECT_UNDERWEAR) + if(href_list[PREFDAT_HIDDEN_BY] == "clothing") + TOGGLE_BITFIELD(bittu, GENITAL_RESPECT_CLOTHING) + features[GD.vis_flags_key] = bittu + return PRACT_TOGGLE(CHECK_BITFIELD(bittu, GENITAL_RESPECT_UNDERWEAR | GENITAL_RESPECT_CLOTHING)) + +// Set the Sub Sub tab +/datum/preferences/proc/SetSubSubTab(mob/user, list/href_list) + var/tab = html_decode(href_list[PREFDAT_SUBSUBTAB]) + if(!tab) + return PRACT_DIALOG_CANCEL + current_sub_subtab = tab + return PRACT_DIALOG_ACCEPT + +// Set the Sub tab +/datum/preferences/proc/SetSubTab(mob/user, list/href_list) + var/tab = html_decode(href_list[PREFDAT_SUBTAB]) + if(!tab) + return PRACT_DIALOG_CANCEL + current_subtab = tab + return PRACT_DIALOG_ACCEPT + +// Set the Main tab +/datum/preferences/proc/SetMainTab(mob/user, list/href_list) + var/tab = html_decode(href_list[PREFDAT_TAB]) + if(!tab) + return PRACT_DIALOG_CANCEL + current_tab = tab + return PRACT_DIALOG_ACCEPT + +// Shift Genital +/datum/preferences/proc/ShiftGenital(mob/user, list/href_list, whichdir) + var/list/corklist = features["genital_order"] + var/wheredex = corklist.Find(href_list[PREFDAT_GENITAL_HAS]) + if(wheredex == LAZYLEN(corklist) && whichdir == "down") + to_chat(user, span_warning("That genital is already at the bottom of the list!")) + return PRACT_DIALOG_DENIED + if(wheredex == 1 && whichdir == "up") + to_chat(user, span_warning("That genital is already at the top of the list!")) + return PRACT_DIALOG_DENIED + var/swapdex = whichdir == "up" ? wheredex - 1 : wheredex + 1 + corklist.Swap(wheredex, swapdex) + return PRACT_DIALOG_ACCEPT + +// Change your skin tone! +/datum/preferences/proc/ChangeSkinTone(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/list/choices = GLOB.skin_tones - GLOB.nonstandard_skin_tones + if(CONFIG_GET(flag/allow_custom_skintones)) + choices += "custom" + var/new_s_tone = input( + user, + "What color is your character's skin? (You can also choose a custom color!) (I recommend playing a furry tho!)", + "Character Preference" + ) as null|anything in choices + if(isnull(new_s_tone)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + if(new_s_tone == "custom") + var/default = use_custom_skin_tone ? skin_tone : null + var/custom_tone = input( + user, + "What color is your custom skin tone?", + "Character Preference", + default + ) as color|null + if(isnull(custom_tone)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + use_custom_skin_tone = TRUE + skin_tone = custom_tone + else + use_custom_skin_tone = FALSE + skin_tone = new_s_tone + to_chat(user, span_green("You have set your skin tone to [new_s_tone]!")) + return PRACT_DIALOG_ACCEPT + +// Delete your character! +/datum/preferences/proc/DeleteSlot(mob/user, list/href_list) + if(!user) + return PRACT_DIALOG_CANCEL + lockdown = TRUE + /// stage one, ask if they are sure, and detail the fact that this will delete the character forever + /// with no chance of retrieval + var/stage1text = "You have clicked the button that will delete [real_name]. If you go through with this, [real_name] will \ + be deleted, forever. There are no backups available, and no way to retrieve [real_name] once deleted. All of your \ + flavor texts, quirks, and preferences associated with [real_name] will be lost, permanently and forever. The only things that will \ + remain of [real_name] are things you have written down or screenshotted. Are you sure you want to delete [real_name]?" + var/choose = alert(user, stage1text, "Character Deletion", "Yes, Delete This Character Forever", "NO WAIT I CHANGED Your MIND") + if(choose != "Yes, Delete This Character Forever") + lockdown = FALSE + to_chat(user, span_green("Your character remains safe and sound.")) + return PRACT_DIALOG_CANCEL + /// stage two, ask if they are really sure, and ask if they'd like to go back and save their flavor text or keep a screenshot of their prefs + /// a chance to back out, but also a chance to save some stuff + var/stage2text = "Are you absolutely sure you want to delete [real_name]? Have you saved their flavor text, OOC notes, or any other \ + information you want to keep? You might also want to take a screenshot of [real_name]'s preferences, just in case you want to \ + recreate them later. Again, there are no backups of [real_name] stored on the server or anywhere else, and there is no possible way \ + to undo this or retrieve any data relating to [real_name]. Once deleted, [real_name] is *gone* for *good*. \ + Are you sure you want to delete [real_name]?" + var/choose2 = alert(user, stage2text, "Character Deletion", "Yes, Delete This Character Forever", "NO WAIT I CHANGED Your MIND") + if(choose2 != "Yes, Delete This Character Forever") + lockdown = FALSE + to_chat(user, span_green("Your character remains safe and sound.")) + return PRACT_DIALOG_CANCEL + /// stage three, have them type in the name of the character to confirm they really want to delete it + var/confirmtext = "To confirm that you really want to delete [real_name], type in their name exactly as it appears in the text box below. \ + Please be careful, as this is your last chance to back out of deleting [real_name]. Again, just to be clear, the file structure \ + that we use with BYOND to save your individual characters does not allow for any feasible method of backing up or restoring \ + deleted characters. Once you delete [real_name], they are gone forever. Please confirm that you want to delete [real_name] by typing \ + their name in the box below." + var/confirm = input(user, confirmtext, "Character Deletion") as text|null + if(confirm != real_name) + lockdown = FALSE + to_chat(user, span_green("Your character remains safe and sound.")) + return PRACT_DIALOG_CANCEL + /// stage four, actually delete the character + log_game("[parent.ckey] has deleted [real_name] via the preferences menu. [real_name] is gone, forever. RIP.") + to_chat(user, span_danger("So be it. Deleting [real_name]...")) + delete_character(default_slot, real_name) + to_chat(user, span_danger("Character deletion complete. They are gone, forever.")) + lockdown = FALSE + return PRACT_DIALOG_ACCEPT + +// Paste a character! +/datum/preferences/proc/PasteSlot(mob/user, list/href_list) + if(!user) + return PRACT_DIALOG_CANCEL + if(copyslot == default_slot) + to_chat(user, span_danger("You can't paste a character to itself, it just wouldn't work!")) + return PRACT_DIALOG_CANCEL + var/tobsure = alert( + user, + "Just to be clear, this will copy everything from [copyname] in slot [copyslot] to \ + [real_name], the currently selected character in slot [copyslot]. Everything on THIS \ + character ([real_name]) will be totally, utterly, completely lost and deleted forever, \ + and in its place will be everything from [copyname]. Are you sure you want to do this?", + "Character Paste", + "Yes, Paste [copyname] to [real_name]", + "NO WAIT I CHANGED MY MIND", + ) + if(tobsure != "Yes, Paste [copyname] to [real_name]") + to_chat(user, span_green("Nevermind!! Your character remains safe and sound.")) + return PRACT_DIALOG_CANCEL + var/sure2 = input( + user, + "Just in case you kinda sorta fat-fingered the last prompt, please type 'Chiara is wide' \ + in the box below to confirm that you really want to paste [copyname] to [real_name] and \ + utterly delete [real_name] forever and ever. No quotes, please!", + "Character Paste, part II", + ) as text|null + if(sure2 != "Chiara is wide") + to_chat(user, span_green("Nevermind!! Your character remains safe and sound.")) + return PRACT_DIALOG_CANCEL + load_character(copyslot, TRUE) + save_character() + to_chat(user, span_notice("Character pasted successfully!")) + return PRACT_DIALOG_ACCEPT + +// Change your socks! +/datum/preferences/proc/ChangeSocks(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/first_try = ShiftAdjustment(user, GLOB.socks_list, socks, href_list) + if(first_try) + socks = first_try + return PRACT_DIALOG_ACCEPT_SMOL + var/new_socks = input( + user, + "What kind of socks does your character wear?", + "Character Preference" + ) as null|anything in GLOB.socks_list + if(isnull(new_socks)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + socks = new_socks + to_chat(user, span_green("Your character is now wearing [new_socks]!")) + return PRACT_DIALOG_ACCEPT + +// Change your species! +/datum/preferences/proc/ChangeSpecies(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/newspecies = input( + user, + "What species is your character?", + "Character Preference" + ) as null|anything in GLOB.roundstart_race_names + if(isnull(newspecies)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + var/newtype = GLOB.species_list[GLOB.roundstart_race_names[newspecies]] + pref_species = new newtype() + custom_species = null + if(!parent.can_have_part("mam_body_markings")) + features["mam_body_markings"] = list() + else if(features["mam_body_markings"] == "None") + features["mam_body_markings"] = list() + if(parent.can_have_part("tail_lizard")) + features["tail_lizard"] = "Smooth" + if(pref_species.id == "felinid") + features["mam_tail"] = "Cat" + features["mam_ears"] = "Cat" + eye_type = pref_species.eye_type + to_chat(user, span_green("Your character is now a [newspecies]!")) + return PRACT_DIALOG_ACCEPT + +// Change your stats! +/datum/preferences/proc/ChangeStats(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/totalcurrentpoints = special_s + special_p + special_e + special_c + special_i + special_a + special_l + var/totalmaxpoints = 40 + var/max_per_stat = 10 + var/min_per_stat = 1 + var/statvarname = href_list[PREFDAT_STAT] + var/stat_current_value = vars["[statvarname]"] // hue + totalcurrentpoints -= stat_current_value + var/points_to_spend = totalmaxpoints - totalcurrentpoints + var/points_to_spend_on_stat = min(points_to_spend, max_per_stat) + var/newpoints = input( + user, + "How many points should this stat be? (Can be between [min_per_stat] and [points_to_spend_on_stat], inclusive!)", + "Character Preference", + stat_current_value + ) as null|num + if(isnull(newpoints)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + newpoints = clamp(newpoints, min_per_stat, points_to_spend_on_stat) + vars["[statvarname]"] = newpoints + to_chat(user, span_green("You have set that stat to [newpoints]!")) + return PRACT_DIALOG_ACCEPT + +// Toggle whether or not you have a certain genital +/datum/preferences/proc/ToggleGenital(mob/user, list/href_list) + var/which = href_list[PREFDAT_GENITAL_HAS] + var/datum/genital_data/GD = GLOB.genital_data_system[which] + if(!GD) + to_chat(user, span_warning("That's not a valid genital! something went wrong :( error code: KENZIE HOWZER'S BUTT")) + return PRACT_DIALOG_ERROR + features[GD.has_key] = features[GD.has_key] ? FALSE : TRUE + if(features[GD.has_key]) + to_chat(user, span_green("Congratulations! You now have a [GD.name]!")) + else + to_chat(user, span_green("Congratulations! You have removed your [GD.name]!")) + return PRACT_TOGGLE(features[GD.has_key]) + +// Change your underwear! +/datum/preferences/proc/ChangeUnderwear(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/first_try = ShiftAdjustment(user, GLOB.underwear_list, underwear, href_list) + if(first_try) + underwear = first_try + return PRACT_DIALOG_ACCEPT_SMOL + var/new_underwear = input( + user, + "What kind of underwear / pants / bottomwear does your character wear?", + "Character Preference" + ) as null|anything in GLOB.underwear_list + if(isnull(new_underwear)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + underwear = new_underwear + to_chat(user, span_green("Your character is now wearing [new_underwear]!")) + return PRACT_DIALOG_ACCEPT + +// Change your unershirt +/datum/preferences/proc/ChangeUndershirt(mob/user, list/href_list) + PlayBoop(user, BOOP_MENU_OPEN) + var/first_try = ShiftAdjustment(user, GLOB.undershirt_list, undershirt, href_list) + if(first_try) + undershirt = first_try + return PRACT_DIALOG_ACCEPT_SMOL + var/new_undershirt = input( + user, + "What kind of undershirt / shirt / topwear does your character wear?", + "Character Preference" + ) as null|anything in GLOB.undershirt_list + if(isnull(new_undershirt)) + to_chat(user, span_warning("Okay nevermind!!")) + return PRACT_DIALOG_CANCEL + undershirt = new_undershirt + to_chat(user, span_green("Your character is now wearing [new_undershirt]!")) + return PRACT_DIALOG_ACCEPT + +// Get a marking by its UID +/datum/preferences/proc/GetMarkingByUID(mob/user, muid) + if(!muid) + return + for(var/list/mark in features["mam_body_markings"]) + if(LAZYLEN(mark) < MARKING_LIST_LENGTH) + mark = SanitizeMarking(mark) + if(mark[MARKING_UID] == muid) + return mark + +// Get the markings that are appropriate for the user's selected limb +/datum/preferences/proc/GetAppropriateMamMarkings(mob/user, list/marking_list, selected_limb) + if(!LAZYLEN(marking_list)) + return + if(!user || !selected_limb) + return + var/list/cooler_markings = list() + for(var/path in marking_list) + var/datum/sprite_accessory/S = marking_list[path] + if(!istype(S)) + continue + if(istype(S, /datum/sprite_accessory/mam_body_markings)) + var/datum/sprite_accessory/mam_body_markings/marking = S + if(selected_limb != "All") + if(!(selected_limb in marking.covered_limbs)) + continue + if((!S.ckeys_allowed) || (S.ckeys_allowed.Find(user.client.ckey))) + cooler_markings[S.name] = path + return cooler_markings + +// Get the default colors for a marking +/datum/preferences/proc/GetDefaultMarkingColors() + return list(features["mcolor"], features["mcolor2"], features["mcolor3"]) // close enough + +// Was accept? +/datum/preferences/proc/WasAccept(did) + if(did == PRACT_DIALOG_ACCEPT) + return TRUE + if(did == PRACT_DIALOG_ACCEPT_SMOL) + return TRUE + return FALSE + +// Play a boob! +/datum/preferences/proc/PlayBoop(mob/user, boop) + if(!user || !boop) + return + var/boopsound + switch(boop) + if(BOOP_ACCEPT) + boopsound = 'sound/effects/prefsmenu/accept.ogg' + if(BOOP_ACCEPT_BIG) + boopsound = 'sound/effects/prefsmenu/accept_big.ogg' + if(BOOP_ACCEPT_SMOL) + boopsound = 'sound/effects/prefsmenu/accept_smol.ogg' + if(BOOP_CANCEL) + boopsound = 'sound/effects/prefsmenu/cancel.ogg' + if(BOOP_DENIED) + boopsound = 'sound/effects/prefsmenu/denied.ogg' + if(BOOP_ERROR) + boopsound = 'sound/effects/prefsmenu/error.ogg' + if(BOOP_BIG_MENU_OPEN) + boopsound = 'sound/effects/prefsmenu/menu_open_big.ogg' + if(BOOP_MENU_OPEN) + boopsound = 'sound/effects/prefsmenu/menu_open.ogg' + if(BOOP_SUB_PROMPT) + boopsound = 'sound/effects/prefsmenu/sub_prompt.ogg' + if(boopsound) + user.playsound_local(user, boopsound) + +// Can the user afford the item? +/datum/preferences/proc/CanAffordLoadoutItem(mob/user, datum/gear/G) + if(!G.cost) + return TRUE + if(G.cost > gear_points) + return FALSE + return TRUE + +// Add an item to the user's loadout +/datum/preferences/proc/AddGearToLoadout(loadout_slot, datum/gear/G) + var/new_loadout_data = list() + new_loadout_data[LOADOUT_ITEM] = "[G.type]" + new_loadout_data[LOADOUT_COLOR] = "FFFFFF" + new_loadout_data[LOADOUT_CUSTOM_NAME] = "" + new_loadout_data[LOADOUT_CUSTOM_DESCRIPTION] = "" + new_loadout_data[LOADOUT_CUSTOM_COLOR] = "FFFFFF" + new_loadout_data[LOADOUT_UID] = GenerateMarkingUID() + if(!islist(loadout_data["SAVE_[loadout_slot]"])) + loadout_data["SAVE_[loadout_slot]"] = list() + loadout_data["SAVE_[loadout_slot]"] += list(new_loadout_data) + return TRUE + +// Does the user have a slot for the item? +/datum/preferences/proc/HasSlotForLoadoutItem(mob/user, datum/gear/G) + if(G.cost) + return TRUE + var/numfound = 0 + for(var/i in loadout_data["SAVE_[loadout_slot]"]) + var/loadie = i[LOADOUT_ITEM] + var/datum/gear/testgear = text2path(loadie) + if(initial(testgear.cost) > 0) // oh right, these are uninitialized, mb + continue // non-free items are self limiting + if(initial(testgear.category) != G.category) + continue + numfound++ + return numfound < MAX_FREE_PER_CAT + +/datum/preferences/proc/RemoveGearFromLoadout(save_slot, gear_type) + var/find_gear = has_loadout_gear(save_slot, gear_type) + if(find_gear) + loadout_data["SAVE_[save_slot]"] -= list(find_gear) + + +/datum/preferences/proc/CopySlot(mob/user, list/href_list) + copyslot = default_slot + copyname = real_name + to_chat(user, span_notice("Copied [real_name] to the clipboard.")) + return PRACT_DIALOG_ACCEPT + +/// Shift the options list for a part change +/datum/preferences/proc/ShiftAdjustment(mob/user, list/optionslist, current, list/href_list) + if(!LAZYLEN(optionslist) || !LAZYLEN(href_list) || !current) + return + if(!href_list[PREFDAT_GO_PREV] && !href_list[PREFDAT_GO_NEXT]) + return + . = PRACT_DIALOG_ERROR + var/which = href_list[PREFDAT_GO_PREV] ? "prev" : "next" + var/newoption + if(which == "prev") + newoption = next_list_item(current, optionslist) + else + newoption = previous_list_item(current, optionslist) + if(!newoption) + to_chat(user, span_warning("Something went wrong! Error code: TWILIGHT SPARKLE'S BUTT")) + return + return newoption + +/// Gets the loadout list for the user +/datum/preferences/proc/GetLoadoutList(mob/user, list/href_list) + var/name = html_decode(href_list[PREFDAT_LOADOUT_GEAR_NAME]) + var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][name] + if(!G) + return + var/loadout_slot = numberfy(href_list[PREFDAT_LOADOUT_SLOT]) + var/usergear = has_loadout_gear(loadout_slot, "[G.type]") + if(!usergear) + return + return usergear + +/// Makes GenerateMarkingUID +/datum/preferences/proc/GenerateMarkingUID() + return "MARKING_[rand(1000000, 9999999)]_[rand(1000000, 9999999)]_[rand(1000000, 9999999)]_[rand(1000000, 9999999)]" + + + diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 470dc748b7..9124bb45d8 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -136,7 +136,24 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(PMC_MOMMYCHAT_IS_COOL) // i broke it =3 pda_skin = "Random!" WRITE_FILE(S["pda_skin"], pda_skin) - current_version |= PMC_MY_PDA_FLIES_IN_FULL_COLOR + current_version |= PMC_MOMMYCHAT_IS_COOL + if(PMR_REMOVE_CORK_STRING) // i broke it =3 + var/corkstring = "" + S["feature_genital_order"] >> corkstring + var/list/corkboard = splittext(corkstring, ":") + var/newjson = json_encode(corkboard) + WRITE_FILE(S["feature_genital_order"], newjson) + current_version |= PMR_REMOVE_CORK_STRING + // if(PMC_MARKINGS_GET_AN_ACTUAL_UID) // i broke it =3 + // var/list/markings = list() + // if(S["feature_mam_body_markings"]) + // markings = safe_json_decode(S["feature_mam_body_markings"]) + // if(islist(markings)) + // for(var/list/mark in markings) + // mark.len = 4 + // mark[4] = GenerateMarkingUID() + // WRITE_FILE(S["feature_mam_body_markings"], safe_json_encode(markings)) + // current_version |= PMC_MARKINGS_GET_AN_ACTUAL_UID if(PMC_FENNY_FINISHED_124_QUESTS) // i broke it =3 current_version |= PMC_FENNY_FINISHED_124_QUESTS var/list/huge_quest_list = list() @@ -893,8 +910,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["feature_vag_visibility_flags"] >> features["vag_visibility_flags"] //womb features S["feature_has_womb"] >> features["has_womb"] - //cockstring - S["feature_genital_order"] >> features["genital_order"] + features["genital_order"] = safe_json_decode(S["feature_genital_order"]) S["feature_genital_hide"] >> features["genital_hide"] S["feature_genital_visibility_flags"] >> features["genital_visibility_flags"] //taste @@ -952,12 +968,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["visualchat_use_contrasting_color"] >> visualchat_use_contrasting_color // Hair gradients electric boogaloo 2!! S["visualchat_see_horny_radio"] >> visualchat_see_horny_radio // Hair gradients electric boogaloo 2!! - S["gradient_color"] >> features_override["grad_color"] // Hair gradients! - S["gradient_style"] >> features_override["grad_style"] // Hair gradients electric boogaloo 2!! - S["gradient_color_2"] >> features_override["grad_color_2"] // Hair gradients! - S["gradient_style_2"] >> features_override["grad_style_2"] // Hair gradients electric boogaloo 2!! - S["s_hair_color_2"] >> features_override["hair_color_2"] // Hair color 2 - S["s_hair_style_2"] >> features_override["hair_style_2"] // Hair style 2 + S["gradient_color"] >> features["grad_color"] // Hair gradients! + S["gradient_style"] >> features["grad_style"] // Hair gradients electric boogaloo 2!! + S["gradient_color_2"] >> features["grad_color_2"] // Hair gradients! + S["gradient_style_2"] >> features["grad_style_2"] // Hair gradients electric boogaloo 2!! + S["s_hair_color_2"] >> features["hair_color_2"] // Hair color 2 + S["s_hair_style_2"] >> features["hair_style_2"] // Hair style 2 S["typing_indicator_sound"] >> features_speech["typing_indicator_sound"] // Typing sounds! S["typing_indicator_sound_play"] >> features_speech["typing_indicator_sound_play"] // Typing sounds electric- you know what I'm gonna stop its not funny anymore. S["typing_indicator_speed"] >> features_speech["typing_indicator_speed"] @@ -1245,7 +1261,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car security_records = copytext(security_records, 1, MAX_FLAVOR_LEN) medical_records = copytext(medical_records, 1, MAX_FLAVOR_LEN) - features["genital_order"] = sanitize_text(features["genital_order"], DEF_COCKSTRING) + features["genital_order"] = sanitize_islist(features["genital_order"], PREFS_ALL_HAS_GENITALS) features["genital_hide"] = sanitize_integer(features["genital_hide"], 0, 4096, 0) features["taste"] = copytext(features["taste"], 1, MAX_TASTE_LEN) features["flavor_text"] = copytext(features["flavor_text"], 1, MAX_FLAVOR_LEN) @@ -1305,6 +1321,17 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car if(S["feature_[tertiary_string]"]) S["feature_[tertiary_string]"] >> features[tertiary_string] + //Sanitize markings + for(var/list/marking in features["mam_body_markings"]) + marking.len = MARKING_LIST_LENGTH + if(LAZYLEN(marking[MARKING_COLOR_LIST]) != 3) + for(var/indx in 1 to 3) + if(marking[MARKING_COLOR_LIST][indx]) + continue + marking[MARKING_COLOR_LIST][indx] = "FFFFFF" + if(!marking[MARKING_UID]) + marking[MARKING_UID] = GenerateMarkingUID() + persistent_scars = sanitize_integer(persistent_scars) scars_list["1"] = sanitize_text(scars_list["1"]) scars_list["2"] = sanitize_text(scars_list["2"]) @@ -1321,14 +1348,14 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car SSchat.SanitizeUserImages(src) SSchat.SanitizeUserPreferences(src) - features_override["grad_color"] = sanitize_hexcolor(features_override["grad_color"], 6, FALSE, default = COLOR_ALMOST_BLACK) - features_override["grad_style"] = sanitize_inlist(features_override["grad_style"], GLOB.hair_gradients, "none") + features["grad_color"] = sanitize_hexcolor(features["grad_color"], 6, FALSE, default = COLOR_ALMOST_BLACK) + features["grad_style"] = sanitize_inlist(features["grad_style"], GLOB.hair_gradients, "none") - features_override["grad_color_2"] = sanitize_hexcolor(features_override["grad_color_2"], 6, FALSE, default = COLOR_ALMOST_BLACK) - features_override["grad_style_2"] = sanitize_inlist(features_override["grad_style_2"], GLOB.hair_gradients, "none") + features["grad_color_2"] = sanitize_hexcolor(features["grad_color_2"], 6, FALSE, default = COLOR_ALMOST_BLACK) + features["grad_style_2"] = sanitize_inlist(features["grad_style_2"], GLOB.hair_gradients, "none") - features_override["hair_color_2"] = sanitize_hexcolor(features_override["hair_color_2"], 6, FALSE, default = COLOR_ALMOST_BLACK) - features_override["hair_style_2"] = sanitize_inlist(features_override["hair_style_2"], GLOB.hair_styles_list, "Bald") + features["hair_color_2"] = sanitize_hexcolor(features["hair_color_2"], 6, FALSE, default = COLOR_ALMOST_BLACK) + features["hair_style_2"] = sanitize_inlist(features["hair_style_2"], GLOB.hair_styles_list, "Bald") if(!LAZYLEN(GLOB.typing_sounds)) SStypinginit.populate_typing_list()//This list is initialized late, so if a savefile is saved during initialization (they almost always are), they might lose their sound selection. Manually populate it early, in that case. @@ -1510,7 +1537,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["feature_belly_shape"], features["belly_shape"]) WRITE_FILE(S["feature_belly_visibility"], features["belly_visibility"]) WRITE_FILE(S["feature_belly_visibility_flags"], features["belly_visibility_flags"]) - WRITE_FILE(S["feature_genital_order"], features["genital_order"]) + WRITE_FILE(S["feature_genital_order"], safe_json_encode(features["genital_order"])) WRITE_FILE(S["feature_genital_hide"], features["genital_hide"]) WRITE_FILE(S["feature_genital_visibility_flags"], features["genital_visibility_flags"]) @@ -1634,14 +1661,14 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["creature_profilepic"], creature_profilepic) WRITE_FILE(S["creature_pfphost"], creature_pfphost) - WRITE_FILE(S["gradient_color"] , features_override["grad_color"]) - WRITE_FILE(S["gradient_style"] , features_override["grad_style"]) + WRITE_FILE(S["gradient_color"] , features["grad_color"]) + WRITE_FILE(S["gradient_style"] , features["grad_style"]) - WRITE_FILE(S["gradient_color_2"] , features_override["grad_color_2"]) - WRITE_FILE(S["gradient_style_2"] , features_override["grad_style_2"]) + WRITE_FILE(S["gradient_color_2"] , features["grad_color_2"]) + WRITE_FILE(S["gradient_style_2"] , features["grad_style_2"]) - WRITE_FILE(S["s_hair_color_2"] , features_override["hair_color_2"]) - WRITE_FILE(S["s_hair_style_2"] , features_override["hair_style_2"]) + WRITE_FILE(S["s_hair_color_2"] , features["hair_color_2"]) + WRITE_FILE(S["s_hair_style_2"] , features["hair_style_2"]) WRITE_FILE(S["typing_indicator_sound"] , features_speech["typing_indicator_sound"]) WRITE_FILE(S["typing_indicator_sound_play"] , features_speech["typing_indicator_sound_play"]) diff --git a/code/modules/client/preferences_tabs.dm b/code/modules/client/preferences_tabs.dm new file mode 100644 index 0000000000..8067375926 --- /dev/null +++ b/code/modules/client/preferences_tabs.dm @@ -0,0 +1,1195 @@ +/* + * File: preferences_tabs.dm + * Author: Kelly + * Date: 2021-07-07 + * License: WWW.PLAYAPOCALYPSE.COM + * + * TGUI preferences is a pipe dream. + * + * This file holds more accessible preferences for the player. + * Part of the Great Preferences Cleanup of 2021. (its actually 2024) + * + * */ + +/* + * This proc takes in its args and outputs a link that'll be printed in the preferences window. + * cus ew, href spam + * @param showtext The text that will be displayed in the link + * @param pref The preference action (basically always TRUE) + * @param list/data A list of key-value pairs that will be added to the URL + * @param kind Used to tell the game what kind of sound to play when the link is clicked + * @param span Extra spans used for styling on your foes + */ +/datum/preferences/proc/PrefLink(showtext, pref, list/data = list(), kind, span, style) + var/argos = "?_src_=prefs;preference=[pref];" + if(kind) + argos += "p_kind=[kind];" + for(var/key in data) + argos += "[key]=[data[key]];" + var/stylepro = "" + if(style) + stylepro = "style='[style]'" + if(span) + return "[showtext]" + else + return "[showtext]" + +/datum/preferences/proc/ShowChoices(mob/user) + if(!user || !user.client) + return + update_preview_icon(current_tab) + ui_interact(user) + return + +/datum/preferences/ui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "PreferencesMenu") + ui.open() + ui.set_autoupdate(FALSE) + +/// packages the entire preferences menu into a handy massive list +/datum/preferences/ui_static_data(mob/user) + var/list/data = list() + var/savefile/S = new /savefile(path) + if(!S) + data["fatal_error"] = TRUE + return data + /// All the characters! + var/list/charlist = list() + var/numslots2show = min(max_save_slots, show_this_many) + charlist.len = numslots2show + for(var/i in 1 to min(max_save_slots, show_this_many)) + var/list/char = list() + S.cd = "/character[i]" + S["real_name"] >> name + if(!name) + name = "Character[i]" + if(i == default_slot) + char["is_selected"] = TRUE + else + char["is_selected"] = FALSE + char["name"] = name + char["command"] = PREFCMD_CHANGE_SLOT + char["data"] = list(PREFDAT_SLOT = i) + charlist[i] = char + data["characters"] = charlist + data["current_slot"] = default_slot + data["copy_slot"] = copyslot + data["copy_slot_name"] = copyname + data["category_tabs_line1"] = list( + PPT_CHARCTER_PROPERTIES, + PPT_CHARCTER_APPEARANCE, + PPT_LOADOUT, + ) + data["category_tabs_line2"] = list( + PPT_GAME_PREFERENCES, + PPT_KEYBINDINGS, + ) + data["subcategory_tabs"] = list() + switch(current_tab) + if(PPT_CHARCTER_PROPERTIES) + GetCharacterPropertiesData(data) + if(PPT_CHARCTER_APPEARANCE) + GetCharacterAppearanceData(data) + if(PPT_LOADOUT) + GetLoadoutData(data) + if(PPT_GAME_PREFERENCES) + GetGamePreferencesData(data) + data["subcategory_tabs"] = list( + PPT_GAME_PREFERENCES_GENERAL, + PPT_GAME_PREFERENCES_UI, + PPT_GAME_PREFERENCES_CHAT, + PPT_GAME_PREFERENCES_RUNECHAT, + PPT_GAME_PREFERENCES_GHOST, + PPT_GAME_PREFERENCES_AUDIO, + PPT_GAME_PREFERENCES_ADMIN, + PPT_GAME_PREFERENCES_CONTENT, + ) + if(PPT_KEYBINDINGS) + GetKeybindingsData(data) + + return data + +// it does a little magic trick and modifies the data in-place +/datum/preferences/proc/GetCharacterPropertiesData(list/data = list()) + data["subcategory_tabs"] = list( + PPT_CHARCTER_PROPERTIES_INFO, + PPT_CHARCTER_PROPERTIES_VOICE, + PPT_CHARCTER_PROPERTIES_MISC, + ) + if(!(current_subtab in data["subcategory_tabs"])) + current_subtab = PPT_CHARCTER_PROPERTIES_INFO + switch(current_subtab) + if(PPT_CHARCTER_PROPERTIES_INFO) + GetCharacterInfoData(data) + if(PPT_CHARCTER_PROPERTIES_VOICE) + GetCharacterVoiceData(data) + if(PPT_CHARCTER_PROPERTIES_MISC) + GetCharacterMiscData(data) + return data + +/datum/preferences/proc/GetCharacterInfoData(list/data = list()) + data["name"] = real_name + var/pfplink = SSchat.GetPicForMode(src, MODE_PROFILE_PIC) + data["pfp_link"] = pfplink || "https://via.placeholder.com/150" + data["age"] = age + var/genwords = "amazing" + switch(gender) + if(MALE) + genwords = "Male" + if(FEMALE) + genwords = "Female" + if("object") + genwords = "Agender" + if("nonbinary") + genwords = "Nonbinary" + data["gender"] = genwords + data["tbs"] = "[tbs]" + data["kisser"] = "[kisser]" + var/ftbutless = "[features["flavor_text"]]" + if(ftbutless == initial(features["flavor_text"])) + ftbutless = "Click to add flavor text!" + if(LAZYLEN(ftbutless) > 100) + ftbutless = "[copytext(ftbutless, 1, 100)]..." + data["flavor_text"] = ftbutless + var/oocbutless = "[features["ooc_notes"]]" + if(oocbutless == initial(features["ooc_notes"])) + oocbutless = "Click to add OOC notes!" + if(LAZYLEN(oocbutless) > 100) + oocbutless = "[copytext(oocbutless, 1, 100)]..." + data["ooc_notes"] = oocbutless + return data + +/datum/preferences/proc/GetCharacterVoiceData(list/data = list()) + data["typing_indicator_sound"] = features["typing_indicator_sound"] + data["typing_indicator_sound_play"] = features["typing_indicator_sound_play"] + data["typing_indicator_variance"] = features["typing_indicator_variance"] + data["typing_indicator_speed"] = features["typing_indicator_speed"] + data["typing_indicator_volume"] = features["typing_indicator_volume"] + data["typing_indicator_pitch"] = features["typing_indicator_pitch"] + data["typing_indicator_max_words_spoken"] = features["typing_indicator_max_words_spoken"] + data["runechat_color"] = features["runechat_color"] + return data + +/datum/preferences/proc/GetCharacterMiscData(list/data = list()) + data["quester_uid"] = quester_uid + data["money_string"] = "[SSeconomy.format_currency(saved_unclaimed_points, TRUE)]" + data["pda_skin"] = pda_skin + data["pda_ringmessage"] = pda_ringmessage + data["pda_color"] = pda_color + data["backbag"] = backbag + data["persistent_scars"] = !!persistent_scars + data["quirks"] = RowifyQuirks() + data["special_s"] = special_s + data["special_p"] = special_p + data["special_e"] = special_e + data["special_c"] = special_c + data["special_i"] = special_i + data["special_a"] = special_a + data["special_l"] = special_l + var/tot = special_s + special_p + special_e + special_c + special_i + special_a + special_l + data["special_totals"] = "[tot] / 40" + return data + +/datum/preferences/proc/RowifyQuirks() + if(!LAZYLEN(char_quirks)) + return QuirkEntry("None!", "NEUTRAL") + var/list/goodquirks = list() + var/list/neutquirks = list() + var/list/badquirks = list() + for(var/quirk in char_quirks) + var/datum/quirk/Q = SSquirks.GetQuirk(quirk) + switch(Q.value) + if(-INFINITY to -1) + badquirks += Q + if(1 to INFINITY) + goodquirks += Q + else + neutquirks += Q + var/list/dat = list() + for(var/datum/quirk/Q in goodquirks) + dat += list(list( + "name" = Q.name, + "class" = "QuirkGood", + )) + for(var/datum/quirk/Q in neutquirks) + dat += list(list( + "name" = Q.name, + "class" = "QuirkNeutral", + )) + for(var/datum/quirk/Q in badquirks) + dat += list(list( + "name" = Q.name, + "class" = "QuirkBad", + )) + return dat + +/datum/preferences/proc/GetCharacterAppearanceData(list/data = list()) + data["subcategory_tabs"] = list( + PPT_CHARCTER_APPEARANCE_MISC, + PPT_CHARCTER_APPEARANCE_HAIR_EYES, + PPT_CHARCTER_APPEARANCE_PARTS, + PPT_CHARCTER_APPEARANCE_MARKINGS, + PPT_CHARCTER_APPEARANCE_UNDERLYING, + ) + switch(current_subtab) + if(PPT_CHARCTER_APPEARANCE_MISC) + GetCharacterMiscAppearanceData(data) + if(PPT_CHARCTER_APPEARANCE_HAIR_EYES) + GetCharacterHairEyesData(data) + if(PPT_CHARCTER_APPEARANCE_PARTS) + GetCharacterPartsData(data) + if(PPT_CHARCTER_APPEARANCE_MARKINGS) + GetCharacterMarkingsData(data) + if(PPT_CHARCTER_APPEARANCE_UNDERLYING) + GetCharacterUnderlyingData(data) + return data + +/datum/preferences/proc/GetCharacterMiscAppearanceData(list/data = list()) + data["species_name"] = pref_species.name + data["species_custom_name"] = custom_species ? custom_species : pref_species.name + var/bmod = "N/A" + if(gender != NEUTER && pref_species.sexes) // oh yeah, my pref species sexes a lot + data["show_body_model"] = TRUE + features["body_model"] = gender == MALE ? "Masculine" : "Feminine" + data["body_model"] = bmod + if(LAZYLEN(pref_species.allowed_limb_ids)) + data["show_body_sprite"] = TRUE + if(!chosen_limb_id || !(chosen_limb_id in pref_species.allowed_limb_ids)) + chosen_limb_id = pref_species.limbs_id || pref_species.id + data["body_sprite"] = chosen_limb_id + if(LAZYLEN(pref_species.alt_prefixes)) + data["show_alt_appearance"] = TRUE + data["alt_appearance"] = alt_appearance ? "[alt_appearance]" : "Select" + data["blood_color"] = features["blood_color"] + data["blood_rainbow"] = features["blood_color"] == "Rainbow" + data["meat_type"] = features["meat_type"] + data["taste"] = features["taste"] + data["body_scale"] = features["body_scale"]*100 + data["body_width"] = features["body_width"]*100 + var/fuzsharp = fuzzy ? "Fuzzy" : "Sharp" + data["fuzzysharp"] = fuzsharp + var/pye = features["pixel_y"] > 0 ? "+[features["pixel_y"]]" : "[features["pixel_y"]]" + data["pixel_y"] = pye + var/pxe = features["pixel_x"] > 0 ? "+[features["pixel_x"]]" : "[features["pixel_x"]]" + data["pixel_x"] = pxe + data["legs"] = features["legs"] + if(pref_species.use_skintones) // humans suck + data["show_skin_tone"] = TRUE + if(use_custom_skin_tone) + data["skin_tone"] = custom_skin_tone + else + data["skin_tone"] = skin_tone + return data + +/datum/preferences/proc/GetCharacterHairEyesData(list/data = list()) + data["eye_type"] = capitalize("[eye_type]") + split_eye_colors = TRUE // just makes it easier + data["eye_over_hair"] = eye_over_hair + data["left_eye_color"] = left_eye_color + data["right_eye_color"] = right_eye_color + data["hair_1_style"] = hair_style + data["hair_1_color"] = hair_color + data["gradient_1_style"] = features["grad_style"] + data["gradient_1_color"] = features["grad_color"] + data["hair_2_style"] = features["hair_style_2"] + data["hair_2_color"] = features["hair_color_2"] + data["gradient_2_style"] = features["grad_style_2"] + data["gradient_2_color"] = features["grad_color_2"] + data["facial_hair_style"] = facial_hair_style + data["facial_hair_color"] = facial_hair_color + return data + +/datum/preferences/proc/GetCharacterPartsData(list/data = list()) + data["all_parts"] = list() + if(features["color_scheme"] != ADVANCED_CHARACTER_COLORING) + features["color_scheme"] = ADVANCED_CHARACTER_COLORING // screw you, use it + for(var/mutant_part in GLOB.all_mutant_parts) + if(mutant_part == "mam_body_markings") + continue // we'll get to this + if(!parent.can_have_part(mutant_part)) + continue + var/part_data = list() + part_data["displayname"] = GLOB.all_mutant_parts[mutant_part] + part_data["featurekey"] = mutant_part + part_data["currentshape"] = features[mutant_part] + var/find_part = features[mutant_part] || pref_species.mutant_bodyparts[mutant_part] + var/find_part_list = GLOB.mutant_reference_list[mutant_part] + if(!find_part || find_part == "None" || !find_part_list) + continue + var/datum/sprite_accessory/accessory = find_part_list[find_part] + if(!accessory) + continue + // fuuck you POOJ + if(accessory.color_src != MATRIXED && \ + accessory.color_src != MUTCOLORS && \ + accessory.color_src != MUTCOLORS2 && \ + accessory.color_src != MUTCOLORS3) + part_data["no_color"] = TRUE + data["all_parts"] += list(part_data) + continue // something something mutcolors are deprecated, not that it matters + var/mutant_string = accessory.mutant_part_string + var/primary_feature = "[mutant_string]_primary" + var/secondary_feature = "[mutant_string]_secondary" + var/tertiary_feature = "[mutant_string]_tertiary" + /// these just sanitize the colors, pay no attention!!! + if(!features[primary_feature]) + features[primary_feature] = features["mcolor"] + if(!features[secondary_feature]) + features[secondary_feature] = features["mcolor2"] + if(!features[tertiary_feature]) + features[tertiary_feature] = features["mcolor3"] + var/matrixed_sections = accessory.matrixed_sections + if(accessory.color_src == MATRIXED) + if(!matrixed_sections) + message_admins("Sprite Accessory Failure (customization): Accessory [accessory.type] is a matrixed item without any matrixed sections set!") + continue + // this part properly shuffles the colors around becausE THANKS POOJ + switch(matrixed_sections) + if(MATRIX_GREEN) //only composed of a green section + primary_feature = secondary_feature //swap primary for secondary, so it properly assigns the second colour, reserved for the green section + if(MATRIX_BLUE) + primary_feature = tertiary_feature //same as above, but the tertiary feature is for the blue section + if(MATRIX_RED_BLUE) //composed of a red and blue section + secondary_feature = tertiary_feature //swap secondary for tertiary, as blue should always be tertiary + if(MATRIX_GREEN_BLUE) //composed of a green and blue section + primary_feature = secondary_feature //swap primary for secondary, as first option is green, which is linked to the secondary + secondary_feature = tertiary_feature //swap secondary for tertiary, as second option is blue, which is linked to the tertiary + // BUT WHAT ABOUT FULL RGB well tahts already set up + /// NOW, the colors are all set up, display the color pickers + part_data["color1"] = features[primary_feature] + part_data["color1_key"] = primary_feature + + part_data["color2"] = features[secondary_feature] + part_data["color2_key"] = secondary_feature + part_data["color2_show"] = accessory.ShouldHaveSecondaryColor() + + part_data["color3"] = features[tertiary_feature] + part_data["color3_key"] = tertiary_feature + part_data["color3_show"] = accessory.ShouldHaveTertiaryColor() + + data["all_parts"] += list(part_data) + data["all_limb_mods"] = list() + for(var/modification in modified_limbs) // mofidiecation is a string, the limb mod + var/limb_mod_data = list() + limb_mod_data["area"] = modification + var/list/mod_data = modified_limbs[modification] + var/pora = mod_data[1] + if(pora == LOADOUT_LIMB_PROSTHETIC) + limb_mod_data["pros_or_amp"] = "Prosthetic" + limb_mod_data["style"] = mod_data[2] + else + limb_mod_data["pros_or_amp"] = "Amputated" + limb_mod_data["style"] = "Missing D:" + data["all_limb_mods"] += list(limb_mod_data) + return data + +/datum/preferences/proc/GetCharacterMarkingsData(list/data = list()) + data["markings"] = list() + if(!parent.can_have_part("mam_body_markings")) + data["can_have_markings"] = FALSE + return data // lousy humans + if(!islist(features["mam_body_markings"])) + features["mam_body_markings"] = list() + if(!LAZYLEN(features["mam_body_markings"])) + return data // no markings 3: + var/list/markings = features["mam_body_markings"] + var/list/rev_markings = reverseList(markings) + for(var/list/mark in rev_markings) + mark = SanitizeMarking(mark) + var/m_uid = mark[MARKING_UID] + var/limb_num = mark[MARKING_LIMB_INDEX_NUM] + var/limb_name = GLOB.bodypart_names[num2text(limb_num)] + var/list/mark_data = list() + mark_data["displayname"] = capitalize(mark[MARKING_NAME]) + mark_data["location_display"] = capitalize(limb_name) + mark_data["marking_uid"] = m_uid + // and here come the colors! + var/datum/sprite_accessory/mam_body_markings/S = GLOB.mam_body_markings_list[mark[2]] + if(!S) + continue + var/matrixed_sections = S.covered_limbs[limb_name] + if(!matrixed_sections) + continue + // index magic + var/primary_index = 1 + var/secondary_index = 2 + var/tertiary_index = 3 + switch(matrixed_sections) + if(MATRIX_GREEN) + primary_index = 2 + if(MATRIX_BLUE) + primary_index = 3 + if(MATRIX_RED_BLUE) + secondary_index = 2 + if(MATRIX_GREEN_BLUE) + primary_index = 2 + secondary_index = 3 + mark_data["color1"] = mark[MARKING_COLOR_LIST][primary_index] + mark_data["color1_index"] = primary_index + if(matrixed_sections == MATRIX_RED_BLUE || \ + matrixed_sections == MATRIX_GREEN_BLUE || \ + matrixed_sections == MATRIX_RED_GREEN || \ + matrixed_sections == MATRIX_ALL) + mark_data["color2"] = mark[MARKING_COLOR_LIST][secondary_index] + mark_data["color2_index"] = secondary_index + mark_data["color2_show"] = TRUE + if(matrixed_sections == MATRIX_ALL) + mark_data["color3"] = mark[MARKING_COLOR_LIST][tertiary_index] + mark_data["color3_index"] = tertiary_index + mark_data["color3_show"] = TRUE + data["markings"] += list(mark_data) + return data + +// teehees and hoohaws +/datum/preferences/proc/GetCharacterUnderlyingData(list/data = list()) + data["subsubcategory_tabs_line1"] = list( + PPT_CHARCTER_APPEARANCE_UNDERLYING_UNDIES, + PPT_CHARCTER_APPEARANCE_UNDERLYING_LAYERING, + ) + data["subsubcategory_tabs_genitals"] = list() + for(var/hasbit in GLOB.genital_data) + var/datum/genital_data/GD = GLOB.genital_data[hasbit] + data["subsubcategory_tabs_genitals"] += GD.has_key + switch(current_sub_subtab) + if(PPT_CHARCTER_APPEARANCE_UNDERLYING_UNDIES) + GetCharacterUnderlyingUndiesData(data) + if(PPT_CHARCTER_APPEARANCE_UNDERLYING_LAYERING) + GetCharacterUnderlyingLayeringData(data) + else + if(GLOB.genital_data[current_sub_subtab]) + GetCharacterUnderlyingGenitalData(data, GLOB.genital_data[current_sub_subtab]) + +/datum/preferences/proc/GetCharacterUnderlyingUndiesData(list/data = list()) + data["underwear_overhands"] = underwear_overhands + data["undies"] = list() // some day this will be FULL of undies + var/list/underpants = list() + underpants["displayname"] = "Bottomwear" + underpants["style"] = underwear + underpants["color1"] = undie_color + underpants["color1_key"] = "undie_color" + underpants["overclothes"] = undies_overclothes + underpants["undie_command"] = PREFCMD_UNDERWEAR + underpants["over_command"] = PREFCMD_UNDERWEAR_OVERCLOTHES + data["undies"] += list(underpants) + var/list/undershirt = list() + undershirt["displayname"] = "Topwear" + undershirt["style"] = undershirt + undershirt["color1"] = shirt_color + undershirt["color1_key"] = "shirt_color" + undershirt["overclothes"] = undershirt_overclothes + undershirt["undie_command"] = PREFCMD_UNDERSHIRT + undershirt["over_command"] = PREFCMD_UNDERSHIRT_OVERCLOTHES + data["undies"] += list(undershirt) + var/list/socks = list() + socks["displayname"] = "Footwear" + socks["style"] = socks + socks["color1"] = socks_color + socks["color1_key"] = "socks_color" + socks["overclothes"] = socks_overclothes + socks["undie_command"] = PREFCMD_SOCKS + socks["over_command"] = PREFCMD_SOCKS_OVERCLOTHES + data["undies"] += list(socks) + return data + +/datum/preferences/proc/GetCharacterUnderlyingLayeringData(list/data = list()) + data["genitals"] = list() + var/list/allnads = list() + for(var/hasbit in GLOB.genital_data) + var/datum/genital_data/GD = GLOB.genital_data[hasbit] + if(!GD.CanLayer()) + continue + allnads += GD + var/indecency = 1 + for(var/datum/genital_data/GD in allnads) + var/gen_data = list() + gen_data["displayname"] = capitalize(GD.name) + gen_data["has_key"] = GD.has_key + var/vfbit = features[GD.vis_flags_key] + gen_data["respect_clothing"] = CHECK_BITFIELD(vfbit, GENITAL_RESPECT_CLOTHING) + gen_data["respect_underwear"] = CHECK_BITFIELD(vfbit, GENITAL_RESPECT_UNDERWEAR) + var/peen_vis_override + if(CHECK_BITFIELD(features[GD.override_key], GENITAL_ALWAYS_HIDDEN)) + peen_vis_override = "Always Hidden" + else if(CHECK_BITFIELD(features[GD.override_key], GENITAL_ALWAYS_VISIBLE)) + peen_vis_override = "Always Visible" + else + peen_vis_override = "Check Coverage" + gen_data["override_coverings"] = peen_vis_override + gen_data["see_on_others"] = CHECK_BITFIELD(features["genital_hide"], GD.hide_flag) + gen_data["has_one"] = !!features[GD.has_key] + //now for the uppydowny arrows + if(indecency > 1) + gen_data["uparrow"] = TRUE + if(indecency < LAZYLEN(GLOB.genital_data)) + gen_data["downarrow"] = TRUE + data["genitals"] += list(gen_data) + indecency++ + return data + +/datum/preferences/proc/GetCharacterUnderlyingGenitalData(list/data = list(), datum/genital_data/GD) + if(!(current_sub_subtab in GLOB.genital_data)) + data["fatal_error"] = "BONBON'S BUTT" + return data + data["this_bingus"] = list() + var/GD = GLOB.genital_data[current_sub_subtab] + var/list/genidata = list() + genidata["displayname"] = capitalize(GD.name) + genidata["one_or_some"] = GD.one_or_some + genidata["has_key"] = GD.has_key + genidata["has_one"] = !!features[GD.has_key] + genidata["can_see"] = !CHECK_BITFIELD(GD.genital_flags, GENITAL_INTERNAL) + genidata["can_color1"] = CHECK_BITFIELD(GD.genital_flags, GENITAL_CAN_RECOLOR) + genidata["color1"] = features[GD.color_key] + genidata["color1_key"] = GD.color_key + genidata["can_shape"] = CHECK_BITFIELD(GD.genital_flags, GENITAL_CAN_RESHAPE) + genidata["shape"] = features[GD.shape_key] + genidata["can_size"] = CHECK_BITFIELD(GD.genital_flags, GENITAL_CAN_RESIZE) + genidata["size"] = features[GD.size_key] + genidata["size_unit"] = GD.size_units + genidata["respect_clothing"] = CHECK_BITFIELD(features[GD.vis_flags_key], GENITAL_RESPECT_CLOTHING) + genidata["respect_underwear"] = CHECK_BITFIELD(features[GD.vis_flags_key], GENITAL_RESPECT_UNDERWEAR) + var/peen_vis_override + if(CHECK_BITFIELD(features[GD.override_key], GENITAL_ALWAYS_HIDDEN)) + peen_vis_override = "Always Hidden" + else if(CHECK_BITFIELD(features[GD.override_key], GENITAL_ALWAYS_VISIBLE)) + peen_vis_override = "Always Visible" + else + peen_vis_override = "Check Coverage" + genidata["override_coverings"] = peen_vis_override + genidata["see_on_others"] = CHECK_BITFIELD(features["genital_hide"], GD.hide_flag) + data["this_bingus"] = genidata + return data + +/datum/preferences/proc/GetLoadoutData(list/data = list()) + data["points_left"] = GetLoadoutPointsLeft() + if(data["points_left"] <= 0) + data["points_span"] = "OutOfPoints" + WashLoadoutCats() + data["primary_categories"] = GetLoadoutCategories() + data["secondary_categories"] = GetLoadoutSubcategories() + data["current_category"] = gear_category + data["current_subcategory"] = gear_subcategory + data["search"] = loadout_search + data["gear_list"] = GetGearList(gear_category, gear_subcategory, loadout_search) + return data + +/datum/preferences/proc/GetGamePreferencesData(list/data = list()) + data["subcategory_tabs"] = list( + PPT_GAME_PREFERENCES_GENERAL, + PPT_GAME_PREFERENCES_UI, + PPT_GAME_PREFERENCES_CHAT, + PPT_GAME_PREFERENCES_RUNECHAT, + PPT_GAME_PREFERENCES_GHOST, + PPT_GAME_PREFERENCES_AUDIO, + PPT_GAME_PREFERENCES_ADMIN, + PPT_GAME_PREFERENCES_CONTENT, + ) + if(!(current_subtab in data["subcategory_tabs"])) + current_subtab = PPT_GAME_PREFERENCES_GENERAL + switch(current_subtab) + if(PPT_GAME_PREFERENCES_GENERAL) + GetGamePreferencesGeneralData(data) + if(PPT_GAME_PREFERENCES_UI) + GetGamePreferencesUIData(data) + if(PPT_GAME_PREFERENCES_CHAT) + GetGamePreferencesChatData(data) + if(PPT_GAME_PREFERENCES_RUNECHAT) + GetGamePreferencesRunechatData(data) + if(PPT_GAME_PREFERENCES_GHOST) + GetGamePreferencesGhostData(data) + if(PPT_GAME_PREFERENCES_AUDIO) + GetGamePreferencesAudioData(data) + if(PPT_GAME_PREFERENCES_ADMIN) + GetGamePreferencesAdminData(data) + if(PPT_GAME_PREFERENCES_CONTENT) + GetGamePreferencesContentData(data) + return data + +#define ADD_OP(lyst, name, value, command) lyst += list(list("name" = name, "value" = value, "command" = command)) +/datum/preferences/proc/GetGamePreferencesGeneralData(list/data = list()) + var/list/op = list() + var/showtext = "Disabled (15x15)" + if(widescreenpref) + showtext = "Enabled ([CONFIG_GET(string/default_view)])" + ADD_OP(op, "Widescreen", "[showtext]", PREFCMD_WIDESCREEN_TOGGLE) + var/showtext2 = "Disabled" + if(autostand) + showtext2 = "Enabled" + ADD_OP(op, "Auto Stand", "[showtext2]", PREFCMD_AUTOSTAND_TOGGLE) + var/showtext3 = "Disabled" + if(no_tetris_storage) + showtext3 = "Enabled" + ADD_OP(op, "Force Slot Storage HUD", "[showtext3]", PREFCMD_TETRIS_STORAGE_TOGGLE) + var/showtext4 = "Disabled" + if(cb_toggles & AIM_CURSOR_ON) + showtext4 = "Enabled" + ADD_OP(op, "Gun Cursor", "[showtext4]", PREFCMD_GUNCURSOR_TOGGLE) + var/showtext5 = "None" + if(screenshake == 100) + showtext5 = "Full" + else if(screenshake != 0) + showtext5 = "[screenshake]" + ADD_OP(op, "Screen Shake", "[showtext5]", PREFCMD_SCREENSHAKE_TOGGLE) + var/showtext6 = "Only when down" + if(damagescreenshake == 1) + showtext6 = "On" + else if(damagescreenshake == 0) + showtext6 = "Off" + ADD_OP(op, "Damage Screen Shake", "[showtext6]", PREFCMD_DAMAGESCREENSHAKE_TOGGLE) + data["options"] = op + return data + +/datum/preferences/proc/GetGamePreferencesUIData(list/data = list()) + var/list/op = list() + ADD_OP(op, "UI Style", UI_style, PREFCMD_UI_STYLE) + var/showtext1 = "All" + if(tgui_lock) + showtext1 = "Primary" + ADD_OP(op, "TGUI Lock", "[showtext1]", PREFCMD_TGUI_LOCK) + var/showtext2 = "No Frills" + if(tgui_fancy) + showtext2 = "Fancy" + ADD_OP(op, "TGUI Fancy", "[showtext2]", PREFCMD_TGUI_FANCY) + ADD_OP(op, "Input Mode Hotkey", "[input_mode_hotkey]", PREFCMD_INPUT_MODE_HOTKEY) + var/showtext3 = "Unlocked" + if(buttons_locked) + showtext3 = "Locked In Place" + ADD_OP(op, "Action Buttons", "[showtext3]", PREFCMD_ACTION_BUTTONS) + var/showtext4 = "Disabled" + if(windowflashing) + showtext4 = "Enabled" + ADD_OP(op, "Window Flashing", "[showtext4]", PREFCMD_WINFLASH) + var/showtext5 = "Disabled" + if(ambientocclusion) + showtext5 = "Enabled" + ADD_OP(op, "Ambient Occlusion", "[showtext5]", PREFCMD_AMBIENTOCCLUSION) + var/showtext6 = "Manual" + if(auto_fit_viewport) + showtext6 = "Auto" + ADD_OP(op, "Fit Viewport", "[showtext6]", PREFCMD_AUTO_FIT_VIEWPORT) + var/showtext7 = "Disabled" + if(hud_toggle_flash) + showtext7 = "Enabled" + ADD_OP(op, "HUD Button Flashes", "[showtext7]", PREFCMD_HUD_TOGGLE_FLASH) + ADD_OP(op, "FPS", "[showtext8]", PREFCMD_CLIENTFPS) + data["options"] = op + return data + +/datum/preferences/proc/GetGamePreferencesChatData(list/data = list()) + var/list/op = list() + var/showtext1 = "Disabled" + if(chat_toggles & CHAT_PULLR) + showtext1 = "Enabled" + ADD_OP(op, "See Pull Requests", "[showtext1]", PREFCMD_PULL_REQUESTS) + var/showtext2 = "Disabled" + if(show_health_smilies) + showtext2 = "Enabled" + ADD_OP(op, "Show Health Smileys", "[showtext2]", PREFCMD_HEALTH_SMILEYS) + ADD_OP(op, "Max PFP Examine Image Height", "[see_pfp_max_hight]px", PREFCMD_MAX_PFP_HEIGHT) + ADD_OP(op, "Max PFP Examine Image Width", "[see_pfp_max_widht]%", PREFCMD_MAX_PFP_WIDTH) + // var/showtext3 = "Disabled" + // if(auto_ooc) + // showtext3 = "Enabled" + // ADD_OP(op, "Auto OOC", "[showtext3]", PREFCMD_AUTO_OOC) + // var/showtext4 = "Muted" + // if(chat_toggles & CHAT_BANKCARD) + // showtext4 = "Allowed" + // ADD_OP(op, "Income Updates", "[showtext4]", PREFCMD_INCOME_UPDATES) + var/showtext5 = "Muted" + if(chat_toggles & CHAT_HEAR_RADIOSTATIC) + showtext5 = "Allowed" + ADD_OP(op, "Hear Radio Static", "[showtext5]", PREFCMD_RADIO_STATIC) + var/showtext6 = "Muted" + if(chat_toggles & CHAT_HEAR_RADIOBLURBLES) + showtext6 = "Allowed" + ADD_OP(op, "Hear Radio Blurbles", "[showtext6]", PREFCMD_RADIO_BLURBLES) + if(usr.client) // byond! + if(unlock_content) + var/showtext7 = "Hidden" + if(toggles & MEMBER_PUBLIC) + showtext7 = "Public" + ADD_OP(op, "BYOND Membership Publicity", "[showtext7]", PREFCMD_BYOND_PUBLICITY) + if(unlock_content || check_rights(R_ADMIN, FALSE)) + ADD_OP(op, "OOC Color", "[ooccolor]", PREFCMD_OOC_COLOR) + ADD_OP(op, "AnonOOC Color", "[aooccolor]", PREFCMD_AOOC_COLOR) + data["options"] = op + return data + +/datum/preferences/proc/GetGamePreferencesRunechatData(list/data = list()) + var/list/op = list() + var/showtext1 = "Disabled" + if(chat_on_map) + showtext1 = "Enabled" + ADD_OP(op, "Show Runechat Chat Bubbles", "[showtext1]", PREFCMD_CHAT_ON_MAP) + ADD_OP(op, "Runechat Message Char Limit", "[max_chat_length]", PREFCMD_MAX_CHAT_LENGTH) + ADD_OP(op, "Runechat Message Width", "[chat_width]", PREFCMD_CHAT_WIDTH) + var/showtext2 = "Disabled" + if(see_fancy_offscreen_runechat) + showtext2 = "Enabled" + ADD_OP(op, "Runechat off-screen", "[showtext2]", PREFCMD_OFFSCREEN) + var/showtext3 = "Disabled" + if(see_chat_non_mob) + showtext3 = "Enabled" + ADD_OP(op, "See Runechat for non-mobs", "[showtext3]", PREFCMD_SEE_CHAT_NON_MOB) + var/showtext4 = "Disabled" + if(see_rc_emotes) + showtext4 = "Enabled" + ADD_OP(op, "See Runechat emotes", "[showtext4]", PREFCMD_SEE_RC_EMOTES) + var/showtext5 = "Disabled" + if(color_chat_log) + showtext5 = "Enabled" + ADD_OP(op, "Runechat Color in Chat Log", "[showtext5]", PREFCMD_COLOR_CHAT_LOG) + data["options"] = op + return data + +/datum/preferences/proc/GetGamePreferencesGhostData(list/data = list()) + if(!check_rights(R_ADMIN, FALSE)) + data["options"] = list( + "name" = "Hey, you're not an admin! Nice job finding this, please report error code LYRA'S BUTT", + "value" = "Oh no!", + "command" = "Oh no!", + ) + return data + var/list/op = list() + var/showtext1 = "Nearest Creatures" + if(chat_toggles & CHAT_GHOSTEARS) + showtext1 = "All Speech" + ADD_OP(op, "Hear All Speech", "[showtext1]", PREFCMD_GHOST_EARS) + var/showtext2 = "No Messages" + if(chat_toggles & CHAT_GHOSTRADIO) + showtext2 = "All Messages" + ADD_OP(op, "Hear All Radios", "[showtext2]", PREFCMD_GHOST_RADIO) + var/showtext3 = "Nearest Creatures" + if(chat_toggles & CHAT_GHOSTSIGHT) + showtext3 = "All Emotes" + ADD_OP(op, "See All Emotes", "[showtext3]", PREFCMD_GHOST_SIGHT) + var/showtext4 = "Nearest Creatures" + if(chat_toggles & CHAT_GHOSTWHISPER) + showtext4 = "All Speech" + ADD_OP(op, "Hear All Whispers", "[showtext4]", PREFCMD_GHOST_WHISPERS) + var/showtext500 = "Nearest Creatures" + if(chat_toggles & CHAT_GHOSTPDA) + showtext500 = "All Messages" + ADD_OP(op, "Hear All PDA Messages", "[showtext500]", PREFCMD_GHOST_PDA) + if(unlock_content || check_rights(R_ADMIN)) // ghost customization! + ADD_OP(op, "Ghost Form", "[ghost_form]", PREFCMD_GHOST_FORM) + ADD_OP(op, "Ghost Orbit", "[ghost_orbit]", PREFCMD_GHOST_ORBIT) + var/showtext5 = "If you see this something went wrong." + switch(ghost_accs) + if(GHOST_ACCS_FULL) + showtext5 = GHOST_ACCS_FULL_NAME + if(GHOST_ACCS_DIR) + showtext5 = GHOST_ACCS_DIR_NAME + if(GHOST_ACCS_NONE) + showtext5 = GHOST_ACCS_NONE_NAME + // Ghost Accessories + ADD_OP(op, "How you look to others", "[showtext5]", PREFCMD_GHOST_ACCS) + var/showtext6 = "If you see this something went wrong." + switch(ghost_others) + if(GHOST_OTHERS_THEIR_SETTING) + showtext6 = GHOST_OTHERS_THEIR_SETTING_NAME + if(GHOST_OTHERS_DEFAULT_SPRITE) + showtext6 = GHOST_OTHERS_DEFAULT_SPRITE_NAME + if(GHOST_OTHERS_SIMPLE) + showtext6 = GHOST_OTHERS_SIMPLE_NAME + // Ghosts of Others + ADD_OP(op, "How you see others", "[showtext6]", PREFCMD_GHOST_OTHERS) + data["options"] = op + return data + +/datum/preferences/proc/GetGamePreferencesAudioData(list/data = list()) + var/list/op = list() + var/showtext1 = "Disabled" + if(toggles & SOUND_HUNTINGHORN) + showtext1 = "Enabled" + ADD_OP(op, "Hear Hunting Horn Sounds", "[showtext1]", PREFCMD_HUNTINGHORN) + var/showtext2 = "Disabled" + if(toggles & SOUND_SPRINTBUFFER) + showtext2 = "Enabled" + ADD_OP(op, "Hear Sprint Depletion Sound", "[showtext2]", PREFCMD_SPRINTBUFFER) + var/showtext3 = "Disabled" + if(toggles & SOUND_MIDI) + showtext3 = "Enabled" + ADD_OP(op, "Hear Admin MIDIs", "[showtext3]", PREFCMD_MIDIS) + var/showtext4 = "Disabled" + if(toggles & SOUND_LOBBY) + showtext4 = "Enabled" + ADD_OP(op, "Hear Lobby Music", "[showtext4]", PREFCMD_LOBBY_MUSIC) + data["options"] = op + return data + +/datum/preferences/proc/GetGamePreferencesAdminData(list/data = list()) + if(!check_rights(R_ADMIN, FALSE)) + data["options"] = list( + "name" = "Hey, you're not an admin! Nice job finding this, please report error code BUBBLECUP'S BUTT", + "value" = "Oh no!", + "command" = "Oh no!", + ) + return data + var/list/op = list() + var/showtext1 = "Disabled" + if(toggles & SOUND_ADMINHELP) + showtext1 = "Enabled" + ADD_OP(op, "Hear All Adminhelp Sounds", "[showtext1]", PREFCMD_ADMINHELP) + var/showtext2 = "Disabled" + if(toggles & ANNOUNCE_LOGIN) + showtext2 = "Enabled" + ADD_OP(op, "Announce Your Arrival", "[showtext2]", PREFCMD_ANNOUNCE_LOGIN) + var/showtext3 = "No Change" + if(toggles & COMBOHUD_LIGHTING) + showtext3 = "Full-bright" + ADD_OP(op, "Combo HUD Lighting", "[showtext3]", PREFCMD_COMBOHUD_LIGHTING) + var/showtext4 = "Disabled" + if(toggles & SPLIT_ADMIN_TABS) + showtext4 = "Enabled" + ADD_OP(op, "Split Admin Tabs", "[showtext4]", PREFCMD_SPLIT_ADMIN_TABS) + data["options"] = op + return data + +/datum/preferences/proc/GetGamePreferencesContentData(list/data = list()) + var/list/op = list() + var/showtext1 = "Disabled" + if(arousable) + showtext1 = "Enabled" + ADD_OP(op, "You can be aroused", "[showtext1]", PREFCMD_AROUSABLE) + var/showtext2 = "Disabled" + if(cit_toggles & GENITAL_EXAMINE) + showtext2 = "Enabled" + ADD_OP(op, "You can see genital examine text", "[showtext2]", PREFCMD_GENITAL_EXAMINE) + var/showtext3 = "Allowed" + if(cit_toggles & NO_BUTT_SLAP) + showtext3 = "Disallowed" + ADD_OP(op, "Your butt can be smacked", "[showtext3]", PREFCMD_BUTT_SLAP) + var/showtext4 = "Enabled" + if(cit_toggles & NO_AUTO_WAG) + showtext4 = "Disabled" + ADD_OP(op, "Your tail will wag if you're petted", "[showtext4]", PREFCMD_AUTO_WAG) + var/showtext5 = "All Disabled" + if(master_vore_toggle) + showtext5 = "Per Preferences" + ADD_OP(op, "Master Vore Toggle", "[showtext5]", PREFCMD_MASTER_VORE_TOGGLE) + var/showtext6 = "Disallowed" + if(allow_being_prey) + showtext6 = "Allowed" + ADD_OP(op, "You can be prey", "[showtext6]", PREFCMD_ALLOW_BEING_PREY) + var/showtext7 = "Disallowed" + if(allow_being_fed_prey) + showtext7 = "Allowed" + ADD_OP(op, "You can be fed prey", "[showtext7]", PREFCMD_ALLOW_BEING_FED_PREY) + var/showtext8 = "Disallowed" + if(allow_digestion_damage) + showtext8 = "Allowed" + ADD_OP(op, "You can take digestion damage", "[showtext8]", PREFCMD_ALLOW_DIGESTION_DAMAGE) + var/showtext9 = "Disallowed" + if(allow_digestion_death) + showtext9 = "Allowed" + ADD_OP(op, "You can die from digestion", "[showtext9]", PREFCMD_ALLOW_DIGESTION_DEATH) + var/showtext10 = "Hidden" + if(allow_vore_messages) + showtext10 = "Visible" + ADD_OP(op, "You can see vore messages", "[showtext10]", PREFCMD_ALLOW_VORE_MESSAGES) + var/showtext11 = "Hidden" + if(allow_trash_messages) + showtext11 = "Visible" + ADD_OP(op, "You can see trash messages", "[showtext11]", PREFCMD_ALLOW_TRASH_MESSAGES) + var/showtext12 = "Hidden" + if(allow_death_messages) + showtext12 = "Visible" + ADD_OP(op, "You can see death messages", "[showtext12]", PREFCMD_ALLOW_DEATH_MESSAGES) + var/showtext13 = "Muted" + if(allow_eating_sounds) + showtext13 = "Audible" + ADD_OP(op, "You can hear eating sounds", "[showtext13]", PREFCMD_ALLOW_EATING_SOUNDS) + var/showtext14 = "Muted" + if(allow_digestion_sounds) + showtext14 = "Audible" + ADD_OP(op, "You can hear digestion sounds", "[showtext14]", PREFCMD_ALLOW_DIGESTION_SOUNDS) + data["options"] = op + return data + +/datum/preferences/proc/Keybindings(list/data = list()) + data["hotkeys_mode"] = hotkeys_mode + data["categories"] = list() + for(var/cat in GLOB.keybindings_by_category) + data["categories"] += cat + // and the keybinds for this category + data["keybindings"] = list() + if(!(keybind_category in GLOB.keybindings_by_category)) + keybind_category = GLOB.keybindings_by_category[1] + data["current_category"] = keybind_category + // Create an inverted list of keybindings -> key + var/list/user_binds = list() + var/list/user_modless_binds = list() + for (var/key in key_bindings) + for(var/kb_name in key_bindings[key]) + user_binds[kb_name] += list(key) + for (var/key in modless_key_bindings) + user_modless_binds[modless_key_bindings[key]] = key + for(var/keybind in GLOB.keybindings_by_category[keybind_category]) + var/datum/keybinding/KB = GLOB.keybindings_by_category[keybind_category][keybind] + var/current_independent_binding = "Unbound" + if(user_modless_binds[KB.name]) + current_independent_binding = user_modless_binds[KB.name] + var/list/kb_data = list() + var/list/ourbinds = user_binds[KB.name] + var/list/defaultbinds = hotkeys ? KB.classic_keys : KB.hotkey_keys + var/bind1 = LAZYACCESS(ourbinds, 1) || LAZYACCESS(defaultbinds, 1) + var/bind2 = LAZYACCESS(ourbinds, 2) || LAZYACCESS(defaultbinds, 2) + var/bind3 = LAZYACCESS(ourbinds, 3) || LAZYACCESS(defaultbinds, 3) + var/defaults = defaultbinds.Join(", ") + kb_data["displayname"] = KB.full_name + kb_data["description"] = KB.description + kb_data["key1"] = bind1 + kb_data["key2"] = bind2 + kb_data["key3"] = bind3 + kb_data["default"] = defaults + kb_data["independent_key"] = current_independent_binding + data["keybindings"] += list(kb_data) + return data + +/datum/preferences/proc/GetLoadoutPointsLeft() + var/gear_points = CONFIG_GET(number/initial_gear_points) + var/list/chosen_gear = loadout_data["SAVE_[loadout_slot]"] + if(chosen_gear) + for(var/loadout_item in chosen_gear) + var/loadout_item_path = loadout_item[LOADOUT_ITEM] + if(loadout_item_path) + var/datum/gear/loadout_gear = text2path(loadout_item_path) + if(loadout_gear) + gear_points -= initial(loadout_gear.cost) + return gear_points + +/datum/preferences/proc/GetLoadoutCategories() + var/list/cats = list() + cats += LOADOUT_CATEGORY_EQUIPPED + for(var/cat in GLOB.loadout_categories) + cats += cat + return cats + +/datum/preferences/proc/GetLoadoutSubcategories() + if(gear_category == GEAR_CAT_ALL_EQUIPPED) + return list("My Stuff") + if(loadout_search) + return list("Results") + var/list/subcats = list() // merek + for(var/subcat in GLOB.loadout_categories[gear_category]) + subcats += subcat // merek + return subcats + +/datum/preferences/proc/GetGearList(gear_category, gear_subcategory, loadout_search) + var/list/gearlist = list() // merek + // okay this can go one (or two) of two (or three) ways + // 1. we're searching for something + // which gets everything that relates to the search, + // which *then* gets capped at some point + // 2. we're looking at all equipped gear + // which gets everything that's equipped, and thats it + // 3. we're looking at a specific subcategory + // which gets everything in that category, and thats it + // and it checks those things, in that order! + + if(loadout_search) + var/found = 0 + for(var/gname in GLOB.flat_loadout_items) + if(found > 50) + break + if(findtext(gname, loadout_search)) + gearlist += gname + found++ + + else if(gear_category == GEAR_CAT_ALL_EQUIPPED) + var/list/my_saved = loadout_data["SAVE_[loadout_slot]"] + for(var/list/loadout_gear in my_saved) + var/gpat = loadout_gear[LOADOUT_ITEM] + if(istype(GLOB.flat_loadout_items[gpat], /datum/gear)) + gearlist += GLOB.flat_loadout_items[gpat] + else + // this is a bad thing, we should remove it + loadout_data["SAVE_[loadout_slot]"] -= loadout_gear + else + if(!LAZYLEN(GLOB.loadout_items[gear_category]) || !LAZYLEN(GLOB.loadout_items[gear_category][gear_subcategory])) + WashLoadoutCats() // quick! get us to safety! + for(var/pathG in GLOB.loadout_items[gear_category][gear_subcategory]) + var/datum/gear/G = GLOB.loadout_items[gear_category][gear_subcategory][pathG] + if(G) + gearlist += G + // now we have the stuff! now, lets turn em into juicy tgui + var/list/geardata = list() + for(var/datum/gear/loag in gearlist) + var/list/cooldat = list() + var/list/gots = has_loadout_gear(loadout_slot, loag.name) + if(gots) + cooldat["has"] = TRUE + if(LAZYLEN(gots[LOADOUT_CUSTOM_NAME])) + cooldat["displayname"] = gots[LOADOUT_CUSTOM_NAME] + cooldat["renamed"] = TRUE + if(LAZYLEN(gots[LOADOUT_CUSTOM_DESCRIPTION])) + cooldat["description"] = gots[LOADOUT_CUSTOM_DESCRIPTION] + cooldat["redesc"] = TRUE + if(LAZYLEN(gots[LOADOUT_CUSTOM_COLOR])) + cooldat["color"] = gots[LOADOUT_CUSTOM_COLOR] + else + cooldat["displayname"] = loag.name + cooldat["description"] = loag.description + cooldat["cost"] = loag.cost + cooldat["gear_path"] = loag.path + cooldat["can_afford"] = (gear_points - loag.cost) >= 0 + geardata += list(cooldat) + return geardata + +// meow +/datum/preferences/proc/WashLoadoutCats() + if(gear_category == GEAR_CAT_ALL_EQUIPPED) + gear_subcategory = "My Stuff" + return + if(loadout_search) + gear_category = "Search Results" + gear_subcategory = "Results" + return + if(!LAZYLEN(GLOB.loadout_items[gear_category])) + for(var/cat in GLOB.loadout_categories) + if(cat == gear_category) + continue + if(LAZYLEN(GLOB.loadout_items[cat])) + gear_category = cat + gear_subcategory = GLOB.loadout_categories[cat][1] + return + stack_trace("WashLoadoutCats: No valid categories found!") + return + if(!LAZYLEN(GLOB.loadout_items[gear_category][gear_subcategory])) + for(var/subcat in GLOB.loadout_categories[gear_category]) + if(subcat == gear_subcategory) + continue + if(LAZYLEN(GLOB.loadout_items[gear_category][subcat])) + gear_subcategory = subcat + return + stack_trace("WashLoadoutCats: No valid subcategories found!") + return + // finally, we're good + return + +/datum/preferences/proc/SanitizeMarking(list/marking) + if(!islist(marking)) + marking = list() + marking.len = 4 + var/list/colist = marking[MARKING_COLOR_LIST] + colist.len = 3 + if(!LAZYACCESS(colist, 1)) + colist[1] = features["mcolor"] + if(!LAZYACCESS(colist, 2)) + colist[2] = features["mcolor2"] + if(!LAZYACCESS(colist, 3)) + colist[3] = features["mcolor3"] + marking[MARKING_COLOR_LIST] = colist + if(!LAZYLEN(marking[MARKING_UID])) + marking[MARKING_UID] = GenerateMarkingUID() + return marking + + + +/* + if(current_subtab == PPT_CHARCTER_APPEARANCE_UNDERLYING) + GetCharacterUnderlyingData(data) + data["subsubcategory_tabs_line1"] = list( + PPT_CHARCTER_APPEARANCE_UNDERLYING_UNDIES, + PPT_CHARCTER_APPEARANCE_UNDERLYING_LAYERING, + ) + data["subsubcategory_tabs_genitals"] = list() + for(var/hasbit in GLOB.genital_data) + var/datum/genital_data/GD = GLOB.genital_data[hasbit] + data["subsubcategory_tabs_genitals"] += GD.has_key + + */ + + +// Author: GremlingSS +// Not all of my work, it's porting over vorestation's gradient system into TG and adapting it basically. +// This is gonna be fun, wish me luck!~ +// +// Also, as obligated to my coding standards, I must design a shitpost related to the code, but because it's hard to think of a meme +// I'm gonna just pull one out my ass and hope it's funny. + + +/* // Disabled random features from providing random gradients, simply to avoid reloading save file errors. +random_features(intendedspecies, intended_gender) + . = ..(intendedspecies, intended_gender) + + var/grad_color = random_color() + + var/list/output = . + + output += list( + "grad_color" = grad_color, + "grad_style" = pick(GLOB.hair_gradients)) + + return output + + +randomize_human(mob/living/carbon/human/H) +// H.dna.features["flavor_text"] = "" // I'm so tempted to put lorem ipsum in the flavor text so freaking badly please someone hold me back god. + H.dna.features["grad_color"] = random_color() + H.dna.features["grad_style"] = pick(GLOB.hair_gradients) + ..(H) +*/ + +/mob/living/carbon/human/proc/change_hair_gradient(hair_gradient) + if(dna.features["grad_style"] == hair_gradient) + return + + if(!(hair_gradient in GLOB.hair_gradients)) + return + + dna.features["grad_style"] = hair_gradient + + update_hair() + return 1 + + + +/datum/preferences/process_link(mob/user, list/href_list) + switch(href_list["task"]) + if("input") + switch(href_list["preference"]) + // if("grad_color") + // var/new_grad_color = input(user, "Choose your character's fading hair colour:", "Character Preference","#"+features["grad_color"]) as color|null + // if(new_grad_color) + // features["grad_color"] = sanitize_hexcolor(new_grad_color, 6, default = COLOR_ALMOST_BLACK) + + // if("grad_style") + // var/new_grad_style + // new_grad_style = input(user, "Choose your character's hair fade style:", "Character Preference") as null|anything in GLOB.hair_gradients + // if(new_grad_style) + // features["grad_style"] = new_grad_style + + // if("grad_color_2") + // var/new_grad_color = input(user, "Choose your character's fading hair colour:", "Character Preference","#"+features["grad_color_2"]) as color|null + // if(new_grad_color) + // features["grad_color_2"] = sanitize_hexcolor(new_grad_color, 6, default = COLOR_ALMOST_BLACK) + + // if("grad_style_2") + // var/new_grad_style + // new_grad_style = input(user, "Choose your character's hair fade style:", "Character Preference") as null|anything in GLOB.hair_gradients + // if(new_grad_style) + // features["grad_style_2"] = new_grad_style + + // if("hair_color_2") + // var/new_color = input(user, "Choose your character's fading hair colour:", "Character Preference","#"+features["hair_color_2"]) as color|null + // if(new_color) + // features["hair_color_2"] = sanitize_hexcolor(new_color, 6, default = COLOR_ALMOST_BLACK) + + if("hair_style_2") + var/new_style + new_style = input(user, "Choose your character's hair fade style:", "Character Preference") as null|anything in GLOB.hair_styles_list + if(new_style) + features["hair_style_2"] = new_style + + // if("previous_hair_style_2") + // features["hair_style_2"] = previous_list_item(features["hair_style_2"], GLOB.hair_styles_list) + + // if("next_hair_style_2") + // features["hair_style_2"] = next_list_item(features["hair_style_2"], GLOB.hair_styles_list) + ..() + + diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index f7da361c3a..1e1c91b872 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -49,7 +49,7 @@ /datum/preferences/proc/update_preview_icon(current_tab) var/equip_job = TRUE switch(current_tab) - if(APPEARANCE_TAB) + if(PPT_CHARCTER_APPEARANCE) equip_job = FALSE if(ERP_TAB) equip_job = FALSE @@ -74,7 +74,7 @@ mannequin.add_overlay(the_floor) copy_to(mannequin, initial_spawn = TRUE, sans_underpants = preview_hide_undies) - if(current_tab == LOADOUT_TAB) + if(current_tab == PPT_LOADOUT) //give it its loadout if not on the appearance tab SSjob.equip_loadout(parent.mob, mannequin, FALSE, bypass_prereqs = TRUE, can_drop = FALSE) else diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm index 0f31003e39..768a75b99a 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm @@ -81,6 +81,56 @@ /datum/sprite_accessory/proc/is_not_visible(mob/living/carbon/human/H, tauric) //return if the accessory shouldn't be shown return FALSE +/datum/sprite_accessory/proc/ShouldHaveSecondaryColor() //return if the accessory shouldn't be shown + if(color_src == MATRIXED) + if(matrixed_sections in list(MATRIX_RED_BLUE, MATRIX_GREEN_BLUE, MATRIX_RED_GREEN, MATRIX_ALL)) + return TRUE + return TRUE + else if(extra) + if(extra_color_src in list(MUTCOLORS, MUTCOLORS2, MUTCOLORS3)) + return TRUE + return FALSE + +/datum/sprite_accessory/proc/ShouldHaveTertiaryColor() //return if the accessory shouldn't be shown + if(!ShouldHaveSecondaryColor()) + return FALSE // BUT THE PERFORMANCE HIT how about i hit you + if(color_src == MATRIXED) + if(matrixed_sections == MATRIX_ALL) + return TRUE + else if(extra2) + if(extra2_color_src in list(MUTCOLORS, MUTCOLORS2, MUTCOLORS3)) + return TRUE + return FALSE + + /// pooj's hall of shame +/* + dat += "Primary Color
" + dat += "    Change
" + if((accessory.color_src == MATRIXED && (matrixed_sections == MATRIX_RED_BLUE || matrixed_sections == MATRIX_GREEN_BLUE || matrixed_sections == MATRIX_RED_GREEN || matrixed_sections == MATRIX_ALL)) || (accessory.extra && (accessory.extra_color_src == MUTCOLORS || accessory.extra_color_src == MUTCOLORS2 || accessory.extra_color_src == MUTCOLORS3))) + dat += "Secondary Color
" + dat += "    Change
" + if((accessory.color_src == MATRIXED && matrixed_sections == MATRIX_ALL) || (accessory.extra2 && (accessory.extra2_color_src == MUTCOLORS || accessory.extra2_color_src == MUTCOLORS2 || accessory.extra2_color_src == MUTCOLORS3))) + dat += "Tertiary Color
" + dat += "    Change
" + if((accessory.color_src == MATRIXED && \ + (matrixed_sections == MATRIX_RED_BLUE || \ + matrixed_sections == MATRIX_GREEN_BLUE || \ + matrixed_sections == MATRIX_RED_GREEN || \ + matrixed_sections == MATRIX_ALL)) || \ + (accessory.extra && \ + (accessory.extra_color_src == MUTCOLORS || \ + accessory.extra_color_src == MUTCOLORS2 || \ + accessory.extra_color_src == MUTCOLORS3))) // WTF IS THIS CONDITONAL, HOLY SHYT POOJ + dat += ColorBox(secondary_feature) + if((accessory.color_src == MATRIXED && matrixed_sections == MATRIX_ALL) || \ + (accessory.extra2 && \ + (accessory.extra2_color_src == MUTCOLORS || \ + accessory.extra2_color_src == MUTCOLORS2 || \ + accessory.extra2_color_src == MUTCOLORS3))) + dat += ColorBox(tertiary_feature) + + */ + /datum/sprite_accessory/underwear icon = 'icons/mob/clothing/underwear.dmi' var/has_color = FALSE @@ -88,3 +138,8 @@ var/covers_groin = FALSE var/covers_chest = FALSE var/covers_belly = FALSE + + + + + diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 2748f6aed0..e2b9a67688 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -589,7 +589,7 @@ GLOBAL_VAR_INIT(crotch_call_cooldown, 0) if("change_genital_whitelist") if(!client?.prefs) return - client.prefs.update_genital_whitelist() + client.prefs.ChangePHUDWhitelist() SSpornhud.request_every_genital(src) update_body(TRUE) show_genital_hide_panel() diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 15e715341d..37b867950f 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1851,7 +1851,7 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) stop_wagging_tail(target) return FALSE else if(aim_for_groin && (target == user || target.lying || same_dir) && (target_on_help || target_restrained || target_aiming_for_groin)) - if(target.client?.prefs.cit_toggles & NO_ASS_SLAP) + if(target.client?.prefs.cit_toggles & NO_BUTT_SLAP) to_chat(user,"A force stays your hand, preventing you from slapping \the [target]'s ass!") return FALSE user.do_attack_animation(target, ATTACK_EFFECT_ASS_SLAP) diff --git a/fortune13.dme b/fortune13.dme index 4131d662da..0ec7d2e81b 100644 --- a/fortune13.dme +++ b/fortune13.dme @@ -1798,6 +1798,7 @@ #include "code\modules\antagonists\wizard\equipment\spellbook.dm" #include "code\modules\antagonists\xeno\xeno.dm" #include "code\modules\arousal\arousal.dm" +#include "code\modules\arousal\genital_data.dm" #include "code\modules\arousal\genitals.dm" #include "code\modules\arousal\genitals_sprite_accessories.dm" #include "code\modules\arousal\organs\belly.dm" @@ -1963,7 +1964,9 @@ #include "code\modules\client\message.dm" #include "code\modules\client\player_details.dm" #include "code\modules\client\preferences.dm" +#include "code\modules\client\preferences_actions.dm" #include "code\modules\client\preferences_savefile.dm" +#include "code\modules\client\preferences_tabs.dm" #include "code\modules\client\preferences_toggles.dm" #include "code\modules\client\preferences_vr.dm" #include "code\modules\client\verbs\aooc.dm" @@ -3846,7 +3849,6 @@ #include "fallout\misc\staffchat.dm" #include "interface\interface.dm" #include "interface\menu.dm" -#include "interface\stylesheet.dm" #include "interface\skin.dmf" #include "modular_citadel\code\datums\components\souldeath.dm" #include "modular_citadel\code\datums\status_effects\chems.dm" diff --git a/html/browser/common.css b/html/browser/common.css index 4e21f77185..d49e0a0a75 100644 --- a/html/browser/common.css +++ b/html/browser/common.css @@ -1,14 +1,17 @@ @import url('https://fonts.googleapis.com/css2?family=Almendra:ital,wght@0,400;0,700;1,400;1,700&display=swap'); +@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css'); +@import 'html/browser/cool.css'; body { padding: 0; margin: 0; background: #000000; color: #890200; - font-size: 16px; + font-size: 12px; font-family: 'VT323', Courier; color: #890200; - line-height: 170%; + line-height: 100%; + box-sizing: border-box; } hr @@ -23,12 +26,12 @@ a, button, a:link, a:visited, a:active, .linkOn, .linkOff text-decoration: none; padding: 1px 4px 1px 4px; margin: 0 2px 0 0; - cursor:default; + cursor:pointer; } a:hover { background-color: #5DC966; - color: black; + color: lime; } a.white, a.white:link, a.white:visited, a.white:active @@ -146,11 +149,13 @@ h4 .uiContent { - animation: scroll 0.25s 1; - clear: both; - padding: 16px; - font-family: Verdana, Geneva, sans-serif; - + width: auto; + height: 100%; + margin: 0px; + padding: 2px; + color: lime; + box-sizing: border-box; + font-family: 'Courier New', Courier, monospace; } .good @@ -388,13 +393,11 @@ ul { ul a:before, p a:before { color: #00dd00; - content: ' > '; } ul a:after, p a:after { color: #00dd00; - content: ' '; } ul.sparse { padding-bottom:20px; @@ -665,3 +668,4 @@ td.undies_cell { text-align: center; } + diff --git a/html/browser/cool.css b/html/browser/cool.css new file mode 100644 index 0000000000..7455b14755 --- /dev/null +++ b/html/browser/cool.css @@ -0,0 +1,807 @@ +/* + Container for the Tab Table +*/ +table.TabHeader { + border: 1px solid green; + width: 100%; + margin: 0px; + padding: 0px; + font-size: inherit; + background-color: rgb(0, 32, 0); + box-sizing: border-box; +} +/* + A cell in the Tab Table + background fills the cell + text must be on one line, no wrapping +*/ +table.TabHeader td { + background-color: rgb(0, 64, 0); + border: 1px solid green; + color: rgb(0, 192, 0); + /* font-weight: bold; */ + text-align: center; + margin: auto; + padding: auto; + /* width: 100%; */ + white-space: nowrap; + box-sizing: border-box; +} +/* + The above cell when hovered over + but ONLY if its child contains an tag +*/ +table.TabHeader td:hover a { + background-color: rgba(0, 128, 0, 0.8); +} +/* + The above cell when selected + use this, instead of TabHeader +*/ +.TabCellselected { + background-color: rgba(0, 128, 0, 0.8) !important; + border: 1px solid green !important; +} +/* + tag inside a cell +*/ +table.TabHeader a { + display: inline-block; + color: lime; + background-color: rgba(0, 0, 0, 0); + width: 100%; +} +/* + The above tag when hovered over +*/ +table.TabHeader a:hover { + color: lime; + background-color: rgba(0, 128, 0, 0); +} +/* + Makes everything strikethrough +*/ +.StruckThrough { + position: relative; +} +.StruckThrough a { + color: green !important; +} + +.StruckThrough::after { + content: ""; + position: absolute; + width: 100%; + height: 1px; + top: 50%; + left: 0; + background: green; +} +/* + Container for the fancy FlexTable that is better than the Tab Table +*/ +div.FlexTable { + display: flex; + flex-direction: row; + flex-wrap: wrap; + width: 100%; + margin: 0px; + padding: 0px; + font-size: inherit; + background-color: rgb(0, 32, 0); + border: 1px solid green; + box-sizing: border-box; +} +/* + A cell in the FlexTable + background fills the cell + text must be on one line, no wrapping +*/ +div.FlexTable a { + display: flex; + text-align: center !important; + background-color: rgb(0, 64, 0); + border: 1px solid green; + color: lime; + text-align: center; + margin: 1px; + padding: auto; + white-space: nowrap; + box-sizing: border-box; + justify-content: center; + flex-direction: column; + flex: 1; +} +/* + The above cell when hovered over +*/ +div.FlexTable a:hover { + background-color: rgba(0, 128, 0, 0.8); +} + + + + + + + + +/* + Flex Container for a Setting Array +*/ +div.SettingArray { + /* display: flex; */ + flex-direction: row; + flex-wrap: wrap; + width: 100%; + margin: 0px; + padding: 0px; + font-size: inherit; + flex-basis: 100%; + /* flex: 1; */ +} + +/* + background-color: rgba(0, 64, 0); + border: 1px solid green; + color: black; + text-align: center; + margin: auto; + padding: 5px; + white-space: nowrap; + color: lime; + display: inline-block; + width: 100%; + box-sizing: border-box; + + Setting flexbox + Contains one setting name and one setting value +*/ +div.SettingFlex { + display: flex; + flex-direction: row; + width: 100%; + background-color: rgb(0, 32, 0); + box-sizing: border-box; + flex: 1; +} +/* + Setting Name +*/ +.SettingName { + display: flex; + width: auto; + padding: 5px; + font-weight: bold; + color: lime; + text-align: center; + line-height: 1; + justify-content: center; + flex-direction: column; + flex: 1; + white-space: nowrap; + box-sizing: border-box; + border: 1px solid green; +} +/* + Setting Value +*/ +.SettingFlex a { + text-decoration: none; + margin: 0px !important; + height: 100%; + display: flex; + background-color: rgb(0, 64, 0); + width: 100%; + color: lime; + line-height: 1; + justify-content: center; + flex-direction: column; + box-sizing: border-box; + border: 1px solid green; +} + +/* + Setting Value when hovered over +*/ +.SettingFlex a:hover { + background-color: green; + color: lime; +} + +/* + Flex Container for a Setting Array + Basically the same as SettingArray, but it's a column +*/ +div.SettingArrayCol { + display: flex; + flex-direction: column; + width: 100%; + margin: 0px; + padding: 0px; + font-size: inherit; + flex: 1; +} + +/* + Setting flexbox + Contains one setting name and one setting value +*/ +div.SettingFlexCol { + display: flex; + flex-direction: column; + width: 100%; + background-color: rgba(0, 32, 0); + box-sizing: border-box; + flex: 1; +} + +/* + Setting Name + Setup similar to SettingName, but it's a column +*/ +.SettingNameCol { + font-weight: bold; + padding: 5px; + color: lime; + text-align: left; + line-height: 1; + box-sizing: border-box; + border: 1px solid green; + white-space: nowrap; + display: flex; + justify-content: center; + flex-direction: column; + white-space: wrap; +} + +/* + Setting Value +*/ +div.SettingFlexCol a { + border: 1px solid green; + text-decoration: none; + padding: 5px; + display: flex; + /* margin: auto; */ + background-color: rgb(0, 64, 0); + width: 100%; + color: lime; + line-height: 1; + flex-grow: 1; + box-sizing: border-box; + word-wrap: break-word; +} +/* + Setting Value, but its not a link +*/ +div.SettingFlexColInfo { + border: 1px solid green; + padding: 5px; + display: flex; + background-color: rgb(0, 64, 0); + width: 100%; + color: lime; + line-height: 1; + flex-grow: 1; + box-sizing: border-box; +} +/* + to make it not coloumnize the text +*/ +.NotCol { + display: inline-block !important; +} + +/* + to make it not coloumnize the text +*/ +.Shrinkify { + flex-shrink: 1; + +} + +/* + Setting Value when hovered over +*/ +div.SettingFlexCol a:hover { + background-color: green; +} + +/* + The following is for semi-generic setting flexboxes +*/ + + +/* + Setting Value, but split into multiple columns +*/ +div.SettingValueSplit { + display: flex; + flex-direction: row; + background-color: rgba(0, 32, 0); + border: 1px solid green; + box-sizing: border-box; + flex: 1; +} +/* + Setting Value, but split into multiple columns +*/ +a.SettingValue { + flex-grow: 1; + width: 999px; + display: flex; +} + +/* + Setting Value, but split into multiple columns +*/ +div.SettingValueSplitRowable { + display: flex; + flex-direction: row; + background-color: rgba(0, 32, 0); + border: 1px solid green; + box-sizing: border-box; + flex-wrap: wrap; + flex-shrink: 1; +} + +/* + Setting Value, but split into multiple columns +*/ +div.SettingValueRowable { + display: flex; + flex-direction: row; + background-color: rgba(0, 32, 0); + box-sizing: border-box; + margin: 0px; + flex: 1; + flex-basis: 25%; +} + +/* + Wide Bar +*/ +.WideBar { + background-color: rgba(0, 64, 0); + border: 1px solid green; + color: black; + text-align: center; + margin: auto; + padding: 5px; + white-space: nowrap; + color: lime; + display: inline-block; + width: 100%; + box-sizing: border-box; +} +/* + Wide Bar when hovered over +*/ +.WideBar:hover { + background-color: green; + border: 1px solid green; + text-align: center; + /* width: auto; */ + color: lime; +} +/* + Wide Bar Dark +*/ +.WideBarDark { + background-color: rgba(0, 32, 0); + border: 1px solid green; + color: black; + text-align: center; + margin: auto; + padding: 5px; + white-space: nowrap; + color: lime; + display: inline-block; + width: 100%; + box-sizing: border-box; +} + + + + +/* + Link button, no relation to the Tab Table +*/ +a.BlockButton { + background-color: rgba(0, 64, 0); + border: 1px solid green; + color: black; + text-align: center; + padding: 1px; + white-space: nowrap; + color: lime; + display: inline-block; + box-sizing: border-box; +} +/* + The above button when hovered over +*/ +a.BlockButton:hover { + background-color: green; + border: 1px solid green; + text-align: center; + width: auto; + color: lime; +} +/* + Wrapper BGsplitContainer +*/ +div.BGsplitContainer { + display: flex; +} +/* + Left side of the split +*/ +div.BGsplit { + display: flex; + border: 1px solid green; + flex: 1; +} + + +/* + Wrapper for the CoolContent +*/ +div.uiContent { + /* cool subtle gradient */ + /* background: linear-gradient(to bottom, rgba(0, 128, 0, 0.3), rgba(0, 128, 0, 0.1)); */ + border: 1px solid green; + width: auto; + height: inherit; + margin: 0px; + padding: 2px; + font-size: 12px; + color: lime; + font-family: 'Courier New', Courier, monospace; +} +/* + ColorBox +*/ +div.ColorBox { + background-color: rgba(0, 64, 0); + border: 1px solid green; + color: black; + padding: 0px; + white-space: nowrap; + display: inline-block; + box-sizing: border-box; + max-width: fit-content; +} +/* + ColorContainer for the cool color thing +*/ +div.ColorContainer { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + margin: 0px; + padding: 0px; + font-size: inherit; + flex: 0 !important; +} +/* + ColorName for the cool color thing +*/ +div.ColorName { + display: flex; + justify-content: center; + flex-direction: column; + font-size: inherit; + border: 1px solid green; + margin: auto; + padding: auto; + text-align: center; + font-size: 8px; + line-height: 1; + height: 100%; +} +/* + Cool ColorBox +*/ +a.ColorBoxxo { + border: 1px solid green; + height: 100%; + margin: auto; + padding: 0px !important; + display: flex; + justify-content: center; + flex-direction: column; +} +/* + A smol button +*/ +a.SmolButton { + background-color: rgba(0, 64, 0); + border: 1px solid green; + text-align: center; + padding: 5px; + margin: auto; + white-space: nowrap; + color: lime; + box-sizing: border-box; + display: flex; + justify-content: center; + flex-direction: column; + flex-shrink: 1; + height: 100%; + flex: 1; + /* font-size: 8px; */ +} +/* + A spacer +*/ +.Spacer { + display: flex; + flex-grow: 999; + height: 0%; +} +/* + PartsContainer +*/ +div.PartsContainer { + display: flex; + flex-direction: row; + flex-wrap: wrap; + margin: 0px; + padding: 0px; + font-size: inherit; + justify-content: space-between; + flex: 1; +} +/* +A part in the PartsContainer +*/ +div.PartsFlex { + display: flex; + flex-direction: column; + background-color: rgba(0, 32, 0); + font-size: inherit; + border: 1px solid green; + flex: 1; + min-width: 150px; +} +/* +A spacer for the PartsFlex +*/ +.PartsSpacer { + display: flex; + flex-grow: 1; + flex-shrink: 1; + margin: 5px 5px 0px 0px; +} +/* + Subclass for making things be a mostly certain width +*/ +.ForceBuffer { + min-width: 100px; +} + +/* + CoolDivider, just a line +*/ +.CoolDivider { + border: 1px solid black; + margin: 0px; + padding: 0px; +} + +/* + CoolDivider, just a line +*/ +.WideDivider { + border: 2px solid black; + margin: 0px; + padding: 0px; +} + +/* + hey im smol +*/ +.SmolBox { + flex-shrink: 999 !important; + flex: 0 !important; + white-space: nowrap !important; + font-weight: normal; + justify-content: center; + flex-direction: column; +} +/* + im not so smol +*/ +.NotSoSmolBox { + white-space: wrap !important; + font-weight: normal; + justify-content: center; + flex-direction: column; +} + +/* + Loadout Description +*/ +.LoadoutDesc { + display: flex; + width: 100%; + padding: 5px; + color: lime; + line-height: 1; + font-size: 10px; + box-sizing: border-box; +} +/* + A cool diagonal line for when you cant afford it! +*/ +.CantAfford { + position: relative; +} +.CantAfford:before { + content: ''; + position: absolute; + left: -0.1em; + right: -0.1em; + top: 0.38em; + bottom: 0.38em; + color: green; + background: linear-gradient(to left top, transparent 45.5%, currentColor 47.5%, currentColor 52.5%, transparent 54.5%); + pointer-events: none; +} +/* + Shortify +*/ +.Shortify { + flex-basis: 10%; + width: 10%; + flex: 1; +} + +/* + Shortify +*/ +.Wider100 { + min-width: 150px; +} + +/* + WellPadded +*/ +.WellPadded { + justify-content: space-between; +} +.WellPadded a { + padding: 2px !important; + flex-basis: 100px !important; + white-space: nowrap; +} + +/* + A cool diagonal line for when you cant afford it! +*/ +.EditedEntry { + position: relative; +} +.EditedEntry:before { + content: '📄'; + position: absolute; + right: 0px; + bottom: 0px; + color: lime; + pointer-events: none; +} + +/* + KeyButton +*/ +.KeyButton { + background-color: rgba(0, 64, 0); + border: 1px solid green; + padding: 5px; + display: flex; + width: 100%; + color: lime; + line-height: 1; + flex-grow: 1; + box-sizing: border-box; + justify-content: center; +} + +/* + KeyBox +*/ +.KeyBox { + border: 1px solid green; + padding: 5px; + display: flex; + width: 100%; + color: lime; + line-height: 1; + flex-grow: 1; + box-sizing: border-box; + justify-content: center; +} + +/* + Words, but theyre off at a cool place? default +*/ +.DefaultKeyText { + position: relative; +} +.DefaultKeyText:before { + content: 'Default'; + font-size: 8px; + position: absolute; + right: 0px; + bottom: 0px; + color: rgb(0, 164, 0); + pointer-events: none; +} + +/* + Words, but theyre off at a cool place? Key1Text +*/ +.Key1Text { + position: relative; +} +.Key1Text:before { + content: 'Primary'; + font-size: 8px; + position: absolute; + right: 0px; + bottom: 0px; + color: rgb(0, 164, 0); + pointer-events: none; +} + +/* + Words, but theyre off at a cool place? Key2Text +*/ +.Key2Text { + position: relative; +} +.Key2Text:before { + content: 'Secondary'; + font-size: 8px; + position: absolute; + right: 0px; + bottom: 0px; + color: rgb(0, 164, 0); + pointer-events: none; +} + +/* + Words, but theyre off at a cool place? Key3Text +*/ +.Key3Text { + position: relative; +} +.Key3Text:before { + content: 'Tertiary'; + font-size: 8px; + position: absolute; + right: 0px; + bottom: 0px; + color: rgb(0, 164, 0); + pointer-events: none; +} + +/* + Words, but theyre off at a cool place? Key4Text +*/ +.Key4Text { + position: relative; +} +.Key4Text:before { + content: 'Independant'; + font-size: 8px; + position: absolute; + right: 0px; + bottom: 0px; + color: rgb(0, 164, 0); + pointer-events: none; +} + + diff --git a/modular_citadel/code/modules/client/loadout/_loadout.dm b/modular_citadel/code/modules/client/loadout/_loadout.dm index 2ce4db1c19..1c8d123160 100644 --- a/modular_citadel/code/modules/client/loadout/_loadout.dm +++ b/modular_citadel/code/modules/client/loadout/_loadout.dm @@ -5,7 +5,9 @@ // and lastly, restricted_roles list allows you to let someone spawn with certain items only if the job they spawned with is on the list. GLOBAL_LIST_EMPTY(loadout_items) +GLOBAL_LIST_EMPTY(flat_loadout_items) GLOBAL_LIST_EMPTY(loadout_whitelist_ids) +GLOBAL_LIST_EMPTY(loadout_categories) /proc/load_loadout_config(loadout_config) if(!loadout_config) @@ -26,14 +28,19 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids) /proc/initialize_global_loadout_items() load_loadout_config() + var/list/flatlyss = list() + var/list/fatlyss = list() for(var/item in subtypesof(/datum/gear)) var/datum/gear/I = item if(!initial(I.name)) continue I = new item - LAZYINITLIST(GLOB.loadout_items[I.category]) - LAZYINITLIST(GLOB.loadout_items[I.category][I.subcategory]) - GLOB.loadout_items[I.category][I.subcategory][I.name] = I + LAZYINITLIST(fatlyss[I.category]) + LAZYINITLIST(fatlyss[I.category][I.subcategory]) + fatlyss[I.category][I.subcategory] += I + flatlyss += I + LAZYINITLIST(GLOB.loadout_categories[I.category]) + GLOB.loadout_categories[I.category] |= I.subcategory if(islist(I.geargroupID)) var/list/ggidlist = I.geargroupID I.ckeywhitelist = list() @@ -42,6 +49,18 @@ GLOBAL_LIST_EMPTY(loadout_whitelist_ids) I.ckeywhitelist |= GLOB.loadout_whitelist_ids["[entry]"] else if(I.geargroupID in GLOB.loadout_whitelist_ids) I.ckeywhitelist = GLOB.loadout_whitelist_ids["[I.geargroupID]"] + flatlyss = sort_list(flatlyss, /proc/cmp_gear_name_asc) + for(var/datum/gear/item in flatlyss) + GLOB.flat_loadout_items[item.type] = item + for(var/cat in fatlyss) + for(var/subcat in fatlyss[cat]) + fatlyss[cat][subcat] = sort_list(fatlyss[cat][subcat], /proc/cmp_gear_name_asc) + for(var/datum/gear/item in fatlyss[cat][subcat]) + LAZYINITLIST(GLOB.loadout_items[item.category]) + LAZYINITLIST(GLOB.loadout_items[item.category][item.subcategory]) + GLOB.loadout_items[item.category][item.subcategory][item.type] = item + + /datum/gear diff --git a/modular_coyote/code/modules/hair_gradient/hair_gradient.dm b/modular_coyote/code/modules/hair_gradient/hair_gradient.dm index 45aab296c9..b9e13573c9 100644 --- a/modular_coyote/code/modules/hair_gradient/hair_gradient.dm +++ b/modular_coyote/code/modules/hair_gradient/hair_gradient.dm @@ -1,164 +1,4 @@ -// Author: GremlingSS -// Not all of my work, it's porting over vorestation's gradient system into TG and adapting it basically. -// This is gonna be fun, wish me luck!~ -// -// Also, as obligated to my coding standards, I must design a shitpost related to the code, but because it's hard to think of a meme -// I'm gonna just pull one out my ass and hope it's funny. - -// Globals/helpers/randomness. -GLOBAL_LIST_INIT(hair_gradients, list( - "None" = "none", - "Fade (Up)" = "fadeup", - "Fade (Down)" = "fadedown", - "Fade Low (Up)" = "fadeup_low", - "Bottom Flat" = "bottomflat", - "Fade Low (Down)" = "fadedown_low", - "Vertical Split" = "vsplit", - "Reflected" = "reflected", - "Reflected (Inverted)" = "reflected_inverse", - "Reflected High" = "reflected_high", - "Reflected High (Inverted)" = "reflected_inverse_high", - "Wavy" = "wavy", - "Striped" = "striped", - "Reversed Stripe" = "stripedreverse", - "Squigly" = "squigly", - "Swayed" = "sinewave", - "Vertical Swayed" = "sinewavesideways", - "Mixy" = "dots", - "Mixy Faded Down" = "fadedowndots", - "Spots" = "skrell_gradient_spots", - "Stripey" = "skr_headtail_stripes", //My beloved - "Horizontal Fading Stripes" = "stripeshorzfade", - "Horizontal Stripes" = "stripeshorz", - "Vertical Fading Stripes" = "stripesvertfaded", - "Vertical Stripes" = "stripesvert", - "Swirly" = "swirls", - "Suspect" = "amogus" //ඞ// - )) - -/* // Disabled random features from providing random gradients, simply to avoid reloading save file errors. -random_features(intendedspecies, intended_gender) - . = ..(intendedspecies, intended_gender) - - var/grad_color = random_color() - - var/list/output = . - - output += list( - "grad_color" = grad_color, - "grad_style" = pick(GLOB.hair_gradients)) - - return output - - -randomize_human(mob/living/carbon/human/H) -// H.dna.features["flavor_text"] = "" // I'm so tempted to put lorem ipsum in the flavor text so freaking badly please someone hold me back god. - H.dna.features["grad_color"] = random_color() - H.dna.features["grad_style"] = pick(GLOB.hair_gradients) - ..(H) -*/ - -/mob/living/carbon/human/proc/change_hair_gradient(var/hair_gradient) - if(dna.features["grad_style"] == hair_gradient) - return - - if(!(hair_gradient in GLOB.hair_gradients)) - return - - dna.features["grad_style"] = hair_gradient - - update_hair() - return 1 - -// Preferences + save file/copy_to and stuff. -/datum/preferences - var/list/features_override = list("grad_style" = "None", "grad_color" = "333333") - -// Moved this to preferences_savefile.dm as we're having issues with overriding the function I think. -// My speculation is that us trying to open the save file multiple times with multiple users is causing a memory overflow on the server end and refusing to open it -// Though surely it would alteast warn us?? IDK. There's no way to debug this live. That's atleast what I think is happening, as it's strange that it works locally, but not server side. -/* -/datum/preferences/load_character(slot) - . = ..() - if(!(. == 1)) - return . // There's an error!! - - var/savefile/S = new /savefile(path) - S.cd = "/character[slot]" - - S["gradient_color"] >> features_override["grad_color"] - S["gradient_style"] >> features_override["grad_style"] - - features_override["grad_color"] = sanitize_hexcolor(features_override["grad_color"], 6, FALSE, default = COLOR_ALMOST_BLACK) - features_override["grad_style"] = sanitize_inlist(features_override["grad_style"], GLOB.hair_gradients, "none") - - return 1 - - -/datum/preferences/save_character() - . = ..() - - if(!(. == TRUE)) - return . // erroooooooooooorrrrrrrrrrr - - var/savefile/S = new /savefile(path) - if(!S) - return 0 - - S.cd = "/character[default_slot]" - - //Character - WRITE_FILE(S["gradient_color"] , features_override["grad_color"]) - WRITE_FILE(S["gradient_style"] , features_override["grad_style"]) - - return 1 -*/ - - -/datum/preferences/process_link(mob/user, list/href_list) - switch(href_list["task"]) - if("input") - switch(href_list["preference"]) - if("grad_color") - var/new_grad_color = input(user, "Choose your character's fading hair colour:", "Character Preference","#"+features_override["grad_color"]) as color|null - if(new_grad_color) - features_override["grad_color"] = sanitize_hexcolor(new_grad_color, 6, default = COLOR_ALMOST_BLACK) - - if("grad_style") - var/new_grad_style - new_grad_style = input(user, "Choose your character's hair fade style:", "Character Preference") as null|anything in GLOB.hair_gradients - if(new_grad_style) - features_override["grad_style"] = new_grad_style - - if("grad_color_2") - var/new_grad_color = input(user, "Choose your character's fading hair colour:", "Character Preference","#"+features_override["grad_color_2"]) as color|null - if(new_grad_color) - features_override["grad_color_2"] = sanitize_hexcolor(new_grad_color, 6, default = COLOR_ALMOST_BLACK) - - if("grad_style_2") - var/new_grad_style - new_grad_style = input(user, "Choose your character's hair fade style:", "Character Preference") as null|anything in GLOB.hair_gradients - if(new_grad_style) - features_override["grad_style_2"] = new_grad_style - - if("hair_color_2") - var/new_color = input(user, "Choose your character's fading hair colour:", "Character Preference","#"+features_override["hair_color_2"]) as color|null - if(new_color) - features_override["hair_color_2"] = sanitize_hexcolor(new_color, 6, default = COLOR_ALMOST_BLACK) - - if("hair_style_2") - var/new_style - new_style = input(user, "Choose your character's hair fade style:", "Character Preference") as null|anything in GLOB.hair_styles_list - if(new_style) - features_override["hair_style_2"] = new_style - - if("previous_hair_style_2") - features_override["hair_style_2"] = previous_list_item(features_override["hair_style_2"], GLOB.hair_styles_list) - - if("next_hair_style_2") - features_override["hair_style_2"] = next_list_item(features_override["hair_style_2"], GLOB.hair_styles_list) - ..() - -/datum/preferences/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE, initial_spawn = FALSE) - features += features_override - ..() +// hi jon +// WE DONT MODULARIZE ROUND THESE PARTS +// MOVED THIS TO THE MAIN PREFS FILE +// EAT IT diff --git a/modular_coyote/code/modules/say/soundbubbles.dm b/modular_coyote/code/modules/say/soundbubbles.dm index 698aa88dae..109d712411 100644 --- a/modular_coyote/code/modules/say/soundbubbles.dm +++ b/modular_coyote/code/modules/say/soundbubbles.dm @@ -259,49 +259,49 @@ GLOBAL_LIST_INIT(typing_indicator_max_words_spoken_list, list( return 1 */ -/datum/preferences/process_link(mob/user, list/href_list) - switch(href_list["task"]) - if("input") - switch(href_list["preference"]) - if("typing_indicator_sound") - var/new_sound = input(user, "Choose your typing sound:", "Character Pogerenfe") as null|anything in GLOB.typing_sounds - if(new_sound) - features_speech["typing_indicator_sound"] = new_sound - - if("typing_indicator_sound_play") - var/new_input = input(user, "Choose your typing sound behaviour", "I stink c:") as null|anything in GLOB.play_methods - if(new_input) - features_speech["typing_indicator_sound_play"] = new_input +// /datum/preferences/process_link(mob/user, list/href_list) +// switch(href_list["task"]) +// if("input") +// switch(href_list["preference"]) +// // if("typing_indicator_sound") +// // var/new_sound = input(user, "Choose your typing sound:", "Character Pogerenfe") as null|anything in GLOB.typing_sounds +// // if(new_sound) +// // features_speech["typing_indicator_sound"] = new_sound + +// // if("typing_indicator_sound_play") +// // var/new_input = input(user, "Choose your typing sound behaviour", "I stink c:") as null|anything in GLOB.play_methods +// // if(new_input) +// // features_speech["typing_indicator_sound_play"] = new_input - if("typing_indicator_speed") - var/new_input - new_input = input(user, "Choose your typing sound speed:", "Sound Indicator") as null|anything in GLOB.typing_indicator_speeds - if(new_input) - features_speech["typing_indicator_speed"] = new_input - - if("typing_indicator_pitch") - var/new_input = input(user, "Choose your typing sound pitch:", "Sound Indicator") as null|anything in GLOB.typing_indicator_pitches - if(new_input) - features_speech["typing_indicator_pitch"] = new_input - - if("typing_indicator_variance") - var/new_input - new_input = input(user, "Choose your typing sound variance:", "Sound Indicator") as null|anything in GLOB.typing_indicator_variances - if(new_input) - features_speech["typing_indicator_variance"] = new_input +// // if("typing_indicator_speed") +// // var/new_input +// // new_input = input(user, "Choose your typing sound speed:", "Sound Indicator") as null|anything in GLOB.typing_indicator_speeds +// // if(new_input) +// // features_speech["typing_indicator_speed"] = new_input + +// // if("typing_indicator_pitch") +// // var/new_input = input(user, "Choose your typing sound pitch:", "Sound Indicator") as null|anything in GLOB.typing_indicator_pitches +// // if(new_input) +// // features_speech["typing_indicator_pitch"] = new_input + +// // if("typing_indicator_variance") +// // var/new_input +// // new_input = input(user, "Choose your typing sound variance:", "Sound Indicator") as null|anything in GLOB.typing_indicator_variances +// // if(new_input) +// // features_speech["typing_indicator_variance"] = new_input - if("typing_indicator_volume") - var/new_input - new_input = input(user, "Choose your typing sound volume:", "Sound Indicator") as null|anything in GLOB.typing_indicator_volumes - if(new_input) - features_speech["typing_indicator_volume"] = new_input - - if("typing_indicator_max_words_spoken") - var/new_input - new_input = input(user, "Choose your maximum number of audible words: (Only animal crossing speech uses this)", "Sound Indicator") as null|anything in GLOB.typing_indicator_max_words_spoken_list - if(new_input) - features_speech["typing_indicator_max_words_spoken"] = new_input - ..() +// // if("typing_indicator_volume") +// // var/new_input +// // new_input = input(user, "Choose your typing sound volume:", "Sound Indicator") as null|anything in GLOB.typing_indicator_volumes +// // if(new_input) +// // features_speech["typing_indicator_volume"] = new_input + +// // if("typing_indicator_max_words_spoken") +// // var/new_input +// // new_input = input(user, "Choose your maximum number of audible words: (Only animal crossing speech uses this)", "Sound Indicator") as null|anything in GLOB.typing_indicator_max_words_spoken_list +// // if(new_input) +// // features_speech["typing_indicator_max_words_spoken"] = new_input +// ..() /datum/preferences/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE, initial_spawn = FALSE, sans_underpants = FALSE) features += features_speech diff --git a/sound/effects/prefsmenu/accept.ogg b/sound/effects/prefsmenu/accept.ogg new file mode 100644 index 0000000000..6d58e05fd8 Binary files /dev/null and b/sound/effects/prefsmenu/accept.ogg differ diff --git a/sound/effects/prefsmenu/accept_big.ogg b/sound/effects/prefsmenu/accept_big.ogg new file mode 100644 index 0000000000..377040705c Binary files /dev/null and b/sound/effects/prefsmenu/accept_big.ogg differ diff --git a/sound/effects/prefsmenu/accept_smol.ogg b/sound/effects/prefsmenu/accept_smol.ogg new file mode 100644 index 0000000000..f7eee6983d Binary files /dev/null and b/sound/effects/prefsmenu/accept_smol.ogg differ diff --git a/sound/effects/prefsmenu/cancel.ogg b/sound/effects/prefsmenu/cancel.ogg new file mode 100644 index 0000000000..0c2fa84429 Binary files /dev/null and b/sound/effects/prefsmenu/cancel.ogg differ diff --git a/sound/effects/prefsmenu/denied.ogg b/sound/effects/prefsmenu/denied.ogg new file mode 100644 index 0000000000..2445791c5a Binary files /dev/null and b/sound/effects/prefsmenu/denied.ogg differ diff --git a/sound/effects/prefsmenu/denied.xmp b/sound/effects/prefsmenu/denied.xmp new file mode 100644 index 0000000000..9eb8776143 --- /dev/null +++ b/sound/effects/prefsmenu/denied.xmp @@ -0,0 +1,123 @@ + + + + + 0101 + + + + EOD + 0 + + + + 4294967295 + + + + 4294967295 + + + + 4294967295 + + + + 4294967295 + + + + 4294967295 + + + + 4294967295 + + + + 4294967295 + + + + 2025-01-02T14:14:49-08:00 + Adobe Audition CC 2015.0 (Windows) + 2025-01-02T14:14:49-08:00 + 2025-01-02T14:14:49-08:00 + xmp.iid:99972fa6-71f0-fb42-bcc9-4dd02294bf6a + xmp.did:cf72ea56-f5a3-6741-9f11-3050b17f8163 + xmp.did:cf72ea56-f5a3-6741-9f11-3050b17f8163 + + + + saved + xmp.iid:cf72ea56-f5a3-6741-9f11-3050b17f8163 + 2025-01-02T14:12:46-08:00 + Adobe Audition CC 2015.0 (Windows) + /metadata + + + saved + xmp.iid:9248bbe1-070c-8f4d-9755-eaf1d9743840 + 2025-01-02T14:14:49-08:00 + Adobe Audition CC 2015.0 (Windows) + /metadata + + + created + xmp.iid:99972fa6-71f0-fb42-bcc9-4dd02294bf6a + 2025-01-02T14:14:49-08:00 + Adobe Audition CC 2015.0 (Windows) + + + + + + + CuePoint Markers + Cue + f44100 + + + CD Track Markers + Track + f44100 + + + Subclip Markers + InOut + f44100 + + + + audio/ogg; codec="vorbis" + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sound/effects/prefsmenu/deny.ogg b/sound/effects/prefsmenu/deny.ogg new file mode 100644 index 0000000000..2683948587 Binary files /dev/null and b/sound/effects/prefsmenu/deny.ogg differ diff --git a/sound/effects/prefsmenu/error.ogg b/sound/effects/prefsmenu/error.ogg new file mode 100644 index 0000000000..0df5ad1397 Binary files /dev/null and b/sound/effects/prefsmenu/error.ogg differ diff --git a/sound/effects/prefsmenu/menu_open.ogg b/sound/effects/prefsmenu/menu_open.ogg new file mode 100644 index 0000000000..4f6aaf78e8 Binary files /dev/null and b/sound/effects/prefsmenu/menu_open.ogg differ diff --git a/sound/effects/prefsmenu/menu_open_big.ogg b/sound/effects/prefsmenu/menu_open_big.ogg new file mode 100644 index 0000000000..ce466a7ac9 Binary files /dev/null and b/sound/effects/prefsmenu/menu_open_big.ogg differ diff --git a/sound/effects/prefsmenu/sub_prompt.ogg b/sound/effects/prefsmenu/sub_prompt.ogg new file mode 100644 index 0000000000..a8781a37b9 Binary files /dev/null and b/sound/effects/prefsmenu/sub_prompt.ogg differ diff --git a/sound/effects/quirkui/reset__click.ogg b/sound/effects/quirkui/reset__click.ogg index cc0adb8f80..7473114813 100644 Binary files a/sound/effects/quirkui/reset__click.ogg and b/sound/effects/quirkui/reset__click.ogg differ diff --git a/sound/effects/quirkui/reset__click.xmp b/sound/effects/quirkui/reset__click.xmp new file mode 100644 index 0000000000..f2ab1a0a8a --- /dev/null +++ b/sound/effects/quirkui/reset__click.xmp @@ -0,0 +1,77 @@ + + + + + + + + CuePoint Markers + Cue + f44100 + + + CD Track Markers + Track + f44100 + + + Subclip Markers + InOut + f44100 + + + + 2025-01-02T14:11:51-08:00 + 2025-01-02T14:11:51-08:00 + xmp.iid:47260dd7-6ac0-8f46-bd92-ae091faa1767 + xmp.did:3c6d5f3e-19c8-3e48-a977-9fc652ef58ef + xmp.did:3c6d5f3e-19c8-3e48-a977-9fc652ef58ef + + + + saved + xmp.iid:3c6d5f3e-19c8-3e48-a977-9fc652ef58ef + 2025-01-02T14:11:51-08:00 + Adobe Audition CC 2015.0 (Windows) + /metadata + + + saved + xmp.iid:47260dd7-6ac0-8f46-bd92-ae091faa1767 + 2025-01-02T14:11:51-08:00 + Adobe Audition CC 2015.0 (Windows) + / + + + + audio/ogg; codec="vorbis" + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testdoc2-A.html b/testdoc2-A.html new file mode 100644 index 0000000000..16ba71e23d --- /dev/null +++ b/testdoc2-A.html @@ -0,0 +1,221 @@ + + + + + + + + + + +
+
Tittle
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+

+

+ + + + + + +
+ Background + + Voice + + Miscellaneous +
+
+

+ +

+
+
Blurble Sound
+ Voice +
+
+
You will blurble when...
+ NEVER! +
+
+
Blurble speed
+ (1) slow +
+
+
Blurble pitch
+ (1) low +
+
+
Blurble volume
+ (1) quiet +
+
+
Max words
+ 100000 +
+
+
Runechat Color
+ +
#FF0000
+
+
+
+ +
+
+ +
+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+
+ + diff --git a/testdoc2-B.html b/testdoc2-B.html new file mode 100644 index 0000000000..19914c51b1 --- /dev/null +++ b/testdoc2-B.html @@ -0,0 +1,262 @@ + + + + + + + + + + +
+
Tittle
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+

+

+ + + + + + +
+ Background + + Voice + + Miscellaneous +
+
+

+ +

+
+
PDA Type
+ Random! +
+ +
+
PDA Color
+ +
+ #7af96c +
+
+
+
+
Backpack Type
+ Wierd shell thing +
+
+
Persistent Scars
+
+
+ Yes +
+
+ Clear em? +
+
+
+
+
+ Attribute Stats (Affects rolls) +
+
+
+
+ Strength +
+ 5 +
+
+
+ Dexterity +
+ 5 +
+
+
+ Constitution +
+ 5 +
+
+
+ Intelligence +
+ 5 +
+
+
+ Wisdom +
+ 5 +
+
+
+ Charisma +
+ 5 +
+
+
+
+
+ +
+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+
+ + diff --git a/testdoc2-C.html b/testdoc2-C.html new file mode 100644 index 0000000000..bd2c974517 --- /dev/null +++ b/testdoc2-C.html @@ -0,0 +1,399 @@ + + + + + + + + + + + +
+
Tittle
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+

+

+ + + + + + +
+ Background + + Voice + + Miscellaneous +
+
+

+ + +

+
+
+
+
+ Account ID (Do not share!) +
+
+ superlagg-manufacturing-inquisitively-7136-7001 +
+
+
+
+ Account Balance +
+
+ ∮ 391039 +
+
+
+
+
+
+
+
PDA Type
+ Random! +
+
+
PDA Ringtone
+ Suckit suckiiiiiiiiit +
+ +
+
Backpack Type
+ Wierd shell thing +
+
+
Persistent Scars
+
+
+ Yes +
+
+ Clear em? +
+
+
+
+
+ Attribute Stats (Affects rolls) +
+
+
+
+ Strength +
+ + 5 + +
+
+
+ Dexterity +
+ + 5 + +
+
+
+ Constitution +
+ + 5 + +
+
+
+ Intelligence +
+ + 5 + +
+
+
+ Wisdom +
+ + 5 + +
+
+
+ Charisma +
+ + 5 + +
+
+
+ Total +
+ + 30 / 40 + +
+
+
+ +
+ +

+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+

+
+ + diff --git a/testdoc2-D.html b/testdoc2-D.html new file mode 100644 index 0000000000..3c4f1352eb --- /dev/null +++ b/testdoc2-D.html @@ -0,0 +1,410 @@ + + + + + + + + + + +
+
Tittle
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+

+

+ + + + + + + + +
+ + General + + + + Hair and Eyes + + + + Body parts + + + + markings + + + + Unmentionables + +
+
+

+ +

+ + + + + + +
+
+
+ Species Type: +
+ + Anthrofurry + +
+ Body model: +
+ + Femur + +
+ Body Sprite: +
+ + Shadekin + +
+
+
+
+
+ Species name: +
+ + SCRUNGULOX + +
+ Blood Color: +
+ +
+ Rainbow Blood? +
+ + No way + +
+
+
+
+
+ Meat (doesnt do anything) +
+ + Avian + +
+ Taste: +
+ + Chicken + +
+ Smell: +
+ + Vaginabold + +
+
+
+
+ Scale: +
+ + 75% + +
+ Width: +
+ + 200% + +
+ Scaling +
+ + Sharp + +
+
+
+
+
+ Offset ⇅ +
+ + 0 + +
+ Offset ⇆ +
+ + 20 + +
+ Legs: +
+ + Digitittigrade + +
+
+
+
+
+ Skintone: +
+ + chud + +
+
+
+
+ + +

+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+

+
+ + diff --git a/testdoc2-E.html b/testdoc2-E.html new file mode 100644 index 0000000000..d8ed27de16 --- /dev/null +++ b/testdoc2-E.html @@ -0,0 +1,506 @@ + + + + + + + + + + +
+
+
+ + Tittle + +
+
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+

+

+ + + + + + + + +
+ + General + + + + Hair and Eyes + + + + Body parts + + + + markings + + + + Unmentionables + +
+
+

+ +

+ +
+
+
+ Eyes +
+ +
+
+
+ Hairea 1 +
+ + +
+
+
+ Hairea 2 +
+ + +
+
+
+ Facial Hair +
+ +
+
+
+

+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+

+
+ + diff --git a/testdoc2-F.html b/testdoc2-F.html new file mode 100644 index 0000000000..d1d3aa8e98 --- /dev/null +++ b/testdoc2-F.html @@ -0,0 +1,731 @@ + + + + + + + + + + + +
+
+
+ + Tittle + +
+
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+

+

+ + + + + + + + +
+ + General + + + + Hair and Eyes + + + + Body parts + + + + markings + + + + Unmentionables + +
+
+

+ +

+ + + + +
+ +
+
+
+
+ Ears +
+
+
+ Style: +
+ + < + + + > + + + Doinkies + + +
+ + + +
+
+
+
+
+ Snout +
+
+
+ Style: +
+ + < + + + > + + + Snootle + + +
+ + +
+ +
+
+
+
+
+
+ Tail +
+
+
+ Style: +
+ + < + + + > + + + RIP IT OFF + + +
+ + + +
+
+
+
+
+ Tail +
+ + + + +
+
+
+
+
+ Tail +
+
+
+ Style: +
+ + < + + + > + + + RIP IT OFF + + +
+ + + +
+
+
+
+
+
+
+
+
+ Cool robot parts: +
+
+
+ Left Arm: +
+ + + X + + + Gross gripper + +
+
+
+ Right Arm: +
+ + X + + + Grosser rupper + +
+ +
+
+
+ + + + +

+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+

+
+ + diff --git a/testdoc2-G.html b/testdoc2-G.html new file mode 100644 index 0000000000..864546e5c4 --- /dev/null +++ b/testdoc2-G.html @@ -0,0 +1,435 @@ + + + + + + + + + + +
+
+
+ + Tittle + +
+
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Keybindings +
+
+

+

+ + + + + + + + +
+ + General + + + + Hair and Eyes + + + + Body parts + + + + markings + + + + Unmentionables + +
+
+

+ +

+ + + + +
+
+
+ Cool Markings: +
+ +
+
+ Color 1: +
+ +
+ Color 2: +
+ +
+ Color 3: +
+ +
+
+
+ +
+
+ Color 1: +
+ +
+ Color 2: +
+ +
+ Color 3: +
+ +
+
+
+ +
+
+
+ + + + +

+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+

+
+ + diff --git a/testdoc2-H.html b/testdoc2-H.html new file mode 100644 index 0000000000..dd811d2cda --- /dev/null +++ b/testdoc2-H.html @@ -0,0 +1,442 @@ + + + + + + + + + + +
+
+
+ + Tittle + +
+
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+

+

+ + + + + + + + +
+ + General + + + + Hair and Eyes + + + + Body parts + + + + markings + + + + Unmentionables + +
+
+

+ +

+ + + + +
+
+
+ Cool Markings: +
+ +
+
+ Color 1: +
+ +
+ Color 2: +
+ +
+ Color 3: +
+ +
+
+
+ +
+
+ Color 1: +
+ +
+ Color 2: +
+ +
+ Color 3: +
+ +
+
+
+ + + + + +
+
+
+ + + + +

+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+

+
+ + diff --git a/testdoc2-I.html b/testdoc2-I.html new file mode 100644 index 0000000000..734f3fcd27 --- /dev/null +++ b/testdoc2-I.html @@ -0,0 +1,450 @@ + + + + + + + + + + +
+
+
+ + Tittle + +
+
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+

+

+ + + + + + + + +
+ + General + + + + Hair and Eyes + + + + Body parts + + + + markings + + + + Unmentionables + +
+
+

+ + +

+

+

+

+

+ + + +
+
+
+
+
+
+ Shirt top +
+ + +
+
+
+
+
+ Underwear +
+
+
+ Style: +
+ + < + + + > + + + skidmark + + +
+ +
+
+
+
+
+ Socks +
+ + +
+
+
+
+
+
+ + + + +

+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+

+
+ + diff --git a/testdoc2-J.html b/testdoc2-J.html new file mode 100644 index 0000000000..42f95df3dd --- /dev/null +++ b/testdoc2-J.html @@ -0,0 +1,388 @@ + + + + + + + + + + +
+
+
+ + Tittle + +
+
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+

+

+ + + + + + + + +
+ + General + + + + Hair and Eyes + + + + Body parts + + + + markings + + + + Unmentionables + +
+
+

+ + +

+

+

+
+
+
+
+ Color 1 +
+ + #FFFFFF + + + + + + + +
+
+
+ Color 1 +
+ + #FFFFFF + + + + + + + +
+
+
+ Color 1 +
+ + #FFFFFF + + + + + + + +
+ + + +
+ +
+
+

+

+ + + +
+
+
+
+ Has one: +
+ + Yes! + +
+ Color 1: +
+ +
+
+
+ Size: +
+ + 200 decigrundles + +
+ Shape: +
+ + horrifying + +
+
+
+ Hidden by: +
+ + Clothes + + + Underpants + +
+
+
+ Override: +
+ + Always visible! + +
+ See on others: +
+ + Yes! + +
+ + +
+
+
+ + + + +

+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+

+
+ + diff --git a/testdoc2-K.html b/testdoc2-K.html new file mode 100644 index 0000000000..961c017dab --- /dev/null +++ b/testdoc2-K.html @@ -0,0 +1,628 @@ + + + + + + + + + + +
+
+
+ + Tittle + +
+
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+

+

+ + + + + + + + +
+ + General + + + + Hair and Eyes + + + + Body parts + + + + markings + + + + Unmentionables + +
+
+

▲▲▲▲ + + +

+

+ +

+

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Part + + Shift + + Hidden by... + + Override + + See on others + + Has +
+ Butt + + + + + + + ⬇️ + + + + Underwear + + + + Clothes + + + + Obey Clothes + + + + Yes + + + + Yes + +
+ Belly + + + ⬆️ + + + + ⬇️ + + + + Underwear + + + + Clothes + + + + Obey Clothes + + + + Yes + + + + Yes + +
+ Breats + + + ⬆️ + + + + ⬇️ + + + + Underwear + + + + Clothes + + + + Obey Clothes + + + + Yes + + + + NO + +
+ Bingus + + + ⬆️ + + + + ⬇️ + + + + Underwear + + + + Clothes + + + + Obey Clothes + + + + Yes + + + + Yes + +
+ Tentacles + + + ⬆️ + + + + ⬇️ + + + + Underwear + + + + Clothes + + + + Obey Clothes + + + + Yes + + + + Yes + +
+ Woom + + + ⬆️ + + + + ⬇️ + + + + Underwear + + + + Clothes + + + + Obey Clothes + + + + Yes + + + + NO + +
+ Chungus + + + ⬆️ + + + + + + Underwear + + + + Clothes + + + + Obey Clothes + + + + Yes + + + + Yes + +
+ + P-Hud Whitelisting + +
+
+ + + + +

+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+

+
+ + diff --git a/testdoc2-L.html b/testdoc2-L.html new file mode 100644 index 0000000000..00c442164c --- /dev/null +++ b/testdoc2-L.html @@ -0,0 +1,481 @@ + + + + + + + + + + + +
+
+
+ + Tittle + +
+
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+
+
+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+
+ +
+ +
+
+
+ You have 10 points! +
+ + Reset + + + + + X + + + Search + +
+
+ +
+
+ +
+
+
+
+
+ +
+
+ You know you've been watching too many videos on assembly language when you see "Player cash: $3500" and your first thought is "Why are you throwing hexidecimal at me? Why not just say they have ... oh wait. DOLLAR SIGN 3500, not 0x3500" +
+
+ +
+
+
+ + Fleshlight + +
+ 1 pts +
+
+
+
+ This is a really cool implement + that is both a flashlight and a weapon. + It's really cool and you should buy it. fa-american-sign-language-interpreting + AA wow abductor abstract adminobserverooc +
+
+ +
+
+
+ + Fleshlight + +
+ 1 pts +
+
+
+
+ This is a really cool implement + that is both a flashlight and a weapon. + It's really cool and you should buy it. fa-american-sign-language-interpreting + AA wow abductor abstract adminobserverooc +
+
+
+
+
+ + Fleshlight + +
+ 1 pts +
+
+
+
+ This is a really cool implement + that is both a flashlight and a weapon. + It's really cool and you should buy it. fa-american-sign-language-interpreting + AA wow abductor abstract adminobserverooc +
+
+
+
+
+ + Fleshlight + +
+ 1 pts +
+
+
+
+ This is a really cool implement + that is both a flashlight and a weapon. + It's really cool and you should buy it. fa-american-sign-language-interpreting + AA wow abductor abstract adminobserverooc +
+
+
+
+ +
+
+ This is a really cool implement + that is both a flashlight and a weapon. + It's really cool and you should buy it. fa-american-sign-language-interpreting + AA wow abductor abstract adminobserverooc +
+
+
+
+
+
+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+
+
+ + diff --git a/testdoc2-L2.html b/testdoc2-L2.html new file mode 100644 index 0000000000..fe263d927c --- /dev/null +++ b/testdoc2-L2.html @@ -0,0 +1,24 @@ + + + + + + + + + +
+
Character Setup - Cecily Mcloskey
+
+ +
PropertiesAppearanceLoadout
Game SettingsKeybindings
You have 10 points!
ResetXSearch
A bright pin to wear with pride whereever you go!
For the big man, you need big boss smokes!.
A bright pin to wear with pride whereever you go!
It's a normal blue ink pen.
A box of crayons for all your graffiti needs.
Yep, bracelets.
A BoS issue holotag, it isnt working now though, kept as a reminder to something.
Used for sweeping, and flying into the night while cackling. Black cat not included.
Since 2057.
It's just a wooden stick with some compressed ash on the end. At least it can write.
An unmarked brand of cigarettes, some would worry about cancer, but you know you'll die well before then.
A case of imported Cohiba cigars, renowned for their strong flavor.
It can hold a few small and personal things. Easily tucked in various discrete places.
A late 20th century camera.
A white vest with black splotches. Yeehaw.
Yeah, you go hard.
A bright pin to showcase the wearer having hearing loss.
Mmm. Donuts.
An early wooden camera.
An early 20th century camera.
The latest and greatest power razor born from the science of shaving.
A and worn Vault-Tech issued ID card, broken beyond use, kept as a reminder to something.
A hand-held emergency light. Comes with a robust lanyard and set of clips for hands-free use. Neat!
It's an expensive Oak fountain pen. The nib is quite sharp.
A label on the packaging reads, \"Endorsed by Phineas, Freddy and Franklin.\"
A generic yet sleek eight-pointed star patch.
A generic chest patch with sleek, eight-pointed star on it.
I probably are a bloodsucker, or at least you tell people you are.
Imported famous cigarettes from the East Coast.
A small, circular brush with an ergonomic grip for efficient brush application.
A case of classy Havanian cigars.
Unce unce unce unce. Boop!
A bright pin to wear with pride whereever you go!
A reinforced metal collar. It seems to have some form of wiring near the front. A small lock is present, though it seems impossible to get it off anyway without external help.
A reinforced metal slave collar, with shock prongs on the inside. Reinforced metal shackles are linked to the collar with heavy chains, limiting movement.
A bright pin to wear with pride whereever you go!
a sturdy bag keeping your tools of choice safe until you pop it open.
It's a fancy four-color ink pen, set to black.
A bright pin to wear with pride whereever you go!
A collar that has a small lock on it to keep it from being removed.
This skirt is so freeing!
Pen
1 pts
It's a normal black ink pen.
A case of premium cigars. Very expensive.
A bright pin to wear with pride whereever you go!
For the fine mans Smoke.
Red Pen
1 pts
It's a normal red ink pen.
A necklace.
A rewritable card that allows you to put your name and assignment on it.
Smoked by the truly robust.
Decrepit uncared for dogtags, kept as a reminder to something.
Is your weight slowing you down? Having trouble running away from gravitational singularities? Can't stop stuffing your mouth? Smoke Shady Jim's Super Slims and watch all that fat burn away. Guaranteed results!
A magnetic tape that can hold up to ten minutes of content.
A device that can record to cassette tapes, and play them. It automatically translates the content in playback.
Everything you need as an aspiring skin artist!
torch
0 pts
A self-lighting handheld torch fashioned from some cloth wrapped around a wooden handle. It could probably fit in a backpack while it isn't burning.
Woefully underpowered in D20.
A bright pin to wear with pride whereever you go!
A firebow! An unreliable yet very useful tool to help start create fires.
Quite fashionable... if you're somebody who's just read their first BDSM-themed erotica novel.
My favorite brand, now menthol flavored.
Vape
0 pts
A classy and highly sophisticated electronic cigarette, for classy and dignified gentlemen. A warning label reads \"Warning: Do not fill with flammable materials.\"
Loaded with 100% pure slime. And also nicotine.
+ +
+
+
+
+
+ + + " + diff --git a/testdoc2-M.html b/testdoc2-M.html new file mode 100644 index 0000000000..5e0cac1ec4 --- /dev/null +++ b/testdoc2-M.html @@ -0,0 +1,334 @@ + + + + + + + + + + +
+
+
+ + Tittle + +
+
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+

+

+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+
+
+ + + + + + + + +
+ + General + + + + Runechat + + + + Ghost + + + + Unused + + + + Other stuff + +
+
+
+ +
+
+
+
+
+ Input Mode Hotkey +
+ + Tab + +
+
+
+
+
+ UI style +
+ + Midnight + +
+
+
+
+
+ TGUI monitors +
+ + Primary + +
+
+
+
+
+ Input Mode Hotkey +
+ + Tab + +
+
+
+
+
+ UI style +
+ + Midnight + +
+
+
+
+
+ TGUI monitors +
+ + Primary + +
+
+
+
+
+ Input Mode Hotkey +
+ + Tab + +
+
+
+
+
+ UI style +
+ + Midnight + +
+
+
+
+
+ TGUI monitors +
+ + Primary + +
+
+
+
+
+ Input Mode Hotkey +
+ + Tab + +
+
+
+
+
+ UI style +
+ + Midnight + +
+
+
+
+
+ TGUI monitors +
+ + Primary + +
+
+
+
+
+ + +
+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+
+
+ + diff --git a/testdoc2-N.html b/testdoc2-N.html new file mode 100644 index 0000000000..8a728b1382 --- /dev/null +++ b/testdoc2-N.html @@ -0,0 +1,234 @@ + + + + + + + + + + +
+
+
+ + Tittle + +
+
+
+ +
+ Copy + Paste + Showing 30 characters, 6 per row + Show Character List +
+
+ + + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +
+
+
+ +
+
+ + + +
+
+
+ + > + +
+ Client +
+
+
+
+
+
+ Boss Key +
+ + = + + + None! + + + None! + +
+ = +
+ + UNBOUND + +
+
+
+ + +
+ Visual Chat Options + SAVE + + + + + +
+ Undo + + DELETE +
+
+
+ + diff --git a/testdoc2-ZZ.html b/testdoc2-ZZ.html new file mode 100644 index 0000000000..e65fb3b428 --- /dev/null +++ b/testdoc2-ZZ.html @@ -0,0 +1,17 @@ + + + + + + + + + + +
+
Tittle
+
+"
PropertiesAppearanceLoadout
Game SettingsKeybindings
You have 10 points!
ResetXSearch
aesthetic gas mask
1 pts
A close-fitting mask. Alas, this one have broken filter along with hose, and could be used only for the looks or to conceal your identity.
balaclava
1 pts
LOADSAMONEY
bat mask
1 pts
A mask made of soft vinyl and latex, representing the head of a bat.
bear mask
1 pts
A mask made of soft vinyl and latex, representing the head of a bear.
bee mask
1 pts
A mask made of soft vinyl and latex, representing the head of a bee.
black kitsune mask
1 pts
A mask made of plastic and paint.
clown gas mask
1 pts
A true prankster's facial attire. A clown is incomplete without his wig and mask.
desert facewrap
1 pts
A facewrap commonly employed by NCR troops in desert environments.
desert headwrap
1 pts
A headwrap to help shield the face from sand and other dirt.
fake moustache
1 pts
Warning: moustache is fake.
fox mask
1 pts
A mask made of soft vinyl and latex, representing the head of a fox.
gas mask
1 pts
A face-covering mask that can be connected to an air supply. While good for concealing your identity, it isn't good for blocking gas flow.
jackal mask
1 pts
A mask made of soft vinyl and latex, representing the head of a jackal.
paper mask
1 pts
A neat, circular mask made out of paper.
pig mask
1 pts
A rubber pig mask with a builtin voice modulator.
rat mask
1 pts
A mask made of soft vinyl and latex, representing the head of a rat.
raven mask
1 pts
A mask made of soft vinyl and latex, representing the head of a raven.
russian balaclava
1 pts
Protects your face from snow.
scarecrow mask
1 pts
A burlap sack with eyeholes.
sexy clown gas mask
1 pts
A feminine clown mask for the dabbling crossdressers or female entertainers.
tribal mask
1 pts
A mask carved out of wood, detailed carefully by hand.
voice changing mask
1 pts
A face-covering mask that can be connected to an air supply. While good for concealing your identity, it isn't good for blocking gas flow.
white kitsune mask
1 pts
A mask made of plastic and paint.
Visual Chat OptionsSave" + + + diff --git a/testdoc2.html b/testdoc2.html index 6e52e9bd3f..9854256425 100644 --- a/testdoc2.html +++ b/testdoc2.html @@ -11,170 +11,161 @@
Tittle
UndoDelete
+ + + + + + + + + + +
+ Properties + + Appearance + + Loadout +
+ Game Settings + + Adult Settings + + Keybindings +

- - - - - - - - -
- - Undo - Save Setup - - Reset Setup -
- -
-
-
- diff --git a/testdoc3.html b/testdoc3.html index ec43accb21..2ee16c6b23 100644 --- a/testdoc3.html +++ b/testdoc3.html @@ -48,3 +48,59 @@ + + + + +table.table_genital_list { + border: 1px solid green; + width: 75%; + margin: auto; + padding: 0px; +} +td.genital_name { + background-color: rgba(0, 128, 0, 0.4); + border: 1px solid rgba(0, 128, 0, 0.3); + font-weight: bold; + text-align: center; + margin: auto; + width: auto; +} +td.genital_arrow_on { + background-color: rgba(0, 128, 0, 0.8); + outline-style: inset; + outline-width: 1px; + outline-color: green; + text-align: center; + width: auto; +} +td.genital_arrow_off { + color : rgba(0, 128, 0, 0); + background-color: rgba(0, 128, 0, 0.4); + outline-width: 1px; + outline-color: green; + text-align: center; + width: auto; +} +td.coverage_on { + background-color: rgba(0, 128, 0, 0.8); + outline-style: inset; + outline-width: 1px; + outline-color: green; + text-align: center; + width: auto; +} +td.coverage_off { + color : rgba(0, 128, 0, 0); + background-color: rgba(0, 128, 0, 0.4); + outline-style: inset; + outline-width: 1px; + outline-color: green; + text-align: center; + width: auto; +} +a.clicky_no_border { + display:inline-table; + text-align: center; + width: 90%; +} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu.js b/tgui/packages/tgui/interfaces/PreferencesMenu.js new file mode 100644 index 0000000000..39498da561 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu.js @@ -0,0 +1,2489 @@ +/* eslint-disable react/jsx-pascal-case */ +// 80 characters is not big enough for my yiff yiff +/* eslint-disable max-len */ +import { useBackend, useLocalState } from '../backend'; +import { toFixed } from 'common/math'; +import { multiline } from 'common/string'; +import { + AnimatedNumber, + Box, + Button, + ByondUi, + Divider, + Dropdown, + Flex, + Fragment, + Icon, + Input, + Knob, + LabeledList, + NoticeBox, + NumberInput, + Section, + Stack, + Table, + TextArea, + ToggleBox, + Tooltip, +} from '../components'; +import { formatMoney } from '../format'; +import { Window } from '../layouts'; +import { marked } from 'marked'; +import { sanitizeText } from '../sanitize'; + +const bigbutton_min_width = "200px"; +const LR_SettingNameWidth = "100px"; +const ColorBoxWidth = "100px"; +const DEF_TEXT_COLOR = "#00FF00"; // we hackerman now + +export const PreferencesMenu = (props, context) => { + const { act, data } = useBackend(context); + const { + real_name = "Rex Bingus", + } = data; + return ( + + + + + + + + + + + + + {/* grow shrink my beloved, you have saved so many of my garbo layouts */} +
+ +
+
+ + + +
+
+ + + +
+
+
+ ); +}; + +// This is the character select menu! Its an array of buttons that you can click +// to select a character! +const CharacterSelect = (props, context) => { + const { act, data } = useBackend(context); + const { + characters = [], + current_slot = 0, + } = data; + + return ( +
+ + {characters.map((character, index) => ( + + + + ))} + +
+ ); +}; + +// This is the character button! It's a button that you can click to select a +// character! It's a button! +const CharacterButton = (props, context) => { + const { act, data } = useBackend(context); + const { + current_slot = 0, + } = data; + const { + character, + index, + } = props; + const charname = character ? character.name : `Character ${index + 1}`; + const is_current = (index + 1) === current_slot; + + return ( +
-
[thing_name]
-
- -
+ + + Genital + + + Shift + + + Hidden by... + + + Override + + + See on Others + + + Has + + + {genitals.map((genital, index) => ( + + + {genital.displayname} + + + {genital.uparrow && ( + genital.has_one && ( + + + + ))} +
+ + ); +}; + +// This is a genital, and it lets you customize that genital! It's a set of +// buttons that you can click to change the shape and color of the genital! +// its a polymorphic menu that displays any part, with the right parameters +const HasBingus = (props, context) => { + const { act, data } = useBackend(context); + const { + this_bingus = {}, // dis fockin bingus + } = props; + const { + displayname = "", + one_or_some = "one", + has_key = "has_bingus", + has_one = false, + can_see = true, + can_color1 = false, + color1 = "000000", + color1_key = "", + can_shape = false, + shape = "None", + can_size = false, + size = "None", + size_unit = "decigrundles", + respect_clothing = false, + respect_underwear = false, + override_coverings = "None", + see_on_others = true, + } = this_bingus; + + const padwidth = "150px"; + + const colorblock = can_see && can_color1 ? ( + + + } /> + + ) : null; + const shapeblock = can_see && can_shape ? ( + + + + ) : null; + const sizeblock = can_see && can_size ? ( + + + + ) : null; + const overrideblock = can_see ? ( + + + + ) : null; + const respectclothingblock = can_see ? ( + + + + ) : null; + const respectunderwearblock = can_see ? ( + + + + ) : null; + const seeonothersblock = can_see ? ( + + + + ) : null; + + return ( +
+ + + + {displayname} + + + + + + {colorblock} + {shapeblock} + {sizeblock} + {overrideblock} + {respectclothingblock} + {respectunderwearblock} + {seeonothersblock} + +
+ ); +}; + +// This is the loadout, and its a big one! Has a few parts: +// - The header +// -- Number of points left, a button to reset, and the search bar +// - The primary categories +// - The secondary categories +// - THe rest of the damn thing +const Loadout = (props, context) => { + const { act, data } = useBackend(context); + const { + points_left = 0, + points_span = "", + search = "", + primary_categories = [], + secondary_categories = [], + current_category = "", + current_subcategory = "", + gear_list = [], + } = data; + + return ( +
+ + {/* Header */} + + + + You have + + + + + {points_left} + + + +
+ ); +}; + +// Options and preferences, this one'll suck it. +const Options = (props, context) => { + const { act, data } = useBackend(context); + const { + headder = "Cool Options", + options = [], + } = data; + + // format of options: + // [ + // { + // "displayname": "Squeeze huge boobs", + // "displayvalue": "Only while in public", + // "command": "PREFCMD_SQUEEZE_BOOBS", + // }, ... boob yeah + // ], + + return ( +
+ + {options.map((option, index) => ( + + + + ))} + +
+ ); +}; // suck it + +// And now, the keybindings. truly the worst of them all. +const Keybindings = (props, context) => { + const { act, data } = useBackend(context); + const { + keybindings = [], + categories = [], + current_category = "", + } = data; + + // format of keybindings: + // [ + // { + // displayname: "Kneed boobs", + // key1: "K", + // key2: "B", + // key3: "None", + // default: "K", + // independant_key: "Q" + // }, ... boob yeah + // ], + + return ( +
+ + {/* Categories */} + + {categories.map((category, index) => ( + +
+ ); +}; + +// save, load, horny chat button! +// also has page buttons, if needed +const SaveLoadHorny = (props, context) => { + const { act, data } = useBackend(context); + const { + pages = 1, + current_page = 1, + page_command = "PREFCMD_PAGE", + } = data; + + return ( +
+ + {pages > 1 && ( + + + +
+ ); +}; + +// the character preview! augh how does this work +const CharacterPreview = (props, context) => { + const { act, data } = useBackend(context); + + return ( +
+ +
+ ); +}; + +// This is a gear item! It has a few parts: +// - The name of the gear +// -- will have a cool diagonal slash if you can't afford it +// -- Will be selected if you gots it +// -- Will have a cool icon if the name has been edited! +// - The cost of the gear +// -- Will be red if you can't afford it, and have a cool diagonal slash +// - The description of the gear +// -- will have a cool icon if the desc has been edited! +// if you have it: +// - Button to change its name, button to change its desc, button to color it +// if you don't have it: +// - none of those +const GearItem = (props, context) => { + const { act, data } = useBackend(context); + const { + gear = {}, + } = props; + const { + displayname = "", + gear_path = "", + cost = 0, + description = "", + has = false, + can_afford = false, + renamed = false, + redesc = false, + color = "000000", + } = gear; + + const costcolor = can_afford ? DEF_TEXT_COLOR : "red"; + const costclass = can_afford ? "SettingValue" : "SettingValue GearItemCannotAfford"; + const nameclassA = has ? "SettingValueSelected" : "SettingValueDeselected"; + const nameclassB = can_afford ? "" : "GearItemCannotAfford"; + const nameclass = `${nameclassA} ${nameclassB}`; + const descclassA = redesc ? "SettingValueEdited" : "SettingValue"; + const descclassB = has ? "SettingValueSelected" : "SettingValueDeselected"; + const descclass = `${descclassA} ${descclassB}`; + + return ( + + + {/* Name and Price */} + + + + {displayname} + + + + + {cost} + + + + + {/* Description */} + + {description} + + + {has && ( + {/* Buttons */} + + +