Read-only archive of the Armageddon Games Forums Archive (2000–2026) · About this archive

Scripting Power!

49 replies · 13,641 views · Started 28 February 2008

It uses a few new functions for grabbing combos from other screens (look at the beta updates), and then basically just a lot of math.

Astounding.... if the collision detection and combo properties are working in Z3 style. It looks from your demo like they're not. More work needed?

In-engine collision detection isn't going to work using my method. As far as combo properties go, just off the top of my head I can think of allocating a bunch empty FFCs for that purpose by aligning them to match the current scroll position and making sure they're always situated around Link. You can always make the script take care of properties by itself of course. And don't even ask about enemies, you're going to have to make them from scratch to even have a chance.

The bigger issue is that expanding the script further can potentially slow things below 60 FPS. We're trying to work on ways to squeeze as much performance from the scripting engine as possible. Hopefully our work won't be for nothing.

Can't the combo code be regiggered so that combos arn't stuck to the 16x16 grid? Or perhaps the grid itself can be moved as the map data is loaded? I dunno. Scrolling isn't cool enough to require the quest maker to re-script the entire engine from scratch. 😉

That's why this is just a proof-of-concept :P Honestly, it's likely not worth the trouble unless you're straying far from what the engine itself is capable of. The video is merely meant to give an idea of what scripting is capable of, rather than necessarily demonstrate actual applications.

...
*stares*
Jman...Jman, when 2.5 comes out and the feature freeze is over, any chance you could actually implement this, overcoming the limitations of scripting to affect collision and properties?

Only...this is awesome...

Z3 SCROLLING!!!
W00T! W00T!

That's pretty much it Russ. Theres some stuff with projectiles as well, but the lag on my computer really kept me from telling what was going on.

Zelda three scrolling! Do my eyes deceive me, or did I really read that post right? Post a demo jman, please post a demo!

Jman, I'm ambivalent toward you right now. I can [hypothetically] hug you for implementing the first signs of Z3 scrolling, but I can also [hypothetically] smack you for possibly making quest-making 100 times more difficult. 😛

russadwan wrote:I really don't care if it gets more dificult! Zelda Three Screen Scrolling!

No... not exactly. All we can do now is draw tiles to the screen to simulate Z3 scrolling, if I follow Jman's demo correctly. (Perhaps warp the player when the screen moves enough, too). We can't yet do collision or combos or enemies or... anything else in true Z3 scrolling style.

In other words, Jman's teasing us all pretty badly.

New beta out, so as promised, the script!

import "std.zh"

int screenX;
int screenY;
int LinkX;
int LinkY;
int screenOriginX;
int screenOriginY;

