PDA

View Full Version : Problem Writing a Function



ZoriaRPG
12-15-2016, 05:00 PM
Gleeok Saffith

I created some functions to write to Link's tiles (using setlinktile(), not something wholly new), as follows:



//Link.h/cpp

void setTile(int state, int tile, int dir, int flip);
void LinkClass::setTile(int state, int tile, int dir, int flip){
setlinktile(tile, flip, getExtend(state), state, dir);
}

int getExtend();
int LinkClass::getExtend()
{
return walkspr[dir][spr_extend];
}

//ffasm.cpp
{ "SETLINKTILE", 0, 0, 0, 0}

//ffscript.cpp

case SETLINKTILE:
set_link_tile(false);
break;

void set_link_tile(bool v)
{
int state = SH::read_stack(ri->sp + 3) / 10000;
int tile = SH::read_stack(ri->sp + 2) / 10000;
int dir = SH::read_stack(ri->sp + 1) / 10000;
int flip = SH::read_stack(ri->sp + 0) / 10000;
Link.setTile(vbound(state,1,14),vbound(tile,0,6551 9),vbound(dir,0,16),vbound(flip,0,16));
}
//ffscript.h
SETLINKTILE, //0x00F1

//Bytecode.cpp

string OSetLinkTile::toString()
{
return "SETLINKTILE";
}

//Bytecode.h

class OSetLinkTile : public Opcode
{
public:
string toString();
Opcode *clone()
{
return new OSetLinkTile();
}
};

//GLobalSymbols.cpp

//void SetLinkTile(link, int,int,int,int)
{
int id = memberids["SetTile"];
int label = lt.functionToLabel(id);
vector<Opcode *> code;
Opcode *first = new OSetLinkTile();
first->setLabel(label);
code.push_back(first);
code.push_back(new OPopRegister(new VarArgument(EXP2)));
code.push_back(new OPopRegister(new VarArgument(EXP2)));
code.push_back(new OPopRegister(new VarArgument(EXP2)));
code.push_back(new OPopRegister(new VarArgument(EXP2)));
//pop pointer, and ignore it
code.push_back(new OPopRegister(new VarArgument(NUL)));

code.push_back(new OPopRegister(new VarArgument(EXP2)));
code.push_back(new OGotoRegister(new VarArgument(EXP2)));
rval[label]=code;
}

{ "SetTile", ScriptParser::TYPE_VOID, FUNCTION, 0, 1, { ScriptParser::TYPE_LINK, ScriptParser::TYPE_FLOAT, ScriptParser::TYPE_FLOAT, ScriptParser::TYPE_FLOAT, ScriptParser::TYPE_FLOAT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } },



Does any of that look amiss? The function doesn't seem to do a blasted thing...

Also, could someone define what the four values used after the string in the array inside ffasm.cpp do, individually?

Number of args, is the stack inputs, AFAIK, buwhat do the next three values mean? It looks like the first two are meant as boolean flags; and what in the world is 'more'?


These...


