Jump to content

Photo

ghost.zh


  • Please log in to reply
645 replies to this topic

#616 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 23 June 2017 - 04:03 PM

What is the reason for this?

I didn't see a reasonable way to handle it at the time, and I'm not entirely certain I do even now. The script data becomes invalid, so it should quit running immediately. It can't be handled like Quit, because that would clear the script you just set. It can't be handled like Waitframe, because then it would try to resume from the same point next frame. It would have to be a new special case.
 

I was not aware that this does not work, and I've been doing this->Script = 0 for years.

Calling Quit() sets the script to 0, so that might at least appear to work.
 

FFSCRIPT in ZASM does not seem to preclude setting the script on a this pointer.

This does it:
void do_set(const bool v, byte whichFFC)
{
    // Trying to change the current script?
    if(sarg1==FFSCRIPT && ri->ffcref==whichFFC)
        return;
        
    long temp = SH::get_arg(sarg2, v);
    set_register(sarg1, temp);
}


#617 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 20 November 2017 - 10:01 PM

Suggestion for the next version: A way to silently kill an npc and its associated ffc, together:

 

void Ghost_Kill(ffc a, npc b)
{
    ___ghost__kill(a); ___ghost__kill(b);
    Quit();
}
void ___ghost__kill(npc n)
{
    n->HP = HP_SILENT;
    Remove(n);
}
void ___ghost__kill(ffc f)
{
    f->Data = 0;
    f->Script = 0;
    f->CSet = 0;
    f->Delay = 0;
    f->X = 0;
    f->Y = 0;
    f->Vx = 0;
    f->Vy = 0;
    f->Ax = 0;
    f->Ay = 0;
    f->TileWidth = 1;
    f->TileHeight = 1;
    f->EffectWidth = 16;
    f->EffectHeight = 16;
    f->Link = 0;
    for ( int q = 0; q <= 15; q++ ) f->Misc[q] = 0;
    for ( int q = 0; q <= 10; q++ ) f->Flags[q] = false;
}

 

Perhaps something like that, or an extension of Ghost_DeathAnimation(), that allows killing a target.



#618 Evan20000

Evan20000

    P͏҉ę͟w͜� ̢͝!

  • Members
  • Real Name:B̵̴̡̕a҉̵̷ņ̢͘͢͜n̷̷ę́͢d̢̨͟͞
  • Location:B̕҉̶͘͝a̶̵҉͝ǹ̵̛͘n̵e̸͜͜͢d҉̶

Posted 06 January 2018 - 03:05 AM

If you use EWM_Throw in sideview, ghost kills the weapon as soon as it exceeds its initial Y position.

 

Makeshift fix in the meantime is to set wpn->Misc[__EWI_WORK_2] to 176-wpn->Y on the first frame, and wpn->Y 176-wpn->Misc[__EWI_WORK_2] on every subsequent frame.



#619 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 07 January 2018 - 05:29 AM

Something to consider, along the same line, is a function set, or a flag that causes weapons to move using HitOffset and DrawOffset, spawning all weapins at x1, y1; so that weapons may move out of bounds, and return.

This is how I typically handle wrapon movement, then I clean up the weapin by moving it offscreen.

#620 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 29 April 2018 - 04:10 PM

Somewhat belated, but I made some HTML documentation: https://www.dropbox....2_docs.zip?dl=0
You have to click the "Download" button, not the folder.
  • Deedee likes this

#621 Avaro

Avaro

    o_o

  • Members
  • Real Name:Robin
  • Location:Germany

Posted 04 June 2018 - 09:10 AM

The random rate doesn't affect anything for 4-way walkers.


Edited by Avataro, 04 June 2018 - 09:18 AM.


#622 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 04 June 2018 - 10:21 AM

Looks to me like it's working okay. How are you using it?



#623 Avaro

Avaro

    o_o

  • Members
  • Real Name:Robin
  • Location:Germany

Posted 05 June 2018 - 11:27 AM