global script freescroll {

void run(){
Initialize();
while(true)
{
int changeX = 0;
int changeY = 0;
if(Link->X < 64)
{
int temp = screenX;
screenX -= 64-Link->X;
if(screenX < 0) screenX=0;
Link->X += temp-screenX;
changeX = screenX-temp;
}
if(Link->X > 176)
{
int temp = screenX;
screenX += Link->X-176;
if(screenX > 256) screenX=256;
Link->X -= screenX-temp;
changeX = screenX-temp;
}
if(Link->Y < 32)
{
int temp = screenY;
screenY -= 32-Link->Y;
if(screenY < 0) screenY=0;
Link->Y += temp-screenY;
changeY = screenY-temp;
}
if(Link->Y > 128)
{
int temp = screenY;
screenY += Link->Y-128;
if(screenY > 176) screenY=176;
Link->Y -= screenY-temp;
changeY = screenY-temp;
}

LinkX = screenX+Link->X;
LinkY = screenY+Link->Y;

int i;
int j;
float k;
lweapon tmpwpn;
for(k=0; k < Screen->NumLWeapons(); k++)
{
tmpwpn = Screen->LoadLWeapon(k);
tmpwpn->X += changeX;
tmpwpn->Y += changeY;
}

//Render code
int screenX1 = screenX % 256;
int screenX2 = Floor(screenX/256);
screenX2 = (screenX2+1)*256;
int screenY1 = screenY % 176;
int screenY2 = Floor(screenY/176);
screenY2 = (screenY2+1)*176;
int startX = screenX1-(screenX1%16);
int startY = screenY1-(screenY1%16);
int originI = Floor(screenY1/16); int originJ = Floor(screenX1/16);
int origScreen = Game->GetCurScreen();
int temp1 = Floor(screenY/176); int temp2 = Floor(screenX/256);
int cmbscr = ((screenOriginY+temp1)*16)+(screenOriginX+temp2);
for(i=0;i<11&&(startY+(i*16))<screenY2;i++)
{
for(j=0;j<16&&(startX+(j*16))<screenX2;j++)
{
Screen->DrawCombo(1,-(screenX1 % 16)+(j*16),-(screenY1 % 16)+(i*16),
Game->GetComboData(0,cmbscr,((originI+i)*16)+(originJ+j)),1,1,
Game->GetComboCSet(0,cmbscr,((originI+i)*16)+(originJ+j)),1,0,0,0,0,0,0,256);
}
}
cmbscr = ((screenOriginY+temp1)*16)+(screenOriginX+temp2+1);
for(i=0;i<11&&(startY+(i*16))<screenY2;i++)
{
for(j=0;j<16&&(j*16)<screenX1;j++)
{
Screen->DrawCombo(1,(256-screenX1)+(j*16),-(screenY1 % 16)+(i*16),
Game->GetComboData(0,cmbscr,((originI+i)*16)+j),1,1,
Game->GetComboCSet(0,cmbscr,((originI+i)*16)+j),1,0,0,0,0,0,0,256);
}
}
cmbscr = ((screenOriginY+temp1+1)*16)+(screenOriginX+temp2);
for(i=0;i<11&&(i*16)<screenY1;i++)
{
for(j=0;j<16&&(startX+(j*16))<screenX2;j++)
{
Screen->DrawCombo(1,-(screenX1 % 16)+(j*16),(176-screenY1)+(i*16),
Game->GetComboData(0,cmbscr,(i*16)+(originJ+j)),1,1,
Game->GetComboCSet(0,cmbscr,(i*16)+(originJ+j)),1,0,0,0,0,0,0,256);
}
}
cmbscr = ((screenOriginY+temp1+1)*16)+(screenOriginX+temp2+1);
for(i=0;i<11&&(i*16)<screenY1;i++)
{
for(j=0;j<16&&(j*16)<screenX1;j++)
{
Screen->DrawCombo(1,(256-screenX1)+(j*16),(176-screenY1)+(i*16),
Game->GetComboData(0,cmbscr,(i*16)+j),1,1,
Game->GetComboCSet(0,cmbscr,(i*16)+j),1,0,0,0,0,0,0,256);
}
}
Waitframe();
}
}

void Initialize(){
screenX = 60;
screenY = 0;
LinkX = 100;
LinkY = 32;
Link->X = 100;
Link->Y = 32;
screenOriginX = 2;
screenOriginY = 1;
}
}

item script arrow{
void run(){
int spd = 2; // You'll have to work out what the speed of the arrows are, by leaving graphics on the arrow sprites and sending the ffc along at the same time, until you get it right.
int cmb = 0; // Set here the combotype of the up-facing arrow combo. Combos should be arranged 'Up, Down, Left, Right' on the page.

//if(Screen->D[0] != 0)
//{
//lweapon tmp = Screen->LoadLWeapon(Screen->D[0]);
//if(tmp->isValid())
//{
//Quit();
//}
//}

if(Screen->NumLWeapons() > 0) Quit();

lweapon arw = Screen->CreateLWeapon(WPN_ARROW);
Screen->D[0] = arw->ID+1;
arw->X = Link->X; arw->Y = Link->Y; arw->Z = Link->Z;
arw->Dir = Link->Dir;
arw->Step = 2.5;
arw->NumFrames = 4;
arw->Frame = 0;
arw->Damage = 4;
arw->ASpeed = 6;
arw->Tile = 21951;
arw->OriginalTile = 21951;
arw->CSet = 6;
arw->OriginalCSet = 6;
arw->Flash = 0;
arw->Flip = 0;
if(arw->Dir == 0){
arw->Y = arw->Y-16;
}
if(arw->Dir == 1){
arw->Y = arw->Y+16;
arw->Flip = 2;
}
if(arw->Dir == 2){
arw->X = arw->X-16;
arw->OriginalTile = arw->OriginalTile+4;
arw->Tile = arw->Tile+4;
arw->Flip = 1;
}
if(arw->Dir == 3){
arw->X = arw->X+16;
arw->OriginalTile = arw->OriginalTile+4;
arw->Tile = arw->Tile+4;
}
Game->PlaySound(SFX_ARROW);
}
}

It's a bit dirty and not commented, but I'll leave it as an exercise to the reader to interpret its meaning. If you have any questions though, I'll answer them.

I'm a bit confused on some of the weapon handling functions.

Do all these variables have to be set for it to work fully?

    arw->NumFrames = 4;