//ffasm.cpp
script_command command_list[NUMCOMMANDS+1]=
{
//name args arg1 arg2 more
{ "SETLINKTILE", 0, 0, 0, 0}


It would be nice to have a basic reference on how these relate to the stack, and what arg1, arg2, and more are, specifically.

Also, in the 'would be nice' category:

-=SPOILER=-

I would love to finish these, once I fully comprehend the stack values and operations.

Saffith
12-15-2016, 05:10 PM
Link's tile is calculated in LinkClass::draw(). Any changes are overridden before they become visible.

ZoriaRPG
12-15-2016, 06:22 PM
Link's tile is calculated in LinkClass::draw(). Any changes are overridden before they become visible.

Oh.I thought that stuff like walkspr[dir][spr_extend] held the base tile and that the functions drawing Lijk, read [i[from it[/i], made their offsets based on the clocks, and selected the tile to draw...

Isn't there somewhere that the base tile for each sprite category is stored, from which these calcs are made?

Does the function set otherwise look right? It's my first attempt at making functions to interact directly with the stack, so I want to know if I did it wrongly.

I also wrote some things for setting and getting the extend value, which should work. Would you mind proofing how I'm handling pushing values onto, and reading values from the stack; and outlining any errors?

Extend Setter/Getter as a Link->Function()
-=SPOILER=-

ZoriaRPG
12-16-2016, 12:55 AM
Gleeok: Clearly, my comprehension of how to create a ZScript function, and opcodes to match, is lacking. I can make variables easily-enough, but I'm not using the correct accumulators, or something with these functions, or I'm failing somewhere in that department.

Is there some chance that you could write up a procedural, that demonstrates how to make a simple zscript function, that accepts one arg, and passes it to an internal zc class.function; then how to add a second, and third input; and likewise for a function that returns a value instead of passing it to an internal call?

What does Couldn't find function label #1820 mean, in context?

DarkDragon
12-16-2016, 03:02 AM
Creating a ZScript function is fairly easy: take a look at GlobalSymbols.cpp. Find the appropriate symbol table and add your function and its parameters as a new row at the bottom. Then function implementations follow the symbol table; just add your implementation (in terms of ZASM opcodes) at the bottom of the appropriate block. You should be able to figure out the ropes by looking at how similar functions are implemented.

If you are just adding a function, and no new syntax, to ZScript, that is all you need to do. You don't even need to touch the parser itself.

EDIT: And if you are adding a new ZASM operator, you will need to add it to ByteCode.h / ByteCode.cpp in order for ZScript to use it. Again, it shouldn't be too tricky to follow the existing examples.

ZoriaRPG
12-16-2016, 03:40 AM
Creating a ZScript function is fairly easy: take a look at GlobalSymbols.cpp. Find the appropriate symbol table and add your function and its parameters as a new row at the bottom. Then function implementations follow the symbol table; just add your implementation (in terms of ZASM opcodes) at the bottom of the appropriate block. You should be able to figure out the ropes by looking at how similar functions are implemented.

If you are just adding a function, and no new syntax, to ZScript, that is all you need to do. You don't even need to touch the parser itself.

EDIT: And if you are adding a new ZASM operator, you will need to add it to ByteCode.h / ByteCode.cpp in order for ZScript to use it. Again, it shouldn't be too tricky to follow the existing examples.

That is in fact, precisely what I was doing, but somewhere in the process I crossed meself up. Look at the functions above, and all of my implementation. They (1) don' work, and (2) return a quirky error (each):
Couldn't find function label #1820
and
Couldn't find function label #1821

I don't know what this is supposed to mean. What does it mean by 'function label', specifically, and what are those numeric values, and to what do they correspond?!

One function is supposed to take four inputs, and modify a variable based on them. A second, does the same, using three inputs. The last, takes two inputs, uses them to get a return in an internal function, and pass that return back to the user via ZScript.

Would you be so kind as to look at those above, see if you can spot the flaws, point them out, and explain what I did wrongly?

I believe one of my failings, is that I used functions intended to pass a value to an existing array pointer, but I've been reading, and re-reading these things all day, and I'm losing track of the accumulators, and such. That's why a simple procedural, do this, pop these stack registers (and why) would be useful.

I'm trying to write a manual for this as I go along, and creating ZScript functions is my only real stumbling point. I've outlined the process of making new setters, getters; making new registers, making new script commands, and making new drawing commands; but this has me going in such circles, that I'm dripping sanity from me ears.

Having some basic docs on how to properly read params passed into a ZScript function from the stack, and how to write values to the stack and return the to the user, would be delicious.

My whole latest package is here:

Beta 23 Sources (http://timelord.insomnia247.nl/zc/zc_dev/ZC_2.54_Sources_Beta_23.zip)

Have a look at ChangeLog.txt if you diff it and get lost at all. The additions in question are all outlined in this thread though, so that may help.

I know that the fault is in the stack functions, in GlobalSymbols.cpp, in the functions directly (ffscript.cpp), or in the string opcode redirects such as:



string OGetLinkExtend::toString()
{
return "GETLINKEXTEND " + getArgument()->toString();
}


in ByteCode.cpp.

The defines, and script_commands entries are all fine, AFAIK. Certainly, I had no trouble adding to these in the past, unless I've surpassed some limit of them that I didn't know existed.

I'd also rather know both how, and why something works the way that it does, and how and why to do things a set way; than to fake it with copy-paste-code.

As an example:



//void SetLinkTile(link, int,int,int,int)
{
int id = memberids["SetTile"];
int label = lt.functionToLabel(id);
vector<Opcode *> code;
Opcode *first = new OSetLinkTile();
first->setLabel(label);
code.push_back(first);
code.push_back(new OPopRegister(new VarArgument(EXP2))); //!ZoriaRPG this can't be right
code.push_back(new OPopRegister(new VarArgument(EXP2))); //only one expr accumulator?
code.push_back(new OPopRegister(new VarArgument(EXP2)));
code.push_back(new OPopRegister(new VarArgument(EXP2)));
//pop pointer, and ignore it
code.push_back(new OPopRegister(new VarArgument(NUL)));

code.push_back(new OPopRegister(new VarArgument(EXP2)));
code.push_back(new OGotoRegister(new VarArgument(EXP2)));
rval[label]=code;
}


I don't know if this is right, but if it is, why expression accumulator 2?

I don't know what the two accumulators do, off-hand. I can guess, but it feels as if I should be using EXP1 to store the script args?

I would be able to do so much more with just a small amount of documentation, from which I can build more comprehensive docs over time. :(

...or stuff like this...



long ID = SH::get_arg(sarg1, v) / 10000;


So, is that a script arg, or is that EXPR1? If it's a script arg, why are only two defined? sarg3 and above don't exist.

Obviously, I need to look at get_arg(), but you can see how easy it is to become lost.

At least I understand this:



int state = SH::read_stack(ri->sp + 2) / 10000;
int extend = SH::read_stack(ri->sp + 1) / 10000;
int dir = SH::read_stack(ri->sp + 0) / 10000;


...but why is the arg order reversed? Is it because they are read off the stack in FILO? That's me guess, but I detest needing to guess.

DarkDragon
12-16-2016, 04:34 AM
When are you getting these errors? At the time you compile the source? Compile the ZScript? Run the ZASM?

What will help is if you install a fresh version of 2.50.3, and then create a patch containing the new command (and nothing else). If it's giving you the same errors, link me to the patch, and I will take a look.

ZoriaRPG
12-16-2016, 04:39 AM
When are you getting these errors? At the time you compile the source? Compile the ZScript? Run the ZASM?

What will help is if you install a fresh version of 2.50.3, and then create a patch containing the new command (and nothing else). If it's giving you the same errors, link me to the patch, and I will take a look.

Those errors are dumped to allegro.log during compilation of the ZScript (in ZQuest). I need to search the source for the string that generates them, to see where it pulls the IDs.

If what I'm doing now does the same thing, I'll try getting you a clean repo with only this, but literally everything else that I have implemented, that is enabled, works. 98% of it is script drawing, and class variable setter/getter stuff.

( If we had a clean repo for a 'next' build, i would clone it, patch all of this in, and add it to a fork of it, so that a diff would be easier. )

DarkDragon
12-16-2016, 04:45 AM
I'm wondering, though, if one of your other changes might have accidentally screwed up the symbol table (so that the other feature itself works, but causes all later function labels to be wrong, or something).

Gleeok
12-16-2016, 04:54 AM
Creating a ZScript function is fairly easy:

You have got to be kidding, dood! :P

I'm usually not a fan of writing heavy c++ metatemplate wrappers and generators, and hiding the whole mess cleverly in MACROS, but if I were to start over with adding new major additions to ZScript I would do this and scrap the current system.

ZoriaRPG: This is why when you asked me to add new functions to ZScript I wait until I have to do a bunch of them first and then do them all at once.

Since you were complaining about angelscript before: Here's how you add something new to scripts in angelscript:


engine->RegisterObjectMethod(className, "IGameObject@ create(const String &in)", asFUNCTIONPR(Create, callConvType);


;)

As for the errors, I need to take a look.

ZoriaRPG
12-16-2016, 05:03 AM
I think that I may have found the cause of that bizarre error, so I'm testing now. I managed to get everything to compile in ZQ without generating it, so I am reverting one change to see if it was the cause. if not, then I will have at least narrowed the possibilities.

The functions compile now, but they do not return or set the correct values, so clearly something in my method is wrong.

Gleeok : You should wait a little bit, until i post the revised code, as that at least doesn't spill errors, and thank you.

...also...

I know that AS would be easier. I'm not against AS... I'm against deprecating ZScript. I think they could coincide, but Saffith is against that because of the extra work. What can I say?

But give me credit for adding so much stuff that does work without breaking everything/ Getting those warp sounds not to conflict was a pain, and I think I'm going to do some mild rewrites of the warp code so that it's easier to handle this sort of thing, and to segregate these into individual vars, so that it is easy for the user to set up sounds per type, and to enable/disable them at will.

How is the merge of the script drawing stuff going?

We're working on migrating to ag 4.4.2 over on our end, in theory.

Gleeok & DarkDragon : Between the three of us, I think we could make a very good, succinct, compact, master doc for adding ZScript. What do you say? I can make the majority of it, and pass it to you two to fill in the blanks, and clarify things.

DarkDragon
12-16-2016, 05:07 AM
Well, it's easy compared to other changes like modifying the language grammar or adding support for arrays or strings, etc ;)

Gleeok
12-16-2016, 05:11 AM
It's also easier than writing my own scripting language, in fairness. ;)




How is the merge of the script drawing stuff going?

I'm not doing anything until the master branch gets sorted out. :( Also, it's the holidays and I probably won't get around to anything major until January.

ZoriaRPG
12-16-2016, 05:20 AM
Here is the entire set of code sections across all the files for these three functions.

Gleeok DarkDragon, this should be a cleaner way to look at it:



//Beta 24

//////////////
/// link.h ///
//////////////

void setTile(int state, int tile, int dir, int flip);
int getExtend(int state, int dir);
void setExtend(int state, int dir, int value);


////////////////
/// link.cpp ///
////////////////

//Set Link's tile
//Link->SetTile(state, tile, dir, flip)
void LinkClass::setTile(int state, int tile, int dir, int flip){
setlinktile(tile, flip, getExtend(state,dir), state, dir);
}

//Link->Extend

void LinkClass::setExtend(int state, int dir, int value){
switch(state){
case 1:
walkspr[dir][spr_extend] = value;
break;
case 2:
floatspr[dir][spr_extend] = value;
break;
case 3:
swimspr[dir][spr_extend] = value;
break;
case 4:
divespr[dir][spr_extend] = value;
break;
case 5:
slashspr[dir][spr_extend] = value;
break;
case 6:
jumpspr[dir][spr_extend] = value;
break;
case 7:
chargespr[dir][spr_extend] = value;
break;
case 8:
stabspr[dir][spr_extend] = value;
break;
case 9:
poundspr[dir][spr_extend] = value;
break;
case 10:
castingspr[spr_extend] = value;
break;
case 11:
holdspr[spr_landhold][spr_hold1][spr_extend] = value;
break;
case 12:
holdspr[spr_landhold][spr_hold2][spr_extend] = value;
break;
case 13:
holdspr[spr_waterhold][spr_hold1][spr_extend] = value;
break;
case 14:
holdspr[spr_waterhold][spr_hold2][spr_extend] = value;

default: break;
}
}

int LinkClass::getExtend(int state, int dir){
switch(state){
case 1:
return walkspr[dir][spr_extend];
case 2:
return floatspr[dir][spr_extend];
case 3:
return swimspr[dir][spr_extend];
case 4:
return divespr[dir][spr_extend];
case 5:
return slashspr[dir][spr_extend];
case 6:
return jumpspr[dir][spr_extend];
case 7:
return chargespr[dir][spr_extend];
case 8:
return stabspr[dir][spr_extend];
case 9:
return poundspr[dir][spr_extend];
case 10:
return castingspr[spr_extend];
case 11:
return holdspr[spr_landhold][spr_hold1][spr_extend];
case 12:
return holdspr[spr_landhold][spr_hold2][spr_extend];
case 13:
return holdspr[spr_waterhold][spr_hold1][spr_extend];
case 14:
return holdspr[spr_waterhold][spr_hold2][spr_extend];
default: return -1;
}
}


/////////////////
/// ffasm.cpp ///
/////////////////

{ "SETLINKTILE", 0, 0, 0, 0},
{ "SETLINKEXTEND", 0, 0, 0, 0},
{ "GETLINKEXTEND", 2, 0, 0, 0},


//////////////////
/// ffscript.h ///
//////////////////

SETLINKTILE, //0x00F1
SETLINKEXTEND, //0x00F2
GETLINKEXTEND, //0x00F3


////////////////////
/// ffscript.cpp ///
////////////////////

case SETLINKTILE:
Z_message("Trying to set Link's tile.\n");
set_link_tile(false);
break;

case SETLINKEXTEND:
Z_message("Trying to set Link->SetExtend().\n");
set_link_extend(false);
break;

case GETLINKEXTEND:
Z_message("Trying to get Link->GetExtend().\n");
get_link_extend(true);
break;



void set_link_tile(bool v)
{
int state = SH::read_stack(ri->sp + 3) / 10000;
int tile = SH::read_stack(ri->sp + 2) / 10000;
int dir = SH::read_stack(ri->sp + 1) / 10000;
int flip = SH::read_stack(ri->sp + 0) / 10000;
Link.setTile(vbound(state,1,14),vbound(tile,0,6551 9),vbound(dir,0,16),vbound(flip,0,16));
}

void set_link_extend(bool v)
{
int state = SH::read_stack(ri->sp + 2) / 10000;
int extend = SH::read_stack(ri->sp + 1) / 10000;
int dir = SH::read_stack(ri->sp + 0) / 10000;
Link.setExtend(vbound(state,1,14),vbound(dir,0,16) ,vbound(extend,0,16));
}

void get_link_extend(bool v)
{
int state = SH::read_stack(ri->sp + 1) / 10000;
int dir = SH::read_stack(ri->sp + 0) / 10000;
int extend = (int)Link.getExtend(state, dir);
set_register(sarg1, extend*10000);
}

//////////////////
/// Bytecode.h ///
//////////////////

#define LINKEXTEND 392
#define SETLINKEXTEND 393
#define GETLINKEXTEND 394


class OSetLinkTile : public Opcode
{
public:
string toString();
Opcode *clone()
{
return new OSetLinkTile();
}
};

class OSetLinkExtend : public Opcode
{
public:
string toString();
Opcode *clone()
{
return new OSetLinkExtend();
}
};

class OGetLinkExtend : public BinaryOpcode
{
public:
OGetLinkExtend(Argument *A, Argument *B) : BinaryOpcode(A,B) {}
string toString();
Opcode *clone()
{
return new OGetLinkExtend(a->clone(), b->clone());
}
};

////////////////////
/// Bytecode.cpp ///
////////////////////

string OSetLinkTile::toString()
{
return "SETLINKTILE";
}

string OSetLinkExtend::toString()
{
return "SETLINKEXTEND";
}
string OGetLinkExtend::toString()
{
return "GETLINKEXTEND " + getFirstArgument()->toString() + "," + getSecondArgument()->toString();
}

/////////////////////////
/// GLobalSymbols.cpp ///
/////////////////////////

{ "SetTile", ScriptParser::TYPE_VOID, FUNCTION, 0, 1, { ScriptParser::TYPE_LINK, ScriptParser::TYPE_FLOAT, ScriptParser::TYPE_FLOAT, ScriptParser::TYPE_FLOAT, ScriptParser::TYPE_FLOAT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } },
{ "SetLinkExtend", ScriptParser::TYPE_VOID, FUNCTION, 0, 1, { ScriptParser::TYPE_LINK, ScriptParser::TYPE_FLOAT, ScriptParser::TYPE_FLOAT, ScriptParser::TYPE_FLOAT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } },
{ "GetLinkExtend", ScriptParser::TYPE_FLOAT, FUNCTION, 0, 1, { ScriptParser::TYPE_LINK, ScriptParser::TYPE_FLOAT, ScriptParser::TYPE_FLOAT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } },

//void SetLinkTile(link, int,int,int,int)
{
int id = memberids["SetTile"];
int label = lt.functionToLabel(id);
vector<Opcode *> code;
Opcode *first = new OSetLinkTile();
first->setLabel(label);
code.push_back(first);
code.push_back(new OPopRegister(new VarArgument(EXP2))); //!ZoriaRPG this can't be right
code.push_back(new OPopRegister(new VarArgument(EXP2))); //only one expr accumulator?
code.push_back(new OPopRegister(new VarArgument(EXP2)));
code.push_back(new OPopRegister(new VarArgument(EXP2)));
//pop pointer, and ignore it
code.push_back(new OPopRegister(new VarArgument(NUL)));

code.push_back(new OPopRegister(new VarArgument(EXP2)));
code.push_back(new OGotoRegister(new VarArgument(EXP2)));
rval[label]=code;
}

//void OSetLinkExtend
{
int id = memberids["SetLinkExtend"];
int label = lt.functionToLabel(id);
vector<Opcode *> code;
Opcode *first = new OSetLinkExtend();
first->setLabel(label);
code.push_back(first);
code.push_back(new OPopRegister(new VarArgument(EXP2))); //!ZoriaRPG this can't be right
code.push_back(new OPopRegister(new VarArgument(EXP2))); //only one expr accumulator, and number two?
code.push_back(new OPopRegister(new VarArgument(EXP2))); //is this extraneous?
//pop pointer, and ignore it
code.push_back(new OPopRegister(new VarArgument(NUL)));

code.push_back(new OPopRegister(new VarArgument(EXP2)));
code.push_back(new OGotoRegister(new VarArgument(EXP2)));
rval[label]=code;
}
//void GetLinkExtend(link, int, int)
{
int id = memberids["GetLinkExtend"];
int label = lt.functionToLabel(id);
vector<Opcode *> code;
//pop off the params
Opcode *first = new OPopRegister(new VarArgument(EXP1));
first->setLabel(label);
code.push_back(first);
code.push_back(new OPopRegister(new VarArgument(EXP2)));
//pop pointer, and ignore it
code.push_back(new OPopRegister(new VarArgument(NUL)));
code.push_back(new OGetLinkExtend(new VarArgument(EXP2), new VarArgument(EXP1)));
code.push_back(new OPopRegister(new VarArgument(EXP2)));
code.push_back(new OGotoRegister(new VarArgument(EXP2)));
rval[label] = code;
}



That function label error was because I was trying to have both setTile and SetTile, with different definitions in GlobalSymbols.cpp. I thought it was case-sensitive, removing the lowercase 'set' from setTile for the setter, and that it would not do this for SetTile uppercase Set) for the function. That part is fixed. All now, that remains, is to determine why the values aren't being read, or set.

I do need to know what the '1' in this set does:



{ "GETSIDEWARPSCR", 1, 0, 0, 0},


...versus the '2' in this set:



{ "GETDMAPTITLE", 2, 0, 0, 0},


Does the '2' signify that the stack is handling two values (one boolean return, one array pointer), or does it signify the number of inputs to the ZScript function? I think it's the former??

I wonder if @jman kept any notes, and if anyone can reach him? It would be interesting to read through any materials that he wrote as refs for himself.

Gleeok
12-16-2016, 05:38 AM
Bad place for typos, right? :P

Now that it's narrowed down a bit; try setting a breakpoint in ffcscript.cpp ; set_register, get_register; inspect the values, and follow through to see what is happening instead of hitting *LINKTILE et. al.

Gleeok
12-16-2016, 05:43 AM
I do need to know what the '1' in this set does:



{ "GETSIDEWARPSCR", 1, 0, 0, 0},


...versus the '2' in this set:



{ "GETDMAPTITLE", 2, 0, 0, 0},


Does the '2' signify that the stack is handling two values (one boolean return, one array pointer), or does it signify the number of inputs to the ZScript function? I think it's the former??

I wonder if @jman kept any notes, and if anyone can reach him? It would be interesting to read through any materials that he wrote as refs for himself.

You ninja'd me.

The 2 is number of args, next is arg 1, arg2 (IIRC). If those are register values then they should be 1, otherwise 0. (I hope I got that right) [edit] No, I didn't. It's 0, otherwise 1...

ZoriaRPG
12-16-2016, 05:45 AM
Bad place for typos, right? :P

Now that it's narrowed down a bit; try setting a breakpoint in ffcscript.cpp ; set_register, get_register; inspect the values, and follow through to see what is happening instead of hitting *LINKTILE et. al.

What's the best way to inspect the stack without a live stack debuger? Throw out ZConsole messages with the values of the expression accumulators?

I'm sort of in the 'how does Gleeok do this' mode...which is why I was hoping for a procedural list from you, on what the flidd you would do; or some kind of step-by-step details on how to build this kind of function in the frrst place.

Gleeok
12-16-2016, 05:54 AM
No wait, 0 means register! #$%^ dammit. :mad:

Also, DarkDragon is much more knowledgeable about the ZScript compiler than I am.



What's the best way to inspect the stack without a live stack debuger? Throw out ZConsole messages with the values of the expression accumulators?

I'm sort of in the 'how does Gleeok do this' mode...which is why I was hoping for a procedural list from you, on what the flidd you would do; or some kind of step-by-step details on how to build this kind of function in the frrst place.

Honestly, I usually half forget some of this stuff, so I just go in order of: 1) Declare constants and opcodes; update script tables; implement compiler procedure as needed; update bytecode in ffscript.cpp; and finally, implement function that gets called.


[edit]
Also, what compiler are you using that doesn't have a debugger?

DarkDragon
12-16-2016, 02:19 PM
ZoriaRPG, to answer your question in your commented lines: the ZScript calling convention is more or less equivalent to C's. The caller first pushes the return address onto the stack, then all of the function's explicit argument, and finally, if the function is a member function, the "this" pointer is implicitly pushed as the last argument.

The return value of the function is by convention stored in EXP1.

The callee, then, before it can return, must pop all of the arguments (including the "this" pointer) off of the stack. That's what the lines are doing that you've commented about. The ZASM instruction uses the top 4 entries of the stack, but leaves them untouched, so ZScript pops them off, then pops off the return address and jumps to it. You could use NUL instead of EXP2 for these pops if you wanted.

The reason EXP2 is used as scratch space instead of EXP1 is simply to avoid accidentally tampering with the return value of the function.

ZoriaRPG
12-18-2016, 11:49 PM
ZoriaRPG, to answer your question in your commented lines: the ZScript calling convention is more or less equivalent to C's. The caller first pushes the return address onto the stack, then all of the function's explicit argument, and finally, if the function is a member function, the "this" pointer is implicitly pushed as the last argument.

The return value of the function is by convention stored in EXP1.

The callee, then, before it can return, must pop all of the arguments (including the "this" pointer) off of the stack. That's what the lines are doing that you've commented about. The ZASM instruction uses the top 4 entries of the stack, but leaves them untouched, so ZScript pops them off, then pops off the return address and jumps to it. You could use NUL instead of EXP2 for these pops if you wanted.

The reason EXP2 is used as scratch space instead of EXP1 is simply to avoid accidentally tampering with the return value of the function.


Got it. Good stuff there; and I put it into the docs. :)

ZoriaRPG
12-25-2016, 04:35 AM
Just a bit of an update. I added in individual setters, just to prove the concept. They do in fact set Link's original tiles, as I expected, but there is an offset from what tile I specify, to what is displayed.

Is thus from the animation style, or should I correct the offset at the function level? I'm going to add one more thing, to set the animation style, and then all that is left to do is to fix the SetTiles function si that each sprite doesn't need it's own idiotic setter.

Fir whatever reason, SetExtend(sprite, dir, extend) worked but SetTile(sprite,dir,tile) didn't, despite the individual setters per tile working.

With extend and tile working, I will move on to setting hotbox sizes. Draw offsets can wait and may never exist, but Hit*Offset and hitwidth/height should be possible.

Gleeok
12-25-2016, 05:04 AM
Just an FYI: Some hitboxes in ZC are not actually correct. Collisions in general should be rewritten. The reason I never did this is because backwards compatibility makes this unreasonably difficult. How correct are they? IDK, depends.

ZoriaRPG
12-25-2016, 02:04 PM
Just an FYI: Some hitboxes in ZC are not actually correct. Collisions in general should be rewritten. The reason I never did this is because backwards compatibility makes this unreasonably difficult. How correct are they? IDK, depends.

I figured that for the present, I would just calculate +offset and for +size in the present maths. That way, scripters can 'correct' them as they see fit. I know that some collisions are just bonkers wrong, and without making a huge list of quest-specific and build-specific compat rules, fixing them is probably unwise. I do not have a reference on what quests 'need' those fixes, and composing it would take forever and 393 days.

Really, the two main types of quests that make use of larger hitboxes, as well as all this rubbish with setting tiles, and extend values, are quests that use a Link that is not 16x16. Any sideview quest falls into this category, as the major grumble from sideview questmakers, is that 16x32 Link has a 16x16 hitbox. If it all pans out, I might do a tiny SMB style demo of it all.

Not that you're wrong here, but I have to concur that the road to rewriting collision is insanely long. I need to rewrite warping first.

-=SPOILER=-