PDA

View Full Version : Lets make a dynamic array function



C-Dawg
02-12-2008, 02:00 PM
Title says it all.

The biggest thing ZScript lacks is the ability to handle arrays. This is a huge problem in making code scalable and prevents scripters from reasonably working with large amounts of data.

My interest is in enemies that produce "bullet hell," or dozens of shots on the screen at once. I don't have enough FFCs to make each bullet and FFC, but I could use draw functions, integers, and a check for Link's location to simulate FFCs moving around. Which would be great, but without arrays I have to make perhaps hundreds of ints and then tediously copy and paste them all into one long, convuluted code.

With arrays, this would be much easier because I could stick the whole shebang into a for loop. It just steps through the integer variables determining the location of each projectile and draws them accordingly. (With structures, this would be even more slick, but I digress.)

I'm at a loss as to how to code an array. Even a simple linked list requires the ability to instantiate, which I don't think ZScript can do. So I post this thread in the hopes that some data structures folks can help out. Anyone know an algorithm for making an array out of functions available in ZScript?

For now, I'm going to simulate what I need using the only dynamic array provided in ZScript - the list of enemies on the screen indexed by the order in which they were spawned. So I get a dynamic array consisting of enemies, and I can hide data in their hit points. (For instance, enemy1->HP could be XXXYYY, where X is the projectiles' X coordinate and Y is the projectile's Y coordinate). But this has some serious limitations: (1) nothing can die or the index gets shifted; and (2) large numbers of enemies slow my scripts down to a crawl due to collision checking.

EDIT: Upon reflection, the items on screen also make up a dynamic array... but items don't have internal integers like hit points and they react unfavorably with the player.

So... any thoughts?

Gleeok
02-13-2008, 01:24 AM
Heh That's funny, I was just messing with this about a month or two ago. Here's the thread which was invariably a result of. http://www.armageddongames.net/forums/showthread.php?t=100980

I kind of gave up on it though, mainly due to the reasons you already listed. I had 25 ffcs on one screen used as "bullets" and that wasn't nearly enough however. Yes, arrays or the ability to use more than 32 ffcs would be nice, I agree.

I did start up a script though to try and implement drawtiles the way an ffc would work, tried using a crapload of int, but quickly decided that it'd be way too much friggin code to proceed in that way. Not to mention, fuck that's confusing to debug.

Where i'm at with this now is "simple" bullet pattern code, such as an ffc projectile splitting into eight drawtiles (16 integers), or a drawtile that simulates rapid fire ffcs moving at Vx or Vy only which is not too complex. Basically getting a repetoire of copy/paste reusable code rocking to start.

I really could use some insight on this myself actually.

DarkDragon
02-13-2008, 01:50 AM
Arrays and a true heap are both on my todo list for the next revision of ZScript.

C-Dawg
02-13-2008, 11:26 AM
So I take it there is no way to implement an array using the functions available to us in ZScript?

I've been working with the enemy list, but I can't get it to cooperate. I'm probably screwing up with the masking functions. I tried godel numbering, too, but i don't think we have a modulus function that works.

DarkDragon
02-13-2008, 12:00 PM
Something's buggy with %?

There are several built-in arrays you can use in the meantime; one of the easiest is just the combos on a random player-unvisitable screen.

C-Dawg
02-13-2008, 01:45 PM
Ah, I didn't even think about using combos on a non-visted screen. That wouldn't be dynamic, though. I guess one could use an entire map, that should be plenty of data...

x location of first shot = map 100, screen 00, 1st combo
y location of first shot = map 100, screen 00, 2nd combo

then the loop marches on by adding 2 to each combo each iteration, bumping ahead to the next screen when it hits the last combo.

What's the speed of accessing/writing combos on another screen compared to manipulating enemy hit points?

As for % ...

Perhaps it does work and my algorithm is wrong. What I was doing was Godel numbering an enemy's Vx, Vy, Vx sign and Vy sign using 2, 3, 5, and 7, then putting the resulting value in enemy->HP. It can't be more than five digits max (assuming Vx and Vy are capped at 4) so I thought I was good to go. I then factor the HP value by checking HP % 2, or whatever prime I'm on, and then increment enemy->Vx each time I find HP % 2 = 0.

