Jump to content

Photo

I have some stuff I'd like help with


  • Please log in to reply
34 replies to this topic

#16 Eragon615

Eragon615

    Junior

  • Members
  • Real Name:Clayton
  • Location:Texas

Posted 21 July 2010 - 03:21 PM

Okay, but what if instead of slot 2 I used an FFC? Each dark screen has a DarkRoom FFC? I think LttP had the same problem anyway. When you scrolled the light completely disappeared didn't it? So could that be done? Just disable the light while scrolling?

#17 Joe123

Joe123

    Retired

  • Members

Posted 21 July 2010 - 03:25 PM

Yeah you could do that, disable the drawing when you scroll screens. Wouldn't look amazing but it'd work.
aLttP had large scrollable areas rather than discrete screens so it didn't really work in the same way.

#18 Eragon615

Eragon615

    Junior

  • Members
  • Real Name:Clayton
  • Location:Texas

Posted 21 July 2010 - 04:48 PM

Well yeah, that's true. Anyway, lemme get started on what I do know, so you guys can help me with what I don't. Let's start with that custom candle. Now, I want both the candle and lantern to use the same new flame. The candle only once, the lantern as many as you have mp for. Do I need to make a separate script for each, or is there a good way to determine which one you're using?

#19 Joe123

Joe123

    Retired

  • Members

Posted 21 July 2010 - 04:50 PM

I think I'd make a separate script personally.

#20 Eragon615

Eragon615

    Junior

  • Members
  • Real Name:Clayton
  • Location:Texas

Posted 21 July 2010 - 05:10 PM

Okay, so The item script should just change a global variable to 1 after checking MP right? Then I make a global slot 2 that activates when that variable is more than 1? Like:

CODE
item script candle{
    void run(){
        if(Link->MP > 16) UseCandle=1;
       else Game->PlaySound(Negative);
    }
}


Umm, yeah. Gotta add the Candle part at the top...

