diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 09c713f9201..a2c004a7e4d 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -367,6 +367,10 @@ #define COMSIG_MOB_CLIENT_LOGIN "comsig_mob_client_login" ///sent from borg mobs to itself, for tools to catch an upcoming destroy() due to safe decon (rather than detonation) #define COMSIG_BORG_SAFE_DECONSTRUCT "borg_safe_decon" +///sent from living mobs every tick of fire +#define COMSIG_LIVING_FIRE_TICK "living_fire_tick" +//sent from living mobs when they are ahealed +#define COMSIG_LIVING_AHEAL "living_aheal" //ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS! @@ -585,6 +589,11 @@ #define COMSIG_JOB_RECEIVED "job_received" // called after DNA is updated #define COMSIG_HUMAN_UPDATE_DNA "human_update_dna" +/// From mob/living/carbon/human/change_body_accessory(): (mob/living/carbon/human/H, body_accessory_style) +#define COMSIG_HUMAN_CHANGE_BODY_ACCESSORY "human_change_body_accessory" + #define COMSIG_HUMAN_NO_CHANGE_APPEARANCE (1<<0) +/// From mob/living/carbon/human/change_head_accessory(): (mob/living/carbon/human/H, head_accessory_style) +#define COMSIG_HUMAN_CHANGE_HEAD_ACCESSORY "human_change_head_accessory" // /datum/species signals diff --git a/code/__DEFINES/dna.dm b/code/__DEFINES/dna.dm index 10da1be145e..c24dbc17786 100644 --- a/code/__DEFINES/dna.dm +++ b/code/__DEFINES/dna.dm @@ -47,12 +47,12 @@ #define DNA_UI_GENDER 32 #define DNA_UI_BEARD_STYLE 33 #define DNA_UI_HAIR_STYLE 34 -/*#define DNA_UI_BACC_STYLE 23*/ #define DNA_UI_HACC_STYLE 35 -#define DNA_UI_HEAD_MARK_STYLE 36 -#define DNA_UI_BODY_MARK_STYLE 37 -#define DNA_UI_TAIL_MARK_STYLE 38 -#define DNA_UI_LENGTH 38 // Update this when you add something, or you WILL break shit. +#define DNA_UI_BACC_STYLE 36 +#define DNA_UI_HEAD_MARK_STYLE 37 +#define DNA_UI_BODY_MARK_STYLE 38 +#define DNA_UI_TAIL_MARK_STYLE 39 +#define DNA_UI_LENGTH 40 // Update this when you add something, or you WILL break shit. #define DNA_SE_LENGTH 55 // Was STRUCDNASIZE, size 27. 15 new blocks added = 42, plus room to grow. diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm index ea1cb9449ee..51a7ef474a5 100644 --- a/code/__DEFINES/flags.dm +++ b/code/__DEFINES/flags.dm @@ -80,11 +80,17 @@ #define HAS_HEAD_MARKINGS 64 #define HAS_BODY_MARKINGS 128 #define HAS_TAIL_MARKINGS 256 -#define HAS_MARKINGS HAS_HEAD_MARKINGS|HAS_BODY_MARKINGS|HAS_TAIL_MARKINGS #define TAIL_WAGGING 512 #define NO_EYES 1024 #define HAS_ALT_HEADS 2048 -#define ALL_RPARTS 4096 +#define HAS_WING 4096 +#define HAS_BODYACC_COLOR 8192 +#define BALD 16384 +#define ALL_RPARTS 32768 + +//Pre-baked combinations of the above body flags +#define HAS_BODY_ACCESSORY HAS_TAIL|HAS_WING +#define HAS_MARKINGS HAS_HEAD_MARKINGS|HAS_BODY_MARKINGS|HAS_TAIL_MARKINGS //Species Diet Flags #define DIET_CARN 1 diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 3105b68630a..b16a04cb143 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -162,6 +162,8 @@ #define MFOAM_IRON 2 //Human Overlays Indexes///////// +#define WING_LAYER 41 +#define WING_UNDERLIMBS_LAYER 40 #define BODY_LAYER 39 #define MUTANTRACE_LAYER 38 #define TAIL_UNDERLIMBS_LAYER 37 //Tail split-rendering. @@ -201,7 +203,7 @@ #define FIRE_LAYER 3 //If you're on fire #define MISC_LAYER 2 #define FROZEN_LAYER 1 -#define TOTAL_LAYERS 39 +#define TOTAL_LAYERS 41 ///Access Region Codes/// #define REGION_ALL 0 diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index a6665768980..21edc27d6db 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -235,6 +235,7 @@ #define ismachineperson(A) (is_species(A, /datum/species/machine)) #define isdrask(A) (is_species(A, /datum/species/drask)) #define iswryn(A) (is_species(A, /datum/species/wryn)) +#define ismoth(A) (is_species(A, /datum/species/moth)) #define isanimal(A) (istype((A), /mob/living/simple_animal)) #define isdog(A) (istype((A), /mob/living/simple_animal/pet/dog)) diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm index 235d016d0a3..76a7fecbc8e 100644 --- a/code/__DEFINES/status_effects.dm +++ b/code/__DEFINES/status_effects.dm @@ -80,6 +80,12 @@ //#define STATUS_EFFECT_ICHORIAL_STAIN /datum/status_effect/ichorial_stain //Prevents a servant from being revived by vitality matrices for one minute. +/// Whether a moth's wings are burnt +#define STATUS_EFFECT_BURNT_WINGS /datum/status_effect/burnt_wings + +/// If a moth is in a cocoon +#define STATUS_EFFECT_COCOONED /datum/status_effect/cocooned + ///////////// // NEUTRAL // ///////////// diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 8996c196b85..53f690ef31e 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -29,6 +29,8 @@ __init_body_accessory(/datum/body_accessory/body) // Different tails __init_body_accessory(/datum/body_accessory/tail) + // Different wings + __init_body_accessory(/datum/body_accessory/wing) // Setup species:accessory relations initialize_body_accessory_by_species() diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index b3f80f85d50..98ebc1b8d60 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -158,21 +158,23 @@ return m_style -/proc/random_body_accessory(species = "Vulpkanin") - var/body_accessory = null +/** + * Returns a random body accessory for a given species name. Can be null based on is_optional argument. + * + * Arguments: + * * species - The name of the species to filter valid body accessories. + * * is_optional - Whether *no* body accessory (null) is an option. + */ +/proc/random_body_accessory(species = "Vulpkanin", is_optional = TRUE) var/list/valid_body_accessories = list() - for(var/B in GLOB.body_accessory_by_name) - var/datum/body_accessory/A = GLOB.body_accessory_by_name[B] - if(!istype(A)) - valid_body_accessories += "None" //The only null entry should be the "None" option. - continue - if(species in A.allowed_species) //If the user is not of a species the body accessory style allows, skip it. Otherwise, add it to the list. - valid_body_accessories += B + if(is_optional) + valid_body_accessories += null - if(valid_body_accessories.len) - body_accessory = pick(valid_body_accessories) + if(GLOB.body_accessory_by_species[species]) + for(var/name in GLOB.body_accessory_by_species[species]) + valid_body_accessories += name - return body_accessory + return length(valid_body_accessories) ? pick(valid_body_accessories) : null /proc/random_name(gender, species = "Human") diff --git a/code/datums/action.dm b/code/datums/action.dm index 42913514406..0d13981f658 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -2,6 +2,7 @@ #define AB_CHECK_STUNNED 2 #define AB_CHECK_LYING 4 #define AB_CHECK_CONSCIOUS 8 +#define AB_CHECK_TURF 16 /datum/action @@ -83,6 +84,9 @@ if(check_flags & AB_CHECK_CONSCIOUS) if(owner.stat) return FALSE + if(check_flags & AB_CHECK_TURF) + if(!isturf(owner.loc)) + return FALSE return TRUE /datum/action/proc/UpdateButtonIcon() diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 4bedba8aa66..115fcc5c1c7 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -245,12 +245,15 @@ GLOBAL_VAR_INIT(record_id_num, 1001) preview_icon.Blend(temp, ICON_OVERLAY) //Tail - if(H.body_accessory && istype(H.body_accessory, /datum/body_accessory/tail)) + if(H.body_accessory && (istype(H.body_accessory, /datum/body_accessory/tail) || istype(H.body_accessory, /datum/body_accessory/wing))) temp = new/icon("icon" = H.body_accessory.icon, "icon_state" = H.body_accessory.icon_state) preview_icon.Blend(temp, ICON_OVERLAY) else if(H.tail && H.dna.species.bodyflags & HAS_TAIL) temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[H.tail]_s") preview_icon.Blend(temp, ICON_OVERLAY) + else if(H.wing && H.dna.species.bodyflags & HAS_WING) + temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[H.wing]_s") + preview_icon.Blend(temp, ICON_OVERLAY) for(var/obj/item/organ/external/E in H.bodyparts) preview_icon.Blend(E.get_icon(), ICON_OVERLAY) diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 447442a9ac0..4779ffdc491 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -511,6 +511,9 @@ if(istype(M.shoes, /obj/item/clothing/shoes/magboots) && (M.shoes.flags & NOSLIP)) return + if(M.dna.species.spec_thunk(M)) //Species level thunk overrides + return + if(M.buckled) //Cam't fall down if you are buckled return diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm index 2dfe4d660c9..2a0f8ef06a7 100644 --- a/code/game/dna/dna2.dm +++ b/code/game/dna/dna2.dm @@ -56,10 +56,14 @@ GLOBAL_LIST_EMPTY(bad_blocks) new_dna.blood_type = blood_type new_dna.real_name = real_name new_dna.species = new species.type - for(var/b=1;b<=DNA_SE_LENGTH;b++) + + for(var/b = 1; b <= DNA_SE_LENGTH; b++) new_dna.SE[b]=SE[b] - if(b<=DNA_UI_LENGTH) - new_dna.UI[b]=UI[b] + if(b <= DNA_UI_LENGTH) + if(b <= length(UI)) //We check index against the length of UI provided, because it may be shorter and thus be out of bounds + new_dna.UI[b]=UI[b] + continue + new_dna.UI[b] = 0 new_dna.UpdateUI() new_dna.UpdateSE() return new_dna @@ -100,7 +104,7 @@ GLOBAL_LIST_EMPTY(bad_blocks) var/body_marks = GLOB.marking_styles_list.Find(character.m_styles["body"]) var/tail_marks = GLOB.marking_styles_list.Find(character.m_styles["tail"]) - head_traits_to_dna(H) + head_traits_to_dna(character, H) eye_color_to_dna(eyes_organ) SetUIValueRange(DNA_UI_SKIN_R, color2R(character.skin_colour), 255, 1) @@ -121,11 +125,13 @@ GLOBAL_LIST_EMPTY(bad_blocks) SetUIValueRange(DNA_UI_SKIN_TONE, 35-character.s_tone, 220, 1) // Value can be negative. - /*SetUIValueRange(DNA_UI_BACC_STYLE, bodyacc, GLOB.facial_hair_styles_list.len, 1)*/ SetUIValueRange(DNA_UI_HEAD_MARK_STYLE, head_marks, GLOB.marking_styles_list.len, 1) SetUIValueRange(DNA_UI_BODY_MARK_STYLE, body_marks, GLOB.marking_styles_list.len, 1) SetUIValueRange(DNA_UI_TAIL_MARK_STYLE, tail_marks, GLOB.marking_styles_list.len, 1) + var/list/bodyacc = GLOB.body_accessory_by_name.Find(character.body_accessory?.name || "None") + SetUIValueRange(DNA_UI_BACC_STYLE, bodyacc, length(GLOB.body_accessory_by_name), 1) + //Set the Gender switch(character.gender) if(FEMALE) @@ -153,6 +159,8 @@ GLOBAL_LIST_EMPTY(bad_blocks) /datum/dna/proc/GetUIValue(block) if(block <= 0) return FALSE + if(block >= length(UI)) + return FALSE return UI[block] // Set a DNA UI block's value, given a value and a max possible value. diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm index 9ecad776e3e..5d6616d196c 100644 --- a/code/game/dna/dna2_helpers.dm +++ b/code/game/dna/dna2_helpers.dm @@ -171,6 +171,10 @@ if((tail_marks > 0) && (tail_marks <= GLOB.marking_styles_list.len)) H.m_styles["tail"] = GLOB.marking_styles_list[tail_marks] + var/bodyacc = dna.GetUIValueRange(DNA_UI_BACC_STYLE, length(GLOB.body_accessory_by_name)) + if(bodyacc > 0 && bodyacc <= length(GLOB.body_accessory_by_name)) + H.body_accessory = GLOB.body_accessory_by_name[GLOB.body_accessory_by_name[bodyacc]] + H.regenerate_icons() return TRUE @@ -205,9 +209,17 @@ head_organ.sec_facial_colour = rgb(head_organ.dna.GetUIValueRange(DNA_UI_BEARD2_R, 255), head_organ.dna.GetUIValueRange(DNA_UI_BEARD2_G, 255), head_organ.dna.GetUIValueRange(DNA_UI_BEARD2_B, 255)) //Head Accessories - var/headacc = GetUIValueRange(DNA_UI_HACC_STYLE,GLOB.head_accessory_styles_list.len) - if((headacc > 0) && (headacc <= GLOB.head_accessory_styles_list.len)) - head_organ.ha_style = GLOB.head_accessory_styles_list[headacc] + var/list/available = list() + for(var/head_accessory in GLOB.head_accessory_styles_list) + var/datum/sprite_accessory/S = GLOB.head_accessory_styles_list[head_accessory] + if(!(head_organ.dna.species.name in S.species_allowed)) //If the user's head is not of a species the head accessory style allows, skip it. Otherwise, add it to the list. + continue + available += head_accessory + var/list/sorted = sortTim(available, /proc/cmp_text_asc) + + var/headacc = GetUIValueRange(DNA_UI_HACC_STYLE, length(sorted)) + if(headacc > 0 && headacc <= length(sorted)) + head_organ.ha_style = sorted[headacc] head_organ.headacc_colour = rgb(head_organ.dna.GetUIValueRange(DNA_UI_HACC_R, 255), head_organ.dna.GetUIValueRange(DNA_UI_HACC_G, 255), head_organ.dna.GetUIValueRange(DNA_UI_HACC_B, 255)) @@ -227,7 +239,7 @@ SetUIValueRange(DNA_UI_EYES_G, color2G(eyes_organ.eye_color), 255, 1) SetUIValueRange(DNA_UI_EYES_B, color2B(eyes_organ.eye_color), 255, 1) -/datum/dna/proc/head_traits_to_dna(obj/item/organ/external/head/head_organ) +/datum/dna/proc/head_traits_to_dna(mob/living/carbon/human/character, obj/item/organ/external/head/head_organ) if(!head_organ) log_runtime(EXCEPTION("Attempting to reset DNA from a missing head!"), src) return @@ -243,7 +255,6 @@ // Head Accessory if(!head_organ.ha_style) head_organ.ha_style = "None" - var/headacc = GLOB.head_accessory_styles_list.Find(head_organ.ha_style) SetUIValueRange(DNA_UI_HAIR_R, color2R(head_organ.hair_colour), 255, 1) SetUIValueRange(DNA_UI_HAIR_G, color2G(head_organ.hair_colour), 255, 1) @@ -267,4 +278,6 @@ SetUIValueRange(DNA_UI_HAIR_STYLE, hair, GLOB.hair_styles_full_list.len, 1) SetUIValueRange(DNA_UI_BEARD_STYLE, beard, GLOB.facial_hair_styles_list.len, 1) - SetUIValueRange(DNA_UI_HACC_STYLE, headacc, GLOB.head_accessory_styles_list.len, 1) + + var/list/available = character.generate_valid_head_accessories() + SetUIValueRange(DNA_UI_HACC_STYLE, available.Find(head_organ.ha_style), max(length(available), 1), 1) diff --git a/code/game/dna/mutations/powers.dm b/code/game/dna/mutations/powers.dm index ebda9032236..c73985ec230 100644 --- a/code/game/dna/mutations/powers.dm +++ b/code/game/dna/mutations/powers.dm @@ -821,7 +821,7 @@ M.change_head_accessory_color(new_head_accessory_colour) //Body accessory. - if(M.dna.species.tail && M.dna.species.bodyflags & HAS_TAIL) + if((M.dna.species.tail && M.dna.species.bodyflags & (HAS_TAIL)) || (M.dna.species.wing && M.dna.species.bodyflags & (HAS_WING))) var/list/valid_body_accessories = M.generate_valid_body_accessories() if(valid_body_accessories.len > 1) //By default valid_body_accessories will always have at the very least a 'none' entry populating the list, even if the user's species is not present in any of the list items. var/new_body_accessory = input("Please select body accessory style", "Character Generation", M.body_accessory) as null|anything in valid_body_accessories diff --git a/code/modules/client/preference/character.dm b/code/modules/client/preference/character.dm index cd050378c37..3db46cb3112 100644 --- a/code/modules/client/preference/character.dm +++ b/code/modules/client/preference/character.dm @@ -18,7 +18,8 @@ var/list/m_styles = list( "head" = "None", "body" = "None", - "tail" = "None" + "tail" = "None", + "wing" = "None" ) //Marking styles. var/list/m_colours = list( "head" = "#000000", @@ -39,6 +40,7 @@ var/language = "None" //Secondary language var/autohiss_mode = AUTOHISS_OFF //Species autohiss level. OFF, BASIC, FULL. + /// The body accessory name of the mob (e.g. wings, tail). var/body_accessory = null var/speciesprefs = 0 //I hate having to do this, I really do (Using this for oldvox code, making names universal I guess @@ -578,10 +580,8 @@ underwear = random_underwear(gender, species) undershirt = random_undershirt(gender, species) socks = random_socks(gender, species) - if(GLOB.body_accessory_by_species[species]) - body_accessory = random_body_accessory(species) - if(body_accessory == "None") //Required to prevent a bug where the information/icons in the character preferences screen wouldn't update despite the data being changed. - body_accessory = null + if(length(GLOB.body_accessory_by_species[species])) + body_accessory = random_body_accessory(species, S.optional_body_accessory) if(S.bodyflags & (HAS_SKIN_TONE|HAS_ICON_SKIN_TONE)) s_tone = random_skin_tone(species) h_style = random_hair_style(gender, species, robohead) @@ -768,6 +768,12 @@ clothes_s.Blend(new /icon('icons/mob/clothing/back.dmi', "satchel"), ICON_OVERLAY) return clothes_s +#define ICON_SHIFT_XY(I, X, Y)\ + if(X)\ + I.Shift(EAST, X);\ + if(Y)\ + I.Shift(NORTH, Y);\ + /datum/character_save/proc/update_preview_icon(for_observer=0) //seriously. This is horrendous. qdel(preview_icon_front) qdel(preview_icon_side) @@ -830,49 +836,52 @@ else preview_icon.Blend(rgb(-s_tone, -s_tone, -s_tone), ICON_SUBTRACT) - //Tail - if(current_species && (current_species.bodyflags & HAS_TAIL)) - var/tail_icon - var/tail_icon_state - var/tail_shift_x - var/tail_shift_y + // Body accessory + if(current_species && (current_species.bodyflags & HAS_BODY_ACCESSORY)) + var/icon + var/icon_state + var/offset_x = 0 + var/offset_y = 0 var/blend_mode = ICON_ADD + var/icon/underlay = null if(body_accessory) - var/datum/body_accessory/accessory = GLOB.body_accessory_by_name[body_accessory] - tail_icon = accessory.icon - tail_icon_state = accessory.icon_state - if(accessory.blend_mode) - blend_mode = accessory.blend_mode - if(accessory.pixel_x_offset) - tail_shift_x = accessory.pixel_x_offset - if(accessory.pixel_y_offset) - tail_shift_y = accessory.pixel_y_offset - else - tail_icon = "icons/effects/species.dmi" + var/datum/body_accessory/BA = GLOB.body_accessory_by_name[body_accessory] + if(BA) + icon = BA.icon + icon_state = BA.icon_state + blend_mode = BA.blend_mode || blend_mode + offset_x = BA.pixel_x_offset + offset_y = BA.pixel_y_offset + // If the body accessory has an underlay, account for it. + if(BA.has_behind) + underlay = new(icon, "[icon_state]_BEHIND") + else if(current_species.bodyflags & HAS_TAIL) + icon = "icons/effects/species.dmi" if(coloured_tail) - tail_icon_state = "[coloured_tail]_s" + icon_state = "[coloured_tail]_s" else - tail_icon_state = "[current_species.tail]_s" + icon_state = "[current_species.tail]_s" + + if(icon) + var/icon/temp = new(icon, icon_state) + if(current_species.bodyflags & HAS_SKIN_COLOR) + temp.Blend(s_colour, blend_mode) + if(current_species.bodyflags & HAS_TAIL_MARKINGS) + var/tail_marking = m_styles["tail"] + var/datum/sprite_accessory/body_markings/BM = GLOB.marking_styles_list[tail_marking] + if(BM) + var/icon/t_marking_s = new(BM.icon, "[BM.icon_state]_s") + t_marking_s.Blend(m_colours["tail"], ICON_ADD) + temp.Blend(t_marking_s, ICON_OVERLAY) - var/icon/temp = new/icon("icon" = tail_icon, "icon_state" = tail_icon_state) - if(tail_shift_x) - temp.Shift(EAST, tail_shift_x) - if(tail_shift_y) - temp.Shift(NORTH, tail_shift_y) + // Body accessory has an underlay, add it too. + if(underlay) + ICON_SHIFT_XY(underlay, offset_x, offset_y) + preview_icon.Blend(underlay, ICON_UNDERLAY) - if(current_species && (current_species.bodyflags & HAS_SKIN_COLOR)) - temp.Blend(s_colour, blend_mode) - - if(current_species && (current_species.bodyflags & HAS_TAIL_MARKINGS)) - var/tail_marking = m_styles["tail"] - var/datum/sprite_accessory/tail_marking_style = GLOB.marking_styles_list[tail_marking] - if(tail_marking_style && tail_marking_style.species_allowed) - var/icon/t_marking_s = new/icon("icon" = tail_marking_style.icon, "icon_state" = "[tail_marking_style.icon_state]_s") - t_marking_s.Blend(m_colours["tail"], ICON_ADD) - temp.Blend(t_marking_s, ICON_OVERLAY) - - preview_icon.Blend(temp, ICON_OVERLAY) + ICON_SHIFT_XY(temp, offset_x, offset_y) + preview_icon.Blend(temp, ICON_OVERLAY) //Markings if(current_species && ((current_species.bodyflags & HAS_HEAD_MARKINGS) || (current_species.bodyflags & HAS_BODY_MARKINGS))) @@ -1490,7 +1499,7 @@ qdel(socks_s) qdel(clothes_s) - +#undef ICON_SHIFT_XY /datum/character_save/proc/get_gear_metadata(datum/gear/G) // NYI . = loadout_gear[G.type] diff --git a/code/modules/client/preference/link_processing.dm b/code/modules/client/preference/link_processing.dm index fe227081368..0ceb146f6bd 100644 --- a/code/modules/client/preference/link_processing.dm +++ b/code/modules/client/preference/link_processing.dm @@ -216,7 +216,7 @@ if(new_age) active_character.age = max(min(round(text2num(new_age)), AGE_MAX),AGE_MIN) if("species") - var/list/new_species = list("Human", "Tajaran", "Skrell", "Unathi", "Diona", "Vulpkanin") + var/list/new_species = list("Human", "Tajaran", "Skrell", "Unathi", "Diona", "Vulpkanin", "Nian") var/prev_species = active_character.species for(var/_species in GLOB.whitelisted_species) @@ -290,8 +290,7 @@ active_character.alt_head = "None" //No alt heads on species that don't have them. active_character.speciesprefs = 0 //My Vox tank shouldn't change how my future Grey talks. - - active_character.body_accessory = null //no vulptail on humans damnit + active_character.body_accessory = random_body_accessory(NS.name, NS.optional_body_accessory) //Reset prosthetics. active_character.organ_data = list() @@ -544,11 +543,14 @@ else for(var/B in GLOB.body_accessory_by_name) var/datum/body_accessory/accessory = GLOB.body_accessory_by_name[B] - if(!istype(accessory)) - possible_body_accessories += "None" //the only null entry should be the "None" option + if(isnull(accessory)) // None continue if(active_character.species in accessory.allowed_species) possible_body_accessories += B + if(S.optional_body_accessory) + possible_body_accessories += "None" //the only null entry should be the "None" option + else + possible_body_accessories -= "None" // in case an admin is viewing it sortTim(possible_body_accessories, /proc/cmp_text_asc) var/new_body_accessory = input(user, "Choose your body accessory:", "Character Preference") as null|anything in possible_body_accessories if(new_body_accessory) diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 0d0ff2348cd..f5bacbf6ccd 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -227,37 +227,37 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts dat += "Tail Markings: " dat += "[active_character.m_styles["tail"]]" dat += "Color [color_square(active_character.m_colours["tail"])]
" + if(!(S.bodyflags & BALD)) + dat += "Hair: " + dat += "[active_character.h_style]" + dat += "Color [color_square(active_character.h_colour)]" + var/datum/sprite_accessory/temp_hair_style = GLOB.hair_styles_public_list[active_character.h_style] + if(temp_hair_style && temp_hair_style.secondary_theme && !temp_hair_style.no_sec_colour) + dat += " Color #2 [color_square(active_character.h_sec_colour)]" + // Hair gradient + dat += "
" + dat += "- Gradient:" + dat += " [active_character.h_grad_style]" + dat += " Color [color_square(active_character.h_grad_colour)]" + dat += " [active_character.h_grad_alpha]" + dat += "
" + dat += "- Gradient Offset: [active_character.h_grad_offset_x],[active_character.h_grad_offset_y]" + dat += "
" - dat += "Hair: " - dat += "[active_character.h_style]" - dat += "Color [color_square(active_character.h_colour)]" - var/datum/sprite_accessory/temp_hair_style = GLOB.hair_styles_public_list[active_character.h_style] - if(temp_hair_style && temp_hair_style.secondary_theme && !temp_hair_style.no_sec_colour) - dat += " Color #2 [color_square(active_character.h_sec_colour)]" - // Hair gradient - dat += "
" - dat += "- Gradient:" - dat += " [active_character.h_grad_style]" - dat += " Color [color_square(active_character.h_grad_colour)]" - dat += " [active_character.h_grad_alpha]" - dat += "
" - dat += "- Gradient Offset: [active_character.h_grad_offset_x],[active_character.h_grad_offset_y]" - dat += "
" - - dat += "Facial Hair: " - dat += "[active_character.f_style ? "[active_character.f_style]" : "Shaved"]" - dat += "Color [color_square(active_character.f_colour)]" - var/datum/sprite_accessory/temp_facial_hair_style = GLOB.facial_hair_styles_list[active_character.f_style] - if(temp_facial_hair_style && temp_facial_hair_style.secondary_theme && !temp_facial_hair_style.no_sec_colour) - dat += " Color #2 [color_square(active_character.f_sec_colour)]" - dat += "
" + dat += "Facial Hair: " + dat += "[active_character.f_style ? "[active_character.f_style]" : "Shaved"]" + dat += "Color [color_square(active_character.f_colour)]" + var/datum/sprite_accessory/temp_facial_hair_style = GLOB.facial_hair_styles_list[active_character.f_style] + if(temp_facial_hair_style && temp_facial_hair_style.secondary_theme && !temp_facial_hair_style.no_sec_colour) + dat += " Color #2 [color_square(active_character.f_sec_colour)]" + dat += "
" if(!(S.bodyflags & ALL_RPARTS)) dat += "Eyes: " dat += "Color [color_square(active_character.e_colour)]
" - if((S.bodyflags & HAS_SKIN_COLOR) || GLOB.body_accessory_by_species[active_character.species] || check_rights(R_ADMIN, 0, user)) //admins can always fuck with this, because they are admins + if((S.bodyflags & HAS_SKIN_COLOR) || ((S.bodyflags & HAS_BODYACC_COLOR) && GLOB.body_accessory_by_species[active_character.species]) || check_rights(R_ADMIN, 0, user)) //admins can always fuck with this, because they are admins dat += "Body Color: " dat += "Color [color_square(active_character.s_colour)]
" diff --git a/code/modules/mob/language.dm b/code/modules/mob/language.dm index 6f4e3a15694..f99d3e8e604 100644 --- a/code/modules/mob/language.dm +++ b/code/modules/mob/language.dm @@ -20,6 +20,8 @@ var/follow = 0 // Applies to HIVEMIND languages - should a follow link be included for dead mobs? var/english_names = 0 // Do we want English names by default, no matter what? var/list/scramble_cache = list() + /// Do we want to override the word-join character for scrambled text? If null, defaults to " " or ". " + var/join_override /datum/language/proc/get_random_name(gender, name_count=2, syllable_count=4) if(!syllables || !syllables.len || english_names) @@ -62,7 +64,9 @@ capitalize = 0 scrambled_text += next var/chance = rand(100) - if(chance <= 5) + if(join_override) + scrambled_text += join_override + else if(chance <= 5) scrambled_text += ". " capitalize = 1 else if(chance > 5 && chance <= space_chance) @@ -70,7 +74,7 @@ scrambled_text = trim(scrambled_text) var/ending = copytext(scrambled_text, length(scrambled_text)) - if(ending == ".") + if(ending == "." || ending == "-") scrambled_text = copytext(scrambled_text,1,length(scrambled_text)-1) var/input_ending = copytext(input, input_size) if(input_ending in list("!","?",".")) @@ -353,6 +357,28 @@ new_name += "-[pick(list("Hoorm","Viisk","Saar","Mnoo","Oumn","Fmong","Gnii","Vrrm","Oorm","Dromnn","Ssooumn","Ovv", "Hoorb","Vaar","Gaar","Goom","Ruum","Rumum"))]" return new_name +/datum/language/moth + name = "Tkachi" + desc = "The language of the Nianae mothpeople borders on complete unintelligibility." + speech_verb = "buzzes" + ask_verb = "flaps" + exclaim_verbs = list("chatters") + colour = "moth" + key = "#" + flags = RESTRICTED | WHITELISTED + join_override = "-" + syllables = list("år", "i", "går", "sek", "mo", "ff", "ok", "gj", "ø", "gå", "la", "le", + "lit", "ygg", "van", "dår", "næ", "møt", "idd", "hvo", "ja", "på", "han", + "så", "ån", "det", "att", "nå", "gö", "bra", "int", "tyc", "om", "när", "två", + "må", "dag", "sjä", "vii", "vuo", "eil", "tun", "käyt", "teh", "vä", "hei", + "huo", "suo", "ää", "ten", "ja", "heu", "stu", "uhr", "kön", "we", "hön") + +/datum/language/moth/get_random_name() + var/new_name = "[pick(list("Abbot","Archer","Arkwright","Baker","Bard","Biologist","Broker","Caller","Chamberlain","Clerk","Cooper","Culinarian","Dean","Director","Duke","Energizer","Excavator","Explorer","Fletcher","Gatekeeper","Guardian","Guide","Healer","Horner","Keeper","Knight","Laidler","Mapper","Marshall","Mechanic","Miller","Navigator","Pilot","Prior","Seeker","Seer","Smith","Stargazer","Teacher","Tech Whisperer","Tender","Thatcher","Voidcrafter","Voidhunter","Voidwalker","Ward","Watcher","Weaver","Webster","Wright"))]" + new_name += "[pick(list(" of"," for"," in Service of",", Servant of"," for the Good of",", Student of"," to"))]" + new_name += " [pick(list("Alkaid","Andromeda","Antlia","Apus","Auriga","Caelum","Camelopardalis","Canes Venatici","Carinae","Cassiopeia","Centauri","Circinus","Cygnus","Dorado","Draco","Eridanus","Errakis","Fornax","Gliese","Grus","Horologium","Hydri","Lacerta","Leo Minor","Lupus","Lynx","Maffei","Megrez","Messier","Microscopium","Monocerotis","Muscae","Ophiuchi","Orion","Pegasi","Persei","Perseus","Polaris","Pyxis","Sculptor","Syrma","Telescopium","Tianyi","Triangulum","Trifid","Tucana","Tycho","Vir","Volans","Zavyava"))]" + return new_name + /datum/language/common name = "Galactic Common" desc = "The common galactic tongue." diff --git a/code/modules/mob/living/carbon/human/appearance.dm b/code/modules/mob/living/carbon/human/appearance.dm index 88f8dc87e24..a8f4f97fa88 100644 --- a/code/modules/mob/living/carbon/human/appearance.dm +++ b/code/modules/mob/living/carbon/human/appearance.dm @@ -52,6 +52,8 @@ var/obj/item/organ/external/head/H = get_organ("head") if(!head_accessory_style || !H || H.ha_style == head_accessory_style || !(head_accessory_style in GLOB.head_accessory_styles_list)) return + if(SEND_SIGNAL(src, COMSIG_HUMAN_CHANGE_HEAD_ACCESSORY, head_accessory_style) & COMSIG_HUMAN_NO_CHANGE_APPEARANCE) + return FALSE H.ha_style = head_accessory_style @@ -103,6 +105,8 @@ var/found if(!body_accessory_style || (body_accessory && body_accessory.name == body_accessory_style)) return + if(SEND_SIGNAL(src, COMSIG_HUMAN_CHANGE_BODY_ACCESSORY, body_accessory_style) & COMSIG_HUMAN_NO_CHANGE_APPEARANCE) + return FALSE for(var/B in GLOB.body_accessory_by_name) if(B == body_accessory_style) @@ -114,7 +118,8 @@ m_styles["tail"] = "None" update_tail_layer() - return 1 + update_wing_layer() + return TRUE /mob/living/carbon/human/proc/change_alt_head(alternate_head) var/obj/item/organ/external/head/H = get_organ("head") @@ -468,17 +473,18 @@ return sortTim(valid_markings, /proc/cmp_text_asc) /mob/living/carbon/human/proc/generate_valid_body_accessories() - var/list/valid_body_accessories = new() + var/list/valid_body_accessories = list() for(var/B in GLOB.body_accessory_by_name) var/datum/body_accessory/A = GLOB.body_accessory_by_name[B] - if(check_rights(R_ADMIN, 0, src)) + if(isnull(A)) + continue + else if(check_rights(R_ADMIN, FALSE, src)) valid_body_accessories = GLOB.body_accessory_by_name.Copy() - else - if(!istype(A)) - valid_body_accessories["None"] = "None" //The only null entry should be the "None" option. - continue - if(dna.species.name in A.allowed_species) //If the user is not of a species the body accessory style allows, skip it. Otherwise, add it to the list. - valid_body_accessories += B + break + else if(dna.species.name in A.allowed_species) //If the user is not of a species the body accessory style allows, skip it. Otherwise, add it to the list. + valid_body_accessories += B + if(dna.species.optional_body_accessory) + valid_body_accessories += "None" return sortTim(valid_body_accessories, /proc/cmp_text_asc) diff --git a/code/modules/mob/living/carbon/human/body_accessories.dm b/code/modules/mob/living/carbon/human/body_accessories.dm index 3759109019f..a00af925e0d 100644 --- a/code/modules/mob/living/carbon/human/body_accessories.dm +++ b/code/modules/mob/living/carbon/human/body_accessories.dm @@ -1,6 +1,6 @@ GLOBAL_LIST_INIT(body_accessory_by_name, list("None" = null)) -GLOBAL_LIST_INIT(body_accessory_by_species, list("None" = null)) +GLOBAL_LIST_INIT(body_accessory_by_species, list()) /proc/initialize_body_accessory_by_species() for(var/B in GLOB.body_accessory_by_name) @@ -8,8 +8,9 @@ GLOBAL_LIST_INIT(body_accessory_by_species, list("None" = null)) if(!istype(accessory)) continue for(var/species in accessory.allowed_species) - if(!GLOB.body_accessory_by_species["[species]"]) GLOB.body_accessory_by_species["[species]"] = list() - GLOB.body_accessory_by_species["[species]"] += accessory + if(!GLOB.body_accessory_by_species["[species]"]) + GLOB.body_accessory_by_species["[species]"] = list() + GLOB.body_accessory_by_species["[species]"]["[accessory.name]"] = accessory if(GLOB.body_accessory_by_species.len) return TRUE @@ -45,8 +46,11 @@ GLOBAL_LIST_INIT(body_accessory_by_species, list("None" = null)) var/list/allowed_species = list() + /// If true, adds an underlay (in addition to the regular overlay!) to the character sprite, with the state "[icon_state]_BEHIND". + var/has_behind = FALSE + /datum/body_accessory/proc/try_restrictions(mob/living/carbon/human/H) - return TRUE + return (H.dna.species.name in allowed_species) /datum/body_accessory/proc/get_animated_icon() //return animated if it has it, return static if it does not. if(animated_icon) @@ -74,9 +78,9 @@ GLOBAL_LIST_INIT(body_accessory_by_species, list("None" = null)) animated_icon_state = "null" /datum/body_accessory/tail/try_restrictions(mob/living/carbon/human/H) - if(!H.wear_suit || !(H.wear_suit.flags_inv & HIDETAIL)) - return TRUE - return FALSE + if(H.wear_suit && (H.wear_suit.flags_inv & HIDETAIL)) + return FALSE + return ..() //Tajaran /datum/body_accessory/tail/wingler_tail // Jay wingler fluff tail @@ -121,4 +125,86 @@ GLOBAL_LIST_INIT(body_accessory_by_species, list("None" = null)) name = "Bee Tail" icon_state = "wryntail" allowed_species = list("Wryn") - + +//Moth wings +/datum/body_accessory/wing + icon = 'icons/mob/sprite_accessories/moth/moth_wings.dmi' + animated_icon = null + name = "Plain Wings" + icon_state = "plain" + allowed_species = list("Nian") + has_behind = TRUE + +/datum/body_accessory/wing/plain + +/datum/body_accessory/wing/monarch + name = "Monarch Wings" + icon_state = "monarch" + +/datum/body_accessory/wing/luna + name = "Luna Wings" + icon_state = "luna" + +/datum/body_accessory/wing/atlas + name = "Atlas Wings" + icon_state = "atlas" + +/datum/body_accessory/wing/reddish + name = "Reddish Wings" + icon_state = "redish" + +/datum/body_accessory/wing/royal + name = "Royal Wings" + icon_state = "royal" + +/datum/body_accessory/wing/gothic + name = "Gothic Wings" + icon_state = "gothic" + +/datum/body_accessory/wing/lovers + name = "Lovers Wings" + icon_state = "lovers" + +/datum/body_accessory/wing/whitefly + name = "White Fly Wings" + icon_state = "whitefly" + +/datum/body_accessory/wing/burnt_off + name = "Burnt Off Wings" + icon_state = "burnt_off" + +/datum/body_accessory/wing/firewatch + name = "Firewatch Wings" + icon_state = "firewatch" + +/datum/body_accessory/wing/deathhead + name = "Deathshead Wings" + icon_state = "deathhead" + +/datum/body_accessory/wing/poison + name = "Poison Wings" + icon_state = "poison" + +/datum/body_accessory/wing/ragged + name = "Ragged Wings" + icon_state = "ragged" + +/datum/body_accessory/wing/moonfly + name = "Moon Fly Wings" + icon_state = "moonfly" + +/datum/body_accessory/wing/snow + name = "Snow Wings" + icon_state = "snow" + +/datum/body_accessory/wing/oakworm + name = "Oak Worm Wings" + icon_state = "oakworm" + +/datum/body_accessory/wing/jungle + name = "Jungle Wings" + icon_state = "jungle" + +/datum/body_accessory/wing/witchwing + name = "Witch Wing Wings" + icon_state = "witchwing" diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index d98e00b1e3f..68f70bc3cc2 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -124,6 +124,11 @@ else //Everyone else fails, skip the emote attempt return + if("flap", "flaps", "aflap", "aflaps","flutter", "flutters") + if(!ismoth(src)) + return + on_CD = handle_emote_CD() + if("scream", "screams") on_CD = handle_emote_CD(50) //longer cooldown if("fart", "farts", "flip", "flips", "snap", "snaps") @@ -283,11 +288,10 @@ m_type = 1 if("wag", "wags") - if(body_accessory) + if(istype(body_accessory, /datum/body_accessory/tail)) if(body_accessory.try_restrictions(src)) message = "[src] starts wagging [p_their()] tail." start_tail_wagging() - else if(dna.species.bodyflags & TAIL_WAGGING) if(!wear_suit || !(wear_suit.flags_inv & HIDETAIL)) message = "[src] starts wagging [p_their()] tail." @@ -299,7 +303,7 @@ m_type = 1 if("swag", "swags") - if(dna.species.bodyflags & TAIL_WAGGING || body_accessory) + if((dna.species.bodyflags & TAIL_WAGGING) || istype(body_accessory, /datum/body_accessory/tail)) message = "[src] stops wagging [p_their()] tail." stop_tail_wagging() else @@ -392,11 +396,16 @@ to_chat(usr, "You need your hands working in order to clap.") if("flap", "flaps") - if(!restrained()) - message = "[src] flaps [p_their()] wings." - m_type = 2 - if(miming) - m_type = 1 + message = "[src] flaps [p_their()] wings." + m_type = 2 + if(miming) + m_type = 1 + + if("flutter", "flutters") + message = "[src] flutters [p_their()] wings." + m_type = 2 + if(miming) + m_type = 1 if("flip", "flips") m_type = 1 @@ -456,11 +465,10 @@ spin(20, 1) if("aflap", "aflaps") - if(!restrained()) - message = "[src] flaps [p_their()] wings ANGRILY!" - m_type = 2 - if(miming) - m_type = 1 + message = "[src] flaps [p_their()] wings ANGRILY!" + m_type = 2 + if(miming) + m_type = 1 if("drool", "drools") message = "[src] drools." @@ -959,13 +967,13 @@ return if("help") - var/emotelist = "aflap(s), airguitar, blink(s), blink(s)_r, blush(es), bow(s)-none/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s), cry, cries, custom, dance, dap(s)-none/mob," \ - + " deathgasp(s), drool(s), eyebrow, fart(s), faint(s), flap(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-none/mob, grin(s), groan(s), grumble(s), grin(s)," \ + var/emotelist = "airguitar, blink(s), blink(s)_r, blush(es), bow(s)-none/mob, burp(s), choke(s), chuckle(s), clap(s), collapse(s), cough(s), cry, cries, custom, dance, dap(s)-none/mob," \ + + " deathgasp(s), drool(s), eyebrow, fart(s), faint(s), flip(s), frown(s), gasp(s), giggle(s), glare(s)-none/mob, grin(s), groan(s), grumble(s), grin(s)," \ + " handshake-mob, hug(s)-none/mob, hem, highfive, johnny, jump, kiss(es), laugh(s), look(s)-none/mob, moan(s), mumble(s), nod(s), pale(s), point(s)-atom, quiver(s), raise(s), salute(s)-none/mob, scream(s), shake(s)," \ + " shiver(s), shrug(s), sigh(s), signal(s)-#1-10, slap(s), smile(s),snap(s), sneeze(s), sniff(s), snore(s), spin(s) stare(s)-none/mob, tremble(s), twitch(es), twitch(es)_s," \ + " wave(s), whimper(s), wink(s), yawn(s)" - switch(dna.species.name) + switch(dna.species.name) //dear future coders, do not use strings like this if("Diona") emotelist += "\nDiona specific emotes :- creak(s)" if("Drask") @@ -986,6 +994,8 @@ emotelist += "\nPlasmaman specific emotes :- rattle(s)-none/mob" if("Skeleton") emotelist += "\nSkeleton specific emotes :- rattle(s)-none/mob" + if("Nian") + emotelist += "\nNian specific emotes :- aflap(s), flap(s), flutter(s)" if(ismachineperson(src)) emotelist += "\nMachine specific emotes :- beep(s)-none/mob, buzz(es)-none/mob, no-none/mob, ping(s)-none/mob, yes-none/mob, buzz2-none/mob" diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index eafecdd4d2f..c48124568a2 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -170,6 +170,11 @@ /mob/living/carbon/human/stok/Initialize(mapload) . = ..(mapload, /datum/species/monkey/unathi) +/mob/living/carbon/human/moth/Initialize(mapload) + . = ..(mapload, /datum/species/moth) + if(!body_accessory) + change_body_accessory("Plain Wings") + /mob/living/carbon/human/Stat() ..() statpanel("Status") @@ -1256,6 +1261,8 @@ tail = dna.species.tail + wing = dna.species.wing + maxHealth = dna.species.total_health if(dna.species.language) @@ -1387,7 +1394,10 @@ m_styles = DEFAULT_MARKING_STYLES //Wipes out markings, setting them all to "None". m_colours = DEFAULT_MARKING_COLOURS //Defaults colour to #00000 for all markings. - body_accessory = null + if(dna.species.bodyflags & HAS_BODY_ACCESSORY) + body_accessory = GLOB.body_accessory_by_name[dna.species.default_bodyacc] + else + body_accessory = null dna.real_name = real_name @@ -1947,6 +1957,11 @@ Eyes need to have significantly high darksight to shine unless the mob has the X /mob/living/carbon/human/proc/get_perceived_trauma() return min(health, maxHealth - getStaminaLoss()) +/mob/living/carbon/human/WakeUp(updating = TRUE) + if(dna.species.spec_WakeUp(src)) + return + ..() + /** * Helper to get the mobs runechat colour span * diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index a6bc7b0d363..1eaa3e02308 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -68,7 +68,10 @@ var/fire_sprite = "Standing" var/datum/body_accessory/body_accessory = null - var/tail // Name of tail image in species effects icon file. + /// Name of tail image in species effects icon file. + var/tail + /// Same as tail but wing + var/wing var/list/splinted_limbs = list() //limbs we know are splinted var/original_eye_color = "#000000" diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 6c05cfcd0a2..333ded583b0 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -7,7 +7,7 @@ /mob/living/carbon/human/Process_Spacemove(movement_dir = 0) if(..()) - return 1 + return TRUE //Do we have a working jetpack? var/obj/item/tank/jetpack/thrust @@ -18,8 +18,10 @@ thrust = C.jetpack if(thrust) if((movement_dir || thrust.stabilizers) && thrust.allow_thrust(0.01, src)) - return 1 - return 0 + return TRUE + if(dna.species.spec_Process_Spacemove(src)) + return TRUE + return FALSE /mob/living/carbon/human/mob_has_gravity() . = ..() diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm index af8ffeca7be..46e9c930955 100644 --- a/code/modules/mob/living/carbon/human/species/_species.dm +++ b/code/modules/mob/living/carbon/human/species/_species.dm @@ -14,7 +14,10 @@ var/datum/species/primitive_form = null // Lesser form, if any (ie. monkey for humans) var/datum/species/greater_form = null // Greater form, if any, ie. human for monkeys. - var/tail // Name of tail image in species effects icon file. + /// Name of tail image in species effects icon file. + var/tail + /// like tail but wings + var/wing var/datum/unarmed_attack/unarmed //For empty hand harm-intent attack var/unarmed_type = /datum/unarmed_attack @@ -138,6 +141,9 @@ var/default_headacc //Default head accessory style for newly created humans unless otherwise set. var/default_headacc_colour + /// Name of default body accessory if any. + var/default_bodyacc + //Defining lists of icon skin tones for species that have them. var/list/icon_skin_tones = list() @@ -171,6 +177,9 @@ // Species specific boxes var/speciesbox + /// Whether the presence of a body accessory on this species is optional or not. + var/optional_body_accessory = TRUE + /datum/species/New() unarmed = new unarmed_type() @@ -266,7 +275,8 @@ . += (health_deficiency / 75) else . += (health_deficiency / 25) - . += 2 * H.stance_damage //damaged/missing feet or legs is slow + if(H.dna.species.spec_movement_delay()) //Species overrides for slowdown due to feet/legs + . += 2 * H.stance_damage //damaged/missing feet or legs is slow if((hungry >= 70) && !flight) . += hungry/50 @@ -952,6 +962,18 @@ It'll return null if the organ doesn't correspond, so include null checks when u if(istype(ears) && !HAS_TRAIT(H, TRAIT_DEAF)) . = TRUE +/datum/species/proc/spec_Process_Spacemove(mob/living/carbon/human/H) + return FALSE + +/datum/species/proc/spec_thunk(mob/living/carbon/human/H) + return FALSE + +/datum/species/proc/spec_movement_delay() + return TRUE + +/datum/species/proc/spec_WakeUp(mob/living/carbon/human/H) + return FALSE + /** * Species-specific runechat colour handler * diff --git a/code/modules/mob/living/carbon/human/species/grey.dm b/code/modules/mob/living/carbon/human/species/grey.dm index 75f4787e7b1..46ba8bd8e34 100644 --- a/code/modules/mob/living/carbon/human/species/grey.dm +++ b/code/modules/mob/living/carbon/human/species/grey.dm @@ -20,7 +20,7 @@ species_traits = list(LIPS, IS_WHITELISTED, CAN_WINGDINGS, NO_HAIR) clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS - bodyflags = HAS_BODY_MARKINGS + bodyflags = HAS_BODY_MARKINGS | HAS_BODYACC_COLOR dietflags = DIET_HERB has_gender = FALSE reagent_tag = PROCESS_ORG diff --git a/code/modules/mob/living/carbon/human/species/kidan.dm b/code/modules/mob/living/carbon/human/species/kidan.dm index df364f6122b..6ef01df5196 100644 --- a/code/modules/mob/living/carbon/human/species/kidan.dm +++ b/code/modules/mob/living/carbon/human/species/kidan.dm @@ -12,7 +12,7 @@ species_traits = list(IS_WHITELISTED, NO_HAIR) inherent_biotypes = MOB_ORGANIC | MOB_HUMANOID | MOB_BUG clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS - bodyflags = HAS_HEAD_ACCESSORY | HAS_HEAD_MARKINGS | HAS_BODY_MARKINGS + bodyflags = HAS_HEAD_ACCESSORY | HAS_HEAD_MARKINGS | HAS_BODY_MARKINGS | HAS_BODYACC_COLOR eyes = "kidan_eyes_s" dietflags = DIET_HERB flesh_color = "#ba7814" diff --git a/code/modules/mob/living/carbon/human/species/monkey.dm b/code/modules/mob/living/carbon/human/species/monkey.dm index 9820f964a2a..6b1ab68353c 100644 --- a/code/modules/mob/living/carbon/human/species/monkey.dm +++ b/code/modules/mob/living/carbon/human/species/monkey.dm @@ -27,7 +27,7 @@ female_scream_sound = 'sound/goonstation/voice/monkey_scream.ogg' tail = "chimptail" - bodyflags = HAS_TAIL + bodyflags = HAS_TAIL | HAS_BODYACC_COLOR reagent_tag = PROCESS_ORG //Has standard darksight of 2. @@ -144,7 +144,7 @@ base_color = "#000000" reagent_tag = PROCESS_ORG - bodyflags = HAS_TAIL + bodyflags = HAS_TAIL | HAS_BODYACC_COLOR has_organ = list( "heart" = /obj/item/organ/internal/heart/unathi, diff --git a/code/modules/mob/living/carbon/human/species/moth.dm b/code/modules/mob/living/carbon/human/species/moth.dm new file mode 100644 index 00000000000..74c0a81ef4b --- /dev/null +++ b/code/modules/mob/living/carbon/human/species/moth.dm @@ -0,0 +1,218 @@ +#define COCOON_WEAVE_DELAY 5 SECONDS +#define COCOON_EMERGE_DELAY 15 SECONDS +#define COCOON_HARM_AMOUNT 50 +#define COCOON_NUTRITION_AMOUNT -200 +#define FLYSWATTER_DAMAGE_MULTIPLIER 9 + +/datum/species/moth + name = "Nian" + name_plural = "Nianae" + language = "Tkachi" + icobase = 'icons/mob/human_races/r_moth.dmi' + inherent_factions = list("nian") + species_traits = list(NO_HAIR) + inherent_biotypes = MOB_ORGANIC | MOB_HUMANOID | MOB_BUG + clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT + bodyflags = HAS_HEAD_ACCESSORY | HAS_HEAD_MARKINGS | HAS_BODY_MARKINGS | HAS_WING | BALD + reagent_tag = PROCESS_ORG + dietflags = DIET_HERB + tox_mod = 1.5 + blood_color = "#b9ae9c" + unarmed_type = /datum/unarmed_attack/claws + scream_verb = "buzzes" + male_scream_sound = 'sound/voice/scream_moth.ogg' + female_scream_sound = 'sound/voice/scream_moth.ogg' + default_headacc = "Plain Antennae" + default_bodyacc = "Plain Wings" + wing = "plain" + eyes = "moth_eyes_s" + butt_sprite = "nian" + siemens_coeff = 1.5 + + has_organ = list( + "heart" = /obj/item/organ/internal/heart/nian, + "lungs" = /obj/item/organ/internal/lungs/nian, + "liver" = /obj/item/organ/internal/liver/nian, + "kidneys" = /obj/item/organ/internal/kidneys/nian, + "brain" = /obj/item/organ/internal/brain/nian, + "eyes" = /obj/item/organ/internal/eyes/nian + ) + + optional_body_accessory = FALSE + + var/datum/action/innate/cocoon/cocoon + + suicide_messages = list( + "is attempting to nibble their antenna off!", + "is twisting their own abdomen!", + "is cracking their exoskeleton!", + "is ripping their wings off!", + "is holding their breath!" + ) + + +/datum/species/moth/on_species_gain(mob/living/carbon/human/H) + ..() + cocoon = new() + cocoon.Grant(H) + RegisterSignal(H, COMSIG_LIVING_FIRE_TICK, .proc/check_burn_wings) + RegisterSignal(H, COMSIG_LIVING_AHEAL, .proc/on_aheal) + RegisterSignal(H, COMSIG_HUMAN_CHANGE_BODY_ACCESSORY, .proc/on_change_body_accessory) + RegisterSignal(H, COMSIG_HUMAN_CHANGE_HEAD_ACCESSORY, .proc/on_change_head_accessory) + +/datum/species/moth/on_species_loss(mob/living/carbon/human/H) + ..() + cocoon.Remove(H) + UnregisterSignal(H, COMSIG_LIVING_FIRE_TICK) + UnregisterSignal(H, COMSIG_LIVING_AHEAL) + UnregisterSignal(H, COMSIG_HUMAN_CHANGE_BODY_ACCESSORY) + UnregisterSignal(H, COMSIG_HUMAN_CHANGE_HEAD_ACCESSORY) + H.remove_status_effect(STATUS_EFFECT_BURNT_WINGS) + +/datum/species/moth/handle_reagents(mob/living/carbon/human/H, datum/reagent/R) + if(R.id == "pestkiller") + H.adjustToxLoss(3) + H.reagents.remove_reagent(R.id, REAGENTS_METABOLISM) + return TRUE + + return ..() + +/datum/species/moth/get_species_runechat_color(mob/living/carbon/human/H) + return H.m_colours["body"] + +/datum/species/moth/spec_attacked_by(obj/item/I, mob/living/user, obj/item/organ/external/affecting, intent, mob/living/carbon/human/H) + if(istype(I, /obj/item/melee/flyswatter) && I.force) + apply_damage(I.force * FLYSWATTER_DAMAGE_MULTIPLIER, I.damtype, affecting, FALSE, H) //making flyswatters do 10x damage to moff + +/datum/species/moth/spec_Process_Spacemove(mob/living/carbon/human/H) + var/turf/A = get_turf(H) + if(isspaceturf(A)) + return FALSE + if(H.has_status_effect(STATUS_EFFECT_BURNT_WINGS)) + return FALSE + var/datum/gas_mixture/current = A.return_air() + if(current && (current.return_pressure() >= ONE_ATMOSPHERE*0.85)) //as long as there's reasonable pressure and no gravity, flight is possible + return TRUE + +/datum/species/moth/spec_thunk(mob/living/carbon/human/H) + if(!H.has_status_effect(STATUS_EFFECT_BURNT_WINGS)) + return TRUE + +/datum/species/moth/spec_movement_delay() + return FALSE + +/datum/species/moth/spec_WakeUp(mob/living/carbon/human/H) + if(H.has_status_effect(STATUS_EFFECT_COCOONED)) + return TRUE //Cocooned mobs dont get to wake up + +/datum/species/moth/proc/check_burn_wings(mob/living/carbon/human/H) //do not go into the extremely hot light. you will not survive + SIGNAL_HANDLER + if(H.on_fire && !H.has_status_effect(STATUS_EFFECT_BURNT_WINGS) && H.bodytemperature >= 400 && H.fire_stacks > 0) + to_chat(H, "Your precious wings burn to a crisp!") + H.apply_status_effect(STATUS_EFFECT_BURNT_WINGS) + +/datum/species/moth/proc/on_aheal(mob/living/carbon/human/H) + SIGNAL_HANDLER + H.remove_status_effect(STATUS_EFFECT_BURNT_WINGS) + +/datum/species/moth/proc/on_change_body_accessory(mob/living/carbon/human/H) + SIGNAL_HANDLER + if(H.has_status_effect(STATUS_EFFECT_BURNT_WINGS)) + return COMSIG_HUMAN_NO_CHANGE_APPEARANCE + +/datum/species/moth/proc/on_change_head_accessory(mob/living/carbon/human/H) + SIGNAL_HANDLER + if(H.has_status_effect(STATUS_EFFECT_BURNT_WINGS)) + return COMSIG_HUMAN_NO_CHANGE_APPEARANCE + +/datum/action/innate/cocoon + name = "Cocoon" + desc = "Restore your wings and antennae, and heal some damage. If your cocoon is broken externally you will take heavy damage!" + check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUNNED|AB_CHECK_CONSCIOUS|AB_CHECK_TURF + icon_icon = 'icons/effects/effects.dmi' + button_icon_state = "cocoon1" + +/datum/action/innate/cocoon/Activate() + var/mob/living/carbon/human/moth/H = owner + if(H.nutrition < COCOON_NUTRITION_AMOUNT) + to_chat(H, "You are too hungry to cocoon!") + return + H.visible_message("[H] begins to hold still and concentrate on weaving a cocoon...", "You begin to focus on weaving a cocoon... (This will take [COCOON_WEAVE_DELAY / 10] seconds, and you must hold still.)") + if(do_after(H, COCOON_WEAVE_DELAY, FALSE, H)) + if(H.incapacitated(ignore_lying = TRUE)) + to_chat(H, "You cannot weave a cocoon in your current state.") + return + H.visible_message("[H] finishes weaving a cocoon!", "You finish weaving your cocoon.") + var/obj/structure/moth/cocoon/C = new(get_turf(H)) + H.forceMove(C) + C.preparing_to_emerge = TRUE + H.apply_status_effect(STATUS_EFFECT_COCOONED) + H.KnockOut() + addtimer(CALLBACK(src, .proc/emerge, C), COCOON_EMERGE_DELAY, TIMER_UNIQUE) + else + to_chat(H, "You need to hold still in order to weave a cocoon!") + +/** + * Removes moth from cocoon, restores burnt wings + */ +/datum/action/innate/cocoon/proc/emerge(obj/structure/moth/cocoon/C) + for(var/mob/living/carbon/human/H in C.contents) + H.remove_status_effect(STATUS_EFFECT_COCOONED) + H.remove_status_effect(STATUS_EFFECT_BURNT_WINGS) + C.preparing_to_emerge = FALSE + qdel(C) + +/obj/structure/moth/cocoon + name = "\improper Nian cocoon" + desc = "Someone wrapped in a Nian cocoon." + icon = 'icons/effects/effects.dmi' + icon_state = "cocoon1" + color = COLOR_PALE_YELLOW //So tiders (hopefully) don't decide to immediately bust them open + max_integrity = 60 + var/preparing_to_emerge + +/obj/structure/moth/cocoon/Initialize(mapload) + . = ..() + icon_state = pick("cocoon1", "cocoon2", "cocoon3") + +/obj/structure/moth/cocoon/Destroy() + if(!preparing_to_emerge) + visible_message("[src] splits open from within!") + else + visible_message("[src] is smashed open, harming the Nian within!") + for(var/mob/living/carbon/human/H in contents) + H.adjustBruteLoss(COCOON_HARM_AMOUNT) + H.adjustFireLoss(COCOON_HARM_AMOUNT) + H.AdjustWeakened(5) + + for(var/mob/living/carbon/human/H in contents) + H.remove_status_effect(STATUS_EFFECT_COCOONED) + H.adjust_nutrition(COCOON_NUTRITION_AMOUNT) + H.WakeUp() + H.forceMove(loc) + return ..() + +/datum/status_effect/burnt_wings + id = "burnt_wings" + alert_type = null + +/datum/status_effect/burnt_wings/on_creation(mob/living/new_owner, ...) + var/mob/living/carbon/human/H = new_owner + if(istype(H)) + H.change_body_accessory("Burnt Off Wings") + H.change_head_accessory("Burnt Off Antennae") + return ..() + +/datum/status_effect/burnt_wings/on_remove() + owner.UpdateAppearance() + return ..() + +/datum/status_effect/cocooned + id = "cocooned" + alert_type = null + +#undef COCOON_WEAVE_DELAY +#undef COCOON_EMERGE_DELAY +#undef COCOON_HARM_AMOUNT +#undef COCOON_NUTRITION_AMOUNT +#undef FLYSWATTER_DAMAGE_MULTIPLIER diff --git a/code/modules/mob/living/carbon/human/species/vox.dm b/code/modules/mob/living/carbon/human/species/vox.dm index a52ae7bb06d..771f685f9d1 100644 --- a/code/modules/mob/living/carbon/human/species/vox.dm +++ b/code/modules/mob/living/carbon/human/species/vox.dm @@ -26,7 +26,7 @@ inherent_traits = list(TRAIT_NOGERMS, TRAIT_NODECAY) clothing_flags = HAS_UNDERWEAR | HAS_UNDERSHIRT | HAS_SOCKS //Species-fitted 'em all. dietflags = DIET_OMNI - bodyflags = HAS_ICON_SKIN_TONE | HAS_TAIL | TAIL_WAGGING | TAIL_OVERLAPPED | HAS_BODY_MARKINGS | HAS_TAIL_MARKINGS + bodyflags = HAS_ICON_SKIN_TONE | HAS_TAIL | TAIL_WAGGING | TAIL_OVERLAPPED | HAS_BODY_MARKINGS | HAS_TAIL_MARKINGS | HAS_BODYACC_COLOR blood_color = "#2299FC" flesh_color = "#808D11" diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 40dec488f86..7f9eae2c26f 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -277,6 +277,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) apply_overlay(BODY_LAYER) //tail update_tail_layer() + update_wing_layer() update_int_organs() //head accessory update_head_accessory() @@ -527,6 +528,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) UpdateDamageIcon() force_update_limbs() update_tail_layer() + update_wing_layer() update_halo_layer() overlays.Cut() // Force all overlays to regenerate update_fire() @@ -898,6 +900,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) apply_overlay(SUIT_LAYER) update_tail_layer() + update_wing_layer() update_collar() /mob/living/carbon/human/update_inv_pockets() @@ -1069,6 +1072,31 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) I.screen_loc = ui_back client.screen += I +/mob/living/carbon/human/proc/update_wing_layer() + remove_overlay(WING_UNDERLIMBS_LAYER) + remove_overlay(WING_LAYER) + if(!istype(body_accessory, /datum/body_accessory/wing)) + if(dna.species.optional_body_accessory) + return + else + body_accessory = GLOB.body_accessory_by_name[dna.species.default_bodyacc] + + if(!body_accessory.try_restrictions(src)) + return + + var/mutable_appearance/wings = mutable_appearance(body_accessory.icon, body_accessory.icon_state, layer = -WING_LAYER) + wings.pixel_x = body_accessory.pixel_x_offset + wings.pixel_y = body_accessory.pixel_y_offset + overlays_standing[WING_LAYER] = wings + + if(body_accessory.has_behind) + var/mutable_appearance/under_wing = mutable_appearance(body_accessory.icon, "[body_accessory.icon_state]_BEHIND", layer = -WING_UNDERLIMBS_LAYER) + under_wing.pixel_x = body_accessory.pixel_x_offset + under_wing.pixel_y = body_accessory.pixel_y_offset + overlays_standing[WING_UNDERLIMBS_LAYER] = under_wing + + apply_overlay(WING_UNDERLIMBS_LAYER) + apply_overlay(WING_LAYER) /mob/living/carbon/human/proc/update_tail_layer() remove_overlay(TAIL_UNDERLIMBS_LAYER) // SEW direction icons, overlayed by LIMBS_LAYER. @@ -1142,6 +1170,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) overlays_standing[TAIL_LAYER] = mutable_appearance(over, layer = -TAIL_LAYER) else // Otherwise, since the user's tail isn't overlapped by limbs, go ahead and use default icon generation. overlays_standing[TAIL_LAYER] = mutable_appearance(tail_s, layer = -TAIL_LAYER) + apply_overlay(TAIL_LAYER) apply_overlay(TAIL_UNDERLIMBS_LAYER) @@ -1242,6 +1271,7 @@ GLOBAL_LIST_EMPTY(damage_icon_parts) /mob/living/carbon/human/handle_transform_change() ..() update_tail_layer() + update_wing_layer() //Adds a collar overlay above the helmet layer if the suit has one // Suit needs an identically named sprite in icons/mob/clothing/collar.dmi diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 5ce7ece322a..a241da11619 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -494,6 +494,7 @@ human_mob.decaylevel = 0 human_mob.remove_all_embedded_objects() + SEND_SIGNAL(src, COMSIG_LIVING_AHEAL) restore_all_organs() surgeries.Cut() //End all surgeries. if(stat == DEAD) diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 73f3da863ee..6edcec8c385 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -207,6 +207,7 @@ return FALSE var/turf/location = get_turf(src) location.hotspot_expose(700, 50, 1) + SEND_SIGNAL(src, COMSIG_LIVING_FIRE_TICK) return TRUE /mob/living/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 6ebc95cc177..529063879f2 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -198,6 +198,7 @@ GLOBAL_LIST_INIT(ai_verbs_default, list( add_language("Chittin", 1) add_language("Bubblish", 1) add_language("Clownish", 1) + add_language("Tkachi", 1) if(!safety)//Only used by AIize() to successfully spawn an AI. if(!B)//If there is no player/brain inside. diff --git a/code/modules/mob/living/silicon/pai/software/pai_toggles.dm b/code/modules/mob/living/silicon/pai/software/pai_toggles.dm index 138fb06d710..b962cacf236 100644 --- a/code/modules/mob/living/silicon/pai/software/pai_toggles.dm +++ b/code/modules/mob/living/silicon/pai/software/pai_toggles.dm @@ -55,6 +55,7 @@ user.add_language("Orluum") user.add_language("Clownish") user.add_language("Neo-Russkiya") + user.add_language("Tkachi") else user.remove_language("Sinta'unathi") user.remove_language("Siik'tajr") @@ -67,6 +68,7 @@ user.remove_language("Orluum") user.remove_language("Clownish") user.remove_language("Neo-Russkiya") + user.remove_language("Tkachi") /datum/pai_software/translator/is_active(mob/living/silicon/pai/user) return user.translator_on diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index 3c202a35029..66baf0cbbc6 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -261,6 +261,7 @@ R.add_language("Bubblish", 0) R.add_language("Orluum", 0) R.add_language("Clownish", 0) + R.add_language("Tkachi", 0) /// Adds anything in `subsystems` to the robot's verbs, and grants any actions that are in `module_actions`. /obj/item/robot_module/proc/add_subsystems_and_actions(mob/living/silicon/robot/R) @@ -527,6 +528,7 @@ R.add_language("Bubblish", 1) R.add_language("Clownish",1) R.add_language("Neo-Russkiya", 1) + R.add_language("Tkachi", 1) /obj/item/robot_module/butler/handle_death(mob/living/silicon/robot/R, gibbed) var/obj/item/storage/bag/tray/cyborg/T = locate(/obj/item/storage/bag/tray/cyborg) in modules diff --git a/code/modules/mob/new_player/sprite_accessories/moth/moth_body_markings.dm b/code/modules/mob/new_player/sprite_accessories/moth/moth_body_markings.dm new file mode 100644 index 00000000000..2ab54261755 --- /dev/null +++ b/code/modules/mob/new_player/sprite_accessories/moth/moth_body_markings.dm @@ -0,0 +1,59 @@ +/datum/sprite_accessory/body_markings/moth + icon = 'icons/mob/sprite_accessories/moth/moth_body_markings.dmi' + species_allowed = list("Nian") + +/datum/sprite_accessory/body_markings/moth/reddish + name = "Reddish Markings" + icon_state = "reddish" + +/datum/sprite_accessory/body_markings/moth/royal + name = "Royal Markings" + icon_state = "royal" + +/datum/sprite_accessory/body_markings/moth/gothic + name = "Gothic Markings" + icon_state = "gothic" + +/datum/sprite_accessory/body_markings/moth/whitefly + name = "White Fly Markings" + icon_state = "whitefly" + +/datum/sprite_accessory/body_markings/moth/lovers + name = "Lovers Markings" + icon_state = "lovers" + +/datum/sprite_accessory/body_markings/moth/burnt_off + name = "Burnt Off Markings" + icon_state = "burnt_off" + +/datum/sprite_accessory/body_markings/moth/firewatch + name = "Firewatch Markings" + icon_state = "firewatch" + +/datum/sprite_accessory/body_markings/moth/deathhead + name = "Deathshead Markings" + icon_state = "deathhead" + +/datum/sprite_accessory/body_markings/moth/poison + name = "Poison Markings" + icon_state = "poison" + +/datum/sprite_accessory/body_markings/moth/ragged + name = "Ragged Markings" + icon_state = "ragged" + +/datum/sprite_accessory/body_markings/moth/moonfly + name = "Moon Fly Markings" + icon_state = "moonfly" + +/datum/sprite_accessory/body_markings/moth/oakworm + name = "Oak Worm Markings" + icon_state = "oakworm" + +/datum/sprite_accessory/body_markings/moth/jungle + name = "Jungle Markings" + icon_state = "jungle" + +/datum/sprite_accessory/body_markings/moth/witchwing + name = "Witch Wing Markings" + icon_state = "witchwing" diff --git a/code/modules/mob/new_player/sprite_accessories/moth/moth_head_accessories.dm b/code/modules/mob/new_player/sprite_accessories/moth/moth_head_accessories.dm new file mode 100644 index 00000000000..fd7878c2fbb --- /dev/null +++ b/code/modules/mob/new_player/sprite_accessories/moth/moth_head_accessories.dm @@ -0,0 +1,73 @@ +/datum/sprite_accessory/head_accessory/moth + icon = 'icons/mob/sprite_accessories/moth/moth_head_accessories.dmi' + species_allowed = list("Nian") + over_hair = TRUE + do_colouration = FALSE + +/datum/sprite_accessory/head_accessory/moth/plain + name = "Plain Antennae" + icon_state = "plain" + +/datum/sprite_accessory/head_accessory/moth/reddish + name = "Reddish Antennae" + icon_state = "reddish" + +/datum/sprite_accessory/head_accessory/moth/royal + name = "Royal Antennae" + icon_state = "royal" + +/datum/sprite_accessory/head_accessory/moth/gothic + name = "Gothic Antennae" + icon_state = "gothic" + +/datum/sprite_accessory/head_accessory/moth/whitefly + name = "White Fly Antennae" + icon_state = "whitefly" + +/datum/sprite_accessory/head_accessory/moth/lovers + name = "Lovers Antennae" + icon_state = "lovers" + +/datum/sprite_accessory/head_accessory/moth/burnt_off + name = "Burnt Off Antennae" + icon_state = "burnt_off" + +/datum/sprite_accessory/head_accessory/moth/firewatch + name = "Firewatch Antennae" + icon_state = "firewatch" + +/datum/sprite_accessory/head_accessory/moth/deathhead + name = "Deathshead Antennae" + icon_state = "deathhead" + +/datum/sprite_accessory/head_accessory/moth/poison + name = "Poison Antennae" + icon_state = "poison" + +/datum/sprite_accessory/head_accessory/moth/moonfly + name = "Moon Fly Antennae" + icon_state = "moonfly" + +/datum/sprite_accessory/head_accessory/moth/oakworm + name = "Oak Worm Antennae" + icon_state = "oakworm" + +/datum/sprite_accessory/head_accessory/moth/jungle + name = "Jungle Antennae" + icon_state = "jungle" + +/datum/sprite_accessory/head_accessory/moth/witchwing + name = "Witch Wing Antennae" + icon_state = "witchwing" + +/datum/sprite_accessory/head_accessory/moth/regal + name = "Regal Antennae" + icon_state = "regal" + +/datum/sprite_accessory/head_accessory/moth/mothra + name = "Mothra Antennae" + icon_state = "mothra" + +/datum/sprite_accessory/head_accessory/moth/mothra + name = "Snow Antennae" + icon_state = "snow" diff --git a/code/modules/mob/new_player/sprite_accessories/moth/moth_head_markings.dm b/code/modules/mob/new_player/sprite_accessories/moth/moth_head_markings.dm new file mode 100644 index 00000000000..3ce6396d9e7 --- /dev/null +++ b/code/modules/mob/new_player/sprite_accessories/moth/moth_head_markings.dm @@ -0,0 +1,59 @@ +/datum/sprite_accessory/body_markings/head/moth + icon = 'icons/mob/sprite_accessories/moth/moth_head_markings.dmi' + species_allowed = list("Nian") + +/datum/sprite_accessory/body_markings/head/moth/reddish + name = "Reddish Head Markings" + icon_state = "reddish" + +/datum/sprite_accessory/body_markings/head/moth/royal + name = "Royal Head Markings" + icon_state = "royal" + +/datum/sprite_accessory/body_markings/head/moth/gothic + name = "Gothic Head Markings" + icon_state = "gothic" + +/datum/sprite_accessory/body_markings/head/moth/whitefly + name = "White Fly Head Markings" + icon_state = "whitefly" + +/datum/sprite_accessory/body_markings/head/moth/lovers + name = "Lovers Head Markings" + icon_state = "lovers" + +/datum/sprite_accessory/body_markings/head/moth/burnt_off + name = "Burnt Off Head Markings" + icon_state = "burnt_off" + +/datum/sprite_accessory/body_markings/head/moth/firewatch + name = "Firewatch Head Markings" + icon_state = "firewatch" + +/datum/sprite_accessory/body_markings/head/moth/deathhead + name = "Deathshead Head Markings" + icon_state = "deathhead" + +/datum/sprite_accessory/body_markings/head/moth/poison + name = "Poison Head Markings" + icon_state = "poison" + +/datum/sprite_accessory/body_markings/head/moth/ragged + name = "Ragged Head Markings" + icon_state = "ragged" + +/datum/sprite_accessory/body_markings/head/moth/moonfly + name = "Moon Fly Head Markings" + icon_state = "moonfly" + +/datum/sprite_accessory/body_markings/head/moth/oakworm + name = "Oak Worm Head Markings" + icon_state = "oakworm" + +/datum/sprite_accessory/body_markings/head/moth/jungle + name = "Jungle Head Markings" + icon_state = "jungle" + +/datum/sprite_accessory/body_markings/head/moth/witchwing + name = "Witch Wing Head Markings" + icon_state = "witchwing" diff --git a/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm b/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm index a3ffe70eb39..c6fdfd91b2e 100644 --- a/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm +++ b/code/modules/mob/new_player/sprite_accessories/sprite_accessories.dm @@ -70,7 +70,7 @@ icon = 'icons/mob/human_face.dmi' // Keep bald hair here, as for some reason, putting it elsewhere lead to it being colourable - Also it make sense as it is shared by everyone. name = "Bald" icon_state = "bald" - species_allowed = list("Human", "Unathi", "Vox", "Diona", "Kidan", "Grey", "Plasmaman", "Skeleton", "Vulpkanin", "Tajaran") + species_allowed = list("Human", "Unathi", "Vox", "Diona", "Kidan", "Grey", "Plasmaman", "Skeleton", "Vulpkanin", "Tajaran", "Nian") glasses_over = 1 /datum/sprite_accessory/facial_hair @@ -98,7 +98,7 @@ /datum/sprite_accessory/body_markings icon = 'icons/mob/sprite_accessories/human/human_body_markings.dmi' - species_allowed = list("Unathi", "Tajaran", "Vulpkanin", "Machine", "Vox", "Kidan") + species_allowed = list("Unathi", "Tajaran", "Vulpkanin", "Machine", "Vox", "Kidan", "Nian") icon_state = "accessory_none" marking_location = "body" @@ -168,7 +168,7 @@ /////////////////////////// /datum/sprite_accessory/underwear icon = 'icons/mob/clothing/underwear.dmi' - species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox") + species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox", "Nian") sprite_sheets = list( "Vox" = 'icons/mob/clothing/species/vox/underwear.dmi', "Grey" = 'icons/mob/clothing/species/grey/underwear.dmi' @@ -178,7 +178,7 @@ /datum/sprite_accessory/underwear/nude name = "Nude" icon_state = null - species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox") + species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox", "Nian") /datum/sprite_accessory/underwear/male gender = MALE @@ -298,7 +298,7 @@ //////////////////////////// /datum/sprite_accessory/undershirt icon = 'icons/mob/clothing/underwear.dmi' - species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox") + species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox", "Nian") sprite_sheets = list( "Vox" = 'icons/mob/clothing/species/vox/underwear.dmi', "Grey" = 'icons/mob/clothing/species/grey/underwear.dmi') @@ -307,7 +307,7 @@ /datum/sprite_accessory/undershirt/nude name = "Nude" icon_state = null - species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox") + species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox", "Nian") //plain color shirts /datum/sprite_accessory/undershirt/shirt_white @@ -537,14 +537,14 @@ /////////////////////// /datum/sprite_accessory/socks icon = 'icons/mob/clothing/underwear.dmi' - species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox") + species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox", "Nian") sprite_sheets = list("Vox" = 'icons/mob/clothing/species/vox/underwear.dmi') gender = NEUTER /datum/sprite_accessory/socks/nude name = "Nude" icon_state = null - species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox") + species_allowed = list("Human", "Unathi", "Diona", "Vulpkanin", "Tajaran", "Kidan", "Grey", "Plasmaman", "Machine", "Skrell", "Slime People", "Skeleton", "Drask", "Vox", "Nian") /datum/sprite_accessory/socks/white_norm name = "Normal White" diff --git a/code/modules/surgery/organs/subtypes/moth.dm b/code/modules/surgery/organs/subtypes/moth.dm new file mode 100644 index 00000000000..fd9730af532 --- /dev/null +++ b/code/modules/surgery/organs/subtypes/moth.dm @@ -0,0 +1,26 @@ +/obj/item/organ/internal/eyes/nian + name = "nian eyeballs" + see_in_dark = 5 + flash_protect = FLASH_PROTECTION_SENSITIVE //BURN THE MOTH EYES + +/obj/item/organ/internal/liver/nian + name = "nian liver" + icon = 'icons/obj/species_organs/nian.dmi' + +/obj/item/organ/internal/heart/nian + name = "nian heart" + icon = 'icons/obj/species_organs/nian.dmi' + +/obj/item/organ/internal/brain/nian + icon = 'icons/obj/species_organs/nian.dmi' + icon_state = "brain2" + mmi_icon = 'icons/obj/species_organs/nian.dmi' + mmi_icon_state = "mmi_full" + +/obj/item/organ/internal/lungs/nian + name = "nian lungs" + icon = 'icons/obj/species_organs/nian.dmi' + +/obj/item/organ/internal/kidneys/nian + name = "nian kidneys" + icon = 'icons/obj/species_organs/nian.dmi' diff --git a/code/modules/tgui/modules/appearance_changer.dm b/code/modules/tgui/modules/appearance_changer.dm index f9f51cafc83..729b728c350 100644 --- a/code/modules/tgui/modules/appearance_changer.dm +++ b/code/modules/tgui/modules/appearance_changer.dm @@ -338,7 +338,7 @@ return owner && (flags & APPEARANCE_MARKINGS) && (body_flags & marking_flag) /datum/ui_module/appearance_changer/proc/can_change_body_accessory() - return owner && (flags & APPEARANCE_BODY_ACCESSORY) && (owner.dna.species.bodyflags & HAS_TAIL) + return owner && (flags & APPEARANCE_BODY_ACCESSORY) && (owner.dna.species.bodyflags & HAS_BODY_ACCESSORY) /datum/ui_module/appearance_changer/proc/can_change_alt_head() if(!head_organ) diff --git a/goon/browserassets/css/browserOutput-dark.css b/goon/browserassets/css/browserOutput-dark.css index bbee5d2625d..ee110da7704 100644 --- a/goon/browserassets/css/browserOutput-dark.css +++ b/goon/browserassets/css/browserOutput-dark.css @@ -346,11 +346,12 @@ h1.alert, h2.alert {color: #FFF;} .kidan {color: #C64C05;} .slime {color: #0077AA;} .drask {color: #a3d4eb; font-family: "Arial Black";} +.moth {color: #869b29; font-family: "Copperplate";} .clown {color: #ff0000;} .shadowling {color: #Cb2799;} .vulpkanin {color: #B97A57;} .abductor {color: #800080; font-style: italic;} -.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} +.mind_control {color: #A00D6F; font-size: 3; font-weight: bold; font-style: italic;} .rough {font-family: 'Trebuchet MS', cursive, sans-serif;} .say_quote {font-family: Georgia, Verdana, sans-serif;} .cult {color: #800080; font-weight: bold; font-style: italic;} diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css index cc6ed7fdcb8..3411927c4aa 100644 --- a/goon/browserassets/css/browserOutput.css +++ b/goon/browserassets/css/browserOutput.css @@ -343,6 +343,7 @@ h1.alert, h2.alert {color: #000000;} .kidan {color: #664205;} .slime {color: #0077AA;} .drask {color: #a3d4eb; font-family: "Arial Black";} +.moth {color: #869b29; font-family: "Copperplate";} .clown {color: #ff0000;} .shadowling {color: #3b2769;} .vulpkanin {color: #B97A57;} diff --git a/icons/mob/human_face.dmi b/icons/mob/human_face.dmi index 9b6d9468b9d..876057298bf 100644 Binary files a/icons/mob/human_face.dmi and b/icons/mob/human_face.dmi differ diff --git a/icons/mob/human_races/r_moth.dmi b/icons/mob/human_races/r_moth.dmi new file mode 100644 index 00000000000..16a1a99f2c2 Binary files /dev/null and b/icons/mob/human_races/r_moth.dmi differ diff --git a/icons/mob/sprite_accessories/moth/moth_body_markings.dmi b/icons/mob/sprite_accessories/moth/moth_body_markings.dmi new file mode 100644 index 00000000000..4dd5227366b Binary files /dev/null and b/icons/mob/sprite_accessories/moth/moth_body_markings.dmi differ diff --git a/icons/mob/sprite_accessories/moth/moth_head_accessories.dmi b/icons/mob/sprite_accessories/moth/moth_head_accessories.dmi new file mode 100644 index 00000000000..d5f1d4ce474 Binary files /dev/null and b/icons/mob/sprite_accessories/moth/moth_head_accessories.dmi differ diff --git a/icons/mob/sprite_accessories/moth/moth_head_markings.dmi b/icons/mob/sprite_accessories/moth/moth_head_markings.dmi new file mode 100644 index 00000000000..65674417733 Binary files /dev/null and b/icons/mob/sprite_accessories/moth/moth_head_markings.dmi differ diff --git a/icons/mob/sprite_accessories/moth/moth_wings.dmi b/icons/mob/sprite_accessories/moth/moth_wings.dmi new file mode 100644 index 00000000000..0bbcd1aeee7 Binary files /dev/null and b/icons/mob/sprite_accessories/moth/moth_wings.dmi differ diff --git a/icons/obj/assemblies.dmi b/icons/obj/assemblies.dmi index b6e458c0e24..92fc44efb9d 100644 Binary files a/icons/obj/assemblies.dmi and b/icons/obj/assemblies.dmi differ diff --git a/icons/obj/butts.dmi b/icons/obj/butts.dmi index 104906120d4..1fbdf5cdfad 100644 Binary files a/icons/obj/butts.dmi and b/icons/obj/butts.dmi differ diff --git a/icons/obj/species_organs/nian.dmi b/icons/obj/species_organs/nian.dmi new file mode 100644 index 00000000000..81ac3c7f142 Binary files /dev/null and b/icons/obj/species_organs/nian.dmi differ diff --git a/paradise.dme b/paradise.dme index f785533761a..737a8b888a8 100644 --- a/paradise.dme +++ b/paradise.dme @@ -1950,6 +1950,7 @@ #include "code\modules\mob\living\carbon\human\species\kidan.dm" #include "code\modules\mob\living\carbon\human\species\machine.dm" #include "code\modules\mob\living\carbon\human\species\monkey.dm" +#include "code\modules\mob\living\carbon\human\species\moth.dm" #include "code\modules\mob\living\carbon\human\species\nucleation.dm" #include "code\modules\mob\living\carbon\human\species\plasmaman.dm" #include "code\modules\mob\living\carbon\human\species\shadow.dm" @@ -2159,6 +2160,9 @@ #include "code\modules\mob\new_player\sprite_accessories\kidan\kidan_hair.dm" #include "code\modules\mob\new_player\sprite_accessories\kidan\kidan_head_accessories.dm" #include "code\modules\mob\new_player\sprite_accessories\kidan\kidan_head_markings.dm" +#include "code\modules\mob\new_player\sprite_accessories\moth\moth_body_markings.dm" +#include "code\modules\mob\new_player\sprite_accessories\moth\moth_head_accessories.dm" +#include "code\modules\mob\new_player\sprite_accessories\moth\moth_head_markings.dm" #include "code\modules\mob\new_player\sprite_accessories\nucleation\nucleation_face.dm" #include "code\modules\mob\new_player\sprite_accessories\shared\shared_tail_markings.dm" #include "code\modules\mob\new_player\sprite_accessories\skrell\skrell_face.dm" @@ -2497,6 +2501,7 @@ #include "code\modules\surgery\organs\subtypes\grey.dm" #include "code\modules\surgery\organs\subtypes\kidan.dm" #include "code\modules\surgery\organs\subtypes\machine.dm" +#include "code\modules\surgery\organs\subtypes\moth.dm" #include "code\modules\surgery\organs\subtypes\nucleation.dm" #include "code\modules\surgery\organs\subtypes\plasmaman.dm" #include "code\modules\surgery\organs\subtypes\skrell.dm" diff --git a/sound/voice/scream_moth.ogg b/sound/voice/scream_moth.ogg new file mode 100644 index 00000000000..482086fb630 Binary files /dev/null and b/sound/voice/scream_moth.ogg differ