Jump to content

Photo

tango.zh


  • Please log in to reply
398 replies to this topic

#331 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 19 July 2017 - 01:29 AM

First off, thanks for the above help! Tango_SlotIsFinished() worked perfectly for what I needed.

My main point though... I think I might have found a tango bug. This is a little complex, so bear with me. What I'm attempting to do is add flavor text to my custom subscreen. Previously, my system worked like this. When the subscreen initialized, it called a PickSubscreenMessage() function. This function ran through a series of if statements, checking the character you were playing and the dmap you were on, then loaded the proper strings into tango slots. I then had another function in the subscreen's update loop play the tango slots in sequential order, using Tango_SlotIsFinished() to time them, mimicking a conversation taking place. So the function looked something like this.
 
int PickSubscreenMessage(){
	if(Link->Item[EMILY_RING] || Link->Item[LUCAS_RING] || Link->Item[CAELAN_RING]){
		if(Game->GetCurDMap() == 1 || Game->GetCurDMap() == 23){ //Caverns
			int String1[] = "How far do you think these caves go?";
			int String2[] = "Only one way to find out.";
			SetTangoSubscreenMessage(String1, STYLE_LUCAS, 0, 40, 106);
			SetTangoSubscreenMessage(String2, STYLE_EMILY, 1, 40, 138);
			return 1;
		}
		if(Game->GetCurDMap() == 2){
			//And so on...
		}
	}
}
This worked at first, until I kept adding DMap checks, with each if statement having 2-4 strings being declared inside. This apparently caused a stack overflow that would sometimes hang ZC and other times would cause tango to give me Error 0 (no such error exists) and just not print any strings.

To get around this stack overflow problem, I figured I could put each dmap's strings in their own function. That way, no one function would contain enough strings to cause a stack overflow. So now my system looks something like this.
 
int PickSubscreenMessage(){
	if(Link->Item[EMILY_RING] || Link->Item[LUCAS_RING] || Link->Item[CAELAN_RING]){
		if(Game->GetCurDMap() == 1 || Game->GetCurDMap() == 23){ //Caverns
			CavernsMessages();
		}
		if(Game->GetCurDMap() == 2){
			//And so on...
		}
	}
}

int CavernsMessages(){
	if(Link->Item[EMILY_RING] || Link->Item[LUCAS_RING] || Link->Item[CAELAN_RING]){
		int String1[] = "How far do you think these caves go?";
		int String2[] = "Only one way to find out.";
		SetTangoSubscreenMessage(String1, STYLE_LUCAS, 0, 40, 106);
		SetTangoSubscreenMessage(String2, STYLE_EMILY, 1, 40, 138);
		return 1;
	}
}
I thought that would solve the problem. Instead... it hangs ZC. Tracing revealed that the SetTangoSubscreenMessage function was the offender, so I did some more tracing there. Here's what it looked like (with some traces added to figure out where it was hanging).
 
void SetTangoSubscreenMessage(int message, int style, int slot, int x, int y){ // x should be 40, y 106 for first and 138 for second
	Trace(1);
	Trace(slot);
	Tango_ClearSlot(slot);
	Trace(2);
	Trace(slot);
	Tango_LoadString(slot, message);
	Trace(3);
	Tango_SetSlotStyle(slot, style);
	Trace(4);
	Tango_SetSlotPosition(slot, x, y);
	Trace(5);
}
There's a good reason for tracing slot multiple times, as will become apparent later. Here's what I get when I load the quest and open the subscreen.
 
1.0000
0.0000
2.0000
0.0000
tango.zh: 
No error could even print. Wonderfully helpful. I was concerned that maybe passing strings into the function was the problem, so I added a dummy string to the function to see if that fixed it.
 
void SetTangoSubscreenMessage(int message, int style, int slot, int x, int y){ // x should be 40, y 106 for first and 138 for second
	Trace(1);
	Trace(slot);
	Tango_ClearSlot(slot);
	Trace(2);
	Trace(slot);
	int String[] = "Test";
	Tango_LoadString(slot, String);
	Trace(3);
	Tango_SetSlotStyle(slot, style);
	Trace(4);
	Tango_SetSlotPosition(slot, x, y);
	Trace(5);
}
And now, attempting to open the subscreen the first time generates a tango error and terminates the script, and attempting to open it a second time hangs ZC. Here's what I get now, pressing start twice (the first time apparently terminating the script, the second time hanging ZC):
 