CODE
global script Slot2{
    void run(){
        UseBall = 0;
        while(true){
        doBottleFairy();
        BallAndChain();
        warpcoreaction();
        Candle();
        Waitframe();
        }
    }
    void BallAndChain(){
        if(UseBall == 0) return;
        else if(UseBall < 25) ThrowBall();
        else SpinBall();
....


Like that. And now

CODE
void Candle(){
     if (UseCandle == 0);
          if (Link->Dir = 0);
              


I need to spawn an LWeapon here, yeah? So I need to define the sprite graphic, but beyond that I'm not so sure...

Edited by Eragon615, 21 July 2010 - 05:11 PM.


#21 Joe123

Joe123

    Retired

  • Members

Posted 21 July 2010 - 05:14 PM

Yeah that looks about right to me. You're missing a 'return' in your last code block which makes a huge amount of difference though =P

also there's a big discretion to be made between '==' and '='. You've got them mixed up.

Well what do you want the lweapon to do exactly?
What do you mean by 'define the sprite graphic'?

#22 Eragon615

Eragon615

    Junior

  • Members
  • Real Name:Clayton
  • Location:Texas

Posted 21 July 2010 - 05:31 PM

Yeah, I don't really understand how lweapons are handled. Sometimes I read a script that looks like it defines a new LWeapon, but I thought you can only use the ones already in ZQuest... So in other words, I have no clue how they work.

I want to spawn a little flame in front of Link. I set up the tiles to make it last about a half second. So I define the sprite of the flame as like T_FLAME = 101.
Then I need to spawn that Sprite with the same properties as the original candle so it can still trigger burn flags, and so it can be an enemy weakness.

As for my mistakes, I think I understand the = vs. ==, == is "is it" and = is "it is". I don't understand return though. Care to clarify?

#23 Gleeok

Gleeok

    It's dangerous to dough alone, bake this.

  • Members
  • Real Name:Pillsbury
  • Location:Magical Land of Dough

Posted 21 July 2010 - 06:19 PM

Look in std.zh for a function "CopyEWeapon" or something similar. There is a lot of example weapon code in there.


return says to return to the line where the function was called...basically

void returnit()
{
{
if(true) return;
}
int a = 99;
}

here int a is never 99 as the function returns beforehand. The function must also return it's return type, ex;

int func()
{
return; // error!
return ffc; // not integral type!
return 23; // OK
}

Edited by Gleeok, 21 July 2010 - 06:23 PM.


#24 Eragon615

Eragon615

    Junior

  • Members
  • Real Name:Clayton
  • Location:Texas

Posted 21 July 2010 - 06:33 PM

Um, yeah. I need to add it, got it. Hahaha.

Okay, I looked through std.zh but didn't really find what I was looking for. I'm just trying to make the flame appear in front of Link, based on the direction he's facing, and deal fire damage or trigger burn flags for the duration of it's animation.

Edited by Eragon615, 21 July 2010 - 07:15 PM.


#25 Joe123

Joe123

    Retired

  • Members

Posted 22 July 2010 - 03:49 AM

OK, to add to what Gleeok said, return works like this:

When you write a 'function' it's like saying 'take this chunk of code and place it somewhere else'.
Inside the function, any variables you declare only last for the duration of the function and aren't passed back to where the function is called:
CODE
float multiplier(float x, float y)
{
    int a = x * y;
}

* script foo
{
    void run()
    {
        int b = 5;
        int c = 6;
        int d = multiplier(b, c);
        Trace(d);
    }
}
So my function's meant to multiply together x and y, and then give the value back. You might expect a trace of '5' here, but that's not what you'd get.
Inside the function, I've correctly worked out the value of 'x * y', but I haven't told the compiler to send it back to where the function was called anywhere.

The way you do that is with 'return' - as Gleeok said it means 'pass this value (or object or pointer) back to where the function was called).
So if it was written like this instead:
CODE
float multiplier(float x, float y)
{
    int a = x * y;
    return a; //now we send back the value
}

* script foo
{
    void run()
    {
        int b = 5;
        int c = 6;
        int d = multiplier(b, c);
        Trace(d);
    }
}
We get the correct trace of 30.

The word before the name of the function is what type it returns; in this case the function returns a float. Sometimes though I might want my function not to return anything, and in which case I declare it to be 'void':
CODE
void placelink(int x, int y)
{
    Link->X = x;
    Link->Y = y;
}
Now I can call 'placelink' to put him at a certain set of coordinates.

If a function is 'void' it can't return any value, so the 'return' keyword just ends it's execution at that point and brings the code back to where the function was called. Say we want to place Link but only if he's not currently frozen:
CODE
void placelink(int x, int y)
{
    if(Link->Action == LA_FROZEN)
        return;
    
    Link->X = x;
    Link->Y = y;
}

You could equally write it like this:
CODE
void placelink(int x, int y)
{
    if(Link->Action != LA_FROZEN)
    {
        Link->X = x;
        Link->Y = y;
    }
}
But it puts all of the code up into an extra set of braces, which is why I don't usually do that with my global scripts.





To make an lweapon that's not hard coded appear you just use one of the 'LW_SCRIPT*' lweapon IDs from std.zh, a bit like this:
CODE
lweapon l = Screen->CreateLWeapon(LW_SCRIPT1);
Then whenever you refer to 'l' from now on, it's an lweapon of type 'script1' (in this instance, CreateLWeapon is a function which returns 'lweapon').

If I wanted to make an lweapon, place it and give it a graphic I'd do it like this:
CODE
const int WSP_FLAME = 1; //Make a weapon/misc. sprite and give it the flame's graphics. Much easier than using at tile

* script foo
{
    void run()
    {
        lweapon l = CreateLWeaponAt(LW_SCRIPT*, some coordinates infront of Link);
            //CreateLWeaponAt is another function declared in std.zh which returns lweapon; have a look to see how it works
        l->UseSprite(WSP_FLAME);
        l->Damage = something;
    }
}


#26 Eragon615

Eragon615

    Junior

  • Members
  • Real Name:Clayton
  • Location:Texas

Posted 22 July 2010 - 07:34 PM

Look at this! I did this! It still has some issues, but it compiles and (mostly) works!

CODE
import "std.zh"

const int WSP_FLAME           = 88;

const int SFX_NEG             = 44;

int UseCandle;

global script Slot2{
    void run(){
        while(true){
            NewCandle();
        Waitframe();
        }
    }
    void NewCandle(){
        if (UseCandle == 0) return;
            if (Link->Dir == 0){
                Link->Action = LA_ATTACKING;
                lweapon Flame = CreateLWeaponAt(LW_SCRIPT1, Link->X+8, Link->Y+24);
                Flame->UseSprite(WSP_FLAME);
                Flame->Damage = 2;}
            else if (Link->Dir == 1){
                Link->Action = LA_ATTACKING;
                lweapon Flame = CreateLWeaponAt(LW_SCRIPT1, Link->X+8, Link->Y-8);
                Flame->UseSprite(WSP_FLAME);
                Flame->Damage = 2;}
            else if (Link->Dir == 2){
                Link->Action = LA_ATTACKING;
                lweapon Flame = CreateLWeaponAt(LW_SCRIPT1, Link->X-8, Link->Y+8);
                Flame->UseSprite(WSP_FLAME);
                Flame->Damage = 2;}
            else if (Link->Dir == 3){
                Link->Action = LA_ATTACKING;
                lweapon Flame = CreateLWeaponAt(LW_SCRIPT1, Link->X+24, Link->Y+8);
                Flame->UseSprite(WSP_FLAME);
                Flame->Damage = 2;}
        Link->MP -= 16
        UseCandle = 0
    }
}


item script Candle{
    void run(){
        if(Link->MP >= 16) UseCandle ++;
        else Game->PlaySound(SFX_NEG);
    }
}


So, first issue. I thought Link->Dir was 0 = Up, 1 = Down, 2 = Left, and 3 = Right. So based on a coordinate plane my Flames would be right. Except they aren't. Now I hear somewhere that Link->X or Y had to be + 8 to get centered. Was that wrong? Because my Left and Right flames are sorta off but at least in front of me, but my Up or Down Flames spawn behind me...

Also, how do I cause the flame to disappear after a time? Because right now it stays on screen until it hits an enemy. I do know you have to give it Dead State, but that's all I know.

How do I make a Burn->Next Flag? Say flag 99.

And last but not least, I do want to make my new candle like the original, that is, only one use per screen, but once you use it I want the graphic for it to change to an unlit candle. Then it relights on the next screen if you still have magic.

#27 Joe123

Joe123

    Retired

  • Members

Posted 23 July 2010 - 07:25 AM

QUOTE(Eragon615 @ Jul 23 2010, 01:34 AM) View Post
Look at this! I did this! It still has some issues, but it compiles and (mostly) works!
Well done =)


I'd do it a bit more like this though, makes the code slightly shorter (a few of the things you're doing in the conditional blocks are the same in each one, so you might as well put them outside):
CODE
import "std.zh"

const int WSP_FLAME           = 88;

const int SFX_NEG             = 44;

int UseCandle;

global script Slot2{
    void run(){
        while(true){
            NewCandle();
            Waitframe();
        }
    }
    void NewCandle(){
        if (UseCandle == 0) return;
        
        lweapon Flame;
        if (Link->Dir == DIR_UP) //using the constants makes it more readable
            Flame = CreateLWeaponAt(LW_SCRIPT1, Link->X+8, Link->Y+24);
        else if (Link->Dir == DIR_DOWN)
            Flame = CreateLWeaponAt(LW_SCRIPT1, Link->X+8, Link->Y-8);
        else if (Link->Dir == DIR_LEFT)
            Flame = CreateLWeaponAt(LW_SCRIPT1, Link->X-8, Link->Y+8);
        else if (Link->Dir == DIR_RIGHT)
            Flame = CreateLWeaponAt(LW_SCRIPT1, Link->X+24, Link->Y+8);
            
        Link->Action = LA_ATTACKING;
        Flame->UseSprite(WSP_FLAME);
        Flame->Damage = 2;
        Link->MP -= 16
        UseCandle = 0
    }
}

item script Candle{
    void run(){
        if(Link->MP >= 16) UseCandle ++;
        else Game->PlaySound(SFX_NEG);
    }
}





QUOTE(Eragon615 @ Jul 23 2010, 01:34 AM) View Post
So, first issue. I thought Link->Dir was 0 = Up, 1 = Down, 2 = Left, and 3 = Right. So based on a coordinate plane my Flames would be right. Except they aren't. Now I hear somewhere that Link->X or Y had to be + 8 to get centered. Was that wrong? Because my Left and Right flames are sorta off but at least in front of me, but my Up or Down Flames spawn behind me...
Yeah, they go up down left right. Might make more sense if they went in a circle but you can flip them using bitwise xor they way they are.

Link's X and Y coordinates refer to the top left corner of his hitbox.
I have a couple of functions for putting things near Link, they go like this:
CODE
int AtFrontX(int dir)
{
    int x = 0;
    if(dir == DIR_UP || dir == DIR_DOWN)
        x = 8;
    else if(dir == DIR_RIGHT)
        x = 16;
    return x;
}

int AtFrontY(int dir)
{
    int y = 0;
    if(dir == DIR_DOWN)
        y = 16;
    else if(dir == DIR_LEFT || dir == DIR_RIGHT)
        y = 8;
    return y;
}

int InFrontX(int dir, int dist)
{
    int x = 0;
    if(dir == DIR_LEFT)
        x = -16 + dist;
    else if(dir == DIR_RIGHT)
        x = 16 - dist;
    return x;
}

int InFrontY(int dir, int dist)
{
    int y = 0;
    if(dir == DIR_UP)
        y = -16 + dist;
    else if(dir == DIR_DOWN)
        y = 16 - dist;
    return y;
}

lweapon NextToLink(int id, int distx, int disty)
{    
    lweapon l = CreateLWeaponAt(id, Link->X + InFrontX(Link->Dir, distx), Link->Y + InFrontY(Link->Dir, disty));
    l->Dir = Link->Dir;
    return l;
}

lweapon NextToLink(int id, int dist)
{
    return NextToLink(id, dist, dist);
}


The 'dist' arguments kind of place the item a little bit further or nearer to Link, so you use it like this:
CODE
lweapon l = NextToLink(LW_SCRIPT1, 8);
Or something, it gets rid of the conditional blocks in your code. I might add them to std.zh actually. You can make dist negative if you want it to be 'inside' Link.




QUOTE(Eragon615 @ Jul 23 2010, 01:34 AM) View Post
Also, how do I cause the flame to disappear after a time? Because right now it stays on screen until it hits an enemy. I do know you have to give it Dead State, but that's all I know.
Yeah, just put 'DeadState = numframestilldisappear' I think.



QUOTE(Eragon615 @ Jul 23 2010, 01:34 AM) View Post
How do I make a Burn->Next Flag? Say flag 99.
This is a bit more complicated, you need to loop through the lweapons every frame. It's a bit like this:

CODE
global script Slot2
{
    void run()
    {
        while(true)
        {
            LWeapons();
            Waitframe();
        }
    }
    
    void LWeapons()
    {
        lweapon l;
        for(int i = Screen->NumLWeapons(); i > 0; i--)
        {
            l = Screen->LoadLWeapon(i);
            if(l->ID == LW_SCRIPT1)
                Flame(l);
            else if(l->ID == AnotherLWeapon)
                DoThatLWeaponsAction(l);
        }
    }
    
    void Flame(lweapon Flame)
    {
        if(ComboFI(l->X, l->Y, CF_SCRIPT1))
        {
            l->DeadState = 0;
            Screen->TriggerSecrets();
        }
    }
}

If there's any of that you don't get ask and I'll explain what it's doing.



QUOTE(Eragon615 @ Jul 23 2010, 01:34 AM) View Post
And last but not least, I do want to make my new candle like the original, that is, only one use per screen, but once you use it I want the graphic for it to change to an unlit candle. Then it relights on the next screen if you still have magic.
Oh yeah, this is a bit more complicated. The way I'd do it would be to have two items, one with the graphic of not being lit and one with the graphic of being lit. The lit one would have the item script, and the other one wouldn't. They'd be in the same item class, the unlit one would be level 1 and the lit one would be level 2, they'd have 'Keep Lower Level Items' checked and the higher level one would have the 'Use Up Item After Usage' (or something similar) checked. Then you'd make the lantern level 3.

Then there'd be a section in your global script that checked if you'd changed screen and then it'd 're-light' the candle by giving you the level 2 item if you have the level 1 one.

#28 Eragon615

Eragon615

    Junior

  • Members
  • Real Name:Clayton
  • Location:Texas

Posted 23 July 2010 - 12:16 PM

I thought I might have to do something like that for the lit and unlit, but I was hoping there was a cool scripting way. So to check if I've changed screens, I think I saw a code once that was something like

CODE
if (screen->currentmap != screen->storedmap)


or something like that. Any suggestions there?

I think I can look through some other weapon codes and maybe figure how deadstates work. It's just the command and a timer, right?

And as for triggering the flag, I want it like the trees in the Oracle games that just burn and disappear, not the trigger flags like we have right now. So I think the Screen->TriggerSecrets(); is unnecessary. I've already got your ball and chain script, so flag 98 is taken, but maybe flag 99 could be Flame->Next. I can most likely copy you example script and get it to work, but since you're all about understanding, I'm going to ask a few questions. Actually, I don't really get that at all, haha. I mean, this part

CODE
global script Slot2
{
    void run()
    {
        while(true)
        {
            LWeapons();
            Waitframe();
        }
    }
    


I understand of course, but once you get into this

CODE
    void LWeapons()
    {
        lweapon l;
        for(int i = Screen->NumLWeapons(); i > 0; i--)
        {
            l = Screen->LoadLWeapon(i);
            if(l->ID == LW_SCRIPT1)
                Flame(l);
            else if(l->ID == AnotherLWeapon)
                DoThatLWeaponsAction(l);
        }
    }
    


I start to lose the reasoning. And here

CODE
    void Flame(lweapon Flame)
    {
        if(ComboFI(l->X, l->Y, CF_SCRIPT1))
        {
            l->DeadState = 0;
            Screen->TriggerSecrets();
        }
    }
}


is where it checks for the flag, right? If the combo on the same tile as the lweapon is the flag, deadstate the lweapon and trigger the secrets. 'Xcept when did you tell it which flag to check for? And instead of secrets, again, I'd really like it to be a ->Next style flag.

#29 Joe123

Joe123

    Retired

  • Members

Posted 23 July 2010 - 05:18 PM

QUOTE(Eragon615 @ Jul 23 2010, 06:16 PM) View Post
I thought I might have to do something like that for the lit and unlit, but I was hoping there was a cool scripting way. So to check if I've changed screens, I think I saw a code once that was something like

CODE
if (screen->currentmap != screen->storedmap)


or something like that. Any suggestions there?
Well, using in-built features (when they work well) is usually better.
Yeah it's a bit like that. I'd do this:

CODE
int LastScreen;
global script Slot2
{
    void run()
    {
        while(true)
        {
            ChangeScreenCheck();
            Waitframe();
        }
    }
    void ChangeScreenCheck()
    {
        if(LastScreen != Game->GetCurDMapScreen)
            OnChangeScreen();
        
        LastScreen = Game->GetCurDMapScreen();
    }
    void OnChangeScreen()
    {
        //What you want to do when screen changes goes here
    }
}


QUOTE(Eragon615 @ Jul 23 2010, 06:16 PM) View Post
I think I can look through some other weapon codes and maybe figure how deadstates work. It's just the command and a timer, right?
'and a timer'?

QUOTE(Eragon615 @ Jul 23 2010, 06:16 PM) View Post
And as for triggering the flag, I want it like the trees in the Oracle games that just burn and disappear, not the trigger flags like we have right now. So I think the Screen->TriggerSecrets(); is unnecessary. I've already got your ball and chain script, so flag 98 is taken, but maybe flag 99 could be Flame->Next.
Ohhh, you want a 'Burn->Next' flag rather than a 'trigger' flag. Ok.

QUOTE(Eragon615 @ Jul 23 2010, 06:16 PM) View Post
I can most likely copy you example script and get it to work, but since you're all about understanding, I'm going to ask a few questions. Actually, I don't really get that at all, haha. I mean, this part

*PART WAS HERE*

is where it checks for the flag, right? If the combo on the same tile as the lweapon is the flag, deadstate the lweapon and trigger the secrets. 'Xcept when did you tell it which flag to check for? And instead of secrets, again, I'd really like it to be a ->Next style flag.
Understanding is better =)