But it doesn't seem to work. Enemy->Vx never increments.

It's pretty complicated, so I guess it's likely I did something wrong. At a glance, I didn't see anything so I assumed % wasn't fully implemented yet.

Perhaps another step in error was my attempt to ensure that Vx is an integer before I load it up. Rationals will gum up the coding. I did this:

Vx = Vx & 1.00000;

In an attempt to zero out the significant figures right of the decimal. But maybe this is bitwise and doesn't work with integers...?

P.S. Gleeok, I got swarms of bullets (50 or more) working nicely, but I have to keep track of the general movement pattern and I can't yet embed Vx and Vy into each bullet enemy individually.

Gleeok
02-13-2008, 07:50 PM
Hehe...using screen combos as data for enemy attacks. Why that's not apparently obvious for some reason....And it seems C-, that you've progressed a bit farther than I have on this too. I'm curious as to what the code looks like for accessing this screen combo array and how much easier it is to keep track of all the variables in the end. I did manage to whip up something, however, another oversight revealed another annoyance; How are you keeping track of bullets that hit Link? I'm thinking right now something like "who wants the bullets to disappear after Link gets hit anyway."

C-Dawg
02-13-2008, 08:07 PM
How are you keeping track of bullets that hit Link? I'm thinking right now something like "who wants the bullets to disappear after Link gets hit anyway."

Ah, I'm not. I didn't go with the "integers-draw functions" solution. I went with the "enemies" solution.

Essentially what I do is put enemies on the screen and tag what number they are (the boss's hit point enemy is No. 1, the rest are Nos. 2 - 52). The enemies get stashed off screen normally. Then each frame the game checks whether each enemy is on the screen. If so, the game adjusts the enemy's X and Y coordinates according to the boss's current state. The boss state code, in turn, only has to move the enemies somewhere on the screen and they take off.

So, for instance, in state 1, the code bumps each enemy's x by:

enemy->x = enemy->x + 2*Sin((360*i)/50);*

where i is the enemy's index number.

The reason I'm doing this is that because enemy objects exist in an array on the screen, so long as no enemies die, I can access them all in turn with a simple for loop rather than copying and pasting code that would move a bunch of draw functions.

I'm not clear at all on whether updating ints, using draw functions, and checking link's location is faster than writing to an enemy's x and y, though. Plus, I can't vary enemy hit boxes, so I can't make really small bullets this way.

My current hurdle is this. I don't want to control enemy movement only based on the enemy's index number, i. I want to be able to store Vx and Vy somewhere so they each move independently and I can treat them like FFCs. For that, I need to effectively encode Vx and Vy in their hit points or somewhere else, like screen combos.

Suprisingly, 50 enemies don't lag my game too much on my system. I bet more would, though, so I'm thinking of modifying my custom weapon code so it only checks the first 25 or so enemies for damage. Any more than 25 enemies on the screen, and you can safely assume some of them are bullets so it doesn't matter you're not checking them for collisions.

* = Where does this function come from? Well, Sin(t) smoothly sweeps all the values from -1 to 1 and back again while (t) varies from 1 to 360. So I change the index number i to a number from 1 to 360 according to the proportion: i/50 = x/360. Then I multiply to speed it up, and presto.

DarkDragon
02-13-2008, 08:21 PM
Access speed should be comparable, ie, both are just a memory dereference. To make it dynamic, pick a value you treat specially as a "NULL" (no more data) symbol, and you can manipulate the array like you would a statically-allocated string in C.

For what you're doing, ideally you want an array of NPC pointers, instead of plain integers, but I don't think that's possible at all currently.

C-Dawg
02-13-2008, 08:38 PM
Yes, an array of NPCs would be best. But we already have that, as long as we control how many enemies are on the screen. Enemies above the ones being manipulated can die, but none below can, or the index goes to shit.

I think my task tonight will be to code a series of generic array functions. I'll choose a map to dedicate to data storage, then code functions to:

retrieve data at an index in the map;
write data to an index in the map;
write data to the end of the map;
return the size of the array;and
zero out the data in the map.

Shouldn't be to hard to do, actually. Tricky bit will be decoding the index into Screen and Combo IDs. Then you'll have at least one array of ints for general use.

What value do you suggest I use for NULL? The highest possible combo, perhaps? And maybe return an error of some kind of the player tries to write that int to the array?

Oh crap, I just realized something else. I can only store positive ints this way. So I still need a sign bit next to each integer. God dammit... I'm going to turn a map into a damn Turing tape.

Gleeok
02-14-2008, 08:21 AM
Haha! I did it! :D ...Using DrawTile I got bullet patterns by "detonating" normal damage projectile FFCs at delayed intervals. By launching groups of ffcs at a time (basically stacking them on top of each other), You can get some cool graphical patterns of death. :P

..One minor problem with this method however: The slowdown is unbearable. Very easily much more lag than custom weapons, and doesn't seem to be fixable either. >_< Pretty noticable on the screen with 20 bullets, And just plain bad on the one with 40. Oh well. My script was buggy anyway.

I guess that leaves the NPC array, which, quite frankly, sounds very complicated. If you get something working please let me know how it works.

C-Dawg
02-14-2008, 12:33 PM
Haha! I did it! :D ...Using DrawTile I got bullet patterns by "detonating" normal damage projectile FFCs at delayed intervals. By launching groups of ffcs at a time (basically stacking them on top of each other), You can get some cool graphical patterns of death. :P

..One minor problem with this method however: The slowdown is unbearable. Very easily much more lag than custom weapons, and doesn't seem to be fixable either. >_< Pretty noticable on the screen with 20 bullets, And just plain bad on the one with 40. Oh well. My script was buggy anyway.

I guess that leaves the NPC array, which, quite frankly, sounds very complicated. If you get something working please let me know how it works.

Not sure I follow - you've got 20 FFCs running around, each checking for collisions with the player, right? And each drawing to the screen each frame? Is that what is causing the slowdown?

As for the NPC array, there's a dumb and easy way to do it (which I've done) and the more complicated way that I havn't coded yet.

