diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_werewolf.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_werewolf.png new file mode 100644 index 000000000000..f9860dab6a3f Binary files /dev/null and b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_werewolf.png differ diff --git a/maplestation.dme b/maplestation.dme index f073cbd17427..fc48815cf2c2 100644 --- a/maplestation.dme +++ b/maplestation.dme @@ -6424,6 +6424,7 @@ #include "maplestation_modules\code\modules\magic\story_spells\ice_blast.dm" #include "maplestation_modules\code\modules\magic\story_spells\ice_knife.dm" #include "maplestation_modules\code\modules\magic\story_spells\illusion.dm" +#include "maplestation_modules\code\modules\magic\story_spells\lycanthropy.dm" #include "maplestation_modules\code\modules\magic\story_spells\mage_hand.dm" #include "maplestation_modules\code\modules\magic\story_spells\mana_charge.dm" #include "maplestation_modules\code\modules\magic\story_spells\mana_sense.dm" @@ -6478,6 +6479,7 @@ #include "maplestation_modules\code\modules\mob\living\carbon\human\species_types\skrell.dm" #include "maplestation_modules\code\modules\mob\living\carbon\human\species_types\species.dm" #include "maplestation_modules\code\modules\mob\living\carbon\human\species_types\vampire.dm" +#include "maplestation_modules\code\modules\mob\living\carbon\human\species_types\werewolf.dm" #include "maplestation_modules\code\modules\mob\living\carbon\human\species_types\synth\synth.dm" #include "maplestation_modules\code\modules\mob\living\carbon\human\species_types\synth\synth_ion.dm" #include "maplestation_modules\code\modules\mob\living\silicon\robot\robot_defines.dm" @@ -6518,8 +6520,11 @@ #include "maplestation_modules\code\modules\surgery\organs\autosurgeon.dm" #include "maplestation_modules\code\modules\surgery\organs\ears.dm" #include "maplestation_modules\code\modules\surgery\organs\eyes.dm" +#include "maplestation_modules\code\modules\surgery\organs\heart.dm" +#include "maplestation_modules\code\modules\surgery\organs\liver.dm" #include "maplestation_modules\code\modules\surgery\organs\tails.dm" #include "maplestation_modules\code\modules\surgery\organs\tongue.dm" +#include "maplestation_modules\code\modules\surgery\organs\werewolf_parts.dm" #include "maplestation_modules\code\modules\uplink\uplink_devices.dm" #include "maplestation_modules\code\modules\uplink\uplink_infiltrator.dm" #include "maplestation_modules\code\modules\uplink\uplink_items.dm" diff --git a/maplestation_modules/code/__DEFINES/DNA.dm b/maplestation_modules/code/__DEFINES/DNA.dm index c4249c288de3..8e4959f01702 100644 --- a/maplestation_modules/code/__DEFINES/DNA.dm +++ b/maplestation_modules/code/__DEFINES/DNA.dm @@ -5,3 +5,4 @@ #define SPECIES_REPLOID "reploid" #define SPECIES_SYNTH "synth" #define SPECIES_ORNITHID "ornithid" +#define SPECIES_WEREWOLF "werewolf" diff --git a/maplestation_modules/code/modules/magic/story_spells/lycanthropy.dm b/maplestation_modules/code/modules/magic/story_spells/lycanthropy.dm new file mode 100644 index 000000000000..a864c688ad4e --- /dev/null +++ b/maplestation_modules/code/modules/magic/story_spells/lycanthropy.dm @@ -0,0 +1,38 @@ +// the many spells that are used to turn into versions of a werewolf + +/datum/action/cooldown/spell/shapeshift/lycanthrope // use this for the simplemob forms, like standard wolves + name = "Wolf Form" + desc = "Channel the wolf within yourself and turn into one of your possible forms. \ + Be careful, for you can still die within this form." + invocation = "RAAAAAAAAWR!" + invocation_type = INVOCATION_SHOUT + spell_requirements = NONE + possible_shapes = list( + /mob/living/simple_animal/hostile/asteroid/wolf, // room to add other forms + ) + +/datum/action/cooldown/spell/werewolf_form + name = "Werewolf Change" + desc = "Change to and from your full werewolf form. \ + You will gain the full effects of this, both negative and positive." + invocation = "ARRRROOOOO!" // i don't know man + invocation_type = INVOCATION_SHOUT + spell_requirements = SPELL_REQUIRES_HUMAN + button_icon = 'maplestation_modules/icons/mob/actions/actions_advspells.dmi' + button_icon_state = "moon" + var/datum/species/owner_base_species // what species we are other than a werewolf + var/list/base_features = list("mcolor" = "#FFFFFF") + // yes this might cause other implications, such as mass species change, or with synths (synthcode moment) but i'll look into it later down the line + +/datum/action/cooldown/spell/werewolf_form/cast(atom/movable/cast_on) + . = ..() + var/mob/living/carbon/human/lycanthrope = owner + if(istype(lycanthrope.dna.species, /datum/species/werewolf)) + lycanthrope.balloon_alert(cast_on, "changing back") + lycanthrope.dna.features = base_features + lycanthrope.set_species(owner_base_species) + else + owner_base_species = lycanthrope.dna.species + base_features = lycanthrope.dna.features.Copy() + lycanthrope.balloon_alert(cast_on, "turning") + lycanthrope.set_species(/datum/species/werewolf) diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/human.dm b/maplestation_modules/code/modules/mob/living/carbon/human/human.dm index bacc2e93e79b..45e085aa313d 100644 --- a/maplestation_modules/code/modules/mob/living/carbon/human/human.dm +++ b/maplestation_modules/code/modules/mob/living/carbon/human/human.dm @@ -52,3 +52,7 @@ outfit_copy.implants = list() for(var/obj/item/implant/I in implants) outfit_copy.implants |= I.type + +// species mobs +/mob/living/carbon/human/species/werewolf + race = /datum/species/werewolf diff --git a/maplestation_modules/code/modules/mob/living/carbon/human/species_types/werewolf.dm b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/werewolf.dm new file mode 100644 index 000000000000..8eb3e688f807 --- /dev/null +++ b/maplestation_modules/code/modules/mob/living/carbon/human/species_types/werewolf.dm @@ -0,0 +1,80 @@ +/datum/species/werewolf + name = "werewolf" + id = SPECIES_WEREWOLF + inherent_traits = list( + TRAIT_USES_SKINTONES, + TRAIT_NO_UNDERWEAR, + TRAIT_NO_AUGMENTS, + TRAIT_IGNOREDAMAGESLOWDOWN, + TRAIT_PUSHIMMUNE, + TRAIT_STUNIMMUNE, + TRAIT_PRIMITIVE, + TRAIT_CAN_STRIP, + TRAIT_CHUNKYFINGERS + ) + mutanttongue = /obj/item/organ/internal/tongue/werewolf + mutantears = /obj/item/organ/internal/ears/cat/werewolf + mutanteyes = /obj/item/organ/internal/eyes/werewolf + mutantbrain = /obj/item/organ/internal/brain/werewolf + mutantliver = /obj/item/organ/internal/liver/werewolf + mutantheart = /obj/item/organ/internal/heart/werewolf + external_organs = list( + /obj/item/organ/external/tail/cat = "Cat", // todo: add custom wolf tail + ) + skinned_type = /obj/item/stack/sheet/animalhide/human + changesource_flags = MIRROR_BADMIN | WABBAJACK | MIRROR_MAGIC | MIRROR_PRIDE | ERT_SPAWN | RACE_SWAP | SLIME_EXTRACT + no_equip_flags = ITEM_SLOT_MASK | ITEM_SLOT_OCLOTHING | ITEM_SLOT_GLOVES | ITEM_SLOT_FEET | ITEM_SLOT_SUITSTORE + + bodypart_overrides = list( + BODY_ZONE_HEAD = /obj/item/bodypart/head/werewolf, + BODY_ZONE_CHEST = /obj/item/bodypart/chest/werewolf, + BODY_ZONE_L_ARM = /obj/item/bodypart/arm/left/werewolf, + BODY_ZONE_R_ARM = /obj/item/bodypart/arm/right/werewolf, + BODY_ZONE_L_LEG = /obj/item/bodypart/leg/left/werewolf, + BODY_ZONE_R_LEG = /obj/item/bodypart/leg/right/werewolf, + ) + +/obj/item/organ/internal/brain/werewolf + name = "werewolf brain" + desc = "a strange mixture of a human and wolf brain" + organ_traits = list(TRAIT_ADVANCEDTOOLUSER, TRAIT_LITERATE, TRAIT_PRIMITIVE, TRAIT_CAN_STRIP) // you may be a raging monster, but you still retain traits of your normal self + // also you can just inject clever mutation and get the first two traits anyways *shrug + +/obj/item/organ/internal/brain/werewolf/get_attacking_limb(mob/living/carbon/human/target) + if(target.body_position == LYING_DOWN) + return owner.get_bodypart(BODY_ZONE_HEAD) // performs a "maul" attack which does increased melee damage + return ..() + +/datum/species/werewolf/prepare_human_for_preview(mob/living/carbon/human/human) + human.set_haircolor("#bb9966", update = FALSE) // brown + human.set_hairstyle("Business Hair", update = TRUE) + +/* this shouldn't be a roundstart/base species players can choose, and is instead obtainable mid round +feel free to update this section if any of the three below can be accessed out of character set up. */ +/datum/species/werewolf/get_species_description() + return "N/A" + +/datum/species/human/get_species_lore() + return list( + "N/A", + ) + +/datum/species/werewolf/create_pref_unique_perks() + var/list/to_add = list() + + to_add += list( + list( + SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, + SPECIES_PERK_ICON = "paw", + SPECIES_PERK_NAME = "Primal Primate", + SPECIES_PERK_DESC = "Werewolves are monstrous humans, and can't do most things a human can do. Computers are impossible, \ + complex machines are right out, and most clothes don't fit your larger form.", + ), + list( + SPECIES_PERK_TYPE = SPECIES_NEGATIVE_PERK, + SPECIES_PERK_ICON = "assistive-listening-systems", + SPECIES_PERK_NAME = "Sensitive Hearing", + SPECIES_PERK_DESC = "Werewolves are more sensitive to loud sounds, such as flashbangs.", + )) + + return to_add diff --git a/maplestation_modules/code/modules/surgery/organs/ears.dm b/maplestation_modules/code/modules/surgery/organs/ears.dm index c3a7380ce876..7b043dc52d00 100644 --- a/maplestation_modules/code/modules/surgery/organs/ears.dm +++ b/maplestation_modules/code/modules/surgery/organs/ears.dm @@ -31,3 +31,35 @@ icon_state = "catcyber" icon = 'maplestation_modules/icons/mob/mutant_bodyparts.dmi' locked = TRUE + +/obj/item/organ/internal/ears/cat/werewolf + name = "wolf ears" + icon = 'icons/obj/clothing/head/costume.dmi' + icon_state = "kitty" + desc = "Allows the user to more easily hear whispers. The user becomes extra vulnerable to loud noises, however" + // Same sensitivity as felinid ears + damage_multiplier = 2 + +/obj/item/organ/internal/ears/cat/werewolf/on_mob_insert(mob/living/carbon/human/ear_owner) + . = ..() + if(istype(ear_owner)) + color = ear_owner.hair_color + ear_owner.dna.features["ears"] = ear_owner.dna.species.mutant_bodyparts["ears"] = "Werewolf" + ear_owner.update_body() + ADD_TRAIT(ear_owner, TRAIT_GOOD_HEARING, ORGAN_TRAIT) + +/obj/item/organ/internal/ears/cat/werewolf/on_mob_remove(mob/living/carbon/human/ear_owner) + . = ..() + if(istype(ear_owner)) + ear_owner.dna.features["ears"] = "None" + ear_owner.dna.species.mutant_bodyparts -= "ears" + ear_owner.update_body() + REMOVE_TRAIT(ear_owner, TRAIT_GOOD_HEARING, ORGAN_TRAIT) + +/datum/sprite_accessory/ears/werewolf + name = "Werewolf" + icon_state = "werewolf" + icon = 'maplestation_modules/icons/mob/mutant_bodyparts.dmi' + locked = TRUE + hasinner = TRUE + color_src = HAIR_COLOR diff --git a/maplestation_modules/code/modules/surgery/organs/eyes.dm b/maplestation_modules/code/modules/surgery/organs/eyes.dm index 1515021eb4b6..a7e9a9e94279 100644 --- a/maplestation_modules/code/modules/surgery/organs/eyes.dm +++ b/maplestation_modules/code/modules/surgery/organs/eyes.dm @@ -5,3 +5,9 @@ /mob/living/carbon /// Overlay file to take (missing) eye icons from var/missing_eye_file = 'icons/mob/human/human_face.dmi' + +/obj/item/organ/internal/eyes/werewolf + name = "wolf eyes" + desc = "Large and powerful eyes." + sight_flags = SEE_MOBS + color_cutoffs = list(25, 5, 42) diff --git a/maplestation_modules/code/modules/surgery/organs/heart.dm b/maplestation_modules/code/modules/surgery/organs/heart.dm new file mode 100644 index 000000000000..e31743256a04 --- /dev/null +++ b/maplestation_modules/code/modules/surgery/organs/heart.dm @@ -0,0 +1,10 @@ +/obj/item/organ/internal/heart/werewolf + name = "massive heart" + desc = "An absolutely monstrous heart." + icon_state = "heart-on" + base_icon_state = "heart" + maxHealth = 2 * STANDARD_ORGAN_THRESHOLD + +/obj/item/organ/internal/heart/wolf/Initialize(mapload) + . = ..() + transform = transform.Scale(1.5) diff --git a/maplestation_modules/code/modules/surgery/organs/liver.dm b/maplestation_modules/code/modules/surgery/organs/liver.dm new file mode 100644 index 000000000000..a4a796db0fc5 --- /dev/null +++ b/maplestation_modules/code/modules/surgery/organs/liver.dm @@ -0,0 +1,23 @@ +// Liver stuff + +// werewolf liver, used for various funny traits, like handling their silver weakness chemically +/obj/item/organ/internal/liver/werewolf + + name = "Beastly liver" + desc = "A large monstrous liver." + icon_state = "liver" + organ_flags = ORGAN_UNREMOVABLE + organ_traits = list(TRAIT_STABLELIVER) + // TODO: implement these + var/blood_brute_healing = 2.5 + ///Var for burn healing via blood + var/blood_burn_healing = 2.5 + +/obj/item/organ/internal/liver/werewolf/handle_chemical(mob/living/carbon/organ_owner, datum/reagent/chem, seconds_per_tick, times_fired) + . = ..() + // parent returned COMSIG_MOB_STOP_REAGENT_CHECK or we are failing + if((. & COMSIG_MOB_STOP_REAGENT_CHECK) || (organ_flags & ORGAN_FAILING)) + return + if(istype(chem, /datum/reagent/silver)) + organ_owner.adjustStaminaLoss(4 * REM * seconds_per_tick, updating_stamina = TRUE) + organ_owner.adjustFireLoss(2 * REM * seconds_per_tick, updating_health = TRUE) diff --git a/maplestation_modules/code/modules/surgery/organs/tongue.dm b/maplestation_modules/code/modules/surgery/organs/tongue.dm index e7c13530e991..4c1e3e8fb789 100644 --- a/maplestation_modules/code/modules/surgery/organs/tongue.dm +++ b/maplestation_modules/code/modules/surgery/organs/tongue.dm @@ -36,3 +36,38 @@ /obj/item/organ/internal/tongue/lizard/get_possible_languages() return ..() + /datum/language/impdraconic + +/obj/item/organ/internal/tongue/werewolf + name = "wolf tongue" + desc = "A large tongue that looks like a mix of a human's and a wolf's." + icon_state = "werewolf_tongue" + icon = 'maplestation_modules/icons/mob/mutant_bodyparts.dmi' + say_mod = "growls" + modifies_speech = TRUE + taste_sensitivity = 5 + liked_foodtypes = GROSS | MEAT | RAW | GORE + disliked_foodtypes = SUGAR + +/obj/item/organ/internal/tongue/werewolf/modify_speech(datum/source, list/speech_args) + var/message = speech_args[SPEECH_MESSAGE] + if(message[1] != "*") + + // all occurrences of characters "eiou" (case-insensitive) are replaced with "r" + message = replacetext(message, regex(@"[eiou]", "ig"), "r") + // all characters other than "zhrgbmna .!?-" (case-insensitive) are stripped + message = replacetext(message, regex(@"[^zhrgbmna.!?-\s]", "ig"), "") + // multiple spaces are replaced with a single (whitespace is trimmed) + message = replacetext(message, regex(@"(\s+)", "g"), " ") + + var/list/old_words = splittext(message, " ") + var/list/new_words = list() + for(var/word in old_words) + // lower-case "r" at the end of words replaced with "rh" + word = replacetext(word, regex(@"\lr\b"), "rh") + // an "a" or "A" by itself will be replaced with "hra" + word = replacetext(word, regex(@"\b[Aa]\b"), "hra") + new_words += word + + message = new_words.Join(" ") + message = capitalize(message) + speech_args[SPEECH_MESSAGE] = message diff --git a/maplestation_modules/code/modules/surgery/organs/werewolf_parts.dm b/maplestation_modules/code/modules/surgery/organs/werewolf_parts.dm new file mode 100644 index 000000000000..131303e1133a --- /dev/null +++ b/maplestation_modules/code/modules/surgery/organs/werewolf_parts.dm @@ -0,0 +1,125 @@ +///WEREWOLF +/obj/item/bodypart/head/werewolf + limb_id = SPECIES_WEREWOLF + icon_greyscale = 'maplestation_modules/icons/mob/werewolf_parts_greyscale.dmi' + is_dimorphic = FALSE + should_draw_greyscale = TRUE + burn_modifier = 0.9 + brute_modifier = 0.7 + unarmed_attack_verb = "bite" + grappled_attack_verb = "maul" + unarmed_attack_effect = ATTACK_EFFECT_BITE + unarmed_attack_sound = 'sound/weapons/bite.ogg' + unarmed_miss_sound = 'sound/weapons/bite.ogg' + unarmed_damage_low = 30 + unarmed_damage_high = 35 + unarmed_effectiveness = 30 + dmg_overlay_type = null + head_flags = HEAD_EYESPRITES|HEAD_EYECOLOR|HEAD_EYEHOLES|HEAD_DEBRAIN|HEAD_HAIR + +/obj/item/bodypart/head/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + if(ishuman(owner)) + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + +/obj/item/bodypart/chest/werewolf + limb_id = SPECIES_WEREWOLF + icon_greyscale = 'maplestation_modules/icons/mob/werewolf_parts_greyscale.dmi' + is_dimorphic = TRUE + should_draw_greyscale = TRUE + burn_modifier = 0.9 + brute_modifier = 0.7 + dmg_overlay_type = null + bodypart_traits = list(TRAIT_NO_JUMPSUIT, TRAIT_IGNOREDAMAGESLOWDOWN, TRAIT_PUSHIMMUNE, TRAIT_STUNIMMUNE) + wing_types = NONE + +/obj/item/bodypart/chest/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + if(ishuman(owner)) + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + + +/obj/item/bodypart/arm/left/werewolf + limb_id = SPECIES_WEREWOLF + icon_greyscale = 'maplestation_modules/icons/mob/werewolf_parts_greyscale.dmi' + should_draw_greyscale = TRUE + unarmed_attack_verb = "slash" + grappled_attack_verb = "lacerate" + unarmed_attack_effect = ATTACK_EFFECT_CLAW + unarmed_attack_sound = 'sound/weapons/slice.ogg' + unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + unarmed_damage_low = 17 + unarmed_damage_high = 23 + unarmed_effectiveness = 15 + burn_modifier = 0.9 + brute_modifier = 0.7 + dmg_overlay_type = null + bodypart_traits = list(TRAIT_CHUNKYFINGERS) + + +/obj/item/bodypart/arm/left/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + if(ishuman(owner)) + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + + +/obj/item/bodypart/arm/right/werewolf + limb_id = SPECIES_WEREWOLF + icon_greyscale = 'maplestation_modules/icons/mob/werewolf_parts_greyscale.dmi' + should_draw_greyscale = TRUE + unarmed_attack_verb = "slash" + grappled_attack_verb = "lacerate" + unarmed_attack_effect = ATTACK_EFFECT_CLAW + unarmed_attack_sound = 'sound/weapons/slice.ogg' + unarmed_miss_sound = 'sound/weapons/slashmiss.ogg' + unarmed_damage_low = 17 + unarmed_damage_high = 23 + unarmed_effectiveness = 15 + burn_modifier = 0.9 + brute_modifier = 0.7 + dmg_overlay_type = null + bodypart_traits = list(TRAIT_CHUNKYFINGERS) + +/obj/item/bodypart/arm/right/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + if(ishuman(owner)) + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + + +/obj/item/bodypart/leg/left/werewolf + limb_id = SPECIES_WEREWOLF + icon_greyscale = 'maplestation_modules/icons/mob/werewolf_parts_greyscale.dmi' + should_draw_greyscale = TRUE + burn_modifier = 0.9 + brute_modifier = 0.7 + speed_modifier = -0.1 + dmg_overlay_type = null + bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + footstep_type = FOOTSTEP_MOB_CLAW + +/obj/item/bodypart/leg/left/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + if(ishuman(owner)) + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color + +/obj/item/bodypart/leg/right/werewolf + limb_id = SPECIES_WEREWOLF + icon_greyscale = 'maplestation_modules/icons/mob/werewolf_parts_greyscale.dmi' + should_draw_greyscale = TRUE + burn_modifier = 0.9 + brute_modifier = 0.7 + speed_modifier = -0.1 + dmg_overlay_type = null + bodytype = BODYTYPE_HUMANOID | BODYTYPE_ORGANIC | BODYTYPE_DIGITIGRADE + footstep_type = FOOTSTEP_MOB_CLAW + +/obj/item/bodypart/leg/right/werewolf/update_limb(dropping_limb, is_creating) + . = ..() + if(ishuman(owner)) + var/mob/living/carbon/human/wolf = owner + species_color = wolf.hair_color diff --git a/maplestation_modules/icons/mob/actions/actions_advspells.dmi b/maplestation_modules/icons/mob/actions/actions_advspells.dmi new file mode 100644 index 000000000000..63b27d78771d Binary files /dev/null and b/maplestation_modules/icons/mob/actions/actions_advspells.dmi differ diff --git a/maplestation_modules/icons/mob/mutant_bodyparts.dmi b/maplestation_modules/icons/mob/mutant_bodyparts.dmi index eb3e768f68d7..b98667f1d55f 100644 Binary files a/maplestation_modules/icons/mob/mutant_bodyparts.dmi and b/maplestation_modules/icons/mob/mutant_bodyparts.dmi differ diff --git a/maplestation_modules/icons/mob/werewolf_parts_greyscale.dmi b/maplestation_modules/icons/mob/werewolf_parts_greyscale.dmi new file mode 100644 index 000000000000..6c388d7b1374 Binary files /dev/null and b/maplestation_modules/icons/mob/werewolf_parts_greyscale.dmi differ