1.0000
0.0000
2.0000
0.0000
tango.zh: tango.zh error: Invalid slot specified.
Slot was 10.0000; valid slots are integers from 0 to 9
1.0000
0.0000
2.0000
0.0000
tango.zh: 
So I see multiple issues which may all stem from the same source. For starters, tango is somehow becoming very confused on what slot I'm referencing. Despite it tracing that slot is 0, on the very next line, when it attempts to load a string into that slot, it panics, thinking that the slot is in fact 10. Furthermore, this is causing ZC to hang without even printing an error at times, happening immediately if I load a string via a an argument in the function and only on the second attempt at running the function when I declare a string within the function.

Needless to say, I'm a little lost here. I don't feel like I'm doing anything wrong; it seems like tango's just freaking out on me, and I don't understand the inner workings nearly enough to address the issue myself. Is this a tango bug? Or am I doing something wrong here?

Unrelated to the above, but I do have a suggestion for the next version of tango (if that ever happens). Could we get functions like Tango_GetSlotPosition? I made a function to draw character portraits to accompany their strings, with the portrait depending on the string's style, and I had to do some stupid stuff with internal variables to get it working...
 
int dataStart=i*__TANGO_SIZEOF_DATA; //My oh my
int CurrentX = __Tango_SlotData[dataStart+__TSDIDX_SCREEN_X]; //We appear to be on an internal variable amusement park ride 
int CurrentY = __Tango_SlotData[dataStart+__TSDIDX_SCREEN_Y]; //Life is suffering and I just make witty remarks to stay sane
int Style = __Tango_SlotData[dataStart+__TSDIDX_STYLE]; //Why did I sign up for this?
I feel like having to dig through the inner workings of the library shouldn't be required for something as simple as this (and boy did that take me a while...). Though on the plus side, tango's much less of a black box to me than it was a month ago. :P

#332 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 19 July 2017 - 09:55 AM

... Huh. I think there must still be something going on on ZC's end, but I don't know what it might be.

No error could even print. Wonderfully helpful.

That one's not even an error; it should just be a message saying the string is loading. There's not much that could be going wrong there. If it's failing even to print that, I think either the arguments are getting corrupted or it's failing to allocate the string, and the latter would probably print an error at some point.
If that's reproducible, try this: in __Tango_LogMessage() in loggingFull.zh, add Trace(msg). If it's not 1, something's wrong there.

I don't know. I'm not coming up with much at the moment.
 

Unrelated to the above, but I do have a suggestion for the next version of tango (if that ever happens). Could we get functions like Tango_GetSlotPosition?

Absolutely. I'm surprised I didn't do that already. (There is a Tango_GetSlotStyle() already, though.)

#333 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 19 July 2017 - 01:15 PM

If that's reproducible, try this: in __Tango_LogMessage() in loggingFull.zh, add Trace(msg). If it's not 1, something's wrong there.

Alright, I wasn't sure where I should add the Trace, so I figured I should just add it twice, once at the beginning, once at the end, like so:

Spoiler


Here's my allegro results:
 
1.0000
0.0000
2.0000
0.0000
1.0000
tango.zh: tango.zh error: Invalid slot specified.
Slot was 10.0000; valid slots are integers from 0 to 9
1.0000
0.0000
2.0000
0.0000
1.0000
tango.zh: 
It is tracing 1, so that's a good sign, right?

Overall, I'm a bit concerned now, I guess. It should be working but it simply isn't, and it sounds like it's uncertain if ZC or tango is the culprit here. Assuming we just can't figure this out, do I have any alternatives here? Really, I just need some way of loading strings into slots based on character and dmap, and I'm willing to make this however silly or absurd it needs to be to avoid ZC imploding.

(There is a Tango_GetSlotStyle() already, though.)


... huh. Guess I'm blind.

#334 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 19 July 2017 - 01:38 PM

Something else I should have thought of: try calling Tango_ValidateConfiguration() at the beginning of the global script. That will try to identify any configuration errors and log a report to allegro.log.
 