1. Dumb and Easy NPC Array

At the code startup, find NumNPCs. Make 50 more and save the index of the first one as "i" (which is NumNPC+1 before you make them!) so you can get back to it later. So your array has NPC's with index numbers i through i + 50.

Never allow any enemy from 1 through all of the ones you just made to die, or your index will be off.

The key to moving each NPC independently is to get variables specific to each NPC. The easiest one is the NPC's index number, which varies from i to i+50, each NPC having a unique index.

So all you need to do is set up a loop that goes through NPCs from i to i+50 and adjusts their X and Y according to each i. For instance, X = X + Sin(i) or something. There are limits to what you can easily do with just one integer per NPC, though.

2. The more complicated and robust NPC array

At the code startup, find NumNPCs. Make 50 more and save the index of the first one as "i" (which is NumNPC+1 before you make them!) so you can get back to it later. So your array has NPC's with index numbers i through i + 50.

Never allow any enemy from 1 through all of the ones you just made to die, or your index will be off.

Figure out what values you need to keep track of for each NPC (Vx, Vy, come to mind) and put them somewhere for safe keeping. Maybe encode them in the enemy's health. Or maybe put them in a screen array. Or maybe stash them in the enemy's projectile damage number or whatever other variable you can access.

Then, your loop takes each NPC in turn from i to i+50, checks the NPC's data, and adjusts X and Y accordingly. It's as if we had true Vx and Vy for each one.

This weekend we should post some YouTube videos so people see what we're talking about. And we can see how many projectiles we can cram into the screen without causing slowdown!

Gleeok
02-15-2008, 02:13 AM
Not sure I follow - you've got 20 FFCs running around, each checking for collisions with the player, right? And each drawing to the screen each frame? Is that what is causing the slowdown?

