diff --git a/code/__DEFINES/_flags.dm b/code/__DEFINES/_flags.dm index 383edbe3e81..6fcac62c8cb 100644 --- a/code/__DEFINES/_flags.dm +++ b/code/__DEFINES/_flags.dm @@ -356,3 +356,7 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define EMPATH_SEE_COLD (1<<7) /// Can the empath see if living mob has the fundamentally evil trait #define EMPATH_SEE_EVIL (1<<8) + +// Flags for using your static for a ghost role +#define GHOSTROLE_ALLOW_SPECIES (1<<0) +#define GHOSTROLE_ALLOW_OTHER (1<<1) diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 205d51029a1..3ffe30aeec9 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -689,3 +689,8 @@ DEFINE_BITFIELD(visible_info, list( "EMPATH_SEE_COLD" = EMPATH_SEE_COLD, "EMPATH_SEE_EVIL" = EMPATH_SEE_EVIL, )) + +DEFINE_BITFIELD(allow_custom_character, list( + "GHOSTROLE_ALLOW_SPECIES" = GHOSTROLE_ALLOW_SPECIES, + "GHOSTROLE_ALLOW_OTHER" = GHOSTROLE_ALLOW_OTHER, +)) diff --git a/code/modules/antagonists/pirate/pirate_roles.dm b/code/modules/antagonists/pirate/pirate_roles.dm index 9d7cf14cbbb..f2e76c6aee6 100644 --- a/code/modules/antagonists/pirate/pirate_roles.dm +++ b/code/modules/antagonists/pirate/pirate_roles.dm @@ -14,6 +14,7 @@ you_are_text = "You are a space pirate." flavour_text = "The station refused to pay for your protection. Protect the ship, siphon the credits from the station, and raid it for even more loot." spawner_job_path = /datum/job/space_pirate + allow_custom_character = GHOSTROLE_ALLOW_OTHER ///Rank of the pirate on the ship, it's used in generating pirate names! var/rank = "Deserter" ///Path of the structure we spawn after creating a pirate. @@ -58,6 +59,7 @@ outfit = /datum/outfit/pirate rank = "Mate" fluff_spawn = null + allow_custom_character = NONE /obj/effect/mob_spawn/ghost_role/human/pirate/skeleton/captain rank = "Captain" @@ -75,6 +77,7 @@ mob_species = /datum/species/lizard/silverscale outfit = /datum/outfit/pirate/silverscale rank = "High-born" + allow_custom_character = NONE /obj/effect/mob_spawn/ghost_role/human/pirate/silverscale/generate_pirate_name(spawn_gender) var/first_name @@ -184,6 +187,7 @@ mob_species = /datum/species/ethereal/lustrous outfit = /datum/outfit/pirate/lustrous rank = "Scintillant" + allow_custom_character = NONE /obj/effect/mob_spawn/ghost_role/human/pirate/lustrous/captain rank = "Radiant" diff --git a/code/modules/bitrunning/spawners.dm b/code/modules/bitrunning/spawners.dm index 69e6cae07a0..fad6da01e59 100644 --- a/code/modules/bitrunning/spawners.dm +++ b/code/modules/bitrunning/spawners.dm @@ -34,12 +34,14 @@ outfit = /datum/outfit/beachbum spawner_job_path = /datum/job/beach_bum antag = FALSE + allow_custom_character = GHOSTROLE_ALLOW_OTHER /obj/effect/mob_spawn/ghost_role/human/virtual_domain/beach/lifeguard name = "virtual lifeguard sleeper" you_are_text = "You are a spunky virtual lifeguard!" flavour_text = "It's up to you to make sure nobody lags or gets eaten by malware and stuff." outfit = /datum/outfit/beachbum/lifeguard + allow_custom_character = NONE /obj/effect/mob_spawn/ghost_role/human/virtual_domain/beach/lifeguard/special(mob/living/carbon/human/lifeguard, mob/mob_possessor) . = ..() @@ -51,6 +53,7 @@ you_are_text = "You are a virtual beach bartender!" flavour_text = "Your job is to keep the virtually rendered drinks coming, and help the dudebros engage drunkness simulations." outfit = /datum/outfit/spacebartender + allow_custom_character = ALL //Skeleton Pirates /obj/effect/mob_spawn/ghost_role/human/virtual_domain/pirate diff --git a/code/modules/mob_spawn/ghost_roles/fugitive_hunter_roles.dm b/code/modules/mob_spawn/ghost_roles/fugitive_hunter_roles.dm index 2d1f3c7a706..a07d17ec60c 100644 --- a/code/modules/mob_spawn/ghost_roles/fugitive_hunter_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/fugitive_hunter_roles.dm @@ -6,6 +6,7 @@ flavour_text = "Write me some god damn flavor text!" //the flavor text will be the backstory argument called on the antagonist's greet, see hunter.dm for details show_flavor = FALSE var/back_story = "error" + allow_custom_character = GHOSTROLE_ALLOW_OTHER /obj/effect/mob_spawn/ghost_role/human/fugitive/special(mob/living/carbon/human/spawned_human, mob/mob_possessor) . = ..() diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm index 84e95326d2d..9b971338109 100644 --- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm @@ -14,6 +14,7 @@ the hostile creatures, and the ash drakes swooping down from the cloudless skies, all you can wish for is the feel of soft grass between your toes and \ the fresh air of Earth. These thoughts are dispelled by yet another recollection of how you got here... " spawner_job_path = /datum/job/hermit + allow_custom_character = ALL /obj/effect/mob_spawn/ghost_role/human/hermit/Initialize(mapload) . = ..() @@ -79,12 +80,14 @@ flavour_text = "Ch'yea. You came here, like, on spring break, hopin' to pick up some bangin' hot chicks, y'knaw?" spawner_job_path = /datum/job/beach_bum outfit = /datum/outfit/beachbum + allow_custom_character = GHOSTROLE_ALLOW_OTHER /obj/effect/mob_spawn/ghost_role/human/beach/lifeguard you_are_text = "You're a spunky lifeguard!" flavour_text = "It's up to you to make sure nobody drowns or gets eaten by sharks and stuff." name = "lifeguard sleeper" outfit = /datum/outfit/beachbum/lifeguard + allow_custom_character = NONE /obj/effect/mob_spawn/ghost_role/human/beach/lifeguard/special(mob/living/carbon/human/lifeguard, mob/mob_possessor) . = ..() @@ -119,6 +122,7 @@ flavour_text = "Time to mix drinks and change lives. Smoking space drugs makes it easier to understand your patrons' odd dialect." spawner_job_path = /datum/job/space_bartender outfit = /datum/outfit/spacebartender + allow_custom_character = ALL /datum/outfit/spacebartender name = "Space Bartender" @@ -284,6 +288,7 @@ outfit = /datum/outfit/lavaland_syndicate spawner_job_path = /datum/job/lavaland_syndicate deletes_on_zero_uses_left = FALSE + allow_custom_character = ALL /obj/effect/mob_spawn/ghost_role/human/lavaland_syndicate/special(mob/living/new_spawn, mob/mob_possessor) . = ..() diff --git a/code/modules/mob_spawn/ghost_roles/space_roles.dm b/code/modules/mob_spawn/ghost_roles/space_roles.dm index 86650f541b3..387472b707b 100644 --- a/code/modules/mob_spawn/ghost_roles/space_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/space_roles.dm @@ -14,6 +14,7 @@ important_text = "Work as a team with your fellow survivors and do not abandon them." outfit = /datum/outfit/oldeng spawner_job_path = /datum/job/ancient_crew + allow_custom_character = GHOSTROLE_ALLOW_OTHER /obj/effect/mob_spawn/ghost_role/human/oldstation/create_from_ghost(mob/dead/user) . = ..() @@ -102,6 +103,7 @@ outfit = /datum/outfit/syndicate_empty/battlecruiser spawner_job_path = /datum/job/battlecruiser_crew uses = 4 + allow_custom_character = ALL /// The antag team to apply the player to var/datum/team/antag_team @@ -191,6 +193,7 @@ important_text = "Work as a team with your fellow actors and the director to make entertainment for the masses." outfit = /datum/outfit/actor spawner_job_path = /datum/job/ghost_role + allow_custom_character = ALL /datum/outfit/actor name = "Actor" @@ -215,6 +218,7 @@ important_text = "Work as a team with your fellow actors and the director to make entertainment for the masses." outfit = /datum/outfit/actor/director spawner_job_path = /datum/job/ghost_role + allow_custom_character = ALL /datum/outfit/actor/director name = "Director" diff --git a/code/modules/mob_spawn/ghost_roles/unused_roles.dm b/code/modules/mob_spawn/ghost_roles/unused_roles.dm index 1ceef16d559..b94e3159d8a 100644 --- a/code/modules/mob_spawn/ghost_roles/unused_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/unused_roles.dm @@ -12,6 +12,7 @@ though fate has other plans for you." flavour_text = "Good. It seems as though your ship crashed. You remember that you were convicted of " spawner_job_path = /datum/job/escaped_prisoner + allow_custom_character = GHOSTROLE_ALLOW_OTHER /obj/effect/mob_spawn/ghost_role/human/prisoner_transport/Initialize(mapload) . = ..() @@ -50,6 +51,7 @@ flavour_text = "Cater to visiting guests with your fellow staff, advertise the hotel, and make sure the manager doesn't fire you. Remember, the customer is always right!" important_text = "Do NOT leave the hotel, as that is grounds for contract termination." spawner_job_path = /datum/job/hotel_staff + allow_custom_character = ALL /datum/outfit/hotelstaff name = "Hotel Staff" @@ -94,6 +96,7 @@ flavour_text = "You have awoken, without instruction. Death to Nanotrasen! If there are some clues around as to what you're supposed to be doing, you best follow those." outfit = /datum/outfit/syndicate_empty spawner_job_path = /datum/job/space_syndicate + allow_custom_character = ALL /datum/outfit/syndicate_empty name = "Syndicate Operative Empty" @@ -119,6 +122,7 @@ flavour_text = "Hang out at the bar and chat with your buddies. Feel free to hop back in the cryogenics when you're done chatting." outfit = /datum/outfit/cryobartender spawner_job_path = /datum/job/space_bar_patron + allow_custom_character = ALL /obj/effect/mob_spawn/ghost_role/human/space_bar_patron/attack_hand(mob/user, list/modifiers) var/despawn = tgui_alert(usr, "Return to cryosleep? (Warning, Your mob will be deleted!)", null, list("Yes", "No")) @@ -178,6 +182,7 @@ you_are_text = "You are a Nanotrasen Private Security Officer!" flavour_text = "If higher command has an assignment for you, it's best you follow that. Otherwise, death to The Syndicate." outfit = /datum/outfit/nanotrasensoldier + allow_custom_character = ALL /obj/effect/mob_spawn/ghost_role/human/commander name = "sleeper" @@ -187,6 +192,7 @@ you_are_text = "You are a Nanotrasen Commander!" flavour_text = "Upper-crusty of Nanotrasen. You should be given the respect you're owed." outfit = /datum/outfit/nanotrasencommander + allow_custom_character = GHOSTROLE_ALLOW_OTHER //space doctor, a rat with cancer, and bessie from an old removed lavaland ruin. @@ -199,6 +205,7 @@ flavour_text = "It's your job- no, your duty as a doctor, to care and heal those in need." outfit = /datum/outfit/job/doctor spawner_job_path = /datum/job/space_doctor + allow_custom_character = ALL /obj/effect/mob_spawn/ghost_role/human/doctor/alive/equip(mob/living/carbon/human/doctor) . = ..() @@ -244,6 +251,7 @@ flavour_text = "Monitor Nanotrasen communications and record information. All intruders should be disposed of \ swiftly to assure no gathered information is stolen or lost. Try not to wander too far from the outpost as the \ caves can be a deadly place even for a trained operative such as yourself." + allow_custom_character = ALL /datum/outfit/snowsyndie name = "Syndicate Snow Operative" @@ -269,6 +277,7 @@ important_text = "Obey orders given by your captain. DO NOT let the ship fall into enemy hands." outfit = /datum/outfit/syndicatespace/syndicrew spawner_job_path = /datum/job/syndicate_cybersun + allow_custom_character = ALL /obj/effect/mob_spawn/ghost_role/human/syndicatespace/special(mob/living/new_spawn, mob/mob_possessor) . = ..() @@ -286,6 +295,7 @@ important_text = "Protect the ship and secret documents in your backpack with your own life." outfit = /datum/outfit/syndicatespace/syndicaptain spawner_job_path = /datum/job/syndicate_cybersun_captain + allow_custom_character = ALL /obj/effect/mob_spawn/ghost_role/human/syndicatespace/captain/Destroy() new /obj/structure/fluff/empty_sleeper/syndicate/captain(get_turf(src)) diff --git a/code/modules/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm index bdb565cc9bc..48b514ea088 100644 --- a/code/modules/mob_spawn/mob_spawn.dm +++ b/code/modules/mob_spawn/mob_spawn.dm @@ -114,6 +114,8 @@ /// A list of the ckeys that currently are trying to access this spawner, so that they can't try to spawn more than once (in case there's sleeps). /// Static because you only really want to be able to spawn in one spawner at a time, obviously. var/static/list/ckeys_trying_to_spawn + ///bitflag that determines if players can spawn in as their statics + var/allow_custom_character = NONE ////descriptions @@ -206,7 +208,7 @@ * If you are manually forcing a player into this mob spawn, * you should be using this and not directly calling [proc/create]. */ -/obj/effect/mob_spawn/ghost_role/proc/create_from_ghost(mob/dead/user) +/obj/effect/mob_spawn/ghost_role/proc/create_from_ghost(mob/dead/observer/user) ASSERT(istype(user)) var/user_ckey = user.ckey // We need to do it before everything else, because after the create() the ckey will already have been transferred. @@ -214,6 +216,15 @@ uses -= 1 // Remove a use before trying to spawn to prevent strangeness like the spawner trying to spawn more mobs than it should be able to if(!temp_body) user.mind = null // dissassociate mind, don't let it follow us to the next life + var/species_pref = user.client.prefs.read_preference(/datum/preference/choiced/species) + var/datum/species/user_species = GLOB.species_prototypes[species_pref] + if(user_species.inherent_respiration_type == RESPIRATION_PLASMA) // Stupid flammable skeletons... + user.started_as_observer = null + else if(user.started_as_observer && allow_custom_character) + var/static_prompt = "Because you haven't taken a role so far, you may spawn in as [(allow_custom_character & GHOSTROLE_ALLOW_SPECIES || user_species == /datum/species/human) ? "" : "a human version of"] your customized character with a random name. Would you like to?" + var/static_prompt_result = tgui_alert(user, static_prompt, "Custom Character", list("Yes", "No"), 10 SECONDS) + if(static_prompt_result != "Yes") + user.started_as_observer = null var/created = create(user) LAZYREMOVE(ckeys_trying_to_spawn, user_ckey) // We do this AFTER the create() so that we're basically sure that the user won't be in their ghost body anymore, so they can't click on the spawner again. @@ -239,6 +250,14 @@ /obj/effect/mob_spawn/ghost_role/special(mob/living/spawned_mob, mob/mob_possessor) . = ..() if(mob_possessor) + var/mob/dead/observer/observer_possessor = mob_possessor + if(observer_possessor.started_as_observer) + var/old_name = spawned_mob.real_name + if(allow_custom_character & GHOSTROLE_ALLOW_OTHER) + mob_possessor.client.prefs.safe_transfer_prefs_to(spawned_mob) + spawned_mob.fully_replace_character_name(newname = old_name) + if(!(allow_custom_character & GHOSTROLE_ALLOW_SPECIES || ishumanbasic(spawned_mob))) + spawned_mob.set_species(/datum/species/human) if(mob_possessor.mind) mob_possessor.mind.transfer_to(spawned_mob, force_key_move = TRUE) else @@ -247,7 +266,6 @@ if(spawned_mind) spawned_mob.mind.set_assigned_role_with_greeting(SSjob.get_job_type(spawner_job_path)) spawned_mind.name = spawned_mob.real_name - if(show_flavor) var/output_message = span_infoplain("[you_are_text]") if(flavour_text != "")