Ha! Right when I wished there was something like this, here it is!
A really great script for making any sized enemies and even large, simple bosses.
Easy to set up and use. Compiles easily... everything works, it's really great!
- Current Location:
- PureZC
- » PureZC Forums
- » Scripts
- » BigEnemyDX
BigEnemyDX
Overview
Creator:
kurt91
Added: 01 Jul 2014
Tags:
FFC
|
View Script |
Information
An improved version of the commonly-requested BigEnemy script, to create enemies larger than 16x16 pixels!\
Test Quest: http://purezc.magesg...rd/100tombs.qst
UPDATE: Accidentially left out some needed constants. Should work properly now.
Test Quest: http://purezc.magesg...rd/100tombs.qst
UPDATE: Accidentially left out some needed constants. Should work properly now.
Description Setup Reviews Comments
Not much to say, other than this should allow you to create larger enemies of any desired size with no glitches. Many thanks to Alucard648, who took the original version of this script and added a ton of further improvements and fixes.
D0 = Enemy on Screen's Enemy List
D1 = Width (measured in pixels)
D2 = Height (measured in pixels)
D3 = Sprite X-Offset
D4 = Sprite Y-Offset
D5 = Hitbox X-Offset
D6 = Hitbox Y-Offset
D7 = Custom Animation Flags.
00000001b - enable custom animation
00000010b - allow 8 way direction
00000100b - always face Link (Tracking)
00001000b - use separate animations when npc is halting (Firing)
00010000b - unused
00100000b - unused
01000000b - unused
10000000b - unused
Requires std.zh
=== Custom Animation ===
A new feature added to this script is a custom animation setting that should prevent any graphical glitches and allow more detailed movement.
The script sets "OriginalTile", the graphic chosen in the Enemy Editor, depending on the enemy's Direction and TileHeight.
Tile arrangement for such enemies would look like this:
Enemy Editor settings would look like this:
Supports the following animation settings:
None, 2-Frame, 3-Frame, 4-Frame
D1 = Width (measured in pixels)
D2 = Height (measured in pixels)
D3 = Sprite X-Offset
D4 = Sprite Y-Offset
D5 = Hitbox X-Offset
D6 = Hitbox Y-Offset
D7 = Custom Animation Flags.
00000001b - enable custom animation
00000010b - allow 8 way direction
00000100b - always face Link (Tracking)
00001000b - use separate animations when npc is halting (Firing)
00010000b - unused
00100000b - unused
01000000b - unused
10000000b - unused
Requires std.zh
=== Custom Animation ===
A new feature added to this script is a custom animation setting that should prevent any graphical glitches and allow more detailed movement.
The script sets "OriginalTile", the graphic chosen in the Enemy Editor, depending on the enemy's Direction and TileHeight.
Tile arrangement for such enemies would look like this:
Enemy Editor settings would look like this:
Supports the following animation settings:
None, 2-Frame, 3-Frame, 4-Frame
Alucard648
Posted 01 July 2014 - 01:40 PM
The script is long outdated. Grab new version here:
//Bossmaker script arguments: // D0: Movement part enemy in the list. // D1: Shooter part enemy in the list. // D2: Collision part enemy in the list. Also known as "core" or "weak point" // D3: Set to 1 if you want for boss` body not to damage Link on direct contact. // Contact with re is always harmful. // D4: Shooter`s X position offset. // D5: Shooter`s Y position offset. // Use these arguments if you want to have boss shoot Eweapons from proper position. // For Collision part use BigEnemy script with HitBox offset argument const int BOSS_INVISITILE = 50000; //Needed to render NPC invisible. const int NPC_MISC_ORIGTILE = 0; //Index for NPC`s Misc array for Npc`s real original tile chosen in Enemy Editor const int NPC_MISC_OLDX = 1; //Index for NPC`s Misc array for Npc`s X coordinate in previous frame. const int NPC_MISC_OLDY = 2; //Index for NPC`s Misc array for Npc`s Y coordinate in previous frame. const int NPC_MISC_HALTCOUNTER = 3; //Index for NPC`s Misc array for Npc`s halt counter ffc script BossMaker{ void run(int Movement, int WeaponFire, int Collision, int Background_Boss, int Shooter_XOffset, int Shooter_YOffset){ Waitframes(4); //DECLARE VARIABLES AND POINTERS npc EnemyMove; //Pointer for Movement Enemy Data npc EnemyFire; //Pointer for Weapon Enemy Data npc EnemyColl; //Pointer for Collision Enemy Data bool Dual_Enemy = true; //Variable for Dual Enemy Mode bool Triple_Enemy = true; //Variable for Triple Enemy Mode int FireOrigWeapon; //Declare 6 variables for backing up Weapon, tiles and CollDetection for Projectile and Collision parts int FireOrigtile; bool FireOrigCollDetection; int CollOrigWeapon; int CollOrigtile; bool CollOrigCollDetection; //DETERMINE HOW MANY ENEMIES ARE BEING USED IN THE SCRIPT Dual_Enemy = true; //Initialize modes as true. Triple_Enemy = true; EnemyMove = Screen->LoadNPC(Movement); //Load enemy data used for appearance and movement if(!EnemyMove->isValid()){ Quit(); //Use Enemy placement flags to set up stationary bosses. } if(WeaponFire>0) EnemyFire = Screen->LoadNPC(WeaponFire); //Load enemy data used for behavior and weapon fire // if(EnemyFire->isValid()){ //If a second enemy exists // Dual_Enemy = true; //Activate "Dual Enemy" mode // } if(!EnemyFire->isValid()){ //If a second enemy does not exist Dual_Enemy = false; //"Dual Enemy" mode does not activate } else{ FireOrigWeapon = EnemyFire->Weapon; //Back up Weapon, Original tile and CollDetection for Projectile part. FireOrigtile = EnemyFire->OriginalTile; FireOrigCollDetection = EnemyFire->CollDetection; } if (Collision>0) EnemyColl = Screen->LoadNPC(Collision); //Load enemy data used for collision and touch effects // if(EnemyColl->isValid()){ //If a third enemy exists // Triple_Enemy = true; //Activate "Triple Enemy" mode // } if(!EnemyColl->isValid()){ //If a third enemy does not exist Triple_Enemy = false; //"Triple Enemy" mode does not activate } else{ CollOrigWeapon = EnemyColl->Weapon; //Back up Weapon, Original tile and CollDetection for Collision part. CollOrigtile = EnemyColl->OriginalTile; CollOrigCollDetection = EnemyColl->CollDetection; } while(EnemyMove->isValid()){ if((Dual_Enemy == true)&&(EnemyFire->isValid())||(Triple_Enemy == true)){ //SETTINGS FOR BOTH DUAL AND TRIPLE ENEMY MODES EnemyFire->X = EnemyMove->X + Shooter_XOffset; //Weapon enemy X-Coordinate attached to Movement enemy. Offset is applied to position. EnemyFire->Y = EnemyMove->Y + Shooter_YOffset; //Weapon enemy Y-Coordinate attached to Movement enemy. Offset is applied to position. WizzrobeUpdate(EnemyMove, EnemyFire, FireOrigtile, FireOrigWeapon, FireOrigCollDetection); if(Background_Boss>0){ //Check if the boss is not in the same plane as Link //Set NPC`s all Defenses to "ignore" if you want for boss body not to take damage from Lweapons. EnemyMove->CollDetection = false; //Movement enemy collision detection turned off EnemyFire->CollDetection = false; //Shooter enemy collision is off } } if((Dual_Enemy == true)&&(Triple_Enemy == false)){ //SETTINGS FOR DUAL ENEMY MODE ONLY if(EnemyMove->HP <= 0){ //If movement enemy's HP reaches zero EnemyFire->HP = 0; //Set Weapon enemy's HP to zero Quit(); //Boss is dead. Finita la comedia. } } if((Triple_Enemy == true)&&(EnemyColl->isValid())){ //SETTINGS FOR TRIPLE ENEMY MODE ONLY EnemyColl->X = EnemyMove->X; //Collision enemy X-Coordinate attached to Movement enemy EnemyColl->Y = EnemyMove->Y; //Collision enemy Y-Coordinate attached to Movement enemy WizzrobeUpdate(EnemyMove, EnemyColl, CollOrigtile, CollOrigWeapon, CollOrigCollDetection); if(Background_Boss>0){ //Check if the boss is not in the same plane as Link //Set NPC`s all Defenses to "ignore" if you want for boss body not to take damage from Lweapons. EnemyMove->CollDetection = false; //Movement enemy collision detection turned off if(EnemyFire->isValid()){ // Some bosses have no turrets but have cores EnemyFire->CollDetection = false; //Shooter enemy collision is off } } if((EnemyColl->HP <= 0)||(EnemyMove->HP <=0 )){ //If Collision enemy's HP reaches zero or movement part is already destroyed. EnemyMove->HP = 0; //Set Movement enemy's HP to zero EnemyColl->HP = 0; //Set Collision enemy`s HP to 0. //This is useful if the Triple boss is killed via chain reaction //if there are multiple Bossmaker scripts running in one screen. if(EnemyFire->isValid()){ EnemyFire->HP = 0; //Set Weapon enemy's HP to zero } Quit();//Boss is dead. Finita la comedia. } } Waitframe(); } // This 2-line piece of code destroys Shooter and Collision parts if EnemyMove pointer // is rendered invalid in the way other than killing enemy. // This is true if enemy splits(like Digdogger) or tribbles. if (EnemyFire->isValid()) EnemyFire->HP=0; if (EnemyColl->isValid()) EnemyColl->HP=0; } } //This function temporarily hides Shooter and Collision enemies if WizzRobe //(if he is Movement part of the boss) is currently teleporting. void WizzrobeUpdate(npc carrier, npc part, int OrigTile, int OrigWeapon, bool OrigCollDetection ){ if (carrier->Type==NPCT_WIZZROBE){ if (carrier->HitXOffset >= 1000){ part->CollDetection=false; part->OriginalTile=BOSS_INVISITILE; part->Weapon=WPN_NONE; } else { part->CollDetection=OrigCollDetection; part->OriginalTile=OrigTile; part->Weapon=OrigWeapon; } } } ffc script BigEnemyDX{ void run(int EnemyNum, int Width, int Height, int XDraw, int YDraw, int XHit, int YHit, int animoverride){ Waitframes(4); npc Boss = Screen->LoadNPC(EnemyNum); Boss->HitWidth = Width; Boss->HitHeight = Height; if (Width >=16){ Boss->Extend=3; Boss->TileWidth = Width/16; } if (Height>=16){ Boss->Extend=3; Boss->TileHeight = Height/16; } Boss->DrawXOffset = XDraw; Boss->DrawYOffset = YDraw; Boss->HitXOffset = XHit; Boss->HitYOffset = YHit; Boss->Misc[NPC_MISC_ORIGTILE] = Boss->OriginalTile; while (Boss->isValid()){ CustomAnimation(Boss, animoverride); Waitframe(); } } } ffc script MassBigEnemy{ //This version of the script applies BigEnemy settings to all enemies on the screen. void run(int Dunmmy,int Width, int Height, int XDraw, int YDraw, int XHit, int YHit, int animoverride){ Waitframes(4); npc Boss; for (int i=1; i<= Screen->NumNPCs(); i++){ Boss = Screen->LoadNPC(i); Boss->HitWidth = Width; Boss->HitHeight = Height; if (Width >= 16){ Boss->Extend=3; Boss->TileWidth = Width/16; } if (Height>=16){ Boss->Extend=3; Boss->TileHeight = Height/16; } Boss->DrawXOffset = XDraw; Boss->DrawYOffset = YDraw; Boss->HitXOffset = XHit; Boss->HitYOffset = YHit; if (Boss->Misc[NPC_MISC_ORIGTILE]==0) Boss->Misc[NPC_MISC_ORIGTILE] = Boss->OriginalTile; while (true){ for(int i=1; i<= Screen->NumNPCs();i++){ Boss = Screen->LoadNPC(i); CustomAnimation(Boss, animoverride); } Waitframe(); } } } } ffc script MassBigEnemyEnemySpecific{ //This version of Bigenemy script is similar to MassBigenemy but affects only specific kind of enemies. void run(int EnemyType,int Width, int Height, int XDraw, int YDraw, int XHit, int YHit, int animoverride){ Waitframes(4); npc Boss; for (int i=1; i<= Screen->NumNPCs(); i++){ Boss = Screen->LoadNPC(i); if (Boss->ID==EnemyType){ Boss->HitWidth = Width; Boss->HitHeight = Height; if (Width >=16){ Boss->Extend=3; Boss->TileWidth = Width/16; } if (Height>=16){ Boss->Extend=3; Boss->TileHeight = Height/16; } Boss->DrawXOffset = XDraw; Boss->DrawYOffset = YDraw; Boss->HitXOffset = XHit; Boss->HitYOffset = YHit; if (Boss->Misc[NPC_MISC_ORIGTILE]==0) Boss->Misc[NPC_MISC_ORIGTILE] = Boss->OriginalTile; } } while(true){ for(int i=1; i<= Screen->NumNPCs();i++){ Boss = Screen->LoadNPC(i); if (Boss->ID==EnemyType) CustomAnimation(Boss, animoverride); } Waitframe(); } } } ffc script MassBigEnemyContinious{ //Similar to MassBigEnemyEnemySpecific but also affects enemies that appear after initialization //(like enemies summoned by SUMMON_LAYER spell). void run(int EnemyType,int Width, int Height, int XDraw, int YDraw, int XHit, int YHit, int animoverride){ Waitframes(4); npc Boss; while(true){ for (int i=1; i<= Screen->NumNPCs(); i++){ Boss = Screen->LoadNPC(i); if (Boss->ID==EnemyType){ Boss->HitWidth = Width; Boss->HitHeight = Height; if (Width >= 16){ Boss->Extend=3; Boss->TileWidth = Width/16; } if (Height>=16){ Boss->Extend=3; Boss->TileHeight = Height/16; } Boss->DrawXOffset = XDraw; Boss->DrawYOffset = YDraw; Boss->HitXOffset = XHit; Boss->HitYOffset = YHit; if (Boss->Misc[NPC_MISC_ORIGTILE]==0) Boss->Misc[NPC_MISC_ORIGTILE] = Boss->OriginalTile; else CustomAnimation(Boss, animoverride); } } Waitframe(); } } } //D0 = Enemy on Screen's Enemy List (or Enemy ID for mass versions) //D1 = Width (measured in pixels) //D2 = Height (measured in pixels) //D3 = Sprite X-Offset //D4 = Sprite Y-Offset //D5 = Hitbox X-Offset //D6 = Hitbox Y-Offset //D7 = Custom Animation Flags. // 00000001b - enable custom animation // 00000010b - allow 8 way direction // 00000100b - always face Link (Tracking) // 00001000b - use separate animations when npc is halting (Firing) // 00010000b - unused // 00100000b - unused // 01000000b - unused // 10000000b - unused //Used to determine animation direction for facing Link int FaceLink (npc b){ if (IsSideview()){ if (b->X > CenterLinkX()) return DIR_LEFT; else return DIR_RIGHT; } else{ int LX = CenterLinkX(); int LY = CenterLinkY(); int BX = CenterX(b); int BY = CenterY(b); int vector = Angle(LX,LY,BX,BY); if (Abs(vector)>135){ return DIR_RIGHT; } else if (Abs(vector)>45){ if (vector > 0) return DIR_UP; else return DIR_DOWN; } else return DIR_LEFT; } } //Defines custom animation. Call this function every frame to prevent glitching tiles. void CustomAnimation(npc b, int animflags){ if ((animflags&1) == 0) return; //Custom animation was not enabled. if (b->Attributes[11] > 0) return; //Stay away from ghosted enemies. int OrigTileOffset = b->TileHeight * 20; //Find incremental for BigEnemy`s OriginalTile offset float HaltThreshold = 100/(b->Step); //Find out the threshold used to detect whether the enemy is halting. if (HaltThreshold==0) HaltThreshold = 1; //Set the threshold for fast enemies int andir=0; //Direction the enemy is facing. Not the npc->Dir! int HaltTileOffset=0; //Tile offset used for "firing"animation int OrigTile = b->Misc[NPC_MISC_ORIGTILE]; //The actual original tile of enemy. // /!\ Must be recorded on enemy initialization int OldX = b->Misc[NPC_MISC_OLDX]; //Enemy`s X coordinate on previous frame. int OldY = b->Misc[NPC_MISC_OLDY]; //Enemy`s Y coordinate on previous frame. if ((animflags&4)>0) andir = FaceLink(b); //Always face Link if approriate flag is used else andir = b->Dir; //Otherwise, use npc->Dir if ((animflags&8)>0){ //Firing animation is used? if ((b->X == OldX)&&(b->Y==OldY)&&(OldX==GridX(OldX))&&(OldY==GridY(OldY))){ //Main halting detection check. Not perfect. :-( b->Misc[NPC_MISC_HALTCOUNTER]++; //Update halt counter if (b->Misc[NPC_MISC_HALTCOUNTER]>HaltThreshold){ if ((animflags&2)>0) HaltTileOffset= OrigTileOffset*8; //Check diagonal allowance flag else HaltTileOffset= OrigTileOffset*4; //And set tile offset accordingly. if (b->Misc[NPC_MISC_HALTCOUNTER] >= 24) HaltTileOffset *= 2; } } else b->Misc[NPC_MISC_HALTCOUNTER] = 0; //Reset halt counter } b->Misc[NPC_MISC_OLDX] = b->X; //Update old coordinates b->Misc[NPC_MISC_OLDY] = b->Y; b->OriginalTile = OrigTile + HaltTileOffset+ (OrigTileOffset * andir); //And, finally, set npc`s Original Tile //debugValue(1, (b->Misc[NPC_MISC_HALTCOUNTER])); //debugValue(2, HaltThreshold); }
DaLink
Edited 01 July 2014 - 07:53 AM
For some reason while compiling my scripts, it says that the variables are undeclared. These include MPC_MISC_ORIGTILE, NPC_MISC_OLDX/OLDY, and NPC_MISC_HALTCOUNTER in your custom animation function. I have ghost.zh, std.zh, string.zh, and ffcscript.zh. I don't know what's the problem!