I have a few questions regarding Ghost, as I am finally getting into using it, and I wanted to point out some oddities:
Oddities first, i noted that Ghosted enemies co not obey the Kill All Enemies and Clock class items. They are not frozen when a clock is used, and they do not die when a Kill All Enemies is used. Is there a way to fix this?
I also have been requested to make a floating enemy (no movement) that explodes (dealing damage) on death.
I need some basic explanation of this function: Ghost_Explode(this, ghost);
Does this only create an explosion image, or doe it deal damage by default?
How do I implement effects on enemy death? I expect I need a while, or an if statement concrning the ghosted enemy HP, such as:
[code[
if ghost HP < 0{
//Do this
}
[/code]
I know there is no tutorial yet, but some explanation with examples would be very helpful to us non-C people.
If anyone could toss some good examples of simple ghosted enemies at me (not bosses, or huge scripts, but merely ghosted versions of basic enemies) I would appreciate it greatly. I need to learn how to control the simple functions before I try to make bigger monsters.
Maybe this is the time to request a tutorial thread, that explains how to make simple enemies, implement drop-sets, death effects, and the like... A basic enemy, that obeys the movement in the enemy editor, and uses some ghosted effects would be the place to start to help people like myself, who want to add attacks and special drops or special SFXor death effects to enemies without scripting their movement entirely; then move on to scripted movement, and more complex tasks.
Is anyone willing to make such a guide, or provide some well-documented scripts for these kinds of enemies from which someone like myself may make a guide? (I am a technical writer by profession, and if I understand something, I can explain to others in human-readable terms.)
Oddities first, i noted that Ghosted enemies co not obey the Kill All Enemies and Clock class items. They are not frozen when a clock is used, and they do not die when a Kill All Enemies is used. Is there a way to fix this?
If clocks don't work, I would guess your clock doesn't have GhostZHClockScript set as its pickup script. I don't know why Kill All Enemies wouldn't work, though. It's working for me, so I don't know what the problem might be.
I need some basic explanation of this function: Ghost_Explode(this, ghost);
Ghost_Explode() shouldn't be used anymore; it's been replaced by Ghost_DeathAnimation(). But the explosions it creates have collision detection disabled, so that's not what you want.
I'm using Ghost_InitWait2 with a Gleeok since Autoghosting segmented enemies tend to cause problems,. Also I problems I have now is that the controller for Gleeok's is what is ghosted and also the first neck segment. I want to use it's body as the collision box for movement. Any ideas Saffith on how to work around this predicament I'm having? Second, if a gleeok head get's disembodied at the edge of the screen it doesn't move around; not sure if that's caused by the No Flying Enemies combos though or an actual bug. Finally is it possible to set Ghost_CSet to use a ESP palette somehow, I know autoghost npcs can. But I'm not sure how I do it.
Thanks again for all your hard work on this Saffith, and let's all love Lain btw. :tard:
Edited by LordVolcanon, 17 August 2013 - 10:15 PM.
I have the FFC flags set to: d0 = 9, D1 = 10. It should use sprite 9 for the explosion, and deal 10 damage. Do I need to hard-code these values?
I tried this next... Now, the enemy appears, and then immediately vanishes, and an explosion happens elsewhere on the screen. The explosion doesn't appear where the enemy was, nor does it wait for Link to kill it.
This is the flowchart as it stands:
1>Link appears on screen.
2>Enemy appears.
3>Enemy vanishes.
4>Explosion appears on screen, but not where enemy was.
I am aiming for:
1>Link appears on screen.
2>Enemy appears on screen.
3> Link kills enemy.
4> Enemy causes explosion where enemy died.
I must be missing something big here; the present script is below:
Will this work at all, and if so, do I need to place:
Ghost_Waitframe(this, ghost, true, true);
...inside the while loop?
Aside from the explosion I am trying to find a way to allow Limk to touch an enemy without having any effects of being hurt:
No bounce, no hurt sound, no flicker, etc.. I have enemies set to 0-damage when touched, and I want touching the enemy to be safe, but other possible effects that do damage (such as shooting, or exploding when broken).
I thought that closing off its collDetection (making it false) may work, but I also think that would make it impossible to use weapons on it. Is there a way to make a ghosted enemy something that Link can destroy, but one that also does not hurt Link (or cause any of the effects that being hurt normally causes) when touched?
I presume that with this, I am calling a function as long as the ghost is alive, so when the waitframe is called, the loop ends and the remainder of the code (outside the loop) is executed?
I tried this; the same problem... The enemy appears, then vanishes, causing an explosion in the top-left corner of the screen, whereas the enemy FFC is on the bottom-right.
I set ghost->CollDetection = false, however touching the ghosted enemy still causes Link to flash, bounce back, and moan in pain. Link is also able to destroy the enemy. I don't think that it did a thing.
Here is the code for the simpler (non-exploding) enemy. I want Link to be able to touch it without any effects of being hurt, but I don't see any obvious way to do this.
// import "std.zh"
// import "string.zh"
// import "ghost.zh"
// A simple boss that moves up and down the side of the screen,
// periodically firing waving fireballs in three directions.
// Appears on screen 2 in the demo.
const int CANDLE_ENEMY_ID=179;
ffc script CandleEnemy
{
void run()
{
npc ghost;
int timer;
int weaponSprite;
int weaponDamage;
eweapon wpn;
ghost->CollDetection = false;
// Initialize
ghost=Ghost_InitCreate(this, CANDLE_ENEMY_ID);
Ghost_SetFlag(GHF_IGNORE_ALL_TERRAIN);
Ghost_SetFlag(GHF_CLOCK);
Ghost_SetFlag(GHF_NO_FALL);
Ghost_SetFlag(GHF_FLYING_ENEMY);
//Ghost_Setflag(GHF_NO_COLLISION);
Ghost_SpawnAnimationPuff(this, ghost);
Ghost_SetHitOffsets(ghost, -1, -1, -1, -1);
Ghost_Waitframe(this, ghost, true, true);
}
}
No, it doesn't, but ghost.zh makes it A LOT easier. It's the difference between trying to build a house with nothing but a saw and a forest and trying to build a house with lots of precut lumber.
Zoria, why not just make your own Waitframe function? Put your death stuff all in that function, and you won't have to deal with that while loop you have. Regarding the enemy death, I know Ghost_Explode somehow handles everything, so you might wanna look at that to see how Saffith did it.
I added this to other.zh as suggested (which is merely a tiny variation of Ghost_Explode) that adds damage. I don't know if Saffith would want to include it in the next version; I also don't know if there is an easy way to set this damage (or duration) as an argument to pass from the FFC to this command.
void Ghost_ExplodeBlast(ffc this, npc ghost, bool flash)
{
eweapon explosion;
npc deathSFXNPC;
// The enemy's death sound should play at the start of the animation, but the enemy has to stay
// alive until the end. There isn't a good way to do that, so here's a stupid way, instead.
// Make another of the same enemy, hide it, and kill it. After the animation finishes,
// kill the real one silently.
deathSFXNPC=Screen->CreateNPC(ghost->ID);
deathSFXNPC->X=ghost->X; // For panning
deathSFXNPC->Y=176;
deathSFXNPC->ItemSet=0;
deathSFXNPC->HP=0;
deathSFXNPC->Misc[__GHI_GHZH_DATA]=0x10000;
this->CSet=Ghost_CSet;
this->Flags[FFCF_OVERLAY]=false;
this->Vx=0;
this->Vy=0;
this->Ax=0;
this->Ay=0;
ghost->HP=1;
ghost->CollDetection=false;
ghost->SFX=0;
if(flash)
__Ghost_FlashCounter=10000;
else
Ghost_StopFlashing();
// One explosion every 16 frames, 15 times
for(int i=0; i<15; i++)
{
explosion=Screen->CreateEWeapon(EW_BOMBBLAST);
explosion->X=Ghost_X+ghost->DrawXOffset+Rand(16*Ghost_TileWidth)-8;
explosion->Y=(Ghost_Y+ghost->DrawYOffset)-
(Ghost_Z+ghost->DrawZOffset)+
Rand(16*Ghost_TileHeight)-8;
explosion->CollDetection=true;
explosion->Damage = 10;
for(int j=0; j<16; j++)
{
Ghost_SetPosition(this, ghost);
Ghost_WaitframeLight(this, ghost);
}
}
ghost->X=1024;
this->Data=GH_INVISIBLE_COMBO;
Ghost_Data=GH_INVISIBLE_COMBO;
Ghost_ClearCombos();
}
I still need a way to make Link able to touch a ghosted enemy without being hurt (i.e. Link is not flashing, bounced back, and groaning.)
Any chance of a No_hurtFX command in the future? Is this even possible?
I also note that any exploding death enemy leaves no drops. Is that because of this (in Ghost_Explode)?
I took a look at the files in this to try and figure out how it works, and I'm completely lost.
What is the difference between Ghost_TileWidth/Ghost_TileHeight and the normal TileWidth/TileHeight? Does using the ghost version improve compatibility with the default movement patterns in the Enemy Editor or anything? I'm asking because I'm just now realizing that the FFC BigEnemy script seems to completely fall apart regarding firing weapons (Spawn locations for eweapons are the edges of the top-left tile of the enemy sprite instead of the whole thing) and any of the 4-Frame 4_direction animations (Up/Down animations work. Left/Right and any firing animations do not), and I was hoping that there was a solution somewhere in this.
I just updated my ghost.zh to the newest version after discovering that EWM_DRIFT only seemed to only push bullets up instead of the specified direction. After the update it still appears to be broken. This has happened with multiple scripts and apparently Evan has had the problem too, so I'm pretty sure it's not just a silly mistake on my end...
Finally, another update. It's mostly internal changes and some bug fixes, but there's some new stuff. This will break existing save files.
Added Ghost_FloaterWalk(), the movement type used by peahats and keese
Added EWF_ROTATE_360
Added settings to change how big an enemy must be to use large shadows
Added an option to use scripted shadows rather than built-in ones when possible
Added new Ghost_Waitframe() variants to simplify usage; you can now leave out quitOnDeath and clearOnDeath (they'll both be true) or specify a death animation
The global script functions have been consolidated into three; you'll need to update the global script, but it should never be necessary for future updates