Preserving ambushflags with randomspawners

Ask about ACS, DECORATE, ZScript, or any other scripting questions here!

Moderator: GZDoom Developers

Forum rules
Before asking on how to use a ZDoom feature, read the ZDoom wiki first. If you still don't understand how to use a feature, then ask here.

Please bear in mind that the people helping you do not automatically know how much you know. You may be asked to upload your project file to look at. Don't be afraid to ask questions about what things mean, but also please be patient with the people trying to help you. (And helpers, please be patient with the person you're trying to help!)
Post Reply
User avatar
Grey-Wolf
Posts: 179
Joined: Sun Jul 15, 2018 4:59 pm
Graphics Processor: nVidia (Modern GZDoom)

Preserving ambushflags with randomspawners

Post by Grey-Wolf »

Hello,
I'm trying to set up an option regulated by CVARS that lets the player what kind of monster spawns he'll get in his playthrough. For example, CVAR = 0 means default spawns, CVAR = 1 means various zombie-type monsters replaced with other lesser monsters (to reduce ammo availability) and CVAR = 2 means randomized monsters.
So after setting it up in menudef and CVARINFO, here's a short example of what I've attempted:

ZSCRIPT:

Code: Select all

class CustomZombieman : Actor Replaces Zombieman
{
    override void PostBeginPlay()
    {
        super.PostBeginPlay();
        actor replacer;

        if(monsterspawns==0) replacer = spawn("PossessedSpawner",pos,ALLOW_REPLACE);
        else if(monsterspawns==1) replacer = spawn("LessZombiemen",pos,ALLOW_REPLACE);
        else if(monsterspawns==2) replacer = spawn("Tier1Mob",pos,ALLOW_REPLACE);


        if(replacer)
        {
            replacer.angle = angle;
            replacer.special = special;
        }
        destroy();
    }
} 
DECORATE:

Code: Select all

Actor PossessedSpawner : BasicWeaponPickup
{
States
    {
	 Spawn:
		TNT1 A 0
		TNT1 A 1
		TNT1 A 0 A_Jump(1, "RocketGuy") 
		TNT1 A 0 A_Jump(2, "Major") 
		TNT1 A 0 A_Jump(10, "RiotShieldGuy") 
		TNT1 A 0 A_Jump(5, "ChainsawZombie") 
		TNT1 A 0 A_Jump(5, "MinigunGuy") 
	RifleZombie:
		TNT1 A 0 A_ChangeFlag("THRUACTORS", 1)
		TNT1 A 0 A_ChangeFlag("COUNTKILL", 0)
		TNT1 A 0 A_SpawnItemEx ("RifleZombie",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION | SXF_TRANSFERAMBUSHFLAG | SXF_TRANSFERPOINTERS ,0, tid)
		Stop		
	MinigunGuy:
		TNT1 A 0 A_ChangeFlag("THRUACTORS", 1)
		TNT1 A 0 A_ChangeFlag("COUNTKILL", 0)
		TNT1 A 0 A_SpawnItemEx ("MinigunGuy",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION | SXF_TRANSFERAMBUSHFLAG | SXF_TRANSFERPOINTERS ,0, tid)
		Stop		
	ChainsawZombie:
		TNT1 A 0 A_ChangeFlag("THRUACTORS", 1)
		TNT1 A 0 A_ChangeFlag("COUNTKILL", 0)
		TNT1 A 0 A_SpawnItemEx ("ChainsawZombie",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION | SXF_TRANSFERAMBUSHFLAG | SXF_TRANSFERPOINTERS ,0, tid)
		Stop	
	Major:
		TNT1 A 0 A_ChangeFlag("THRUACTORS", 1)
		TNT1 A 0 A_ChangeFlag("COUNTKILL", 0)
		TNT1 A 0 A_SpawnItemEx ("Major",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION | SXF_TRANSFERAMBUSHFLAG | SXF_TRANSFERPOINTERS ,0, tid)
		Stop
	RiotShieldGuy:
		TNT1 A 0 A_ChangeFlag("THRUACTORS", 1)
		TNT1 A 0 A_ChangeFlag("COUNTKILL", 0)
		TNT1 A 0 A_SpawnItemEx ("RiotShieldGuy",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION | SXF_TRANSFERAMBUSHFLAG | SXF_TRANSFERPOINTERS ,0, tid)
		Stop
	RocketGuy:
		TNT1 A 0 A_ChangeFlag("THRUACTORS", 1)
		TNT1 A 0 A_ChangeFlag("COUNTKILL", 0)
		TNT1 A 0 A_SpawnItemEx ("RocketGuy",0,0,0,0,0,0,0,SXF_NOCHECKPOSITION | SXF_TRANSFERAMBUSHFLAG | SXF_TRANSFERPOINTERS ,0, tid)
		Stop
	}
}
----------------

Code: Select all

Actor LessZombiemen : Randomspawner
{
dropitem "PossessedSpawner"
dropitem "Imp"
dropitem "FleshSpawn"
}
----------------