CODE
    void LWeapons()
    {
        lweapon l; //Declare a pointer that we're going to store lweapons in
        for(int i = Screen->NumLWeapons(); i > 0; i--) //This loop iterates over each lweapon on the screen. lweapons are
        {                                               //numbered from '1' to 'Screen->NumLWeapons' inclusive, so now we've
                                                       //got some code that has 'i' as the number of each lweapon in turn
            l = Screen->LoadLWeapon(i); //Load the 'ith' lweapon into l
            if(l->ID == LW_SCRIPT1) //If the lweapon's ID is LW_SCRIPT1 (the type that our flame is)
                Flame(l); //Run the flame code
            else if(l->ID == AnotherLWeapon) //You might want to do some stuff with other lweapon types too
                DoThatLWeaponsAction(l);
        }
    }
    


CODE
    void Flame(lweapon Flame) //We pass in the lweapon that we've found is a Flame (so I've called the argument 'Flame'
    {                              //rather than 'l' which was just a generic lweapon)
        if(ComboFI(l->X, l->Y, CF_SCRIPT1)) //If the flag at the position of the lweapon is CF_SCRIPT1 (or 2 or whatever)
        {
            l->DeadState = 0; //Kill the lweapon
            Screen->TriggerSecrets(); //Trigger secrets (or instead, Screen->ComboD[ComboAt(Flame->X, Flame->Y)]++;
                                      //would move the combo to the next one)
        }
    }
}


