Jump to content

Photo

Non-Scripter's Custom Boss Kit


  • Please log in to reply
98 replies to this topic

#1 kurt91

kurt91

    Follower of Destiny

  • Members
  • Real Name:Kurtis
  • Location:Eastern Washington University

Posted 15 January 2014 - 07:15 AM

I've been mentioning this particular project of mine a couple times, but I'm currently working on a Custom Boss Kit. No, it isn't for me. I plan on learning how to script ghosted enemies. It's intended for people who don't know how to script yet still want custom bosses in their quest. Here's what I have so far:

import "std.zh"
import "stdExtra.zh"
import "ffcscript.zh"

ffc script BossMaker{
	void run(int EnemyMove, int EnemyFire, int EnemyColl){
		Waitframes(4);
		while(true){
			npc n1 = Screen->LoadNPC(EnemyMove);  //Load enemy data used for appearance and movement
				if(!n1->isValid()){
					Quit();
				}
			npc n2 = Screen->LoadNPC(EnemyFire);  //Load enemy data used for behavior and weapon fire
				if(!n2->isValid()){
					Quit();
				}
			npc n3 = Screen->LoadNPC(EnemyColl);  //Load enemy data used for collision and touch effects
				if(!n3->isValid()){
					Quit();
				}
			n2->X = n1->X;  //Weapon enemy X-Coordinate attached to Movement enemy
			n2->Y = n1->Y;  //Weapon enemy Y-Coordinate attached to Movement enemy
			n3->X = n1->X;  //Collision enemy X-Coordinate attached to Movement enemy
			n3->Y = n1->Y;  //Collision enemy Y-Coordinate attached to Movement enemy
			
			n1->CollDetection = false;  //Movement enemy collision detection turned off
			n2->CollDetection = false;  //Weapon enemy collision detection turned off
			
			if(n3->HP <= 0){   //If Collision enemy's HP reaches zero
				n1->HP = 0;  //Set Movement enemy's HP to zero
				n2->HP = 0;  //Set Weapon enemy's HP to zero
			}
		}
	}
}

However, I've found that it doesn't work, and I can't figure out why. What it's meant to do is take three different enemies, one for movement and graphics, one for firing EWeapons, and one for collision data, and overlap them on top of each other every frame. Finally, when the collision enemy is killed, the other two die as well. That way, it would look as though you had one enemy with the combined traits of three. For instance, a Keese that shoots fireballs and eats Link if it makes contact.

 

That's actually what I was using to test it. I used a Keese as enemy 1 (movement/graphics) and a fireball shooter as enemy 2 (weapon fire). For some reason, it's not attaching the shooter to the Keese. I've looked over everything and it should be working. Any ideas why? Once I get this working, I can start incorporating other scripts like the BigEnemy script so they actually look like bosses instead of common enemies.



#2 Alucard648

Alucard648

    Wizard

  • Members
  • Location:castle Dracula

Posted 15 January 2014 - 08:26 AM

For some reason, it's not attaching the shooter to the Keese. I've looked over everything and it should be working. Any ideas why? Once I get this working, I can start incorporating other scripts like the BigEnemy script so they actually look like bosses instead of common enemies.