arw->Frame = 0;
arw->Damage = 4;
arw->ASpeed = 6;
arw->Tile = 21951;
arw->OriginalTile = 21951;
arw->CSet = 6;
arw->OriginalCSet = 6;
arw->Flash = 0;
arw->Flip = 0;

Also with the angle and angular, is this necessary to achieve diagonal movement or simply to simulate the boomerang return effect?

What I'm trying to experiment with is lweapons and eweapons to replace ffcs. For lweapons I really only need the basics, just 8-12 sprites fired upward, but how could I go about mimicing the pattern of enemy ffc projectiles such as Vx and Vy? For example, something like a simple bullet spread fired from an npc:


{
ffc1->Vy=2;Waitframe();
ffc2->Vy=2;ffc2->Vx=-0.1;Waitframe();
ffc3->Vy=2;ffc3->Vx=-0.2;Waitframe();
ffc4->Vy=2;ffc4->Vx=-0.3;Waitframe();
ffc5->Vy=2;ffc5->Vx=-0.4;Waitframe();
ffc6->Vy=2;ffc6->Vx=-0.5;Waitframe();
ffc7->Vy=2;ffc7->Vx=-0.6;Waitframe();
ffc8->Vy=2;ffc8->Vx=-0.7;Waitframe();
}

Would it be possible to reproduce this with eweapons? To eliminate the problems with lag and use the built in zc hit detection, What i'm doing is sort of dependant on the use of trajectories or integers that behave like them and trying to cram as many sprites as possible on screen before I get lag from it.

Indeed, you can set projectiles to go at an angle. zscript.txt sort of touches on it, but basically if the Angular property is set to true, then Dir will be overridden by the angle attribute. The projectile will then move in that direction. Think of the normal fireball projectile that statues shoot. The only difficulty is that you're going to have to convert the normal degrees to Radians. Fortunately, this is as simple as going radians = degrees * (PI/180); but if you forget to do that before setting the lweapon angle it can be bad.

Ha! I just put your reworked script engine through a rigorous workout. I'll spare you the details, but I had DrawTiles, 180 enemies being controlled by 32 ffc's, and tons of weapon sprites being thrown around. Got 60fps on my crappy pentium III 900mhz 512ram machine. And, no bugs so far. O_o. Great work!

jman2050 wrote:Indeed, you can set projectiles to go at an angle. zscript.txt sort of touches on it, but basically if the Angular property is set to true, then Dir will be overridden by the angle attribute. The projectile will then move in that direction. Think of the normal fireball projectile that statues shoot. The only difficulty is that you're going to have to convert the normal degrees to Radians. Fortunately, this is as simple as going radians = degrees * (PI/180); but if you forget to do that before setting the lweapon angle it can be bad.

Fooey, I suppose I needed a crash course in radians sooner than later. ;p ..Ok, so for example: To script an enemy weapon attack that fires off 36 sprites in a circular pattern, how would one go about that...

