diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 21b66f5e37..3407b3342b 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -86,6 +86,7 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list( #define isinsect(A) (is_species(A, /datum/species/insect)) #define isxenoperson(A) (is_species(A, /datum/species/xeno)) #define isstartjelly(A) (is_species(A, /datum/species/jelly/roundstartslime)) +#define isarachnid(A) (is_species(A, /datum/species/arachnid)) //more carbon mobs #define ismonkey(A) (istype(A, /mob/living/carbon/monkey)) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 1119ef44ed..b8c009ff4f 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -32,6 +32,9 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/caps, GLOB.caps_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_wings, GLOB.insect_wings_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_fluff, GLOB.insect_fluffs_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/arachnid_legs, GLOB.arachnid_legs_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/arachnid_spinneret, GLOB.arachnid_spinneret_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/arachnid_mandibles, GLOB.arachnid_mandibles_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/deco_wings, GLOB.deco_wings_list) //CIT CHANGES START HERE, ADDS SNOWFLAKE BODYPARTS AND MORE diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 52e26b67e7..513437e57e 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -76,6 +76,12 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_fluff, GLOB.insect_fluffs_list) if(!GLOB.insect_markings_list.len) init_sprite_accessory_subtypes(/datum/sprite_accessory/insect_markings, GLOB.insect_markings_list) + if(!GLOB.arachnid_legs_list.len) + init_sprite_accessory_subtypes(/datum/sprite_accessory/arachnid_legs, GLOB.arachnid_legs_list) + if(!GLOB.arachnid_spinneret_list.len) + init_sprite_accessory_subtypes(/datum/sprite_accessory/arachnid_spinneret, GLOB.arachnid_spinneret_list) + if(!GLOB.arachnid_mandibles_list.len) + init_sprite_accessory_subtypes(/datum/sprite_accessory/arachnid_mandibles, GLOB.arachnid_mandibles_list) //CIT CHANGES - genitals and such if(!GLOB.cock_shapes_list.len) @@ -177,6 +183,9 @@ "insect_wings" = pick(GLOB.insect_wings_list), "insect_fluff" = "None", "insect_markings" = pick(GLOB.insect_markings_list), + "arachnid_legs" = pick(GLOB.arachnid_legs_list), + "arachnid_spinneret" = pick(GLOB.arachnid_spinneret_list), + "arachnid_mandibles" = pick(GLOB.arachnid_mandibles_list), "taur" = "None", "mam_body_markings" = snowflake_markings_list.len ? pick(snowflake_markings_list) : "None", "mam_ears" = snowflake_ears_list ? pick(snowflake_ears_list) : "None", @@ -278,6 +287,13 @@ if(!findname(.)) break +/proc/random_unique_arachnid_name(attempts_to_find_unique_name=10) + for(var/i in 1 to attempts_to_find_unique_name) + . = capitalize(pick(GLOB.arachnid_first)) + " " + capitalize(pick(GLOB.arachnid_last)) + + if(!findname(.)) + break + #define SKINTONE2HEX(skin_tone) GLOB.skin_tones[skin_tone] || skin_tone /proc/random_skin_tone() diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index e1848b21a2..a61e3a6492 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -16,6 +16,9 @@ /proc/moth_name() return "[pick(GLOB.moth_first)] [pick(GLOB.moth_last)]" +/proc/arachnid_name() + return "[pick(GLOB.arachnid_first)] [pick(GLOB.arachnid_last)]" + /proc/church_name() var/static/church_name if (church_name) diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index a327b7fcde..0444e42e91 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -38,6 +38,9 @@ GLOBAL_LIST_EMPTY(r_wings_list) GLOBAL_LIST_EMPTY(insect_wings_list) GLOBAL_LIST_EMPTY(insect_fluffs_list) GLOBAL_LIST_EMPTY(insect_markings_list) +GLOBAL_LIST_EMPTY(arachnid_legs_list) +GLOBAL_LIST_EMPTY(arachnid_spinneret_list) +GLOBAL_LIST_EMPTY(arachnid_mandibles_list) GLOBAL_LIST_EMPTY(caps_list) //a way to index the right bodypart list given the type of bodypart @@ -60,6 +63,9 @@ GLOBAL_LIST_INIT(mutant_reference_list, list( "insect_wings" = GLOB.insect_wings_list, "insect_fluff" = GLOB.insect_fluffs_list, "insect_markings" = GLOB.insect_markings_list, + "arachnid_legs" = GLOB.arachnid_legs_list, + "arachnid_spinneret" = GLOB.arachnid_spinneret_list, + "arachnid_mandibles" = GLOB.arachnid_mandibles_list, "caps" = GLOB.caps_list, "ipc_screen" = GLOB.ipc_screens_list, "ipc_antenna" = GLOB.ipc_antennas_list, @@ -275,7 +281,7 @@ GLOBAL_LIST_INIT(roundstart_tongues, list("default","human tongue" = /obj/item/o //locked parts are those that your picked species requires to have //unlocked parts are those that anyone can choose on customisation regardless //parts not in unlocked, but in all, are thus locked -GLOBAL_LIST_INIT(all_mutant_parts, list("tail_lizard" = "Tail", "mam_tail" = "Tail", "tail_human" = "Tail", "snout" = "Snout", "frills" = "Frills", "spines" = "Spines", "body_markings" = "Body Markings", "mam_body_markings" = "Species Markings" , "mam_ears" = "Ears", "ears" = "Ears", "mam_snouts" = "Snout", "legs" = "Legs", "deco_wings" = "Decorative Wings", "insect_wings" = "Insect Wings", "insect_fluff" = "Insect Fluff", "taur" = "Tauric Body", "insect_markings" = "Insect Markings", "wings" = "Wings", "xenohead" = "Caste Head", "xenotail" = "Tail", "xenodorsal" = "Dorsal Spines", "ipc_screen" = "Screen", "ipc_antenna" = "Antenna", "meat_type" = "Meat Type", "horns" = "Horns")) +GLOBAL_LIST_INIT(all_mutant_parts, list("tail_lizard" = "Tail", "mam_tail" = "Tail", "tail_human" = "Tail", "snout" = "Snout", "frills" = "Frills", "spines" = "Spines", "body_markings" = "Body Markings", "mam_body_markings" = "Species Markings" , "mam_ears" = "Ears", "ears" = "Ears", "mam_snouts" = "Snout", "legs" = "Legs", "deco_wings" = "Decorative Wings", "insect_wings" = "Insect Wings", "insect_fluff" = "Insect Fluff", "taur" = "Tauric Body", "insect_markings" = "Insect Markings", "wings" = "Wings", "arachnid_legs" = "Arachnid Legs", "arachnid_spinneret" = "Spinneret", "arachnid_mandibles" = "Mandibles", "xenohead" = "Caste Head", "xenotail" = "Tail", "xenodorsal" = "Dorsal Spines", "ipc_screen" = "Screen", "ipc_antenna" = "Antenna", "meat_type" = "Meat Type", "horns" = "Horns")) 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 diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm index b80fcf0bbf..1148e92dd5 100644 --- a/code/_globalvars/lists/names.dm +++ b/code/_globalvars/lists/names.dm @@ -16,6 +16,8 @@ GLOBAL_LIST_INIT(carp_names, world.file2list("strings/names/carp.txt")) GLOBAL_LIST_INIT(golem_names, world.file2list("strings/names/golem.txt")) GLOBAL_LIST_INIT(moth_first, world.file2list("strings/names/moth_first.txt")) GLOBAL_LIST_INIT(moth_last, world.file2list("strings/names/moth_last.txt")) +GLOBAL_LIST_INIT(arachnid_first, world.file2list("strings/names/arachnid_first.txt")) +GLOBAL_LIST_INIT(arachnid_last, world.file2list("strings/names/arachnid_last.txt")) GLOBAL_LIST_INIT(plasmaman_names, world.file2list("strings/names/plasmaman.txt")) GLOBAL_LIST_INIT(ethereal_names, world.file2list("strings/names/ethereal.txt")) GLOBAL_LIST_INIT(posibrain_names, world.file2list("strings/names/posibrain.txt")) diff --git a/code/controllers/subsystem/traumas.dm b/code/controllers/subsystem/traumas.dm index f556f7dee7..1dea40a802 100644 --- a/code/controllers/subsystem/traumas.dm +++ b/code/controllers/subsystem/traumas.dm @@ -198,7 +198,8 @@ SUBSYSTEM_DEF(traumas) "aliens" = typecacheof(list(/datum/species/abductor, /datum/species/jelly, /datum/species/pod, /datum/species/shadow)), "anime" = typecacheof(list(/datum/species/human/felinid)), "cats" = typecacheof(list(/datum/species/human/felinid)), - "syndicate" = typecacheof(list(/datum/species/corporate, /datum/species/zombie/infectious)) + "syndicate" = typecacheof(list(/datum/species/corporate, /datum/species/zombie/infectious)), + "arachnid" = typecacheof(list(/datum/species/arachnid)) ) return ..() diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm index bd9ecaeeaa..c859d38587 100644 --- a/code/datums/mutations/actions.dm +++ b/code/datums/mutations/actions.dm @@ -342,8 +342,9 @@ to_chat(user, "You can't lay webs here!") failed = TRUE var/turf/T = get_turf(user) - var/obj/structure/spider/stickyweb/genetic/W = locate() in T - if(W) + var/obj/structure/spider/stickyweb/W = locate() in T + var/obj/structure/arachnid/W2 = locate() in T + if(W || W2) to_chat(user, "There's already a web here!") failed = TRUE if(failed) diff --git a/code/game/objects/effects/arachnid_web.dm b/code/game/objects/effects/arachnid_web.dm new file mode 100644 index 0000000000..2adaa12dc9 --- /dev/null +++ b/code/game/objects/effects/arachnid_web.dm @@ -0,0 +1,70 @@ +/obj/structure/arachnid + name = "large web" + icon = 'icons/effects/effects.dmi' + desc = "It's stringy and sticky, but the threads are larger than what spiderlings could produce." + anchored = TRUE + density = FALSE + max_integrity = 20 + +/obj/structure/arachnid/New() + ..() + icon_state = pick(list("stickyweb1", "stickyweb2")) + + +/obj/structure/arachnid/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) + if(damage_type == BURN)//the stickiness of the web mutes all attack sounds except fire damage type + playsound(loc, 'sound/items/welder.ogg', 100, TRUE) + +/obj/structure/arachnid/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) + if(damage_flag == "melee") + switch(damage_type) + if(BURN) + damage_amount *= 2 + if(BRUTE) + damage_amount *= 0.5 + . = ..() + +/obj/structure/arachnid/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) + if(exposed_temperature > 300) + take_damage(5, BURN, 0, 0) + +/obj/structure/arachnid/CanPass(atom/movable/mover, turf/target) + . = ..() + if(isarachnid(mover)) + + return TRUE + else if(isliving(mover)) + if(isarachnid(mover.pulledby)) + + return TRUE + if(prob(20)) + to_chat(mover, "You get stuck in \the [src] for a moment.") + return FALSE + +/obj/structure/arachnid/cocoon + name = "cocoon" + desc = "Something wrapped in silky spider web." + icon_state = "cocoon1" + anchored = FALSE + density = FALSE + max_integrity = 60 + +/obj/structure/arachnid/cocoon/Initialize() + icon_state = pick("cocoon1","cocoon2","cocoon3") + . = ..() + +/obj/structure/arachnid/cocoon/container_resist(mob/living/user) + var/breakout_time = 150 // DECI not DECA ffs + to_chat(user, "You struggle against the tight bonds... (This will take about [DisplayTimeText(breakout_time)].)") + visible_message("You see something struggling and writhing in \the [src]!") + if(do_after(user,(breakout_time), target = src)) + if(!user || user.stat != CONSCIOUS || user.loc != src) + return + qdel(src) + +/obj/structure/arachnid/cocoon/Destroy() + var/turf/T = get_turf(src) + src.visible_message("\The [src] splits open.") + for(var/atom/movable/A in contents) + A.forceMove(T) + return ..() diff --git a/code/modules/admin/create_mob.dm b/code/modules/admin/create_mob.dm index e287d9b1b3..6aab698a4a 100644 --- a/code/modules/admin/create_mob.dm +++ b/code/modules/admin/create_mob.dm @@ -43,6 +43,9 @@ H.dna.features["insect_wings"] = pick(GLOB.insect_wings_list) H.dna.features["deco_wings"] = pick(GLOB.deco_wings_list) H.dna.features["insect_fluff"] = pick(GLOB.insect_fluffs_list) + H.dna.features["arachnid_legs"] = pick(GLOB.arachnid_legs_list) + H.dna.features["arachnid_spinneret"] = pick(GLOB.arachnid_spinneret_list) + H.dna.features["arachnid_mandibles"] = pick(GLOB.arachnid_mandibles_list) H.dna.features["flavor_text"] = "" //Oh no. H.dna.features["body_model"] = H.gender diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 7133e3d6c5..2110ae7277 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -120,6 +120,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) "insect_wings" = "Plain", "insect_fluff" = "None", "insect_markings" = "None", + "arachnid_legs" = "Plain", + "arachnid_spinneret" = "Plain", + "arachnid_mandibles" = "Plain", "mam_body_markings" = "Plain", "mam_ears" = "None", "mam_snouts" = "None", @@ -1715,6 +1718,24 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(new_ipc_antenna) features["ipc_antenna"] = new_ipc_antenna + if("arachnid_legs") + var/new_arachnid_legs + new_arachnid_legs = input(user, "Choose your character's variant of arachnid legs:", "Character Preference") as null|anything in GLOB.arachnid_legs_list + if(new_arachnid_legs) + features["arachnid_legs"] = new_arachnid_legs + + if("arachnid_spinneret") + var/new_arachnid_spinneret + new_arachnid_spinneret = input(user, "Choose your character's spinneret markings:", "Character Preference") as null|anything in GLOB.arachnid_spinneret_list + if(new_arachnid_spinneret) + features["arachnid_spinneret"] = new_arachnid_spinneret + + if("arachnid_mandibles") + var/new_arachnid_mandibles + new_arachnid_mandibles = input(user, "Choose your character's variant of mandibles:", "Character Preference") as null|anything in GLOB.arachnid_mandibles_list + if (new_arachnid_mandibles) + features["arachnid_mandibles"] = new_arachnid_mandibles + 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 @@ -1880,6 +1901,24 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(new_insect_markings) features["insect_markings"] = new_insect_markings + if("arachnid_legs") + var/new_arachnid_legs + new_arachnid_legs = input(user, "Choose your character's variant of arachnid legs:", "Character Preference") as null|anything in GLOB.arachnid_legs_list + if(new_arachnid_legs) + features["arachnid_legs"] = new_arachnid_legs + + if("arachnid_spinneret") + var/new_arachnid_spinneret + new_arachnid_spinneret = input(user, "Choose your character's spinneret markings:", "Character Preference") as null|anything in GLOB.arachnid_spinneret_list + if(new_arachnid_spinneret) + features["arachnid_spinneret"] = new_arachnid_spinneret + + if("arachnid_mandibles") + var/new_arachnid_mandibles + new_arachnid_mandibles = input(user, "Choose your character's variant of mandibles:", "Character Preference") as null|anything in GLOB.arachnid_mandibles_list + if (new_arachnid_mandibles) + features["arachnid_mandibles"] = new_arachnid_mandibles + if("s_tone") var/list/choices = GLOB.skin_tones - GLOB.nonstandard_skin_tones if(CONFIG_GET(flag/allow_custom_skintones)) @@ -1919,6 +1958,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["xenotail"] = "None" features["tail_human"] = "None" features["tail_lizard"] = "None" + features["arachnid_spinneret"] = "None" if("ears") var/list/snowflake_ears_list = list() diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 8215301cd7..3bad31a919 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -563,6 +563,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["feature_insect_wings"] >> features["insect_wings"] S["feature_insect_fluff"] >> features["insect_fluff"] S["feature_insect_markings"] >> features["insect_markings"] + S["feature_arachnid_legs"] >> features["arachnid_legs"] + S["feature_arachnid_spinneret"] >> features["arachnid_spinneret"] + S["feature_arachnid_mandibles"] >> features["arachnid_mandibles"] S["feature_horns_color"] >> features["horns_color"] S["feature_wings_color"] >> features["wings_color"] S["persistent_scars"] >> persistent_scars @@ -747,6 +750,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car features["insect_fluff"] = sanitize_inlist(features["insect_fluff"], GLOB.insect_fluffs_list) features["insect_markings"] = sanitize_inlist(features["insect_markings"], GLOB.insect_markings_list, "None") features["insect_wings"] = sanitize_inlist(features["insect_wings"], GLOB.insect_wings_list) + features["arachnid_legs"] = sanitize_inlist(features["arachnid_legs"], GLOB.arachnid_legs_list, "Plain") + features["arachnid_spinneret"] = sanitize_inlist(features["arachnid_spinneret"], GLOB.arachnid_spinneret_list, "Plain") + features["arachnid_mandibles"] = sanitize_inlist(features["arachnid_mandibles"], GLOB.arachnid_mandibles_list, "Plain") var/static/size_min if(!size_min) @@ -886,6 +892,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["feature_insect_wings"] , features["insect_wings"]) WRITE_FILE(S["feature_insect_fluff"] , features["insect_fluff"]) WRITE_FILE(S["feature_insect_markings"] , features["insect_markings"]) + WRITE_FILE(S["feature_arachnid_legs"] , features["arachnid_legs"]) + WRITE_FILE(S["feature_arachnid_spinneret"] , features["arachnid_spinneret"]) + WRITE_FILE(S["feature_arachnid_mandibles"] , features["arachnid_mandibles"]) WRITE_FILE(S["feature_meat"] , features["meat_type"]) WRITE_FILE(S["feature_has_cock"], features["has_cock"]) diff --git a/code/modules/language/arachnid.dm b/code/modules/language/arachnid.dm new file mode 100644 index 0000000000..92ea47781e --- /dev/null +++ b/code/modules/language/arachnid.dm @@ -0,0 +1,15 @@ +/datum/language/arachnid + name = "Rachnidian" + desc = "A language that exploits the multiple limbs of arachnids to do subtle dance like movements to communicate.\ + A proper speaker's movements are quick and sharp enough to make audible whiffs and thumps however, which are intelligible over the radio." + speech_verb = "chitter" + ask_verb = "chitter" + exclaim_verb = "chitter" + key = "r" + flags = NO_STUTTER | LANGUAGE_HIDE_ICON_IF_NOT_UNDERSTOOD + + icon_state = "arachnid" + +/datum/language/arachnid/scramble(input) + . = prob(65) ? "wiff" : "thump" + . += (copytext(input, length(input)) == "?") ? "?" : "!" diff --git a/code/modules/language/language_holder.dm b/code/modules/language/language_holder.dm index c1677117e9..219d8dc184 100644 --- a/code/modules/language/language_holder.dm +++ b/code/modules/language/language_holder.dm @@ -330,6 +330,12 @@ Key procs spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), /datum/language/voltaic = list(LANGUAGE_ATOM)) +/datum/language_holder/arachnid + understood_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/arachnid = list(LANGUAGE_ATOM)) + spoken_languages = list(/datum/language/common = list(LANGUAGE_ATOM), + /datum/language/arachnid = list(LANGUAGE_ATOM)) + /datum/language_holder/empty understood_languages = list() spoken_languages = list() diff --git a/code/modules/mob/dead/new_player/sprite_accessories/arachnid.dm b/code/modules/mob/dead/new_player/sprite_accessories/arachnid.dm new file mode 100644 index 0000000000..f75c6208f8 --- /dev/null +++ b/code/modules/mob/dead/new_player/sprite_accessories/arachnid.dm @@ -0,0 +1,68 @@ +/datum/sprite_accessory/arachnid_legs + icon = 'icons/mob/arachnid_legs.dmi' + relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER) + mutant_part_string = "arachnid_legs" + color_src = 0 + +/datum/sprite_accessory/arachnid_legs/none + name = "None" + icon_state = null + relevant_layers = null + +/datum/sprite_accessory/arachnid_legs/plain + name = "Plain" + icon_state = "plain" + +/datum/sprite_accessory/arachnid_legs/fuzzy + name = "Fuzzy" + icon_state = "fuzzy" + +/datum/sprite_accessory/arachnid_legs/spiky + name = "Spiky" + icon_state = "spiky" + +/datum/sprite_accessory/arachnid_spinneret + icon = 'icons/mob/arachnid_spinneret.dmi' + relevant_layers = list(BODY_BEHIND_LAYER, BODY_ADJ_LAYER, BODY_FRONT_LAYER) + mutant_part_string = "spinneret" + color_src = 0 + +/datum/sprite_accessory/arachnid_spinneret/none + name = "None" + icon_state = null + relevant_layers = null + +/datum/sprite_accessory/arachnid_spinneret/plain + name = "Plain" + icon_state = "plain" + +/datum/sprite_accessory/arachnid_spinneret/fuzzy + name = "Fuzzy" + icon_state = "fuzzy" + +/datum/sprite_accessory/arachnid_spinneret/black_widow + name = "Black Widow" + icon_state = "blackwidow" + +/datum/sprite_accessory/arachnid_mandibles + icon = 'icons/mob/arachnid_mandibles.dmi' + relevant_layers = list(BODY_ADJ_LAYER, BODY_FRONT_LAYER) + mutant_part_string = "mandibles" + color_src = 0 + +/datum/sprite_accessory/arachnid_mandibles/none + name = "None" + icon_state = null + relevant_layers = null + +/datum/sprite_accessory/arachnid_mandibles/plain + name = "Plain" + icon_state = "plain" + +/datum/sprite_accessory/arachnid_mandibles/fuzzy + name = "Fuzzy" + icon_state = "fuzzy" + +/datum/sprite_accessory/arachnid_mandibles/spiky + name = "Spiky" + icon_state = "spiky" \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index 1b7ab81d59..710d49c075 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1250,3 +1250,6 @@ /mob/living/carbon/human/species/roundstartslime race = /datum/species/jelly/roundstartslime + +/mob/living/carbon/human/species/arachnid + race = /datum/species/arachnid diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 50a725f8cf..7ec2fb6cc6 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -118,7 +118,9 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) //the ids you can use for your species, if empty, it means default only and not changeable var/list/allowed_limb_ids - //the type of eyes this species has + //override for the icon path used when setting bodypart overlays. Intended for species that don't fit in the standard 32x32 files. + var/override_bp_icon + //the icon state of the eyes this species has var/eye_type = "normal" /////////// diff --git a/code/modules/mob/living/carbon/human/species_types/arachnid.dm b/code/modules/mob/living/carbon/human/species_types/arachnid.dm new file mode 100644 index 0000000000..2072883c54 --- /dev/null +++ b/code/modules/mob/living/carbon/human/species_types/arachnid.dm @@ -0,0 +1,155 @@ +/datum/species/arachnid + name = "Arachnid" + id = "arachnid" + override_bp_icon = 'icons/mob/arachnid_parts.dmi' + say_mod = "chitters" + default_color = "00FF00" + species_traits = list(LIPS, NOEYES, NO_UNDERWEAR) + inherent_biotypes = MOB_ORGANIC|MOB_HUMANOID|MOB_BUG + mutant_bodyparts = list("arachnid_legs" = "Plain", "arachnid_spinneret" = "Plain", "arachnid_mandibles" = "Plain") + attack_verb = "slash" + attack_sound = 'sound/weapons/slash.ogg' + miss_sound = 'sound/weapons/slashmiss.ogg' + meat = /obj/item/reagent_containers/food/snacks/meat/slab/spider + liked_food = MEAT | RAW + disliked_food = FRUIT | GROSS + toxic_food = VEGETABLES | DAIRY + mutanteyes = /obj/item/organ/eyes/night_vision/arachnid + mutanttongue = /obj/item/organ/tongue/arachnid + species_language_holder = /datum/language_holder/arachnid + brutemod = 1.1 + var/web_cooldown = 200 + var/web_ready = TRUE + var/spinner_rate = 25 + +/datum/species/arachnid/random_name(gender,unique,lastname) + if(unique) + return random_unique_arachnid_name() + + var/randname = arachnid_name() + + if(lastname) + randname += " [lastname]" + + return randname + +/datum/species/arachnid/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H) + . = ..() + if(chem.type == /datum/reagent/toxin/pestkiller) + H.adjustToxLoss(3) + H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM) + +/datum/species/arachnid/check_weakness(obj/item/weapon, mob/living/attacker) + if(istype(weapon, /obj/item/melee/flyswatter)) + return 9 //flyswatters deal 10x damage to arachnids + return 0 + +/datum/species/arachnid/on_species_gain(mob/living/carbon/human/H, datum/species/old_species) + . = ..() + var/datum/action/innate/spin_web/SW = new + var/datum/action/innate/spin_cocoon/SC = new + SC.Grant(H) + SW.Grant(H) + +/datum/species/arachnid/on_species_loss(mob/living/carbon/human/H) + . = ..() + var/datum/action/innate/spin_web/SW = locate(/datum/action/innate/spin_web) in H.actions + var/datum/action/innate/spin_cocoon/SC = locate(/datum/action/innate/spin_cocoon) in H.actions + SC?.Remove(H) + SW?.Remove(H) + +/datum/action/innate/spin_web + name = "Spin Web" + check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS + icon_icon = 'icons/mob/actions/actions_animal.dmi' + button_icon_state = "lay_web" + +/datum/action/innate/spin_cocoon + name = "Spin Cocoon" + check_flags = AB_CHECK_RESTRAINED|AB_CHECK_STUN|AB_CHECK_CONSCIOUS + icon_icon = 'icons/mob/actions/actions_animal.dmi' + button_icon_state = "wrap_0" + +/datum/action/innate/spin_web/Activate() + var/mob/living/carbon/human/species/arachnid/H = owner + var/datum/species/arachnid/E = H.dna.species + if(H.stat == "DEAD") + return + if(E.web_ready == FALSE) + to_chat(H, "You need to wait a while to regenerate web fluid.") + return + var/turf/T = get_turf(H) + if(!T) + to_chat(H, "There's no room to spin your web here!") + return + var/obj/structure/spider/stickyweb/W = locate() in T + var/obj/structure/arachnid/W2 = locate() in T + if(W || W2) + to_chat(H, "There's already a web here!") + return + // Should have some minimum amount of food before trying to activate + var/nutrition_threshold = NUTRITION_LEVEL_FED + if (H.nutrition >= nutrition_threshold) + to_chat(H, "You begin spinning some web...") + if(!do_after(H, 10 SECONDS, 1, T)) + to_chat(H, "Your web spinning was interrupted!") + return + H.adjust_nutrition(-E.spinner_rate) + addtimer(VARSET_CALLBACK(E, web_ready, TRUE), E.web_cooldown) + to_chat(H, "You use up a fair amount of energy weaving a web on the ground with your spinneret!") + new /obj/structure/arachnid(T, owner) + + else + to_chat(H, "You're too hungry to spin web right now, eat something first!") + return +/* + This took me far too long to figure out so I'm gonna document it here. + 1) Create an innate action for the species + 2) Have that action trigger a RegisterSignal for mob clicking + 3) Trigger the cocoonAtom proc on that signal + 4) Validate the target then start spinning + 5) if you're not interrupted, force move the target to the cocoon created at their location. +*/ +/datum/action/innate/spin_cocoon/Activate() + var/mob/living/carbon/human/species/arachnid/H = owner + var/datum/species/arachnid/E = H.dna.species + if(H.stat == "DEAD") + return + if(E.web_ready == FALSE) + to_chat(H, "You need to wait awhile to regenerate web fluid.") + return + var/nutrition_threshold = NUTRITION_LEVEL_FED + if (H.nutrition >= nutrition_threshold) + to_chat(H, "You pull out a strand from your spinneret, ready to wrap a target.
\ + (Press ALT+CLICK on the target to start wrapping.)
") + H.adjust_nutrition(E.spinner_rate * -0.5) + addtimer(VARSET_CALLBACK(E, web_ready, TRUE), E.web_cooldown) + RegisterSignal(H, list(COMSIG_MOB_ALTCLICKON), .proc/cocoonAtom) + return + else + to_chat(H, "You're too hungry to spin web right now, eat something first!") + return + +/datum/action/innate/spin_cocoon/proc/cocoonAtom(mob/living/carbon/human/species/arachnid/H, atom/movable/A) + UnregisterSignal(H, list(COMSIG_MOB_ALTCLICKON)) + var/datum/species/arachnid/E = H.dna.species + if (!H || !isarachnid(H)) + return COMSIG_MOB_CANCEL_CLICKON + else + if(E.web_ready == FALSE) + to_chat(H, "You need to wait awhile to regenerate web fluid.") + return + if(!do_after(H, 10 SECONDS, 1, A)) + to_chat(H, "Your web spinning was interrupted!") + return + H.adjust_nutrition(E.spinner_rate * -3) + var/obj/structure/arachnid/cocoon/C = new(A.loc) + if(isliving(A)) + C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3") + A.forceMove(C) + H.visible_message("[H] wraps [A] into a large cocoon!") + return + else + A.forceMove(C) + H.visible_message("[H] wraps [A] into a cocoon!") + return \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm index a8799f4e8c..bde5a19518 100644 --- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm +++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm @@ -368,7 +368,8 @@ var/turf/T = get_turf(S) var/obj/structure/spider/stickyweb/W = locate() in T - if(W) + var/obj/structure/arachnid/W2 = locate() in T + if(W || W2) to_chat(S, "There's already a web here!") return diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 86f6460ff7..bbc44730b6 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -1969,7 +1969,7 @@ All effects don't start immediately, but rather get worse over time; the rate is /datum/reagent/consumable/ethanol/bug_spray/on_mob_life(mob/living/carbon/M) //Bugs should not drink Bug spray. - if(isinsect(M) || isflyperson(M)) + if(isinsect(M) || isflyperson(M) || isarachnid(M)) M.adjustToxLoss(1,0) return ..() diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index 0021a49e51..e64647028c 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -781,6 +781,12 @@ race = /datum/species/lizard/ashwalker mutationtext = "The pain subsides. You feel... savage." +/datum/reagent/mutationtoxin/arachnid + name = "Arachnid Mutation Toxin" + description = "A glowing toxin." + color = "#5EFF3B" //RGB: 94, 255, 59 + race = /datum/species/arachnid + mutationtext = "The pain subsides. You feel... silky." //DANGEROUS RACES /datum/reagent/mutationtoxin/shadow diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 0ab8a69aa0..019394e3c8 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -715,21 +715,27 @@ required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/medicine/synaptizine = 1, /datum/reagent/water = 1) /datum/chemical_reaction/cat - name = "felinid mutation toxic" + name = "felinid mutation toxin" id = /datum/reagent/mutationtoxin/felinid results = list(/datum/reagent/mutationtoxin/felinid = 1) required_reagents = list(/datum/reagent/toxin/mindbreaker = 1, /datum/reagent/ammonia = 1, /datum/reagent/water = 1, /datum/reagent/pax/catnip = 1, /datum/reagent/mutationtoxin = 1) required_temp = 450 /datum/chemical_reaction/moff - name = "insect mutation toxic" + name = "insect mutation toxin" id = /datum/reagent/mutationtoxin/insect results = list(/datum/reagent/mutationtoxin/insect = 1) required_reagents = list(/datum/reagent/liquid_dark_matter = 2, /datum/reagent/ammonia = 5, /datum/reagent/lithium = 1, /datum/reagent/mutationtoxin = 1) required_temp = 320 +/datum/chemical_reaction/mutationtoxin/arachnid + name = "arachnid mutation toxin" + id = /datum/reagent/mutationtoxin/arachnid + results = list(/datum/reagent/mutationtoxin/arachnid = 1) + required_reagents = list(/datum/reagent/mutationtoxin/insect = 1, /datum/reagent/toxin/heparin = 10) + /datum/chemical_reaction/notlight //Harder to make do to it being a hard race to play - name = "shadow muatatuin toxic" + name = "shadow mutation toxin" id = /datum/reagent/mutationtoxin/shadow results = list(/datum/reagent/mutationtoxin/shadow = 1) required_reagents = list(/datum/reagent/liquid_dark_matter = 5, /datum/reagent/medicine/synaptizine = 10, /datum/reagent/medicine/oculine = 10, /datum/reagent/mutationtoxin = 1) diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 80740ee6f7..704dbffe51 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -656,8 +656,11 @@ body_markings = null aux_marking = null - if(species_id in GLOB.greyscale_limb_types) //should they have greyscales? - base_bp_icon = DEFAULT_BODYPART_ICON_ORGANIC + if(S.override_bp_icon) + base_bp_icon = S.override_bp_icon + else + if(species_id in GLOB.greyscale_limb_types) //should they have greyscales? + base_bp_icon = DEFAULT_BODYPART_ICON_ORGANIC if(base_bp_icon != DEFAULT_BODYPART_ICON) color_src = mut_colors ? MUTCOLORS : ((H.dna.skin_tone_override && S.use_skintones == USE_SKINTONES_GRAYSCALE_CUSTOM) ? CUSTOM_SKINTONE : SKINTONE) diff --git a/code/modules/surgery/organs/eyes.dm b/code/modules/surgery/organs/eyes.dm index b4c58b31ed..794823448f 100644 --- a/code/modules/surgery/organs/eyes.dm +++ b/code/modules/surgery/organs/eyes.dm @@ -430,6 +430,12 @@ if(severity >= 70) owner.adjustOrganLoss(ORGAN_SLOT_EYES, 20) +/obj/item/organ/eyes/night_vision/arachnid + name = "arachnid eyes" + desc = "These eyes seem to have increased sensitivity to bright light, offset by basic night vision." + see_in_dark = 4 + flash_protect = -1 + #undef BLURRY_VISION_ONE #undef BLURRY_VISION_TWO #undef BLIND_VISION_THREE diff --git a/code/modules/surgery/organs/tongue.dm b/code/modules/surgery/organs/tongue.dm index 929b42f96d..5c26235193 100644 --- a/code/modules/surgery/organs/tongue.dm +++ b/code/modules/surgery/organs/tongue.dm @@ -258,3 +258,22 @@ /obj/item/organ/tongue/ethereal/Initialize(mapload) . = ..() languages_possible = languages_possible_ethereal + +/obj/item/organ/tongue/arachnid + name = "inner mandible" + desc = "A set of soft, spoon-esque mandibles closer to the mouth opening, that allow for basic speech, and the ability to speak Rachnidian." + say_mod = "chitters" + var/static/list/languages_possible_arachnid = typecacheof(list( + /datum/language/common, + /datum/language/draconic, + /datum/language/codespeak, + /datum/language/monkey, + /datum/language/narsie, + /datum/language/beachbum, + /datum/language/aphasia, + /datum/language/arachnid, + )) + +/obj/item/organ/tongue/arachnid/Initialize(mapload) + . = ..() + languages_possible = languages_possible_arachnid \ No newline at end of file diff --git a/config/game_options.txt b/config/game_options.txt index a5b0d0b8c4..bb6c5d8f01 100644 --- a/config/game_options.txt +++ b/config/game_options.txt @@ -477,6 +477,7 @@ ROUNDSTART_RACES xeno ROUNDSTART_RACES slimeperson ROUNDSTART_RACES guilmon ROUNDSTART_RACES ipc +ROUNDSTART_RACES arachnid ##------------------------------------------------------------------------------------------- diff --git a/icons/misc/language.dmi b/icons/misc/language.dmi index 9501dc9216..a33f914885 100644 Binary files a/icons/misc/language.dmi and b/icons/misc/language.dmi differ diff --git a/icons/mob/arachnid_legs.dmi b/icons/mob/arachnid_legs.dmi new file mode 100644 index 0000000000..bdd67a518f Binary files /dev/null and b/icons/mob/arachnid_legs.dmi differ diff --git a/icons/mob/arachnid_mandibles.dmi b/icons/mob/arachnid_mandibles.dmi new file mode 100644 index 0000000000..9369e2d5fa Binary files /dev/null and b/icons/mob/arachnid_mandibles.dmi differ diff --git a/icons/mob/arachnid_parts.dmi b/icons/mob/arachnid_parts.dmi new file mode 100644 index 0000000000..1b70935450 Binary files /dev/null and b/icons/mob/arachnid_parts.dmi differ diff --git a/icons/mob/arachnid_spinneret.dmi b/icons/mob/arachnid_spinneret.dmi new file mode 100644 index 0000000000..688ff90e0d Binary files /dev/null and b/icons/mob/arachnid_spinneret.dmi differ diff --git a/strings/names/spider_first.txt b/strings/names/spider_first.txt new file mode 100644 index 0000000000..06fbae057c --- /dev/null +++ b/strings/names/spider_first.txt @@ -0,0 +1,30 @@ +Zerzir +Lalnuth +Avisreb +Qeqarnai +Rhikkiezhith +Necaqtex +Aqi +Shozhish +Sraiza +Ranqu +Zellalshi +Necoq +Zaqod +Salaree +Xavis +Cheqirni +Nieqi +Cakirkix +Ivad +Shenqazhe +Azurte +Lizire +Ivur +Kavur +Raicheca +Iqashe +Eq'za +Sak'sad +Hiezih +Cessix \ No newline at end of file diff --git a/strings/names/spider_last.txt b/strings/names/spider_last.txt new file mode 100644 index 0000000000..2b663f6df3 --- /dev/null +++ b/strings/names/spider_last.txt @@ -0,0 +1,30 @@ +Ik'sir +Sechathi +Qok'sut +Yeqied +Iravhoh +Kriaqux +Yikih +Khaqa +Azasnet +Qhecid +Qhin'qu +Zhechikzor +Qhovi +Hirath +Szornud +Zasokaq +Lhaqish +Qhiretid +Avizad +Qallazi +Qhizrud +Qicirne +Sezuveth +Zelriker +Rhiallor +Zhaliesh +Qoutirk'ab +Chavi +Riel'shes +Khentax \ No newline at end of file diff --git a/tgstation.dme b/tgstation.dme index 750486e032..3ca900be09 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -951,6 +951,7 @@ #include "code\game\objects\structures.dm" #include "code\game\objects\effects\alien_acid.dm" #include "code\game\objects\effects\anomalies.dm" +#include "code\game\objects\effects\arachnid_web.dm" #include "code\game\objects\effects\blessing.dm" #include "code\game\objects\effects\bump_teleporter.dm" #include "code\game\objects\effects\contraband.dm" @@ -2303,6 +2304,7 @@ #include "code\modules\keybindings\keybind\robot.dm" #include "code\modules\keybindings\keybind\targeting.dm" #include "code\modules\language\aphasia.dm" +#include "code\modules\language\arachnid.dm" #include "code\modules\language\beachbum.dm" #include "code\modules\language\codespeak.dm" #include "code\modules\language\common.dm" @@ -2421,6 +2423,7 @@ #include "code\modules\mob\dead\new_player\preferences_setup.dm" #include "code\modules\mob\dead\new_player\sprite_accessories\_sprite_accessories.dm" #include "code\modules\mob\dead\new_player\sprite_accessories\alienpeople.dm" +#include "code\modules\mob\dead\new_player\sprite_accessories\arachnid.dm" #include "code\modules\mob\dead\new_player\sprite_accessories\body_markings.dm" #include "code\modules\mob\dead\new_player\sprite_accessories\caps.dm" #include "code\modules\mob\dead\new_player\sprite_accessories\Citadel_Snowflake.dm" @@ -2552,6 +2555,7 @@ #include "code\modules\mob\living\carbon\human\species_types\abductor.dm" #include "code\modules\mob\living\carbon\human\species_types\android.dm" #include "code\modules\mob\living\carbon\human\species_types\angel.dm" +#include "code\modules\mob\living\carbon\human\species_types\arachnid.dm" #include "code\modules\mob\living\carbon\human\species_types\anthromorph.dm" #include "code\modules\mob\living\carbon\human\species_types\bugmen.dm" #include "code\modules\mob\living\carbon\human\species_types\corporate.dm"