Don`t know if it`s true, but ZC`s internal code seems to strictly prohibit "Projectile shooter" enemies (like statue shooters) from moving under any circumstances.  :shiver:



#3 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 15 January 2014 - 04:29 PM

You seem to be missing a waitframe(); at the end of the while(true) loop. This is the single most common mistake you'll make in scripting, and if you're like me, every missing waitframe() will bury itself in the back of your mind, slowly accumulating, reminding you with each one of what a miserable failure you are and how you'll never accomplish anything, how your past can't escape you, how you'll never live up to your abuse father's expectations, how every script you write will only bring upon you pain and misery and untold sorrow...

 

... But yeah, add a waitframe and it should work fine.


  • Din, Moosh, RetraRoyale and 1 other like this

#4 kurt91

kurt91

    Follower of Destiny

  • Members
  • Real Name:Kurtis
  • Location:Eastern Washington University

Posted 15 January 2014 - 05:07 PM

Actually, I originally had one there. It didn't work, giving me the same problem, so I tried taking it out, since I can never keep straight when they're needed or not. I'm probably going to put it back, just to be on the safe side, since I intend on adding other functions to it like the BigEnemy script I mentioned earlier.



#5 anikom15

anikom15

    Dictator

  • Banned
  • Real Name:Westley
  • Location:California, United States

Posted 16 January 2014 - 12:52 AM

Waitframe basically tells ZC, 'go do everything you need to do, then come back when your ready for more instructions.' Without it, the program won't do anything else other than what you specify in the loop.



#6 kurt91

kurt91

    Follower of Destiny

  • Members
  • Real Name:Kurtis
  • Location:Eastern Washington University

Posted 17 January 2014 - 03:04 AM

I found my problem with the script. It seems that attaching the Projectile Shooter is actually a viable method. My problem was, I didn't realize that the way it's put together, the entire script breaks and falls apart if all three enemy slots aren't used. I skipped the collision enemy slot, so the entire script stopped working, including the position adjusting portion.

 

I built a Fire Keese as a test subject. It flies around and shoots fireballs at Link without having to stop moving. The positioning is still slightly buggy, with the fireballs spawning slightly off-position, but everything works as it should. The Keese provides movement, the Projectile Shooter fires the Fireball weapons, and the motionless Walking Enemy makes the whole thing take damage from attacks as well as damage Link when it hits him.



#7 Alucard648

Alucard648

    Wizard

  • Members
  • Location:castle Dracula

Posted 17 January 2014 - 06:25 AM

I found my problem with the script. It seems that attaching the Projectile Shooter is actually a viable method. My problem was, I didn't realize that the way it's put together, the entire script breaks and falls apart if all three enemy slots aren't used. I skipped the collision enemy slot, so the entire script stopped working, including the position adjusting portion.

 

I built a Fire Keese as a test subject. It flies around and shoots fireballs at Link without having to stop moving. The positioning is still slightly buggy, with the fireballs spawning slightly off-position, but everything works as it should. The Keese provides movement, the Projectile Shooter fires the Fireball weapons, and the motionless Walking Enemy makes the whole thing take damage from attacks as well as damage Link when it hits him.

Grand Fantastic! The only things left are pair of updates for BigEnemy script: One for proper collision in sideview areas (otherwise the FFC falls troughsolid floors partially) and one for handling interaction with Lweapons. And custom bosses will be more common in future ZC quests...

P.S. Would it be possible to have multiple bosses in one screen? I am planning to have Monster Frankenstein as boss in my quest (a walking 1x3 enemy for the Creature itself (ring leader) and invincible Tektite+fireball shooter fusion for Igor companion) Feel free to use stdArguments.zh in case of argument shortage.

P.P.S. Try to test this script with Wizzrobe as moving part.



#8 kurt91

kurt91

    Follower of Destiny

  • Members
  • Real Name:Kurtis
  • Location:Eastern Washington University

Posted 17 January 2014 - 07:17 AM

Well, I wanted an excuse to post an update on how this script is doing, so here goes...

 

As it is now, I've got the basic necessities of the script finished. There are four user-defined settings controlled through D0 to D4. These settings are:

 

D0: Movement Enemy Data

Which enemy on the screen's Enemy List controls the boss's movement patterns.

 

D1: Weapon Enemy Data

Which enemy on the screen's Enemy List controls the attacks fired at the player.

 

D2: Collision Enemy Data

Which enemy on the screen's Enemy List controls the boss's HP, vulnerability to attack, touch effects, etc.

 

D3: BigEnemy Script Controls

This one's a little more complex to explain, but even easier to use than the first three. Using a modified version of the BigEnemy script that's been adjusted for weapon fire (the original would shoot from the top-left corner, this one is set up to shoot from the center of the sprite), you can control it entirely through this number.

 

0 = Width: 1, Height: 1

1 = Width: 1, Height: 2

2 = Width: 2, Height: 1

3 = Width: 2, Height: 2

 

This should cover all of the most commonly used sizes for enemies. However, while writing the basic functionality for the script is finished, I haven't yet tested the BigEnemy adjustments. I still need to make an enemy of each respective size, and test it in-game to make sure that it's set up properly and fires from the correct part of the sprite.

 

Multiple bosses on one screen is just as easy as one boss. Because there are ten enemy slots for each screen, you would simple set up three instances of the script, the first one using the first three enemies on the list, the second one using enemies 4 through 6, and the third one using enemies 7 through 9.

 

I have only tested the script using a Keese enemy for Movement data, to see if I could make it fire while still moving. I haven't tested teleporting enemies yet. I also unfortunately have not taken sideview areas into account. I'm not entirely sure how those work, having not actually used them in a quest before. If the script works in sideview areas, then it's a happy coincidence. If not, then I'm not really sure what to do about that just yet.

 

(EDIT: Wait a minute. I just re-read your post. I'm pretty sure that as long as a normal enemy would function properly in a sideview area, it can be used as the boss's movement data and the whole thing would work. The FFC is only to make the script function. The entire enemy itself is made through the Enemy Editor. This is one of those scripts where you just make an invisible FFC tucked in the corner, and it doesn't interact with anything, it just sits there silently and does it's thing.)

 

If by "handling interaction with LWeapons", you mean how only certain parts of the boss take damage when hit, I have already fixed that. It was simply two lines per enemy component for each setting to adjust the hitbox. (I'm kind of surprised that the original script never took that into account. It was such an easy fix.)

 

Right now, the biggest drawbacks to the boss script is that I have absolutely no idea how to make splitting enemies work, so if you want a multi-phase boss fight, you're going to need to use multiple rooms to do so, just like if you were using 2.10 to make a custom boss. Not a major issue, though, since it can be somewhat worked around.

 

Once I get the BigEnemy portion of the script tested and any adjustments that are needed have been made, I'd like to know if there are any other common scripts I should include. I'd like this to be as useful as possible, so that this single script can be used to make many different bosses. However, I need to be able to keep it as easy to use as I can, so that as many people can use this as possible.


Edited by kurt91, 17 January 2014 - 07:24 AM.


#9 Alucard648

Alucard648

    Wizard

  • Members
  • Location:castle Dracula

Posted 17 January 2014 - 03:28 PM

 

D3: BigEnemy Script Controls
This one's a little more complex to explain, but even easier to use than the first three. Using a modified version of the BigEnemy script that's been adjusted for weapon fire (the original would shoot from the top-left corner, this one is set up to shoot from the center of the sprite), you can control it entirely through this number.

0 = Width: 1, Height: 1
1 = Width: 1, Height: 2
2 = Width: 2, Height: 1
3 = Width: 2, Height: 2

This should cover all of the most commonly used sizes for enemies.

Not for my quest.  :sly: Frankenstein is 1x3, Grim reaper is 3x4 and Dracula is 2x4. Apparently, you should expand value range to take all dimansion combinations from 1x1 to 4x4. Here is my suggestion on how to do this:

4 = 1x3

5 = 3x1

6 = 2x3

7 = 3x2

8 = 3x3

9 = 1x4

10 = 4x1

11 = 2x4

12 = 4x2

13 = 3x4

14 = 4x3

15 = 4x4

If by "handling interaction with LWeapons", you mean how only certain parts of the boss take damage when hit, I have already fixed that. It was simply two lines per enemy component for each setting to adjust the hitbox. (I'm kind of surprised that the original script never took that into account. It was such an easy fix.)

Yes, just like this. Bonus points if it would be an option to turn on collision detection with Link for "Movement" part of boss as well as separate BigEnemy controls for it. This would allow bigger weak points for certain bosses. Another option would be an offset for Collision and Shooter part relative to body of the boss so one who use this script can have boss spawn projectiles from proper point as well as proper location of boss weak point.

 

I would also want to to have standalone version of updated BigEnemy script released.



#10 kurt91

kurt91

    Follower of Destiny

  • Members
  • Real Name:Kurtis
  • Location:Eastern Washington University

Posted 17 January 2014 - 04:40 PM

The BigEnemy script wouldn't be a problem, but I'd need time to tweak it for public use. As it is now, the adjustments I made are hard-coded into the script instead of done through arguments and variables, since I originally only planned on using it for a specific project.

 

The different sizes you're wanting I could do easily in theory, but I'm not sure how animation would work. The biggest boss I've ever made was still just 2x2, so if the animation rules are the same for my alternate sizes, you just leave spots blank.

 

I had more to type, but I've got to go. I've just gotten some really bad news and need to watch my siblings. When I have a bit of time, I'll make the adjustments to the BigEnemy script and post it for you. If you don't mind, see if it'll work for the different sizes you want, and I'll add the appropriate settings to my kit.

 

 

EDIT: I made the necessary changes. It's slightly more complicated to use, but not by much. I haven't tested it, though. It's just a quick adjustment. See how well this works for you.

import "std.zh"
 
ffc script BigEnemy{
    void run(int enemyNum, int Width, int Height, int XPosition, int YPosition){
        Waitframes(4);
        npc n = Screen->LoadNPC(enemyNum);
        if(!n->isValid()){
            Quit();
        }
        n->Extend = 3;
        n->HitWidth = (Width*16);
        n->HitHeight = (Height*16);
        n->TileWidth = Width;
        n->TileHeight = Height;
 
        n->DrawXOffset = XPosition;
        n->DrawYOffset = YPosition;
        n->HitXOffset = XPosition;
        n->HitYOffset = YPosition;
    }
}
 
//D0: Number of enemy on screen Enemy List
//D1: Enemy width (measured in tiles)
//D2: Enemy height (measured in tiles)
//D3: X Offset (measured in pixels)
//D4: Y Offset (measured in pixels)

The X Offset and Y Offset are for if your sprite graphics need to have the sprite shoot from a specific location. For example, my "Corrupt Fairy" is a 2x2 enemy with its head in the top-center of the sprite. It's meant to breathe fireballs, so I set the X Offset to "-8" so it would fire from the head's location. I believe if you want it centered between two vertical tiles, the Y Offset would be "-8".

 

EDIT II: This was just added in as an edit to avoid double-posting. I was looking over zscript.txt to try and find this, but I can't seem to figure it out. Is there a way to tell the script to skip a particular part if a condition is not met instead of stopping entirely? I want to replace the "Quit();" lines in the first part of my script so that they don't break the entire script if they're left blank. That way, less complex enemies wouldn't require as many enemy slots. The way it is now, if all three slots are not used, the entire script stops working. I'd like it to just skip the step if it's left blank, instead.


Edited by kurt91, 18 January 2014 - 06:37 PM.


#11 Alucard648

Alucard648

    Wizard

  • Members
  • Location:castle Dracula

Posted 18 January 2014 - 08:47 AM

EDIT II: This was just added in as an edit to avoid double-posting. I was looking over zscript.txt to try and find this, but I can't seem to figure it out. Is there a way to tell the script to skip a particular part if a condition is not met instead of stopping entirely? I want to replace the "Quit();" lines in the first part of my script so that they don't break the entire script if they're left blank. That way, less complex enemies wouldn't require as many enemy slots. The way it is now, if all three slots are not used, the entire script stops working. I'd like it to just skip the step if it's left blank, instead.

This should logically depend on type of empty slot (and empty slot should return 0). Empty Shooter slot means no projectile shooting, empty Movement slot means boss is stationary and empty Collision slot causes boss to commit suicide right after entering it`s screen (maybe good for cutscenes).

 