Set eweapon->Step;
Set eweapon->Angular=true;
Set eweapon->Damage=d;
Set eweapon->Angle= Rad ? (deg*(PI/180)? ...then increment 10 for deg each sprite..

Or would I need Angle=RadianSin(//?);Angle=RadianCos..nuts..it's like cryptonite to me...

in other words, have no idea how to set Angle. :/

eweapon->Angle = deg*(PI/180) should do fine.

Ha! I just put your reworked script engine through a rigorous workout. I'll spare you the details, but I had DrawTiles, 180 enemies being controlled by 32 ffc's, and tons of weapon sprites being thrown around. Got 60fps on my crappy pentium III 900mhz 512ram machine. And, no bugs so far. O_o. Great work!

Excellent. This is exactly the type of feedback I'm hoping for.

Also, a new episode coming soon. Something a bit less proof-of-concept 😉

EDIT - Actually, just realized there was a bug with the assignment of angle in the engine. It'll be fixed in the next beta. Sorry :/

Cool, Thanks.

Also I found something with eweapons; Passing something like WPN_ENEMYFIREBALL or others into CreateEWeapon() doesn't display the right graphic. They all seem to use Tile->0.....lweapons seem fine though from what i've tried. Figured you're still ironing this stuff out, but just in case you don't know, well here it is.

..And did I mention: wow, holy shit man.

edit:

russadwan wrote:Dang, I can't view that webpage. Could someone please tell me what happened?

Ahahaha! I must of missed that earlier.
Dude, did your web browser come in a box with a picture of an angry nun smacking her hand with a ruler or something?

Gleeok wrote:Cool, Thanks.

Also I found something with eweapons; Passing something like WPN_ENEMYFIREBALL or others into CreateEWeapon() doesn't display the right graphic. They all seem to use Tile->0.....lweapons seem fine though from what i've tried. Figured you're still ironing this stuff out, but just in case you don't know, well here it is.

..And did I mention: wow, holy shit man.

Yeah, that's because the constants in std.zh aren't correct for this assignment. Like I said, the ZC engine is kinda screwy regarding weapons. If you want to pass an existing weapon type into the engine, use these. I just copied the enumeration from the code for the time being

enum
{
wNone,wSword,wBeam,wBrang,wBomb,wSBomb,wLitBomb,wLitSBomb,wArrow,
wFire,wWhistle,wBait,wWand,wMagic,wCatching,wWind,wRefMagic,wRefFireball,wRefRock,
wHammer, wHookshot,
wHSHandle, wHSChain, wSSparkle, wFSparkle,
wSmack, /* wGArrow, */ wPhantom, wCByrna, wRefBeam, wStomp, lwMax,
wEnemyWeapons=128,
ewFireball,ewArrow,ewBrang,ewSword,ewRock,ewMagic,ewBomb,ewSBomb,
ewLitBomb,ewLitSBomb,ewFireTrail,ewFlame,ewWind,ewFlame2,ewFlame2Trail,
ewIce,ewFireball2, wMax
};

For reference, what this enum keyword means is that the first value in the list is 0 and all values after that are incremented by 1. So if 2None is 0, wSword would be 1, wBeam 2, wSBomb 5, etc. This changes when you get to the EnemyWeapons. As you can see, wEnemyWeapons is 128. That isn't actually used by the engine, it's just a marker. From there, ewFireball is 129, ewArrow is 130, etc etc.

So for your fireballs, you want to use the number 129 for that purpose. New constants should be included in std.zh for the next version.

So are fully aim-able projectiles implemented in 758?

EDIT: Where does the angle of an enemy projectile measure from? That is, which way does an angle of 0 go? And does the angle measure clockwise or counterclockwise?

The angle's origin is directly to the right of center. For Angle, as usual, the angle progresses clockwise. However, for some reason, Allegro needs the angles in the Arc function counterclockwise. Go figure that one out.

Also, part 2!

http://www.youtube.com/watch?v=XAGlpcxbhsU

As you can see, I went a little less 'tease' this time around :P Lots and lots of crap in this script, and writing it has helped me to see a few of the deficiencies in the current engine model. Hopefully they can be addressed as ZC 2.5 comes closer to completion. Also, you all get a quest file and the scripts to look at!... after the next beta is released, which this was done on to address a few annoying bugs that interfered with the scripting.

Next time I'm hoping to get a bit more down and dirty with the primitive drawing functions.

Hahahaha

That was awesome, Jman! Truly bad-ass. I really, REALLY like the boss death animation. Much better than mine. And the boss entry setup was really slick.

Way to put us lowly scripters in our place!

EDIT: I'm having trouble getting the projectiles to DO anything. Is Step a variable like Vx or Vy that will automatically apply itself each frame? Or do we have to move it manually with our script (that is, read Step and move it at Angle ourselves because the engine isn't doing jack?)

F'ing shit. Amazing stuff Jman. But wait, Are you saying that you made the aquamentus about 3x3 via a drawtile? ..And how the hell did you get that awesome intro to work? ....wow. I salute you sir.

C-Dawg wrote:

EDIT: I'm having trouble getting the projectiles to DO anything. Is Step a variable like Vx or Vy that will automatically apply itself each frame? Or do we have to move it manually with our script (that is, read Step and move it at Angle ourselves because the engine isn't doing jack?)

Here's some stuff I messed around with. Works great for the most part. Really neat stuff:

ffc script eweap_test{

void run(){

int attack_delay;

while(true){

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

if(attack_delay>0)attack_delay--;

else{
eweapon laser = Screen->CreateEWeapon(129);
laser->X=tx;laser->Y=ty+8;
laser->Dir=1;laser->Step=4;
laser->Damage=2;
laser->CSet=0;
attack_delay=3;
}
}
}
}

					eweapon laser;
laser = Screen->CreateEWeapon(129);
laser->X=tx;laser->Y=ty;laser->Step=2;laser->Damage=2;laser->CSet=0;
laser->Angular=true;laser->Angle = 90*(PI/180);

It's not working that way, though. Whether I use Fireball's number, or some new number for a dummy weapon, I set Step to something... and no reaction.