It is tracing 1, so that's a good sign, right?

It's a good thing in itself, but then I don't know why it would be failing to print anything further. If it's failing to allocate an array, ZC should catch that and log an error. And I don't think that should be happening anyway.
 

Assuming we just can't figure this out, do I have any alternatives here? Really, I just need some way of loading strings into slots based on character and dmap, and I'm willing to make this however silly or absurd it needs to be to avoid ZC imploding.

I'm sure we can come up with something. If you remove some of those XXXMessages functions, do the remaining ones work?

#335 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 19 July 2017 - 01:57 PM

Something else I should have thought of: try calling Tango_ValidateConfiguration() at the beginning of the global script. That will try to identify any configuration errors and log a report to allegro.log.

This wasn't very telling.

Spoiler


The slots overlapping isn't an issue; since only two consecutive slots are ever active at once on the subscreen, I have every other slot occupy the same slot on the bitmap just to make life easier on me. Other than that, it didn't find any errors.

If you remove some of those XXXMessages functions, do the remaining ones work?

I removed all but one of them. The one remaining still doesn't function.

Thank you for all your help, by the way. I don't think I'd ever be able to work through this on my own.

#336 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 19 July 2017 - 02:17 PM

Sure, glad to help out. And I still haven't ruled out a tango.zh bug. Definitely would want to find it if that's the problem.

Something I just noticed...
 
int PickSubscreenMessage(){
	if(Link->Item[EMILY_RING] || Link->Item[LUCAS_RING] || Link->Item[CAELAN_RING]){
		if(Game->GetCurDMap() == 1 || Game->GetCurDMap() == 23){ //Caverns
			int String1[] = "How far do you think these caves go?";
			int String2[] = "Only one way to find out.";
			SetTangoSubscreenMessage(String1, STYLE_LUCAS, 0, 40, 106);
			SetTangoSubscreenMessage(String2, STYLE_EMILY, 1, 40, 138);
			return 1;
		}
		if(Game->GetCurDMap() == 2){
			//And so on...
		}
	}
}
int PickSubscreenMessage(){
	if(Link->Item[EMILY_RING] || Link->Item[LUCAS_RING] || Link->Item[CAELAN_RING]){
		if(Game->GetCurDMap() == 1 || Game->GetCurDMap() == 23){ //Caverns
			CavernsMessages();
		}
		if(Game->GetCurDMap() == 2){
			//And so on...
		}
	}
}

int CavernsMessages(){
	if(Link->Item[EMILY_RING] || Link->Item[LUCAS_RING] || Link->Item[CAELAN_RING]){
		int String1[] = "How far do you think these caves go?";
		int String2[] = "Only one way to find out.";
		SetTangoSubscreenMessage(String1, STYLE_LUCAS, 0, 40, 106);
		SetTangoSubscreenMessage(String2, STYLE_EMILY, 1, 40, 138);
		return 1;
	}
}
Maybe it's just missing from those snippets, but it looks like PickSubscreenMessage is no longer returning a value. Any chance that would cause problems?
But even if it does, that can't explain everything.

One other thing to try. At the beginning of __Tango_LoadString() (loading.zh, line 57), Trace(slot). If slot is really 10 there, something is badly broken. If not... Maybe I just screwed up the validation somehow.

And you do have the quest rule to log script errors enabled, right? Just have to make sure.

#337 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 19 July 2017 - 02:34 PM

Maybe it's just missing from those snippets, but it looks like PickSubscreenMessage is no longer returning a value. Any chance that would cause problems?
But even if it does, that can't explain everything.

Oh. Yeah, it is missing from those snippets. Actually, it's more that I made a quick edit in my post rather than copying the snippet; the PickSubscreenMessage does return by means of "return CavernsMessage();".

One other thing to try. At the beginning of __Tango_LoadString() (loading.zh, line 57), Trace(slot). If slot is really 10 there, something is badly broken. If not... Maybe I just screwed up the validation somehow.

It is returning 0, not 10, so that's good. But...

And you do have the quest rule to log script errors enabled, right? Just have to make sure.

:doh: I thought I did. Turns out I didn't. This is what I get for juggling three quests at once. With that turned on, here's what I get (with my annotations).

