Jump to content

Photo

Reading Ghost enemy flags by other scripts.

ghost.zh 2.53.1

  • Please log in to reply
3 replies to this topic

#1 Alucard648

Alucard648

    Wizard

  • Members
  • Location:castle Dracula

Posted 04 October 2021 - 08:48 AM

One final step before releasing 1st beta of sideview engine, besides making example quest and documentation, is doing support for interaction between solid FFCs and ghosted enemies. And discovered that Ghost flags are visible only by ghosted enemy scripts themselves, not anywhere outside. Any chance for other scripts to detect whether a ghosted enemy is set to ignore solidity or not?



#2 Moosh

Moosh

    Tiny Little Questmaker

  • ZC Developers

Posted 05 October 2021 - 12:56 AM

You know it's a fun question when I'm not entirely sure how to answer it. Accessing ghost.zh internal data is this thing where you can and you can't do it. It's pretty strange. GetEnemyProperty() and SetEnemyProperty() are designed for getting and setting stuff like the enemy's X, Y, HP, and the like. It also "works" for values ghost doesn't provide constants for, but this is horribly wonky and completely unsupported. Because this is a temporary array that's being stuffed into an npc->Misc[] index, whether it exists or what data is in it cannot be entirely relied on as far as I'm aware, and I've had many horrible scripting headaches caused by script timing and a whole bunch of other stuff that's just beyond me. I've looked at this stuff plenty, I have a vague idea how it works, but I still don't fully understand it.

 

You can find the tempGhostData[] array in ghost2_update.zh.

    // Initializing the array is faster than setting it up afterward...
    // but the difference is probably negligible, realistically
    float tempGhostData[24] = {
        Ghost_X, // 0
        Ghost_Y, // 1
        Ghost_Z, // 2
        Ghost_Jump, // 3
        Ghost_Vx, // 4
        Ghost_Vy, // 5
        Ghost_Ax, // 6
        Ghost_Ay, // 7
        __Ghost_PrevX, // 8
        __Ghost_PrevY, // 9
        Ghost_CSet, // 10
        Ghost_Dir, // 11
        Ghost_Data, // 12
        Ghost_TileWidth, // 13
        Ghost_TileHeight, // 14
        __Ghost_Flags, // 15
        __Ghost_Flags2, // 16
        __Ghost_InternalFlags, // 17
        __Ghost_FlashCounter, // 18
        __Ghost_KnockbackCounter, // 19
        Ghost_HP, // 20
        __Ghost_XOffsets, // 21
        __Ghost_YOffsets // 22
        // 23 is for either drawingData or tempGhostAdditionalCombos;
        // update DrawGhostFFCs if that changes
    };

So then the other option is to just do it yourself. Save the flags to a Misc[] index in a custom waitframe and accept that only scripts written for your system will be compatible with your system. This seems to be the simplest solution to the problem with the fewest headaches, but is pretty much the same thing as accepting that what you really want here isn't possible.


  • Twilight Knight likes this

#3 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 05 October 2021 - 06:16 AM

I ran into this problem and came up with a solution, but fair warning, it's janky. I was specifically interesting in the KnockbackCounter (flag 19), but this should work for any of them. Lemme just paste the relevant code snippit.
 
 
if((n->Misc[__GHI_NPC_DATA]&0x10000)!=0){ //This flag is a check that what we're about to do is valid
    float aptr=n->Misc[__GHI_NPC_DATA]&0xFFFF; //This pulls the pointer for a size 24 array. That array is or'd with 0x10000 to form this misc value.
    if(aptr > 0){ //Make sure we have a valid array as an extra failsafe
        aptr[19] = 0; //Ghost has no associated constant for this, for whatever reason, but this index corresponds to __Ghost_KnockbackCounter
    }
}
 
This example would halt knockback on a ghosted enemy, but once you've pulled aptr and ensured it's a valid array, you can use any of this indices Moosh posted above and read or write them.
 
THe reason the code works like this is because, like Moosh said, ghost works by creating a size 24 array, then or's it with 0x10000 as a validity check, then passes that array's pointer or'd with the valie into an n->Misc value I don't pretend to understand the system perfectly, but the sanity checks in this should ensure that, if the ghost's misc array doesn't exist for some reason, nothing will happen and you won't pull invalid data, alleviating Moosh's concerns. I use this system for preventing knockback on enemies you hit with dash attacks, and it works perfectly fine there and has never thrown a script error at me.
  • Twilight Knight and Alucard648 like this

#4 Alucard648

Alucard648

    Wizard

  • Members
  • Location:castle Dracula

Posted 05 October 2021 - 02:00 PM

I ran into this problem and came up with a solution, but fair warning, it's janky. I was specifically interesting in the KnockbackCounter (flag 19), but this should work for any of them. Lemme just paste the relevant code snippit.
 
 

if((n->Misc[__GHI_NPC_DATA]&0x10000)!=0){ //This flag is a check that what we're about to do is valid
    float aptr=n->Misc[__GHI_NPC_DATA]&0xFFFF; //This pulls the pointer for a size 24 array. That array is or'd with 0x10000 to form this misc value.
    if(aptr > 0){ //Make sure we have a valid array as an extra failsafe
        aptr[19] = 0; //Ghost has no associated constant for this, for whatever reason, but this index corresponds to __Ghost_KnockbackCounter
    }
}
 
This example would halt knockback on a ghosted enemy, but once you've pulled aptr and ensured it's a valid array, you can use any of this indices Moosh posted above and read or write them.
 
THe reason the code works like this is because, like Moosh said, ghost works by creating a size 24 array, then or's it with 0x10000 as a validity check, then passes that array's pointer or'd with the valie into an n->Misc value I don't pretend to understand the system perfectly, but the sanity checks in this should ensure that, if the ghost's misc array doesn't exist for some reason, nothing will happen and you won't pull invalid data, alleviating Moosh's concerns. I use this system for preventing knockback on enemies you hit with dash attacks, and it works perfectly fine there and has never thrown a script error at me.

 

Thanks for advice. Here is what I wanted to do:

//Returns True, if ghosted enemy`s flag is set. Old 16 flags are checked.
bool GhostHasFlagSetOld (npc ghost, int flag){
	if((ghost->Misc[__GHI_NPC_DATA]&0x10000)!=0){ //This flag is a check that what we're about to do is valid
    		float aptr=ghost->Misc[__GHI_NPC_DATA]&0xFFFF; //This pulls the pointer for a size 24 array. That array is or'd with 0x10000 to form this misc value.
    		if(aptr > 0){ //Make sure we have a valid array as an extra failsafe
    			int flagset = aptr[15]; //Get flagset.
	        return ((flagset & flag)>0); //And retrive flag. If result is > 0, return true. Otherwise, return false.
		}
	}
}

Gotta go finishing roadmap for engine...





Also tagged with one or more of these keywords: ghost.zh, 2.53.1

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users