Code: Select all

Actor Tier1Mob : RandomSpawner
{
dropitem "PossessedSpawner"
dropitem "PossessedSpawner"
dropitem "PossessedSpawner"
dropitem "ImpSpawner"
dropitem "ImpSpawner"
dropitem "FleshSpawn"
dropitem "FleshSpawn"
dropitem "BullDemon"
dropitem "Tier2Mob"
}
However, this way even "default" spawns result in all the spawned entities losing their ambushflags, which means level progression in many vanilla and custom maps will break. How could I avoid this while achieving the same result with the spawn chances?
Gez
 
 
Posts: 17946
Joined: Fri Jul 06, 2007 3:22 pm

Re: Preserving ambushflags with randomspawners

Post by Gez »

RandomSpawners automatically and transparently transfer ambush flags. However, you are not using randomspawners where it would matter. Your problem is in the CustomZombieman Actor.

What you should do is turn your CustomZombieman class into a descendent of RandomSpawner, and then instead of having weird bizarro code to spawn three variants of other spawners, one of which is not even a proper RandomSpawner, just override the ChooseSpawn() method.

See https://github.com/coelckers/gzdoom/blo ... spawner.zs for info. Put all your logic from CustomZombieman, PossessedSpawner, LessZombiemen, and Tier1Mob in it and get rid of the DECORATE classes.
User avatar
Grey-Wolf
Posts: 179
Joined: Sun Jul 15, 2018 4:59 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Preserving ambushflags with randomspawners

Post by Grey-Wolf »

Hmm, would it be too much to ask for an example? I'm just starting learning zScript so I'm not really sure how to integrate all that with the CVars conditions.
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: Preserving ambushflags with randomspawners

Post by Player701 »

It is perfectly valid for a RandomSpawner to spawn another RandomSpawner, which means you can subclass your actors from RandomSpawner and tweak them according to your needs. Define your special logic to choose who to spawn by overriding the ChooseSpawn method. To do something with the newly spawned actor right after it materializes, override PostSpawn.

Code: Select all

class CustomZombieman : RandomSpawner replaces ZombieMan
{
    override Name ChooseSpawn()
    {
        if (monsterspawns == 0) return 'PossessedSpawner';
        if (monsterspawns == 1) return 'LessZombiemen';
        if (monsterspawns == 2) return 'Tier1Mob';

        return 'None';
    }
}

class PossessedSpawner : RandomSpawner
{
    Default
    {
        // adjust these values to your liking
        // NB: probabilities are slightly different than in your original code
        DropItem 'RocketGuy', 1;
        DropItem 'Major', 2;
        DropItem 'RiotShieldGuy', 10;
        DropItem 'ChainsawZombie', 5;
        DropItem 'MinigunGuy', 5;
        DropItem 'RifleZombie', 232;
    }
    
    override void PostSpawn (Actor spawned)
    {
        spawned.bThruActors = true;
        spawned.bCountKill = false;

        // Synchronize the kill counter
        Level.total_monsters--;        
    }
}
User avatar
Grey-Wolf
Posts: 179
Joined: Sun Jul 15, 2018 4:59 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Preserving ambushflags with randomspawners

Post by Grey-Wolf »

I see, thanks for your help, everything is starting to become clearer.
Thing is I used some of the DECORATE spawners because for some monster tier, especially larger ones, I used to check for space and ceiling height before spawning them, and if there wasn't enough space, it would spawn something smaller. With this code instead if there's not enough space I'm guessing nothing would spawn, since by default monsters always check for position, right?
Any way I could integrate that too?
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: Preserving ambushflags with randomspawners

Post by Player701 »

Grey-Wolf wrote:if there's not enough space I'm guessing nothing would spawn, since by default monsters always check for position, right?
No, that's not true. RandomSpawner doesn't have any code to do such checks.

What you could do is spawn a temporary monster in your ChooseSpawn override and see if it fits by calling TestMobjLocation. If it does, return the class name of that monster, otherwise choose something else. Don't forget to destroy the temporary monster too since the actual spawning with proper initialization will be done later.