EDIT: BigEnemy fails to compile:

fail2_zps7e8acdc3.png


Edited by Alucard648, 18 January 2014 - 09:34 AM.


#12 Alucard648

Alucard648

    Wizard

  • Members
  • Location:castle Dracula

Posted 18 January 2014 - 11:28 AM

Also: Enemies (CV1 zombies here) partially fall trough floor.

zelda004_zpsa1950867.png



#13 kurt91

kurt91

    Follower of Destiny

  • Members
  • Real Name:Kurtis
  • Location:Eastern Washington University

Posted 18 January 2014 - 06:36 PM

Okay, I'm pretty sure that the non-compiling issue is simply my multiplying part. I think there's something you're supposed to use that isn't "x", I just don't recall what it is. Give me a minute and I'll edit the script.

 

The issue with them falling through the floor is a quirk of the BigEnemy script itself. You see, the original enemy is still 16x16. The script basically makes it just look larger, and allows the expanded sprite image to interact correctly with Link and his weapons. Collision with solid tiles is still only done with the original 16x16 enemy. If you have it set to shoot anything at Link, look closely and you can see that the shots still originate from the original 16x16 tile that the enemy would normally take up. For instance, on a 32x32 enemy, the original sprite is on the top-left corner of the boss.

 

That's what the offset values are for. They will take the whole image and Link-interaction hit-box and slides it over so that you can reposition the original enemy. Use the Y-Offset value (It would be either 16 or -16, let me know which one does it) to move the original sprite to the bottom half of your zombie instead of the top half that you currently have it set to, and it should work.

 