Aah, not quite. To make coding easier with int's, each ffc is responsible for between 4-8 drawtile bullets. (Actually adding many more wouldn't be too hard.) ..Imagine the seaweed spitter but with the spit ffcs exploding into drawtiles. Problem with this method is the mega lag. :(


1. Dumb and Easy NPC Array

OK, I'm getting it now I think...but the part about moving that many numbers in one loop still eludes me.. The first gameplay problem I can think of would be the hitbox, or the built in zc hit detection for enemies. Keese I believe are the one enemy which is about half size of normal. Also as long as the weapon code isn't checking all these every frame you should be able to get 200+ on screen without any problems. I have used a "breath atack" where 60 keese are spawned at a point every second for 4 seconds and theres no problem there.


This weekend we should post some YouTube videos so people see what we're talking about. And we can see how many projectiles we can cram into the screen without causing slowdown!

...274. ;)

C-Dawg
02-15-2008, 02:52 PM
OK, I'm getting it now I think...but the part about moving that many numbers in one loop still eludes me..

I'd post the code if I was home. The idea very basic idea is this:

for(i =first_enemy_projectile_number; i>50+first_enemy_projectile_number; i++){

current_enemy = Screen->LoadNPC(i);
current_enemy->X = current_enemy->X + Sin(i);
current_enemy->Y = current_enemy->Y + Cos(i);

}

But the Sin and Cos functions can be whatever you want. So each enemy will be moved differently from the others depending on it's index "i" value. The next step is to use a value other than "i," like enemy health, that also varies by enemy and can hold more information for more complicated movement.



The first gameplay problem I can think of would be the hitbox, or the built in zc hit detection for enemies. Keese I believe are the one enemy which is about half size of normal.

Really? I didn't know this. I'll try using Keese-type enemies and see if I can make smaller bullets. A half-size hit box should be fine and dandy for all of my purposes.


Also as long as the weapon code isn't checking all these every frame you should be able to get 200+ on screen without any problems.

I tried limiting my general weapon code to only checking the first 25 enemies, and it totally eliminated lag. That should work great for me. I'll have to see how many enemies I can use before I get slowdown... remember, I'm not just spawning them, I'm also performing a few calculations, reading and writing to each enemy's X and Y each frame.

Gleeok
02-15-2008, 11:16 PM
I tried limiting my general weapon code to only checking the first 25 enemies, and it totally eliminated lag. That should work great for me. I'll have to see how many enemies I can use before I get slowdown... remember, I'm not just spawning them, I'm also performing a few calculations, reading and writing to each enemy's X and Y each frame.

Oh yeah, sorry about the delay. I was meaning to post some weapon code that was optimized a while ago. For the Megaman stuff I had tested all eight ffcs weapons at a time with no lag as long as there is a reasonable amount of enemies on a screen. With 3 ffcs I think I maxed out at 9 patras or something before a drop in fps. Anyway, I'll get to it, I will!


Also, I realized If we had full access to en_weapon sprites, this would be much easier to do. But then also, Shooters still create bullets and don't require anything complex to manipulate. For example: To create a dense bullet pattern you could create a grouping of 20 shooters at a set location + or - Rand(n) in a single frame, then kill them, and reapeat. Those would still count towards the the bullet hell, but wouldn't produce much lag as that loop would only run for 2 frames every so often. I used that before on a much less grand scale, you'd only have to change a few things here and there:


if(attack_state == 2){ // direct fire stream!

while(shooter_number < 25){

npc shooter = Screen->CreateNPC(83);
shooter->X=this->X;shooter->Y=this->Y;
shooter_number++;
}
enemy_number = Screen->NumNPCs();

while(enemy_number > 1){

npc remove_shooter = Screen->LoadNPC(enemy_number);

if(remove_shooter->Tile==0){
remove_shooter->X=this->X;
remove_shooter->Y=this->Y;
}
enemy_number--;
}

}
if(attack_state != 2){

enemy_number = Screen->NumNPCs();

while(enemy_number > 1){

npc remove_shooter = Screen->LoadNPC(enemy_number);

if(remove_shooter->Tile==0) remove_shooter->HP = 0;
enemy_number--;
}
shooter_number = 0;
}

C-Dawg
02-16-2008, 03:53 PM
Yea, shooters are fine for making a lot of player-seeking projectiles. But they arn't good for projectiles that follow other paths. Plus, all fireballs in the game use the same graphics.

Rather than spawning a bunch, I prefer to spawn them right away, stash them at -16,-16 until needed and then move them into location. They only fire when on-screen.