Here's an example of how this could be done. This RandomSpawner will make at most 50 tries to choose a monster that wouldn't get stuck. If it can't find one in 50 attempts, it will give up. You can modify this code so that instead of giving up, it spawns something anyway, or even make the algorithm more deterministic so that it won't randomly choose monsters that have already been chosen once and did not pass the location test (for that, please refer to the original implementation of ChooseSpawn via Gez's link, to see how to work with DropItems). Whatever you write, you can always make use of the CanSpawn method to verify that whatever you're trying to spawn will fit at the destination location. Also see this thread for more useful information and example code.

Code: Select all

class RandomSpawnerWithLocationTest : RandomSpawner
{
    override Name ChooseSpawn()
    {        
        for (int i = 0; i < 50; i++)
        {
            let chosen = Super.ChooseSpawn();
            
            if (CanSpawn(chosen))
            {
                return chosen;
            }
        }

        return 'None';
    }

    private bool CanSpawn(Name what)
    {
        bool result = false;
        let probe = Spawn(what, Pos);

        if (probe != null)
        {
            result = probe.TestMobjLocation();

            // prevent the statistics counters from increasing
            probe.ClearCounters();
            probe.Destroy();
        }

        return result;
    }
}

class MyRandomSpawner1 : RandomSpawnerWithLocationTest
{
    Default
    {
        DropItem 'Cyberdemon';
        DropItem 'DoomImp';
    }
}
User avatar
Grey-Wolf
Posts: 179
Joined: Sun Jul 15, 2018 4:59 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Preserving ambushflags with randomspawners

Post by Grey-Wolf »

So, I've tried with this:
https://pastebin.com/AjfZQbjK

But this is what I'm getting:
https://i.gyazo.com/407fec4546ca6219980 ... e7d292.png

Did I mess something up?
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: Preserving ambushflags with randomspawners

Post by Player701 »

Sorry, I forgot that it's also possible for ChooseSpawn to not choose anything at all, so let's rewrite the CanSpawn method as follows:

Code: Select all

private bool CanSpawn(Name what)
{
    bool result = true;
    
    if (what != 'None')
    {
        let probe = Spawn(what, Pos);

        if (probe != null)
        {
            result = probe.TestMobjLocation();

            // prevent the statistics counters from increasing
            probe.ClearCounters();
            probe.Destroy();
        }
    }

    return result;
}
User avatar
Grey-Wolf
Posts: 179
Joined: Sun Jul 15, 2018 4:59 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Preserving ambushflags with randomspawners

Post by Grey-Wolf »

Yeah, no. That was a disaster.
The game now launches, but only a very small portion of the monsters are spawning, which means that location test fails like 8 times out of 10, even when only spawning small humanoid monsters. Not only that, many of the few monsters that actually spawn, don't even update the kills counters when they die. So I'm guessing something went very wrong.

EDIT: can confirm that summoning the spawners ingame has just a low chance of spawning something, while gives nothing all the other times. Plus, looks like the monster spawned through these spawners often have no collision... what the hell?
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: Preserving ambushflags with randomspawners

Post by Player701 »

Sorry, I misread your original code and for some reason thought you were calling A_ChangeFlag for the monsters who get spawned instead of the spawner itself. Just remove the PostSpawn method from PossessedSpawner, and collision and everything else should work properly now.

As for the location test, it relies on the built-in GZDoom functionality, so I don't see how anything could be wrong with it. Try tweaking the height and radius of your monsters and see if it fixes your problem.
User avatar
Grey-Wolf
Posts: 179
Joined: Sun Jul 15, 2018 4:59 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Preserving ambushflags with randomspawners

Post by Grey-Wolf »

The collisions are working now, as for the monster not spawning, the problem is in the dropitem chances, apparently. Looks like if the spawner picks a spawn with let's say, 5 as the chance, and that chance is not triggered, it won't try to pick another monster with higher chance, but just fail. That's why I can spawn monsters just fine with other methods, but the randomspawner you gave me are not working. Setting the dropitem chances to blank, makes them spawn correctly again, although now I need to set the chances in some other way...
User avatar
Player701
 
 
Posts: 1710
Joined: Wed May 13, 2009 3:15 am
Graphics Processor: nVidia with Vulkan support
Contact:

Re: Preserving ambushflags with randomspawners

Post by Player701 »

I haven't used RandomSpawners in a while, now I've checked the code again, and, well, turns out I forgot that DropItem has two values, probability and weight, while I thought it was only weight. To ensure that something always spawns, set the probability to 255. This is an approximation of your DECORATE code (you have sequential random jumps while RandomSpawner rolls a die only once), but it should work more or less the same.

Code: Select all

DropItem 'RocketGuy', 255, 1;
DropItem 'Major', 255, 2;
DropItem 'RiotShieldGuy', 255, 10;
DropItem 'ChainsawZombie', 255, 5;
DropItem 'MinigunGuy', 255, 5;
DropItem 'RifleZombie', 255, 232;
You can find a lot of useful information on RandomSpawner in the wiki article.
User avatar
Grey-Wolf
Posts: 179
Joined: Sun Jul 15, 2018 4:59 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Preserving ambushflags with randomspawners

Post by Grey-Wolf »

So basically 255 is the chance that actor will be spawned if that dropitem line is picked, while the other number is the chance that line will be picked, correct?
Gez
 
 
Posts: 17946
Joined: Fri Jul 06, 2007 3:22 pm

Re: Preserving ambushflags with randomspawners

Post by Gez »

Yes.
User avatar
Grey-Wolf
Posts: 179
Joined: Sun Jul 15, 2018 4:59 pm
Graphics Processor: nVidia (Modern GZDoom)

Re: Preserving ambushflags with randomspawners

Post by Grey-Wolf »

Now everything is working as intended, thanks a lot for all your help!
Post Reply

Return to “Scripting”