[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:
SkyratBot
2023-10-16 08:46:24 -07:00
committed by GitHub
co-authored by Jacquerel
parent 772c48d05d
commit a34d9b2da9
4 changed files with 89 additions and 42 deletions
+31
View File
@@ -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
+25 -20
View File
@@ -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
+33 -21
View File
@@ -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
-1
View File
@@ -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++