mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-29 19:11:51 +00:00
About The Super Hyper Ultra Ultimate Deluxe Perfect Amazing Shining Mob Spawn Refactor
The Super Hyper Ultra Ultimate Deluxe Perfect Amazing Shining Mob Spawn Refactor is my attempt to clean up the file structure, the code, and the type tree for mob spawns.
Splits mob spawn types into corpses (dead spawns) and ghost roles (living spawns you can possess). The vars that didn't make sense for corpses and vice versa for ghost roles are now appropriately there
Because of above, there are no longer the fucking "death, roundstart, and instant" vars. thank god
Removes a lot of single or very few used vars, whose properties can be applied on special().
All Mob Spawns are given fitting folders instead of just being stuck in a single ghost roles file. Corpses are in the corpse folder, Ghost Roles are in the ghost role folder. Only exception are drones which should stay near their respective homes
Just generally cleaner all around you know
spider structures file renamed to spiderwebs now that spider eggs are gone
Why Super Hyper Ultra Ultimate Deluxe Perfect Amazing Shining Mob Spawn Refactor Is Good For The Game
The Super Hyper Ultra Ultimate Deluxe Perfect Amazing Shining Mob Spawn Refactor cleans up so many terrible cases and uses
Changelog For The Super Hyper Ultra Ultimate Deluxe Perfect Amazing Shining Mob Spawn Refactor
cl armhulen
refactor: Mob spawns are refactored, no more assortment of "random, instant, and roundstart" vars on every mob spawn type
refactor: if there are some minimal differences in how mob spawners feel, that's why!
/cl
268 lines
9.9 KiB
Plaintext
268 lines
9.9 KiB
Plaintext
/obj/effect/mob_spawn
|
|
name = "Mob Spawner"
|
|
density = TRUE
|
|
anchored = TRUE
|
|
//So it shows up in the map editor
|
|
icon = 'icons/effects/mapping_helpers.dmi'
|
|
icon_state = "mobspawner"
|
|
///A forced name of the mob, though can be overridden if a special name is passed as an argument
|
|
var/mob_name
|
|
///the type of the mob, you best inherit this
|
|
var/mob_type = /mob/living/basic/cockroach
|
|
///Lazy string list of factions that the spawned mob will be in upon spawn
|
|
var/list/faction
|
|
|
|
////Human specific stuff. Don't set these if you aren't using a human, the unit tests will put a stop to your sinful hand.
|
|
|
|
///sets the human as a species, use a typepath (example: /datum/species/skeleton)
|
|
var/mob_species
|
|
///equips the human with an outfit.
|
|
var/datum/outfit/outfit
|
|
///for mappers to override parts of the outfit. really only in here for secret away missions, please try to refrain from using this out of laziness
|
|
var/list/outfit_override
|
|
///sets a human's hairstyle
|
|
var/hairstyle
|
|
///sets a human's facial hair
|
|
var/facial_hairstyle
|
|
///sets a human's hair color (use special for gradients, sorry)
|
|
var/haircolor
|
|
///sets a human's facial hair color
|
|
var/facial_haircolor
|
|
///sets a human's skin tone
|
|
var/skin_tone
|
|
|
|
/obj/effect/mob_spawn/Initialize(mapload)
|
|
. = ..()
|
|
if(faction)
|
|
faction = string_list(faction)
|
|
|
|
/obj/effect/mob_spawn/proc/create(mob/mob_possessor, newname)
|
|
var/mob/living/spawned_mob = new mob_type(get_turf(src)) //living mobs only
|
|
name_mob(spawned_mob, newname)
|
|
special(spawned_mob, mob_possessor)
|
|
equip(spawned_mob)
|
|
return spawned_mob
|
|
|
|
/obj/effect/mob_spawn/proc/special(mob/living/spawned_mob)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
if(faction)
|
|
spawned_mob.faction = faction
|
|
if(ishuman(spawned_mob))
|
|
var/mob/living/carbon/human/spawned_human = spawned_mob
|
|
if(mob_species)
|
|
spawned_human.set_species(mob_species)
|
|
spawned_human.underwear = "Nude"
|
|
spawned_human.undershirt = "Nude"
|
|
spawned_human.socks = "Nude"
|
|
if(hairstyle)
|
|
spawned_human.hairstyle = hairstyle
|
|
else
|
|
spawned_human.hairstyle = random_hairstyle(spawned_human.gender)
|
|
if(facial_hairstyle)
|
|
spawned_human.facial_hairstyle = facial_hairstyle
|
|
else
|
|
spawned_human.facial_hairstyle = random_facial_hairstyle(spawned_human.gender)
|
|
if(haircolor)
|
|
spawned_human.hair_color = haircolor
|
|
else
|
|
spawned_human.hair_color = "#[random_color()]"
|
|
if(facial_haircolor)
|
|
spawned_human.facial_hair_color = facial_haircolor
|
|
else
|
|
spawned_human.facial_hair_color = "#[random_color()]"
|
|
if(skin_tone)
|
|
spawned_human.skin_tone = skin_tone
|
|
else
|
|
spawned_human.skin_tone = random_skin_tone()
|
|
spawned_human.update_hair()
|
|
spawned_human.update_body()
|
|
|
|
/obj/effect/mob_spawn/proc/name_mob(mob/living/spawned_mob, forced_name)
|
|
var/chosen_name
|
|
//passed arguments on mob spawns are number one priority
|
|
if(forced_name)
|
|
chosen_name = forced_name
|
|
//then the mob name var
|
|
else if(mob_name)
|
|
chosen_name = mob_name
|
|
//then if no name was chosen the one the mob has by default works great
|
|
if(!chosen_name)
|
|
return
|
|
//not using an old name doesn't update records- but ghost roles don't have records so who cares
|
|
spawned_mob.fully_replace_character_name(null, chosen_name)
|
|
|
|
/obj/effect/mob_spawn/proc/equip(mob/living/spawned_mob)
|
|
if(outfit)
|
|
var/mob/living/carbon/human/spawned_human = spawned_mob
|
|
if(outfit_override)
|
|
outfit = new outfit //create it now to apply vars
|
|
for(var/outfit_var in outfit_override)
|
|
if(!ispath(outfit_override[outfit_var]) && !isnull(outfit_override[outfit_var]))
|
|
CRASH("outfit_override var on [mob_name] spawner has incorrect values! it must be an assoc list with outfit \"var\" = path | null")
|
|
outfit.vars[outfit_var] = outfit_override[outfit_var]
|
|
spawned_human.equipOutfit(outfit)
|
|
|
|
///these mob spawn subtypes do not trigger until attacked by a ghost.
|
|
/obj/effect/mob_spawn/ghost_role
|
|
///a short, lowercase name for the mob used in possession prompt that pops up on ghost attacks. must be set.
|
|
var/prompt_name = ""
|
|
///if false, you won't prompt for this role. best used for replacing the prompt system with something else like a radial, or something.
|
|
var/prompt_ghost = TRUE
|
|
///how many times this spawner can be used (it won't delete unless it's out of uses)
|
|
var/uses = 1
|
|
|
|
////descriptions
|
|
|
|
///This should be the declaration of what the ghost role is, and maybe a short blurb after if you want. Shown in the spawner menu and after spawning first.
|
|
var/you_are_text = ""
|
|
///This should be the actual instructions/description/context to the ghost role. This should be the really long explainy bit, basically.
|
|
var/flavour_text = ""
|
|
///This is critical non-policy information about the ghost role. Shown in the spawner menu and after spawning last.
|
|
var/important_text = ""
|
|
|
|
///Show these on spawn? Usually used for hardcoded special flavor
|
|
var/show_flavor = TRUE
|
|
|
|
////bans and policy
|
|
|
|
///which role to check for a job ban (ROLE_LAVALAND is the default ghost role ban)
|
|
var/role_ban = ROLE_LAVALAND
|
|
/// Typepath indicating the kind of job datum this ghost role will have. PLEASE inherit this with a new job datum, it's not hard. jobs come with policy configs.
|
|
var/spawner_job_path = /datum/job/ghost_role
|
|
|
|
/obj/effect/mob_spawn/ghost_role/Initialize(mapload)
|
|
. = ..()
|
|
SSpoints_of_interest.make_point_of_interest(src)
|
|
LAZYADD(GLOB.mob_spawners[name], src)
|
|
|
|
/obj/effect/mob_spawn/Destroy()
|
|
var/list/spawners = GLOB.mob_spawners[name]
|
|
LAZYREMOVE(spawners, src)
|
|
if(!LAZYLEN(spawners))
|
|
GLOB.mob_spawners -= name
|
|
return ..()
|
|
|
|
//ATTACK GHOST IGNORING PARENT RETURN VALUE
|
|
/obj/effect/mob_spawn/ghost_role/attack_ghost(mob/user)
|
|
if(!SSticker.HasRoundStarted() || !loc)
|
|
return
|
|
if(prompt_ghost)
|
|
var/ghost_role = tgui_alert(usr, "Become [prompt_name]? (Warning, You can no longer be revived!)",, list("Yes", "No"))
|
|
if(ghost_role != "Yes" || !loc || QDELETED(user))
|
|
return
|
|
if(!(GLOB.ghost_role_flags & GHOSTROLE_SPAWNER) && !(flags_1 & ADMIN_SPAWNED_1))
|
|
to_chat(user, span_warning("An admin has temporarily disabled non-admin ghost roles!"))
|
|
return
|
|
if(!uses) //just in case
|
|
to_chat(user, span_warning("This spawner is out of charges!"))
|
|
return
|
|
if(is_banned_from(user.key, role_ban))
|
|
to_chat(user, span_warning("You are banned from this role!"))
|
|
return
|
|
if(!allow_spawn(user, silent = FALSE))
|
|
return
|
|
if(QDELETED(src) || QDELETED(user))
|
|
return
|
|
log_game("[key_name(user)] became a [prompt_name]")
|
|
create(user)
|
|
|
|
/obj/effect/mob_spawn/ghost_role/special(mob/living/spawned_mob, mob/mob_possessor)
|
|
. = ..()
|
|
spawned_mob.ckey = mob_possessor.ckey
|
|
if(show_flavor)
|
|
var/output_message = "<span class='infoplain'><span class='big bold'>[you_are_text]</span></span>"
|
|
if(flavour_text != "")
|
|
output_message += "\n<span class='infoplain'><b>[flavour_text]</b></span>"
|
|
if(important_text != "")
|
|
output_message += "\n[span_userdanger("[important_text]")]"
|
|
to_chat(spawned_mob, output_message)
|
|
var/datum/mind/spawned_mind = spawned_mob.mind
|
|
spawned_mob.mind.set_assigned_role(SSjob.GetJobType(spawner_job_path))
|
|
spawned_mind.name = spawned_mob.real_name
|
|
|
|
//multiple use mob spawner functionality here- doesn't make sense on corpses
|
|
/obj/effect/mob_spawn/ghost_role/create(mob/mob_possessor, newname)
|
|
. = ..()
|
|
if(uses > 0)
|
|
uses--
|
|
if(!uses)
|
|
qdel(src)
|
|
|
|
///override this to add special spawn conditions to a ghost role
|
|
/obj/effect/mob_spawn/ghost_role/proc/allow_spawn(mob/user, silent = FALSE)
|
|
return TRUE
|
|
|
|
///these mob spawn subtypes trigger immediately (New or Initialize) and are not player controlled... since they're dead, you know?
|
|
/obj/effect/mob_spawn/corpse
|
|
///when this mob spawn should auto trigger.
|
|
var/spawn_when = CORPSE_INSTANT
|
|
|
|
////damage values (very often, mappers want corpses to be mangled)
|
|
|
|
///brute damage this corpse will spawn with
|
|
var/brute_damage = 0
|
|
///oxy damage this corpse will spawn with
|
|
var/oxy_damage = 0
|
|
///burn damage this corpse will spawn with
|
|
var/burn_damage = 0
|
|
|
|
/obj/effect/mob_spawn/corpse/Initialize(mapload)
|
|
. = ..()
|
|
switch(spawn_when)
|
|
if(CORPSE_INSTANT)
|
|
INVOKE_ASYNC(src, .proc/create)
|
|
if(CORPSE_ROUNDSTART)
|
|
if(mapload || (SSticker && SSticker.current_state > GAME_STATE_SETTING_UP))
|
|
INVOKE_ASYNC(src, .proc/create)
|
|
|
|
/obj/effect/mob_spawn/corpse/special(mob/living/spawned_mob)
|
|
. = ..()
|
|
spawned_mob.death(TRUE)
|
|
spawned_mob.adjustOxyLoss(oxy_damage)
|
|
spawned_mob.adjustBruteLoss(brute_damage)
|
|
spawned_mob.adjustFireLoss(burn_damage)
|
|
|
|
/obj/effect/mob_spawn/corpse/create(mob/mob_possessor, newname)
|
|
. = ..()
|
|
qdel(src)
|
|
|
|
//almost all mob spawns in this game, dead or living, are human. so voila
|
|
|
|
/obj/effect/mob_spawn/ghost_role/human
|
|
//gives it a base sprite instead of a mapping helper. makes sense, right?
|
|
icon = 'icons/obj/machines/sleeper.dmi'
|
|
icon_state = "sleeper"
|
|
mob_type = /mob/living/carbon/human
|
|
|
|
/obj/effect/mob_spawn/corpse/human
|
|
icon_state = "corpsehuman"
|
|
mob_type = /mob/living/carbon/human
|
|
///disables PDA and sensors. only makes sense on corpses because ghost roles could simply turn those on again.
|
|
var/conceal_presence = TRUE
|
|
///husks the corpse if true.
|
|
var/husk = FALSE
|
|
|
|
/obj/effect/mob_spawn/corpse/human/special(mob/living/carbon/human/spawned_human)
|
|
. = ..()
|
|
if(husk)
|
|
spawned_human.Drain()
|
|
else //Because for some reason I can't track down, things are getting turned into husks even if husk = false. It's in some damage proc somewhere.
|
|
spawned_human.cure_husk()
|
|
|
|
/obj/effect/mob_spawn/corpse/human/equip(mob/living/carbon/human/spawned_human)
|
|
. = ..()
|
|
if(conceal_presence)
|
|
// We don't want corpse PDAs to show up in the messenger list.
|
|
var/obj/item/pda/messenger = locate(/obj/item/pda) in spawned_human
|
|
if(messenger)
|
|
messenger.toff = TRUE
|
|
// Or on crew monitors
|
|
var/obj/item/clothing/under/sensor_clothes = spawned_human.w_uniform
|
|
if(istype(sensor_clothes))
|
|
sensor_clothes.sensor_mode = NO_SENSORS
|
|
spawned_human.update_suit_sensors()
|
|
|
|
//don't use this in subtypes, just add 1000 brute yourself. that being said, this is a type that has 1000 brute. it doesn't really have a home anywhere else, it just needs to exist
|
|
/obj/effect/mob_spawn/corpse/human/damaged
|
|
brute_damage = 1000
|