diff --git a/code/__DEFINES/loadout.dm b/code/__DEFINES/loadout.dm index 94059c0880..767894050d 100644 --- a/code/__DEFINES/loadout.dm +++ b/code/__DEFINES/loadout.dm @@ -54,3 +54,16 @@ //donator items #define LOADOUT_CATEGORY_DONATOR "Donator" + +//how many prosthetics can we have +#define MAXIMUM_LOADOUT_PROSTHETICS 2 + +//what limbs can be amputated or be prosthetic +#define LOADOUT_ALLOWED_LIMB_TARGETS list(BODY_ZONE_L_ARM,BODY_ZONE_R_ARM,BODY_ZONE_L_LEG,BODY_ZONE_R_LEG) + +//options for modifiying limbs +#define LOADOUT_LIMB_NORMAL "Normal" +#define LOADOUT_LIMB_PROSTHETIC "Prosthetic" +#define LOADOUT_LIMB_AMPUTATED "Amputated" + +#define LOADOUT_LIMBS list(LOADOUT_LIMB_NORMAL,LOADOUT_LIMB_PROSTHETIC,LOADOUT_LIMB_AMPUTATED) //you can amputate your legs/arms though \ No newline at end of file diff --git a/code/_globalvars/lists/flavor_misc.dm b/code/_globalvars/lists/flavor_misc.dm index 71c2b2e13b..09d4aadf50 100644 --- a/code/_globalvars/lists/flavor_misc.dm +++ b/code/_globalvars/lists/flavor_misc.dm @@ -279,7 +279,8 @@ GLOBAL_LIST_INIT(unlocked_mutant_parts, list("horns", "insect_fluff")) //parts in either of the above two lists that require a second option that allows them to be coloured GLOBAL_LIST_INIT(colored_mutant_parts, list("insect_wings" = "wings_color", "deco_wings" = "wings_color", "horns" = "horns_color")) -//species ids that have greyscale sprites +//body ids that have greyscale sprites GLOBAL_LIST_INIT(greyscale_limb_types, list("human","moth","lizard","pod","plant","jelly","slime","golem","lum","stargazer","mush","ethereal","snail","c_golem","b_golem","mammal","xeno","ipc","insect","synthliz","avian","aquatic")) -//species ids that need snowflake coloring applied +//body ids that have prosthetic sprites +GLOBAL_LIST_INIT(prosthetic_limb_types, list("xion","bishop","cybersolutions","grayson","hephaestus","nanotrasen","talon")) diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 0bc4e6665a..9af86653f4 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -396,6 +396,7 @@ SUBSYSTEM_DEF(ticker) SSjob.EquipRank(N, player.mind.assigned_role, 0) if(CONFIG_GET(flag/roundstart_traits) && ishuman(N.new_character)) SSquirks.AssignQuirks(N.new_character, N.client, TRUE, TRUE, SSjob.GetJob(player.mind.assigned_role), FALSE, N) + N.client.prefs.post_copy_to(player) CHECK_TICK if(captainless) for(var/mob/dead/new_player/N in GLOB.player_list) diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm index 68b5d6f987..322fba0a33 100644 --- a/code/datums/traits/negative.dm +++ b/code/datums/traits/negative.dm @@ -211,24 +211,27 @@ GLOBAL_LIST_EMPTY(family_heirlooms) H.gain_trauma(T, TRAUMA_RESILIENCE_ABSOLUTE) /datum/quirk/paraplegic/on_spawn() - if(quirk_holder.buckled) // Handle late joins being buckled to arrival shuttle chairs. - quirk_holder.buckled.unbuckle_mob(quirk_holder) + if(quirk_holder.client) + var/modified_limbs = quirk_holder.client.prefs.modified_limbs + if(!(modified_limbs[BODY_ZONE_L_LEG] == LOADOUT_LIMB_AMPUTATED && modified_limbs[BODY_ZONE_R_LEG] == LOADOUT_LIMB_AMPUTATED && !isjellyperson(quirk_holder))) + if(quirk_holder.buckled) // Handle late joins being buckled to arrival shuttle chairs. + quirk_holder.buckled.unbuckle_mob(quirk_holder) - var/turf/T = get_turf(quirk_holder) - var/obj/structure/chair/spawn_chair = locate() in T + var/turf/T = get_turf(quirk_holder) + var/obj/structure/chair/spawn_chair = locate() in T - var/obj/vehicle/ridden/wheelchair/wheels = new(T) - if(spawn_chair) // Makes spawning on the arrivals shuttle more consistent looking - wheels.setDir(spawn_chair.dir) + var/obj/vehicle/ridden/wheelchair/wheels = new(T) + if(spawn_chair) // Makes spawning on the arrivals shuttle more consistent looking + wheels.setDir(spawn_chair.dir) - wheels.buckle_mob(quirk_holder) + wheels.buckle_mob(quirk_holder) - // During the spawning process, they may have dropped what they were holding, due to the paralysis - // So put the things back in their hands. + // During the spawning process, they may have dropped what they were holding, due to the paralysis + // So put the things back in their hands. - for(var/obj/item/I in T) - if(I.fingerprintslast == quirk_holder.ckey) - quirk_holder.put_in_hands(I) + for(var/obj/item/I in T) + if(I.fingerprintslast == quirk_holder.ckey) + quirk_holder.put_in_hands(I) /datum/quirk/poor_aim name = "Poor Aim" @@ -244,42 +247,6 @@ GLOBAL_LIST_EMPTY(family_heirlooms) mob_trait = TRAIT_PROSOPAGNOSIA medical_record_text = "Patient suffers from prosopagnosia and cannot recognize faces." -/datum/quirk/prosthetic_limb - name = "Prosthetic Limb" - desc = "An accident caused you to lose one of your limbs. Because of this, you now have a random prosthetic!" - value = -1 - var/slot_string = "limb" - -/datum/quirk/prosthetic_limb/on_spawn() - var/mob/living/carbon/human/H = quirk_holder - var/limb_slot - if(HAS_TRAIT(H, TRAIT_PARA))//Prevent paraplegic legs being replaced - limb_slot = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM) - else - limb_slot = pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) - var/obj/item/bodypart/old_part = H.get_bodypart(limb_slot) - var/obj/item/bodypart/prosthetic - switch(limb_slot) - if(BODY_ZONE_L_ARM) - prosthetic = new/obj/item/bodypart/l_arm/robot/surplus(quirk_holder) - slot_string = "left arm" - if(BODY_ZONE_R_ARM) - prosthetic = new/obj/item/bodypart/r_arm/robot/surplus(quirk_holder) - slot_string = "right arm" - if(BODY_ZONE_L_LEG) - prosthetic = new/obj/item/bodypart/l_leg/robot/surplus(quirk_holder) - slot_string = "left leg" - if(BODY_ZONE_R_LEG) - prosthetic = new/obj/item/bodypart/r_leg/robot/surplus(quirk_holder) - slot_string = "right leg" - prosthetic.replace_limb(H) - qdel(old_part) - H.regenerate_icons() - -/datum/quirk/prosthetic_limb/post_add() - to_chat(quirk_holder, "Your [slot_string] has been replaced with a surplus prosthetic. It is fragile and will easily come apart under duress. Additionally, \ - you need to use a welding tool and cables to repair it, instead of bruise packs and ointment.") - /datum/quirk/insanity name = "Reality Dissociation Syndrome" desc = "You suffer from a severe disorder that causes very vivid hallucinations. Mindbreaker toxin can suppress its effects, and you are immune to mindbreaker's hallucinogenic properties. This is not a license to grief." diff --git a/code/game/objects/items/miscellaneous.dm b/code/game/objects/items/miscellaneous.dm index 33349cee67..7e14fb9d35 100644 --- a/code/game/objects/items/miscellaneous.dm +++ b/code/game/objects/items/miscellaneous.dm @@ -272,4 +272,3 @@ icon_state = "skub" w_class = WEIGHT_CLASS_BULKY attack_verb = list("skubbed") - diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index 51e027522c..cff3040926 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -163,6 +163,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) ) var/custom_speech_verb = "default" //if your say_mod is to be something other than your races var/custom_tongue = "default" //if your tongue is to be something other than your races + var/modified_limbs = list() //prosthetic/amputated limbs var/chosen_limb_id //body sprite selected to load for the users limbs, null means default, is sanitized when loaded /// Security record note section @@ -429,12 +430,19 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Gender:[gender == MALE ? "Male" : (gender == FEMALE ? "Female" : (gender == PLURAL ? "Non-binary" : "Object"))]
" if(gender != NEUTER && pref_species.sexes) dat += "Body Model:[features["body_model"] == MALE ? "Masculine" : "Feminine"]
" + dat += "Limb Modification:
" + dat += "Modify Limbs
" + for(var/modification in modified_limbs) + if(modified_limbs[modification][1] == LOADOUT_LIMB_PROSTHETIC) + dat += "[modification]: [modified_limbs[modification][2]]
" + else + dat += "[modification]: [modified_limbs[modification][1]]
" + dat += "
" dat += "Species:[pref_species.name]
" dat += "Custom Species Name:[custom_species ? custom_species : "None"]
" dat += "Random Body:Randomize!
" dat += "Always Random Body:[be_random_body ? "Yes" : "No"]
" dat += "
Cycle background:[bgstate]
" - var/use_skintones = pref_species.use_skintones if(use_skintones) dat += APPEARANCE_CATEGORY_COLUMN @@ -1235,6 +1243,9 @@ GLOBAL_LIST_EMPTY(preferences_datums) for(var/V in all_quirks) var/datum/quirk/T = SSquirks.quirks[V] bal -= initial(T.value) + for(var/modification in modified_limbs) + if(modified_limbs[modification][1] == LOADOUT_LIMB_PROSTHETIC) + return bal + 1 //max 1 point regardless of how many prosthetics return bal /datum/preferences/proc/GetPositiveQuirkCount() @@ -1492,6 +1503,29 @@ GLOBAL_LIST_EMPTY(preferences_datums) if("cycle_bg") bgstate = next_list_item(bgstate, bgstate_options) + if("modify_limbs") + var/limb_type = input(user, "Choose the limb to modify:", "Character Preference") as null|anything in LOADOUT_ALLOWED_LIMB_TARGETS + if(limb_type) + var/modification_type = input(user, "Choose the modification to the limb:", "Character Preference") as null|anything in LOADOUT_LIMBS + if(modification_type) + if(modification_type == LOADOUT_LIMB_PROSTHETIC) + var/prosthetic_type = input(user, "Choose the type of prosthetic", "Character Preference") as null|anything in (list("prosthetic") + GLOB.prosthetic_limb_types) + if(prosthetic_type) + var/number_of_prosthetics = 0 + for(var/modification in modified_limbs) + if(modified_limbs[modification][1] == LOADOUT_LIMB_PROSTHETIC) + number_of_prosthetics += 1 + if(number_of_prosthetics >= MAXIMUM_LOADOUT_PROSTHETICS && !(limb_type in modified_limbs && modified_limbs[limb_type][1] == LOADOUT_LIMB_PROSTHETIC)) + to_chat(user, "You can only have up to two prosthetic limbs!") + else + //save the actual prosthetic data + modified_limbs[limb_type] = list(modification_type, prosthetic_type) + else + if(modification_type == LOADOUT_LIMB_NORMAL) + modified_limbs -= limb_type + else + modified_limbs[limb_type] = list(modification_type) + if("underwear") var/new_underwear = input(user, "Choose your character's underwear:", "Character Preference") as null|anything in GLOB.underwear_list if(new_underwear) @@ -2478,7 +2512,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) ShowChoices(user) return 1 -/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE) +/datum/preferences/proc/copy_to(mob/living/carbon/human/character, icon_updates = 1, roundstart_checks = TRUE, initial_spawn = FALSE) if(be_random_name) real_name = pref_species.random_name(gender) @@ -2573,6 +2607,35 @@ GLOBAL_LIST_EMPTY(preferences_datums) if(custom_speech_verb != "default") character.dna.species.say_mod = custom_speech_verb + //limb stuff, only done when initially spawning in + if(initial_spawn) + //delete any existing prosthetic limbs to make sure no remnant prosthetics are left over + for(var/obj/item/bodypart/part in character.bodyparts) + if(part.status == BODYPART_ROBOTIC) + qdel(part) + character.regenerate_limbs() //regenerate limbs so now you only have normal limbs + for(var/modified_limb in modified_limbs) + var/modification = modified_limbs[modified_limb][1] + var/obj/item/bodypart/old_part = character.get_bodypart(modified_limb) + if(modification == LOADOUT_LIMB_PROSTHETIC) + var/obj/item/bodypart/new_limb + switch(modified_limb) + if(BODY_ZONE_L_ARM) + new_limb = new/obj/item/bodypart/l_arm/robot/surplus(character) + if(BODY_ZONE_R_ARM) + new_limb = new/obj/item/bodypart/r_arm/robot/surplus(character) + if(BODY_ZONE_L_LEG) + new_limb = new/obj/item/bodypart/l_leg/robot/surplus(character) + if(BODY_ZONE_R_LEG) + new_limb = new/obj/item/bodypart/r_leg/robot/surplus(character) + var/prosthetic_type = modified_limbs[modified_limb][2] + if(prosthetic_type != "prosthetic") //lets just leave the old sprites as they are + new_limb.icon = file("icons/mob/augmentation/cosmetic_prosthetic/[prosthetic_type].dmi") + new_limb.replace_limb(character) + qdel(old_part) + + if(length(modified_limbs)) + character.regenerate_icons() SEND_SIGNAL(character, COMSIG_HUMAN_PREFS_COPIED_TO, src, icon_updates, roundstart_checks) @@ -2581,6 +2644,18 @@ GLOBAL_LIST_EMPTY(preferences_datums) character.update_body() character.update_hair() +/datum/preferences/proc/post_copy_to(mob/living/carbon/human/character) + //if no legs, and not a paraplegic or a slime, give them a free wheelchair + if(modified_limbs[BODY_ZONE_L_LEG] == LOADOUT_LIMB_AMPUTATED && modified_limbs[BODY_ZONE_R_LEG] == LOADOUT_LIMB_AMPUTATED && !character.has_quirk(/datum/quirk/paraplegic) && !isjellyperson(character)) + if(character.buckled) + character.buckled.unbuckle_mob(character) + var/turf/T = get_turf(character) + var/obj/structure/chair/spawn_chair = locate() in T + var/obj/vehicle/ridden/wheelchair/wheels = new(T) + if(spawn_chair) // Makes spawning on the arrivals shuttle more consistent looking + wheels.setDir(spawn_chair.dir) + wheels.buckle_mob(character) + /datum/preferences/proc/get_default_name(name_id) switch(name_id) if("human") diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 8591d77e50..5856a7b6e1 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -514,6 +514,12 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car S["scars3"] >> scars_list["3"] S["scars4"] >> scars_list["4"] S["scars5"] >> scars_list["5"] + var/limbmodstr + S["modified_limbs"] >> limbmodstr + if(length(limbmodstr)) + modified_limbs = safe_json_decode(limbmodstr) + else + modified_limbs = list() S["chosen_limb_id"] >> chosen_limb_id S["hide_ckey"] >> hide_ckey //saved per-character @@ -845,8 +851,6 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["feature_ooc_notes"], features["ooc_notes"]) - WRITE_FILE(S["chosen_limb_id"], chosen_limb_id) - //Custom names for(var/custom_name_id in GLOB.preferences_custom_names) var/savefile_slot_name = custom_name_id + "_name" //TODO remove this @@ -874,6 +878,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car WRITE_FILE(S["scars3"] , scars_list["3"]) WRITE_FILE(S["scars4"] , scars_list["4"]) WRITE_FILE(S["scars5"] , scars_list["5"]) + if(islist(modified_limbs)) + WRITE_FILE(S["modified_limbs"] , safe_json_encode(modified_limbs)) + WRITE_FILE(S["chosen_limb_id"], chosen_limb_id) //gear loadout diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm index 1238b37919..0feceaf1a8 100644 --- a/code/modules/jobs/job_types/_job.dm +++ b/code/modules/jobs/job_types/_job.dm @@ -80,6 +80,9 @@ if(mind_traits) for(var/t in mind_traits) ADD_TRAIT(H.mind, t, JOB_TRAIT) + if(/datum/quirk/paraplegic in blacklisted_quirks) + H.regenerate_limbs() //if you can't be a paraplegic, attempt to regenerate limbs to stop amputated limb selection + H.set_resting(FALSE, TRUE) //they probably shouldn't be on the floor because they had no legs then suddenly had legs /datum/job/proc/announce(mob/living/carbon/human/H) if(head_announce) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index 768c4c943e..312449064f 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -414,6 +414,8 @@ give_magic(humanc) if(GLOB.curse_of_madness_triggered) give_madness(humanc, GLOB.curse_of_madness_triggered) + if(humanc.client) + humanc.client.prefs.post_copy_to(humanc) GLOB.joined_player_list += character.ckey GLOB.latejoiners += character @@ -567,7 +569,7 @@ client.prefs.scars_list["[cur_scar_index]"] = valid_scars client.prefs.save_character() - client.prefs.copy_to(H) + client.prefs.copy_to(H, initial_spawn = TRUE) H.dna.update_dna_identity() if(mind) if(transfer_after) diff --git a/code/modules/mob/dead/new_player/preferences_setup.dm b/code/modules/mob/dead/new_player/preferences_setup.dm index 9a0d9f9242..b77fae68c8 100644 --- a/code/modules/mob/dead/new_player/preferences_setup.dm +++ b/code/modules/mob/dead/new_player/preferences_setup.dm @@ -41,7 +41,7 @@ var/mob/living/carbon/human/dummy/mannequin = generate_or_wait_for_human_dummy(DUMMY_HUMAN_SLOT_PREFERENCES) // Apply the Dummy's preview background first so we properly layer everything else on top of it. mannequin.add_overlay(mutable_appearance('modular_citadel/icons/ui/backgrounds.dmi', bgstate, layer = SPACE_LAYER)) - copy_to(mannequin) + copy_to(mannequin, initial_spawn = TRUE) if(previewJob && equip_job) mannequin.job = previewJob.title diff --git a/code/modules/mob/living/carbon/human/dummy.dm b/code/modules/mob/living/carbon/human/dummy.dm index 2f5c94b784..ed1ba3852f 100644 --- a/code/modules/mob/living/carbon/human/dummy.dm +++ b/code/modules/mob/living/carbon/human/dummy.dm @@ -18,6 +18,9 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy) /mob/living/carbon/human/dummy/Life() return +/mob/living/carbon/human/dummy/update_mobility() + return + /mob/living/carbon/human/dummy/proc/wipe_state() delete_equipment() icon_render_key = null diff --git a/icons/mob/augmentation/cosmetic_prosthetic/bishop.dmi b/icons/mob/augmentation/cosmetic_prosthetic/bishop.dmi new file mode 100644 index 0000000000..8641ef2d3c Binary files /dev/null and b/icons/mob/augmentation/cosmetic_prosthetic/bishop.dmi differ diff --git a/icons/mob/augmentation/cosmetic_prosthetic/cybersolutions.dmi b/icons/mob/augmentation/cosmetic_prosthetic/cybersolutions.dmi new file mode 100644 index 0000000000..eeed0d0c01 Binary files /dev/null and b/icons/mob/augmentation/cosmetic_prosthetic/cybersolutions.dmi differ diff --git a/icons/mob/augmentation/cosmetic_prosthetic/grayson.dmi b/icons/mob/augmentation/cosmetic_prosthetic/grayson.dmi new file mode 100644 index 0000000000..9ed6c5f06f Binary files /dev/null and b/icons/mob/augmentation/cosmetic_prosthetic/grayson.dmi differ diff --git a/icons/mob/augmentation/cosmetic_prosthetic/hephaestus.dmi b/icons/mob/augmentation/cosmetic_prosthetic/hephaestus.dmi new file mode 100644 index 0000000000..4bb6b72fd0 Binary files /dev/null and b/icons/mob/augmentation/cosmetic_prosthetic/hephaestus.dmi differ diff --git a/icons/mob/augmentation/cosmetic_prosthetic/nanotrasen.dmi b/icons/mob/augmentation/cosmetic_prosthetic/nanotrasen.dmi new file mode 100644 index 0000000000..18c7738ba3 Binary files /dev/null and b/icons/mob/augmentation/cosmetic_prosthetic/nanotrasen.dmi differ diff --git a/icons/mob/augmentation/cosmetic_prosthetic/talon.dmi b/icons/mob/augmentation/cosmetic_prosthetic/talon.dmi new file mode 100644 index 0000000000..9e4b93fb54 Binary files /dev/null and b/icons/mob/augmentation/cosmetic_prosthetic/talon.dmi differ diff --git a/icons/mob/augmentation/cosmetic_prosthetic/ward.dmi b/icons/mob/augmentation/cosmetic_prosthetic/ward.dmi new file mode 100644 index 0000000000..b2622ef6a1 Binary files /dev/null and b/icons/mob/augmentation/cosmetic_prosthetic/ward.dmi differ diff --git a/icons/mob/augmentation/cosmetic_prosthetic/xion.dmi b/icons/mob/augmentation/cosmetic_prosthetic/xion.dmi new file mode 100644 index 0000000000..823205742a Binary files /dev/null and b/icons/mob/augmentation/cosmetic_prosthetic/xion.dmi differ