mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-26 14:39:58 +01:00
[MIRROR] Summoning affix fixes [MDB IGNORE] (#24369)
* Summoning affix fixes (#78983) ## About The Pull Request The fantasy "summon x" affix blacklist doesn't work, and probably hasn't worked for a significant amount of time. This is because it generated a typecache with true/false values representing whether we should be able to spawn a mob... and then performed a `pick` on it. Pick doesn't care if the value is true or false, so everything in the blacklist was explicitly whitelisted. For some reason the list was also containing subtypes of a datum? Then passing this to a component which expected typepaths of mobs it could spawn? That doesn't work either. We _also_ never added basic mobs to this list, so it would never spawn those and they're an increasing number of our mobs total. While I was there I also just did some general code tidying. I moved the list of "specific subtypes to remove" to a global list because I suspect something else either will need it in the future or already does. ## Changelog 🆑 fix: Megafauna, lavaland elites, and abstract mobs now correctly cannot be spawned by a toolbox of ash drake summoning /🆑 * Summoning affix fixes --------- Co-authored-by: Jacquerel <hnevard@gmail.com>
This commit is contained in:
@@ -12,6 +12,37 @@ GLOBAL_LIST_INIT(dangerous_turfs, typecacheof(list(
|
||||
/turf/open/space,
|
||||
/turf/open/openspace)))
|
||||
|
||||
/// List of types of abstract mob which shouldn't usually exist in the world on its own if we're spawning random mobs
|
||||
GLOBAL_LIST_INIT(abstract_mob_types, list(
|
||||
/mob/living/basic/blob_minion,
|
||||
/mob/living/basic/construct,
|
||||
/mob/living/basic/heretic_summon,
|
||||
/mob/living/basic/mining,
|
||||
/mob/living/basic/pet,
|
||||
/mob/living/basic,
|
||||
/mob/living/basic/spider,
|
||||
/mob/living/carbon/alien/adult,
|
||||
/mob/living/carbon/alien,
|
||||
/mob/living/carbon/human/consistent,
|
||||
/mob/living/carbon/human/dummy/consistent,
|
||||
/mob/living/carbon/human/dummy,
|
||||
/mob/living/carbon/human/species,
|
||||
/mob/living/carbon,
|
||||
/mob/living/silicon,
|
||||
/mob/living/simple_animal/bot,
|
||||
/mob/living/simple_animal/hostile/asteroid/elite,
|
||||
/mob/living/simple_animal/hostile/asteroid,
|
||||
/mob/living/simple_animal/hostile/construct,
|
||||
/mob/living/simple_animal/hostile/guardian,
|
||||
/mob/living/simple_animal/hostile/megafauna,
|
||||
/mob/living/simple_animal/hostile/mimic, // Cannot exist if spawned without being passed an item reference
|
||||
/mob/living/simple_animal/hostile/retaliate,
|
||||
/mob/living/simple_animal/hostile,
|
||||
/mob/living/simple_animal/pet,
|
||||
/mob/living/simple_animal/soulscythe, // As mimic, can't exist if spawned outside an item
|
||||
/mob/living/simple_animal,
|
||||
))
|
||||
|
||||
|
||||
//Since it didn't really belong in any other category, I'm putting this here
|
||||
//This is for procs to replace all the goddamn 'in world's that are chilling around the code
|
||||
|
||||
@@ -103,30 +103,35 @@
|
||||
. = ..()
|
||||
// This is set up to be easy to add to these lists as I expect it will need modifications
|
||||
var/static/list/possible_mobtypes
|
||||
if(!possible_mobtypes)
|
||||
// The base list of allowed mob/species types
|
||||
possible_mobtypes = zebra_typecacheof(list(
|
||||
/mob/living/simple_animal = TRUE,
|
||||
/mob/living/carbon = TRUE,
|
||||
/datum/species = TRUE,
|
||||
// Some types to remove them and their subtypes
|
||||
/mob/living/carbon/human/species = FALSE,
|
||||
/mob/living/simple_animal/hostile/asteroid/elite = FALSE,
|
||||
/mob/living/simple_animal/hostile/megafauna = FALSE,
|
||||
))
|
||||
// Some particular types to disallow if they're too broad/abstract
|
||||
// Not in the above typecache generator because it includes subtypes and this doesn't.
|
||||
possible_mobtypes -= list(
|
||||
/mob/living/simple_animal/hostile,
|
||||
if(isnull(possible_mobtypes))
|
||||
possible_mobtypes = list()
|
||||
var/list/mob_subtype_whitelist = list(
|
||||
/mob/living/basic,
|
||||
/mob/living/carbon,
|
||||
/mob/living/simple_animal,
|
||||
)
|
||||
for(var/type in mob_subtype_whitelist)
|
||||
possible_mobtypes += subtypesof(type)
|
||||
|
||||
var/list/mob_subtype_blacklist = list(
|
||||
/mob/living/simple_animal/hostile/asteroid/elite,
|
||||
/mob/living/simple_animal/hostile/megafauna,
|
||||
)
|
||||
for(var/type in mob_subtype_blacklist)
|
||||
possible_mobtypes -= subtypesof(type)
|
||||
|
||||
possible_mobtypes -= GLOB.abstract_mob_types
|
||||
|
||||
var/mob/picked_mobtype = pick(possible_mobtypes)
|
||||
// This works even with the species picks since we're only accessing the name
|
||||
|
||||
var/obj/item/master = comp.parent
|
||||
var/max_mobs = max(CEILING(comp.quality/2, 1), 1)
|
||||
var/spawn_delay = 300 - 30 * comp.quality
|
||||
comp.appliedComponents += master.AddComponent(/datum/component/summoning, list(picked_mobtype), 100, max_mobs, spawn_delay)
|
||||
var/max_mobs = max(CEILING(comp.quality / 2, 1), 1)
|
||||
var/spawn_delay = 30 SECONDS - (3 SECONDS * comp.quality)
|
||||
comp.appliedComponents += master.AddComponent(\
|
||||
/datum/component/summoning,\
|
||||
mob_types = list(picked_mobtype),\
|
||||
max_mobs = max_mobs,\
|
||||
spawn_delay = spawn_delay,\
|
||||
)
|
||||
return "[newName] of [initial(picked_mobtype.name)] summoning"
|
||||
|
||||
/datum/fantasy_affix/shrapnel
|
||||
|
||||
@@ -1,16 +1,32 @@
|
||||
/datum/component/summoning
|
||||
/// Types of mob we can create
|
||||
var/list/mob_types = list()
|
||||
var/spawn_chance // chance for the mob to spawn on hit in percent
|
||||
/// Percentage chance to spawn a mob
|
||||
var/spawn_chance
|
||||
/// Maximum mobs we can have active at once
|
||||
var/max_mobs
|
||||
var/spawn_delay // delay in spawning between mobs (deciseconds)
|
||||
/// Cooldown between spawning mobs
|
||||
var/spawn_delay
|
||||
/// Text to display when spawning a mob
|
||||
var/spawn_text
|
||||
/// Sound to play when spawning a mob
|
||||
var/spawn_sound
|
||||
/// Factions to assign to a summoned mob
|
||||
var/list/faction
|
||||
|
||||
var/last_spawned_time = 0
|
||||
/// Cooldown tracker for when we can summon another mob
|
||||
COOLDOWN_DECLARE(summon_cooldown)
|
||||
/// List containing all of our mobs
|
||||
var/list/spawned_mobs = list()
|
||||
|
||||
/datum/component/summoning/Initialize(mob_types, spawn_chance=100, max_mobs=3, spawn_delay=100, spawn_text="appears out of nowhere", spawn_sound='sound/magic/summon_magic.ogg', faction)
|
||||
/datum/component/summoning/Initialize(
|
||||
mob_types,
|
||||
spawn_chance = 100,
|
||||
max_mobs = 3,
|
||||
spawn_delay = 10 SECONDS,
|
||||
spawn_text = "appears out of nowhere",
|
||||
spawn_sound = 'sound/magic/summon_magic.ogg',
|
||||
list/faction,
|
||||
)
|
||||
if(!isitem(parent) && !ishostile(parent) && !isgun(parent) && !ismachinery(parent) && !isstructure(parent) && !isprojectilespell(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
@@ -54,26 +70,22 @@
|
||||
do_spawn_mob(get_turf(target), firer)
|
||||
|
||||
/datum/component/summoning/proc/do_spawn_mob(atom/spawn_location, summoner)
|
||||
if(spawned_mobs.len >= max_mobs)
|
||||
if(length(spawned_mobs) >= max_mobs || !COOLDOWN_FINISHED(src, summon_cooldown) || !prob(spawn_chance))
|
||||
return
|
||||
if(last_spawned_time > world.time)
|
||||
return
|
||||
if(!prob(spawn_chance))
|
||||
return
|
||||
last_spawned_time = world.time + spawn_delay
|
||||
COOLDOWN_START(src, summon_cooldown, spawn_delay)
|
||||
var/chosen_mob_type = pick(mob_types)
|
||||
var/mob/living/simple_animal/L = new chosen_mob_type(spawn_location)
|
||||
if(ishostile(L))
|
||||
var/mob/living/simple_animal/hostile/H = L
|
||||
H.friends += summoner // do not attack our summon boy
|
||||
spawned_mobs += L
|
||||
var/mob/living/summoned = new chosen_mob_type(spawn_location)
|
||||
if(ishostile(summoned))
|
||||
var/mob/living/simple_animal/hostile/angry_boy = summoned
|
||||
angry_boy.friends |= summoner // do not attack our summon boy
|
||||
spawned_mobs |= summoned
|
||||
if(faction != null)
|
||||
L.faction = faction
|
||||
RegisterSignal(L, COMSIG_LIVING_DEATH, PROC_REF(on_spawned_death)) // so we can remove them from the list, etc (for mobs with corpses)
|
||||
playsound(spawn_location,spawn_sound, 50, TRUE)
|
||||
spawn_location.visible_message(span_danger("[L] [spawn_text]."))
|
||||
summoned.faction = faction.Copy()
|
||||
RegisterSignals(summoned, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING), PROC_REF(on_spawned_death))
|
||||
spawn_location.visible_message(span_danger("[summoned] [spawn_text]!"))
|
||||
|
||||
/// When a spawned thing dies, remove it from our list
|
||||
/datum/component/summoning/proc/on_spawned_death(mob/killed, gibbed)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
UnregisterSignal(killed, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING))
|
||||
spawned_mobs -= killed
|
||||
|
||||
@@ -520,7 +520,6 @@
|
||||
return
|
||||
var/datum/fantasy_affix/affix = affixes[picked_affix_name]
|
||||
affixes.Remove(affix)
|
||||
QDEL_LIST_ASSOC(affixes) //remove the rest, we didn't use them
|
||||
var/fantasy_quality = 0
|
||||
if(affix.alignment & AFFIX_GOOD)
|
||||
fantasy_quality++
|
||||
|
||||
Reference in New Issue
Block a user