1.0000 //These traces are from the SetTangoSubscreenMessage function
0.0000
2.0000
0.0000
0.0000 //This is the result of tracing slot in __Tango_LoadString() 
tango.zh: Global script 2 (RhoneActive): Stack over or underflow, stack pointer = 0
Global script 2 (RhoneActive): Stack over or underflow, stack pointer = 0
Global script 2 (RhoneActive): Invalid ZASM command 57344 reached
Global script 2 (RhoneActive): Invalid ZASM command 32768 reached
Global script 2 (RhoneActive): Stack over or underflow, stack pointer = 0
tango.zh error: Invalid slot specified.
Slot was 10.0000; valid slots are integers from 0 to 9 //This is the point at which the subscreen script terminates after pressing start the first time
1.0000 //Now this begins after pressing start the second time
0.0000
2.0000
0.0000
0.0000
tango.zh: Global script 2 (RhoneActive): Stack over or underflow, stack pointer = 0
Global script 2 (RhoneActive): Invalid pointer (50) passed to array (don't change the values of your array pointers)
Global script 2 (RhoneActive): Invalid pointer (50) passed to array (don't change the values of your array pointers)
//This same message is printed ad infitinum, until I reset ZC, at which point this is printed
Global script 2 (RhoneActive): Invalid ZASM command 65535 reached
I don't pretend to be able to interpret it all, but I can clearly see that something's not right here. I'm admittedly confused why the apparent stack overflow terminates the script on the first attempt but hangs ZC on the second.

#338 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 19 July 2017 - 03:02 PM

Once the stack overflows, there's no telling what will happen. Really, it ought to stop running at that point. It never ends well.

The stack size depends on the function call depth and local variables, including function arguments. No telling without seeing it how much restructuring it'll take to get it down, but maybe you could make some local variables global or put them into arrays. It may be enough just to strcpy the strings into global arrays, then load them into Tango later on from a shallower function depth.

#339 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 19 July 2017 - 03:14 PM

I see... Well, good to know, though it is a bit upsetting to hear. This was already my attempt to get around stack overflows by minimizing the amount of local variables, so I guess short of making all the strings global, there's not a whole lot I can do.

Pardon my ignorance, but how exactly does strcpy work?

#340 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 19 July 2017 - 03:32 PM

int str[]="A string";
int buffer[32];
strcpy(buffer, str);
// Now buffer contains the same string
It simply copies one array into another until it hits 0. Just make sure the destination array's big enough or it'll hang.

#341 Russ

Russ

    Caelan, the Encouraging

  • Administrators
  • Location:Washington

Posted 19 July 2017 - 05:33 PM

You appear to have solved the problem. With a series of global strings, I can have my XXMessages() functions declare the strings, then strcpy them into the global strings, then have a function that sets up the tango slots and styles but doesn't actually load the string. Then, loading the string into the slot immediately before activating the slot works. I'm not gonna pretend it's not dumb, but it works, so that's enough for me. Thanks for the help!

#342 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 10 September 2017 - 08:42 PM

Updated. Not a big update, but whatever.
  • Added Tango_GetSlotX() and Tango_GetSlotY().
  • __Tango_PressAdvance() now takes an argument indicating how long the slot has been waiting. This allows the slot to advance if A or B are held for a period of time.
  • It's now possible to highlight text in alternate colors with [[double brackets]]. You can set different colors for (( )) [[ ]] << >> and {{ }}.

  • Russ likes this

#343 ywkls

ywkls

    Master

  • Members

Posted 10 September 2017 - 09:43 PM

@Saffith- Not exactly related to tango.zh; but were the updated versions of this and ghost.zh supposed to be entered in the database as separate entries from the previous ones?



#344 Saffith

Saffith

    IPv7 user

  • ZC Developers

Posted 10 September 2017 - 09:45 PM

... Nope, not sure what happened there. I'll see about getting that corrected.

#345 Aevin

Aevin

  • Members
  • Pronouns:He / Him
  • Location:Oregon

Posted 11 September 2017 - 12:16 AM

The old submissions for tango and ghost should now be updated appropriately, but I'd suggest double checking your file versions if you update in case I messed something up.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users