ffc script Enemy{
    void run(int enemyID){
        npc ghost = Ghost_InitAutoGhost(this, enemyID);
        Ghost_SpawnAnimationPuff(this, ghost);
        Ghost_SetFlag(GHF_NORMAL);
	Ghost_SetFlag(GHF_KNOCKBACK_4WAY);
        int walkcounter = -1;
        while(true){
            walkcounter = Ghost_HaltingWalk4(walkcounter, ghost->Step, ghost->Rate, ghost->Homing, ghost->Hunger, 0, 48);

            Ghost_Waitframe(this, ghost, true, true);
        }
    }
}

Now, no matter if i use a rate of 16 or 2, or 0, it's behavior is always the same. It tries turning on every tile. I'd like it to walk more straight.


Edited by Avataro, 09 July 2018 - 01:09 PM.


#624 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 05 June 2018 - 04:18 PM

Are you using an old version of ghost.zh? I'd forgotten about it, but I see that was an issue until 2.8.0.
  • Avaro likes this

#625 Avaro

Avaro

    o_o

  • Members
  • Real Name:Robin
  • Location:Germany

Posted 09 July 2018 - 12:56 PM

Turns out EWM_VEER and EWM_DRIFT use neither degree, nor radians, they use DIR. That wasn't clear to me since the word "direction" means angle elsewhere (for example in the description of random re-aim).



#626 ywkls

ywkls

    Master

  • Members

Posted 22 October 2018 - 01:14 PM

If you use EWM_Throw in sideview, ghost kills the weapon as soon as it exceeds its initial Y position.

 

Makeshift fix in the meantime is to set wpn->Misc[__EWI_WORK_2] to 176-wpn->Y on the first frame, and wpn->Y 176-wpn->Misc[__EWI_WORK_2] on every subsequent frame.

I encountered another bug after fixing this issue for both EWM_THROW and EWM_FALL.

These behaviors do no respect Sideview solid platforms at all.

To get them to do that, I added this:

if(wpn->Misc[__EWI_WORK_2]>0 &&
   !OnSidePlatform(wpn->X, wpn->Y, 
		   wpn->HitXOffset,
		   wpn->HitYOffset, 
		   wpn->HitHeight)) 

This is the line which ghost.zh checks to see if the Eweapon has hit the ground.

By changing this they should now support impacting solid platforms below them.

 

Edit: I should add that I'm still having trouble getting the shots to arc in the correct fashion, rather than simply flying upwards offscreen.


Edited by ywkls, 22 October 2018 - 01:18 PM.


#627 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 29 January 2019 - 06:48 AM

Here is the patch for ghost.zh.

 

Replace ghost_zh/other.zh with this file.

 

Saffith, would you mind updating your package with this revision?

I didn't see a reasonable way to handle it at the time, and I'm not entirely certain I do even now. The script data becomes invalid, so it should quit running immediately. It can't be handled like Quit, because that would clear the script you just set. It can't be handled like Waitframe, because then it would try to resume from the same point next frame. It would have to be a new special case.
 
Calling Quit() sets the script to 0, so that might at least appear to work.
 
This does it:

void do_set(const bool v, byte whichFFC)
{
    // Trying to change the current script?
    if(sarg1==FFSCRIPT && ri->ffcref==whichFFC)
        return;
        
    long temp = SH::get_arg(sarg2, v);
    set_register(sarg1, temp);
}

 

Long time on this, but I think that clearing the stack on that ffc, and if needed some of its refinfo (e.g., SP), then returning should do it.



#628 ywkls

ywkls

    Master

  • Members

Posted 24 March 2019 - 08:24 PM

Another thing I've always wanted in ghost.zh: circular Eweapon movement.

 

Since the current script doesn't support this, I added it.

 

In EWeaponMovement.zh:

//Handles Lweapons that circle Link.