Gleeok
02-17-2008, 03:10 AM
Ah yes, that's a good point. I had another small breakthrough of sorts too. I can easily reuse my bullet code and just delete the drawtiles bit and replace it with enemies that en->Tile<n so as not to even check those enemies with weapons at all. Also To make boss attack patterns I could just copy/paste a bunch of these to one ffc. I post something If I get anywhere on it tomorrow.

edit: Aha! We have success! Check it out; all the orange bullets are destructable and can be killed by special attacks. ie; scripted weapons only, as seen in picture 2. ...I'm thinking Pink for invincible bullets. <cough>*DoDonPachi*<cough>

http://i235.photobucket.com/albums/ee138/Tiamat_AD/zelda006-1.jpg...http://i235.photobucket.com/albums/ee138/Tiamat_AD/zelda007.jpg


Sofar i've got 65 bullets with 60 fps. I just need to clean up some bugs and the code so I can attempt to triple that number. How did you get them all in one loop for a circular pattern though? Or did you use more than one loop for each wave of bullets?

C-Dawg
02-17-2008, 11:51 AM
Ah yes, that's a good point. I had another small breakthrough of sorts too. I can easily reuse my bullet code and just delete the drawtiles bit and replace it with enemies that en->Tile<n so as not to even check those enemies with weapons at all. Also To make boss attack patterns I could just copy/paste a bunch of these to one ffc. I post something If I get anywhere on it tomorrow.

edit: Aha! We have success! Check it out; all the orange bullets are destructable and can be killed by special attacks. ie; scripted weapons only, as seen in picture 2. ...I'm thinking Pink for invincible bullets. <cough>*DoDonPachi*<cough>

http://i235.photobucket.com/albums/ee138/Tiamat_AD/zelda006-1.jpg...http://i235.photobucket.com/albums/ee138/Tiamat_AD/zelda007.jpg


Sofar i've got 65 bullets with 60 fps. I just need to clean up some bugs and the code so I can attempt to triple that number. How did you get them all in one loop for a circular pattern though? Or did you use more than one loop for each wave of bullets?

Hard to explain; you have to look at the Cloak_Wing code to see how it's set up. I like geometric attack patterns better than bullet spamming, so I'm working on circles and lines and waves and such.

From the picture, I dont understand your bullet attack pattern. Upload the quest?

Gleeok
02-18-2008, 01:03 AM
I'm just working out some kinks right now. And I managed to max out at 192 bullets without for loops, or sin or cos for circular waving patterns. It seems that lag appears after about 120 enemies though, and thats not using weapons or even checking if enemies are out of the screens borders each frame....hmm.

Hypothetically, I could easily add a few more ffcs and shooters to hit 274. I'll see about another pic or two and some new code.




From the picture, I dont understand your bullet attack pattern.

Ah, here's the one used for that:



ffc script bullet_8way{

void run(int enemy, int time){

if(time==0)time=Rand(20)+20;
if(enemy==0)enemy=85;

int a1x; int a1y; int a2x; int a2y;
int a3x; int a3y; int a4x; int a4y;

int a5x; int a5y; int a6x; int a6y;
int a7x; int a7y; int a8x; int a8y;

npc e1; npc e2; npc e3; npc e4;
npc e5; npc e6; npc e7; npc e8;


bool xplode; bool init;
int timed_burst = time;
int delay;
int dam_counter;

while(true){

Waitframe();

int tx = this->X; int ty = this->Y;
int lx = Link->X; int ly = Link->Y;

delay++;

if(delay>=timed_burst && !xplode){

this->Data=1;this->X=0;this->Y=0;xplode=true;

a1x=tx;a1y=ty;a2x=tx;a2y=ty;a3x=tx;a3y=ty;a4x=tx;a 4y=ty;
a5x=tx;a5y=ty;a6x=tx;a6y=ty;a7x=tx;a7y=ty;a8x=tx;a 8y=ty;

}
else if(xplode){



//=======================
// ~DAMAGE~
//=======================


//=======================
// ~ENEMY CREATION~
//=======================
if(!init){

e1 = Screen->CreateNPC(enemy);
e2 = Screen->CreateNPC(enemy);
e3 = Screen->CreateNPC(enemy);
e4 = Screen->CreateNPC(enemy);

e5 = Screen->CreateNPC(enemy);
e6 = Screen->CreateNPC(enemy);
e7 = Screen->CreateNPC(enemy);
e8 = Screen->CreateNPC(enemy);

init = true;
}

//=======================
// ~ENEMY MAINTENANCE~
//=======================

e1->X=a1x; e1->Y=a1y;
e2->X=a2x; e2->Y=a2y;
e3->X=a3x; e3->Y=a3y;
e4->X=a4x; e4->Y=a4y;

e5->X=a5x; e5->Y=a5y;
e6->X=a6x; e6->Y=a6y;
e7->X=a7x; e7->Y=a7y;
e8->X=a8x; e8->Y=a8y;


//=======================
// ~ENEMY MOVEMENT~
//=======================

// 8-way burst

a1y--; a2y++; a3x--; a4x++;

a5x-=0.7; a5y-=0.7; a6x+=0.7; a6y-=0.7;
a7x-=0.7; a7y+=0.7; a8x+=0.7; a8y+=0.7;


//=======================
// ~REUSABLE~
//=======================

if(this->Data>1){

xplode = false;delay = 0;init = false;

e1->HP=0;e2->HP=0;e3->HP=0;e4->HP=0;
e5->HP=0;e6->HP=0;e7->HP=0;e8->HP=0;

}
}
}
}
}
Standard 8way spread, depending on things like delay, coordinates shot from, and movement of the "cannon", You can get different groupings and sway out of each burst. ....However I'm still undecided whether to just Create a batch of new enemies, or store them off the screen then move them back in each time.

Gleeok
03-02-2008, 05:03 AM
Mwahahahaha!!! 400+ XD ..$$$

...Aaaand 45fps was the result....I guess 300 will have to do. oh well, what can you do. :O


http://i235.photobucket.com/albums/ee138/Tiamat_AD/zelda006-3.jpg
Dodge this bitch!


OK, I'm pretty much done experimenting with ways to get more crap on screen since Jman solved that problem for us, but perhaps someone might like to take my concept and improve upon it, since the tedious bits are done already. It's not fully finished but it's set up for the most part where you don't need to rewrite anything. If I finish it i'll put it in showcase, but anyone can use it as they wish.

Usefull for things like....uh, screensaver quest, or maybe fireworks quest 2. I dunno, whatever. Here it is:


const int CIRCLE=98;
const int CIR_ROTATE=99;
const int SPREAD_D=97;

