Jump to content

Photo

Limiting SummonRobes (take two)


  • Please log in to reply
9 replies to this topic

#1 Lüt

Lüt

    Germanize

  • Members
  • Real Name:Steve
  • Location:Chicago

Posted 29 July 2017 - 02:05 PM

Late last year I made this Limiting SummonRobes topic in regard to adding official ZQuest options to control their summon floods.

 

But in the meantime, seeing how that's probably not going to happen, I'm wondering if there could be a scripted equivalent?

 

I figure there's 2 good ways to do it.

 

The Quick Hack - either an FFC script with D0 being the summon limit, or a global script with a "hard-coded" limit (I would personally set it at 20).

 

The Full Build - this would be a per-room FFC that intercepts/overrides the "Summon" attack(s).

 

D0: Total summoned enemy limit.

D1 - D5: Up to 5 enemy IDs that can be summoned.

D6: Minimum summons per attack.

D7: Maximum summons per attack.

 

I suggested both D6 and D7 because the current code randomly summons between 1 - 3 enemies. Setting D6 and D7 to the same number would force the same amount of summons per attack (or maybe it's easier to code it so that if D7 = 0, then it uses D6 every attack). However, if that's too complicated, then make D7 the fixed amount of summons per attack and open D6 for a 6th enemy ID that can be summoned.

 

The quick hack's fine for my purposes, but I think the full enemy control version would be useful for anybody using SummonRobes, and could (hopefully) become a staple database entry.

 

I guess the catch is, there's 2 kinds of summon attacks - one using a specific enemy ID (i.e. BatRobes) and one using enemies on Layer 1 (current SummonRobes) - so both of those would have to be accounted for.

 

Any chance either of these could be done?


  • Anthus likes this

#2 Avaro

Avaro

    o_o

  • Members
  • Real Name:Robin
  • Location:Germany

Posted 30 July 2017 - 10:53 AM

ffc script EnemyLimit{
	void run(int EnemyLimit){
		while(true){
			if ( Screen->NumNPCs() > EnemyLimit ) {
				npc Unwanted = Screen->LoadNPC(Screen->NumNPCs());
				Unwanted->X = -1000;
			}
			Waitframe();
		}
	}
}

D0 is the maximum number of enemies you allow on the screen. If it goes above, it moves the newest enemy/enemies far offscreen, which automatically kills them.


  • Anthus and Lüt like this

#3 Lüt

Lüt

    Germanize

  • Members
  • Real Name:Steve
  • Location:Chicago

Posted 30 July 2017 - 02:38 PM

Well thanks, it's a good start :)

 

However, I did come across some issues.

 

Disappearance rate - In a room with only summoners, it seems true that the newest summoned enemies disappear first. However, their disappearance rate varies. Using Fire Zols as a reference, sometimes they only linger for a frame or two, but other times they drop a fire trail and travel all the way to the next tile before disappearing. In another instance, a Bombchu charged me halfway across an open room before disappearing right in front of me. Is removal a function that gets processed every certain amount of frames? Like, say 60, or 120? And that's why some linger one or two frames while others wander and carry out attacks before disappearing? Because if there's a way to set that rate to 1 or 0 frames, that would be great.

 

(The same delayed disappearance applies to their splits. The splits also seem to get reduced or eliminated, but I understand why that's to be expected.)

 

Statue interference - so here's an unexpected development. Apparently shooting statues count as spawning an enemy when they shoot. And apparently they also take priority over summons as well as summoners. So not only do enemies suddenly disappear in the middle of combat, but summoners do too. In one room with a lot of statues and an enemy limit of 12, all the summoners disappeared and the shutter doors opened before a single one was able to summon. And I know I can raise the limit to allow for the summoners, but it still leaves the issue of randomly disappearing enemies.

 

Ham Sandwich transfer - if you're trapped inside a LikeLike when it disappears, the screen immediately scrolls left to the next screen and you get stuck in the wall (if it exists) or outside the level.

 

Willful ignorance - this probably isn't relevant given the behavior problems these enemies already have, but the limit doesn't seem to work on things like Dodongo/Manhandla/Digdogger/etc. I guess ZC recognizes them as "boss" enemies despite not being used in a boss room, so there's probably nothing that can be done here.

 

So yeah, good start, and I like seeing how much cleaner some of these rooms are. But the random disappearance rates and shooting statues need to be addressed - which in turn should render the LikeLike issue irrelevant - before the setup's fully functional.


  • Avaro likes this

#4 Avaro

Avaro

    o_o

  • Members
  • Real Name:Robin
  • Location:Germany

Posted 30 July 2017 - 03:17 PM

I could fix the disappearance rate to make them instant, but as for the statue issue I have no clue how they work. Why would statues mess with enemy count when they shoot? xD I fear this might need to be scripted differently.


Actually, try if this fixes the issues.

ffc script EnemyLimit{
	void run(int EnemyLimit){
		while(true){
			int EnemyCount;
			for (int i = 1; i <= Screen->NumNPCs(); i++) {
				npc enem = Screen->LoadNPC(i);
				if ( enem->ID != 83 ) //ignore fireball shooters
					EnemyCount ++;
				if ( EnemyCount > EnemyLimit )
					enem->X = -1000;
			}
			Waitframe();
		}
	}
}

Edited by Avataro, 30 July 2017 - 03:28 PM.

  • Lüt likes this

#5 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 30 July 2017 - 03:38 PM

You want to check npc->MiscFlags&8 for the "Doesn't Count As Beatable Enemy" flag.


Here's another option, but this one requires ghost.zh. Set up an Other-type enemy to run this script with the invisible combo, and make the enemy itself invisible. Set misc. attribute 1 to the maximum number of enemies and attributes 2-10 to the IDs of enemies to summon. Make the summoner summon nothing but this enemy.
 
ffc script LimitedSummon
{
    void run(int enemyID)
    {
        npc ghost=Ghost_InitAutoGhost(this, enemyID);
        TrySpawnEnemy(this, ghost);
        ghost->X=1024;
        ghost->HP=HP_SILENT;
    }
    
    void TrySpawnEnemy(ffc this, npc ghost)
    {
        if(CountEnemies(ghost->ID)>=ghost->Attributes[0])
            return;
        
        int enemyIDs[9];
        int numEnemyIDs=0;
        for(int i=1; i<10; i++)
        {
            if(ghost->Attributes[i]==0)
                continue;
            enemyIDs[numEnemyIDs]=ghost->Attributes[i];
            numEnemyIDs++;
        }
        
        if(numEnemyIDs==0)
            return;
        
        npc enemy=Screen->CreateNPC(enemyIDs[Rand(numEnemyIDs)]);
        enemy->X=ghost->X;
        enemy->Y=ghost->Y;
    }
    
    int CountEnemies(int ignore)
    {
        int total=0;
        for(int i=1; i<=Screen->NumNPCs(); i++)
        {
            npc en=Screen->LoadNPC(i);
            if(en->ID<20 || en->ID==84 || en->ID==ignore) // Guy, fairy, or one of these
                continue;
            if((en->MiscFlags&8)==0)
                total++;
        }
        return total;
    }
}
(Edit: corrected ID check)
  • Lüt likes this

#6 Lüt

Lüt

    Germanize

  • Members
  • Real Name:Steve
  • Location:Chicago

Posted 30 July 2017 - 04:11 PM

Actually, try if this fixes the issues.

Wow, that was quick.

 

Yeah that fixed everything. No temporary enemy appearances before removal, no fireballs removing enemies, thus no LikeLike issue, and now the "boss" enemies are cooperating as well. Thanks! :D

 

Hey I'm curious, what part did you change that reduced the removal time?

Here's another option, but this one requires ghost.zh. Set up an Other-type enemy to run this script with the invisible combo, and make the enemy itself invisible. Set misc. attribute 1 to the maximum number of enemies and attributes 2-10 to the IDs of enemies to summon. Make the summoner summon nothing but this enemy.

Wow, that was thorough.

 

OK, I want to give this a try too. I think I get it so far - enemy 418 uses the script (that's my first open ID), then the standard summoner summons ID 418, which activates the script. And 418 doesn't need any further data besides the misc attributes, right? Not even HP?

 

Anyway, I'm going to bed now, and I'll be out a lot of tomorrow, so I'll get to it in a day or two. I'll probably be back with more questions by then heh.



#7 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 30 July 2017 - 05:26 PM

The HP shouldn't matter. An enemy with 0 HP will die immediately after it spawns, but that's enough to get the script launched. That's the only thing the enemy exists to do - trigger the script, then die - so none its other properties are important.
  • Lüt likes this

#8 Lüt

Lüt

    Germanize

  • Members
  • Real Name:Steve
  • Location:Chicago

Posted 09 August 2017 - 08:40 AM

Hi. I'm terribly sorry for such a delayed response, but I wanted to thoroughly test this in a variety of situations before posting back here.

So I managed to get ghost.zh successfully configured with a lot of reading/video-watching and a little grayswandir. Relating to the documentation/video tutorial (nice Sonic CD music btw), I pasted the FFC scripts into my main script file rather than using "import 'LimitedSummon.z'" and it seemed to work fine. For global, since plain old "import 'ghost.zh'" was forcing me to select between the existing global and the ghost global, I added to the existing global "StartGhostZH();" under "void run()" - "UpdateGhostZH1();" under "while(true)" - and "UpdateGhostZH2();" under "Waitdraw();" - and again it seemed to work fine. There was still a ghost global in addition to the existing global after compiling, but I chose to ignore the ghost global in favor of the updated existing global. If any of that was wrong, please let me know.

Also, although the clock is irrelevant to my needs, I'd still like to add it for the sake of a complete ghosh.zh import, but the way to add it to an existing global is eluding me (if that's required at all).

Anyway, as for the actual LimitedSummon script - this is absolutely beautiful. It's everything I ever wanted out of a summoner control system, and so easily configurable to boot. True, I ended up making 31 different summon sets and 31 summoners to go with them, but hey, totally worth it. That's the kind of precision I love. So I'll definitely be using this one for now and in any future projects I do. Sorry Avataro, yours was certainly a close second, and still great for people wanting a quick fix :) Thanks so much, both of you.

Only one small issue arises - enemies using sprite palettes rather than standard CSets change to green (CSet 5 I believe) after a while, then change back after another while. I couldn't track down a specific reason. For my purposes, this is an easy fix - adding a few additional colors to CSet9 and mass-recoloring a few enemy sprites will take me all of 5 minutes to set up. It's also worth noting that I only ever summoned single enemies using the same sprite palette to a single room - I already know that multiple enemies using multiple sprite palettes glitch, in that I believe they're forced to use only one sprite palette per room. So I'm totally fine with it, but if you were planning to upload this to the database as an official release, that might need to be addressed, if possible.



#9 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 09 August 2017 - 10:37 AM

If any of that was wrong, please let me know.

Nope, exactly right.
 

Also, although the clock is irrelevant to my needs, I'd still like to add it for the sake of a complete ghosh.zh import, but the way to add it to an existing global is eluding me (if that's required at all).

There's no global component anymore (or rather, it's been integrated into another function), so you only need the item script.
 