void __UpdateEWM_Circle(eweapon wpn){
	wpn->Misc[__EWI_WORK]= (wpn->Misc[__EWI_WORK]
				+((wpn->Step/100)*wpn->Misc[__EWI_MOVEMENT_ARG_2]))%360;
	wpn->HitXOffset =VectorX(wpn->Misc[__EWI_MOVEMENT_ARG],wpn->Misc[__EWI_WORK]);
	wpn->HitYOffset = VectorY(wpn->Misc[__EWI_MOVEMENT_ARG],wpn->Misc[__EWI_WORK]);
	
	wpn->Angle = DegtoRad(wpn->Misc[__EWI_WORK]);
	SetEWeaponDir(wpn);
	wpn->X= wpn->Misc[__EWI_XPOS];
        wpn->Y= wpn->Misc[__EWI_YPOS];							
	wpn->DrawXOffset= wpn->HitXOffset;
	wpn->DrawYOffset= wpn->HitYOffset;
}

In EWeapon.zh:

else if(wpn->Misc[__EWI_MOVEMENT]==EWM_CIRCLE)
	__UpdateEWM_Circle(wpn);

And finally, an example script that used these:

//A Mario-style set of flames that rotate around a core.
ffc script Firebar_NME{
	void run(int length, int Damage, bool Double, bool Clockwise, int speed){
		int i;
		float angle = Rand(0,360);
		eweapon fireball;
		eweapon fireball2;
		int direction;
		if(speed ==0)speed =1;
		if(Clockwise)
			direction = speed;
		else
			direction = -1*speed;
		for(i= 1;i<=length;i++){
			fireball = FireEWeapon(EW_FIRE2, this->X,
						this->Y, DegtoRad(angle), 100, 
						Damage,SPR_FIRE, 0, EWF_UNBLOCKABLE);
			SetEWeaponMovement(fireball,EWM_CIRCLE,(16*i),1);
			if(Double){
				fireball2 = FireEWeapon(EW_FIRE2, this->X,
						        this->Y, DegtoRad(angle+180), 100, 
							Damage,SPR_FIRE, 0, EWF_UNBLOCKABLE);
				SetEWeaponMovement(fireball2,EWM_CIRCLE,(16*i),1);						
			}
		}			
	}
}

I also added a new type of lifespan for enemy weapons which can't be destroyed: EWL_FOREVER


Edited by ywkls, 24 March 2019 - 08:25 PM.


#629 Timelord

Timelord

    The Timelord

  • Banned
  • Location:Prydon Academy

Posted 15 July 2019 - 05:18 AM

...

 
 
ghost->Misc[__GHI_NPC_DATA]=0x10000; //in __Ghost_InitInternal

void Ghost_MarkAsInUse(npc ghost)
{
    ghost->Misc[__GHI_NPC_DATA]|=0x10000;
}


//and in GetEnemyProperty
if((enemy->Misc[__GHI_NPC_DATA]&0x10000)!=0)
    {
        float array=enemy->Misc[__GHI_NPC_DATA]&0xFFFF;
        return array[property];
    }

// Give ghost an array pointer so its data can be found by other scripts
    if(ghost->isValid())
        ghost->Misc[__GHI_NPC_DATA]=0x10000|tempGhostData;

I do not see a point where a system-legal array is declared, or where a system-legal array pointer is being stored in npc->Misc[__GHI_NPC_DATA].

Are you forcing an array pointer here in a way that keeps a temp script array in scope at all times, or something of that sort?

tempGhostData doesn't seem to have a global source. It seems to be created inside a function body?

What exactly are you doing here?

I recall that there was some sort of bug that forces an array pointer to a value where it is never deallocated by the interpreter. Is that what I'm seeing here?

If so, I need a reminder on how to produce this effect, so that we don't fix it (w/o a rule, anyway) and break ghost forevermore.

Spoiler


#630 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 15 July 2019 - 09:55 AM

tempGhostData is created just before it's assigned, at the beginning of Ghost_WaitframeLight(), and the pointer is cleared at the end of that function. The array only exists until the script resumes in the next frame; Set and GetEnemyProperty() are meant to be called from other scripts during that time.

It's a bit complicated, but there's nothing out of the ordinary going on there. As long as array pointers are still integers, it should be fine as long as they're not greater than 65535.


0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users