EDIT: It just occurred to me to mention this. By doing this, the top half of your zombie will be able to pass through solid objects instead, so the enemy will be able to walk through the one-tile-high spaces in your picture. You can fix this by adding in "No Enemies" flags inside those spaces, so it will look as though they're hitting the blocks in their way.

 

Did I explain that well? I'm not sure if I did or not.

 

 

 

Empty Shooter slot means no projectile shooting, empty Movement slot means boss is stationary and empty Collision slot causes boss to commit suicide right after entering it`s screen (maybe good for cutscenes).

Naturally, I intended to alter the script to fit the change. If no third enemy is needed, then the Weapon enemy would also act as the Collision enemy. If only the BigEnemy script is needed, then the Movement enemy would act as all three. Until I figure out how to make it work that way, though, I think I can tweak the script so that the same enemy number can be used in D0, D1, and D2.

 

EDIT: Fixed the BigEnemy script in the post above. I just needed to replace the "x" with "*" in the multiplying portion. Copy/Paste it now and it should work.


Edited by kurt91, 18 January 2014 - 06:46 PM.


#14 Alucard648

Alucard648

    Wizard

  • Members
  • Location:castle Dracula

Posted 18 January 2014 - 07:35 PM

EDIT: Fixed the BigEnemy script in the post above. I just needed to replace the "x" with "*" in the multiplying portion. Copy/Paste it now and it should work.

Already fugured out this fix before (otherwise there wouldn`t be any zombies here  :sly: ).

 

But now, zombies glitch trough narrow spaces like here:

zelda007_zpse9ff2f0a.png

This quirk/bug makes it very hard to design bosses and large enemies for cramped sideview areas, especially when there are both small and large enemies in one screen.

 

Also I have glitchy death animation for those enemies. But when I try to catch it by screenshot it does not show up!

So I had to prepare and upload test quest for this:

https://www.mediafir...igydmfboqdm6cd9

 

Hope this helps.


Edited by Alucard648, 18 January 2014 - 07:37 PM.


#15 kurt91

kurt91

    Follower of Destiny

  • Members
  • Real Name:Kurtis
  • Location:Eastern Washington University

Posted 18 January 2014 - 10:08 PM

I mentioned earlier that problem would come up with the zombies. The only thing I can think of doing is tucking a No Enemies flag inside every 1-tile-tall opening to keep them out.

 

The glitchy death animation came up with some of my bosses as well. I'm not sure what I did that fixed it, but I drew a new animation and pointed the sprite graphics to it instead and it seems to have fixed it. If not, look at what graphic shows up when they die, and search through the sprite list to see what it is. If it's something you don't intend on using, you could always just replace that graphic so the bug looks like it works normally.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users