Only one small issue arises - enemies using sprite palettes rather than standard CSets change to green (CSet 5 I believe) after a while, then change back after another while.

That's weird... I'll have to check that out. Might be a ghost.zh bug, might be a ZC bug, but I don't know why it would happen either way. I might need help tracking it down if I can't reproduce it.

#10 Lüt

Lüt

    Germanize

  • Members
  • Real Name:Steve
  • Location:Chicago

Posted 12 August 2017 - 07:24 PM

There's no global component anymore (or rather, it's been integrated into another function), so you only need the item script.

OK great, got it set now.

I might need help tracking it down if I can't reproduce it.

Here's a demo quest I threw together. It somewhat mimics two summon setups I use, except that I raised the max summon numbers, and made a third room with a Gleeok already present. The left room summons a Darknut that uses Sprite CSet 4, the right room summons a standard Digdogger Kid that uses Sprite CSet 2, and the Gleeok in the top room uses Sprite CSet 1.

 

The colors change during the summoning process, but I can't track down why. I thought it might be due to summoning the Sprite CSet-using enemies, then I thought it might be due to *not* summoning them, but neither seemed to be the case (though I haven't done extended analysis, so see for yourself). The Gleeok seems to always change during the very first summon attack, and never change back. Yet, other Sprite CSet-using bosses change back and forth like the summoned enemies do (you could swap the Gleeok with a Gohma L3 using Sprite CSet 4, for example).

 

To my observation, the color changes only occur during the summon attack, as they stop happening once the room fills to its limit, so you'll eventually need to kill some of the summoned enemies if you want the color changes to resume.

 

Again, not an issue I can't easily work around for my own personal uses, but if you're interested in seeing it happen, there you go.




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users