#30 Eragon615

Eragon615

    Junior

  • Members
  • Real Name:Clayton
  • Location:Texas

Posted 24 July 2010 - 03:23 AM

Okay, lemme see if I got this right. The LWeapon block still scares me a bit, but I think I got it.

CODE
    void LWeapons()
    {
        lweapon l; //Declare a pointer that we're going to store lweapons in
        for(int i = Screen->NumLWeapons(); i > 0; i--) //This loop iterates over each lweapon on the screen. lweapons are
        {                                               //numbered from '1' to 'Screen->NumLWeapons' inclusive, so now we've
                                                       //got some code that has 'i' as the number of each lweapon in turn
            l = Screen->LoadLWeapon(i); //Load the 'ith' lweapon into l
            if(l->ID == LW_SCRIPT1) //If the lweapon's ID is LW_SCRIPT1 (the type that our flame is)
                Flame(l); //Run the flame code
            else if(l->ID == AnotherLWeapon) //You might want to do some stuff with other lweapon types too
                DoThatLWeaponsAction(l);
        }
    }
    


I understand how it works now, but what is the purpose? My code works just fine right now. Does this just put all the LWeapons into a block so I can call them with a simple command? Let me review here... This code puts an ID into the pointer l. If it's script 1 it runs the flame code, or if it's something else it runs another lweapon. So by using LWeapons() I just define the ID and it pulls the script for me? I get the feeling I'm way off here... At least I'm sure I've got the rest down.


1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users