ffc script bullet{

void run(){

int b_enemy=38;
int delay=0;
bool init;
int rand = Rand(20);

//========================================
// ~BULLET DATA~
//========================================

int a1x; int a1y; int a2x; int a2y;
int a3x; int a3y; int a4x; int a4y;

int a5x; int a5y; int a6x; int a6y;
int a7x; int a7y; int a8x; int a8y;

int a9x; int a9y; int a10x; int a10y;
int a11x; int a11y; int a12x; int a12y;

int a13x; int a13y; int a14x; int a14y;
int a15x; int a15y; int a16x; int a16y;

npc e1; npc e2; npc e3; npc e4;
npc e5; npc e6; npc e7; npc e8;

npc e9; npc e10; npc e11; npc e12;
npc e13; npc e14; npc e15; npc e16;

bool init_bullet;int bullet_delay;int slow_lag;int bullet=0;


while(true){

Waitframe();
int tx = this->X; int ty = this->Y;
int lx = Link->X; int ly = Link->Y;



//=======================
// ~ENEMY CREATION~
//=======================

if(!init_bullet){

Waitframes(6);
e1 = Screen->CreateNPC(b_enemy);
e2 = Screen->CreateNPC(b_enemy);
e3 = Screen->CreateNPC(b_enemy);
e4 = Screen->CreateNPC(b_enemy);

e5 = Screen->CreateNPC(b_enemy);
e6 = Screen->CreateNPC(b_enemy);
e7 = Screen->CreateNPC(b_enemy);
e8 = Screen->CreateNPC(b_enemy);

e9 = Screen->CreateNPC(b_enemy);
e10 = Screen->CreateNPC(b_enemy);
e11 = Screen->CreateNPC(b_enemy);
e12 = Screen->CreateNPC(b_enemy);

e13 = Screen->CreateNPC(b_enemy);
e14 = Screen->CreateNPC(b_enemy);
e15 = Screen->CreateNPC(b_enemy);
e16 = Screen->CreateNPC(b_enemy);

e1->X=-48; e1->Y=-48;e2->X=-48; e2->Y=-48;
e3->X=-48; e3->Y=-48;e4->X=-48; e4->Y=-48;
e5->X=-48; e5->Y=-48;e6->X=-48; e6->Y=-48;
e7->X=-48; e7->Y=-48;e8->X=-48; e8->Y=-48;
e9->X=-48; e9->Y=-48;e10->X=-48; e10->Y=-48;
e11->X=-48; e11->Y=-48;e12->X=-48; e12->Y=-48;
e13->X=-48; e13->Y=-48;e14->X=-48; e14->Y=-48;
e15->X=-48; e15->Y=-48;e16->X=-48; e16->Y=-48;

init_bullet = true;
}

//=======================
// ~BULLET HANDLING~
//=======================

if(this->Data>1){

if(!init){

a1x=tx;a1y=ty;a2x=tx;a2y=ty;a3x=tx;a3y=ty;a4x=tx;a 4y=ty;
a5x=tx;a5y=ty;a6x=tx;a6y=ty;a7x=tx;a7y=ty;a8x=tx;a 8y=ty;

a9x=tx;a9y=ty;a10x=tx;a10y=ty;a11x=tx;a11y=ty;a12x =tx;a12y=ty;
a13x=tx;a13y=ty;a14x=tx;a14y=ty;a15x=tx;a15y=ty;a1 6x=tx;a16y=ty;
init=true;
}



if(this->Data==CIRCLE){ //8way

a1y++;
a2x-=0.35; a2y+=0.85;
a3x-=0.7; a3y+=0.7;
a4x-=0.85; a4y+=0.35;

a5x--;
a6x-=0.85; a6y-=0.35;
a7x-=0.7; a7y-=0.7;
a8x-=0.35; a8y-=0.85;

a9y--;
a10x+=0.35; a10y-=0.85;
a11x+=0.7; a11y-=0.7;
a12x+=0.85; a12y-=0.35;

a13x++;
a14x+=0.85; a14y+=0.35;
a15x+=0.7; a15y+=0.7;
a16x+=0.35; a16y+=0.85;
}
else if(this->Data==CIR_ROTATE){ //rotating circle

a1y++;
if(delay>2){ a2x-=0.4; a2y+=0.85;}
if(delay>4){ a3x-=0.7; a3y+=0.7;}
if(delay>6){ a4x-=0.85; a4y+=0.4;}

if(delay>8){ a5x--; }
if(delay>10){ a6x-=0.85; a6y-=0.4; }
if(delay>12){ a7x-=0.7; a7y-=0.7;}
if(delay>14){ a8x-=0.4; a8y-=0.85;}

if(delay>16){ a9y--; }
if(delay>18){ a10x+=0.4; a10y-=0.85;}
if(delay>20){ a11x+=0.7; a11y-=0.7;}
if(delay>22){ a12x+=0.85; a12y-=0.4; }

if(delay>24){ a13x++; }
if(delay>28){ a14x+=0.85; a14y+=0.4; }
if(delay>30){ a15x+=0.7; a15y+=0.7;}
if(delay>32){ a16x+=0.4; a16y+=0.85;}
delay++;
}
else if(this->Data==SPREAD_D){ //downward spread

a1y++; a1x-=0.18; a2y++; a2x+=0.18;
a3x--; a4x++;

a5x-=0.8; a5y+=0.35; a6x+=0.8; a6y+=0.35;
a7x-=0.7; a7y+=0.7; a8x+=0.7; a8y+=0.7;
}

//=======================
// ~ENEMY MAINTENANCE~
//=======================

bullet_delay++;
if(bullet_delay>60){

if(a1x>270)a1x=270; else if(a1x<-20)a1x=-20; if(a1y>180)a1y=180; else if(a1y<-20)a1y=-20;
if(a2x>270)a2x=270; else if(a2x<-20)a2x=-20; if(a2y>180)a2y=180; else if(a2y<-20)a2y=-20;
if(a3x>270)a3x=270; else if(a3x<-20)a3x=-20; if(a3y>180)a3y=180; else if(a3y<-20)a3y=-20;
if(a4x>270)a4x=270; else if(a4x<-20)a4x=-20; if(a4y>180)a4y=180; else if(a4y<-20)a4y=-20;
if(a5x>270)a5x=270; else if(a5x<-20)a5x=-20; if(a5y>180)a5y=180; else if(a5y<-20)a5y=-20;
if(a6x>270)a6x=270; else if(a6x<-20)a6x=-20; if(a6y>180)a6y=180; else if(a6y<-20)a6y=-20;
if(a7x>270)a7x=270; else if(a7x<-20)a7x=-20; if(a7y>180)a7y=180; else if(a7y<-20)a7y=-20;
if(a8x>270)a8x=270; else if(a8x<-20)a8x=-20; if(a8y>180)a8y=180; else if(a8y<-20)a8y=-20;
if(a9x>270)a9x=270; else if(a9x<-20)a9x=-20; if(a9y>180)a9y=180; else if(a9y<-20)a9y=-20;
if(a10x>270)a10x=270; else if(a10x<-20)a10x=-20; if(a10y>180)a10y=180; else if(a10y<-20)a10y=-20;
if(a11x>270)a11x=270; else if(a11x<-20)a11x=-20; if(a11y>180)a11y=180; else if(a11y<-20)a11y=-20;
if(a12x>270)a12x=270; else if(a12x<-20)a12x=-20; if(a12y>180)a12y=180; else if(a12y<-20)a12y=-20;
if(a13x>270)a13x=270; else if(a13x<-20)a13x=-20; if(a13y>180)a13y=180; else if(a13y<-20)a13y=-20;
if(a14x>270)a14x=270; else if(a14x<-20)a14x=-20; if(a14y>180)a14y=180; else if(a14y<-20)a14y=-20;
if(a15x>270)a15x=270; else if(a15x<-20)a15x=-20; if(a15y>180)a15y=180; else if(a15y<-20)a15y=-20;
if(a16x>270)a16x=270; else if(a16x<-20)a16x=-20; if(a16y>180)a16y=180; else if(a16y<-20)a16y=-20;
bullet_delay=0;
}

e1->X=a1x; e1->Y=a1y;
e2->X=a2x; e2->Y=a2y;
e3->X=a3x; e3->Y=a3y;
e4->X=a4x; e4->Y=a4y;

e5->X=a5x; e5->Y=a5y;
e6->X=a6x; e6->Y=a6y;
e7->X=a7x; e7->Y=a7y;
e8->X=a8x; e8->Y=a8y;

e9->X=a9x; e9->Y=a9y;
e10->X=a10x; e10->Y=a10y;
e11->X=a11x; e11->Y=a11y;
e12->X=a12x; e12->Y=a12y;

e13->X=a13x; e13->Y=a13y;
e14->X=a14x; e14->Y=a14y;
e15->X=a15x; e15->Y=a15y;
e16->X=a16x; e16->Y=a16y;
}
else{
slow_lag++;init=false;
if(slow_lag>100+rand){

e1->X=-48; e1->Y=-48;e2->X=-48; e2->Y=-48;
e3->X=-48; e3->Y=-48;e4->X=-48; e4->Y=-48;
e5->X=-48; e5->Y=-48;e6->X=-48; e6->Y=-48;
e7->X=-48; e7->Y=-48;e8->X=-48; e8->Y=-48;
e9->X=-48; e9->Y=-48;e10->X=-48; e10->Y=-48;
e11->X=-48; e11->Y=-48;e12->X=-48; e12->Y=-48;
e13->X=-48; e13->Y=-48;e14->X=-48; e14->Y=-48;
e15->X=-48; e15->Y=-48;e16->X=-48; e16->Y=-48;
slow_lag=0;
}
}
}
}
}