[SOLVED] While loop not updating.

Started by monkey0506, Mon 18/07/2005 21:51:45

Previous topic - Next topic

monkey0506

I have the following function definition for a member function of a struct I'm using, and the game keeps crashing because it says the while loop isn't updating:

Code: ags
/*protected*/ void ScrollingDialog::SetHalfText(int option, string text) {
Ã,  if ((option < 0) || (option > ScrollingDialog_MAX_OPTS))
Ã,  Ã,  AbortGame("Invalid parameter to function ScrollingDialog::SetHalfText parameter 'option'.Ã,  Range from 0 to %d, value %d.", ScrollingDialog_MAX_OPTS, option);
Ã,  readonly int strstart = option * 200;
Ã,  int cindex = strstart;
Ã,  int tindex = 0;
Ã,  while (cindex < strstart + 200) {
Ã,  Ã,  this.HalfText[cindex] = StrGetCharAt(text, tindex);
Ã,  Ã,  cindex++;
Ã,  Ã,  tindex++;
Ã,  Ã,  }
Ã,  }


I start off by checking that the parameter is within the appropriate range because if it isn't then the array index won't work correctly.Ã,  Then I store the starting position of the string I am storing (in a char array of 6000 members (30 strings)).Ã,  Then I create index buffers, one for the char array index (cindex) and one for the string index (tindex).

As the initial value of cindex is the same as that of strstart, and the loop should only be run if the value is less than strstart + 200, I don't see why this code should run more than 200 times, and it updates the value of cindex with each loop.

Also, I have a similar function, which doesn't crash the game:

Code: ags
/*protected*/ void ScrollingDialog::SetText(int option, string text) {
Ã,  if ((option < 0) || (option > ScrollingDialog_MAX_OPTS))
Ã,  Ã,  AbortGame("Invalid parameter to function ScrollingDialog::SetText parameter 'option'.Ã,  Range from 0 to %d, value %d.", ScrollingDialog_MAX_OPTS, option);
Ã,  readonly int strstart = option * 200;
Ã,  int cindex = strstart;
Ã,  int tindex = 0;
Ã,  while (cindex < strstart + 200) {
Ã,  Ã,  this.Text[cindex] = StrGetCharAt(text, tindex);
Ã,  Ã,  cindex++;
Ã,  Ã,  tindex++;
Ã,  Ã,  }
Ã,  }


I can think of one instance where I called something to the effect of "Dialog[dialog].SetHalfText(option, "");", but it should still only run 200 times.Ã,  Even if it somehow threw the loop bounds way out of proportion it should only be capable of running 6000 times before it accesses illegal array indeces (sp?).

Like I said, I don't see how this could run 150000 times, but it keeps crashing my game (I call the function that calls this function from game_start btw).Ã,  I have to go, and I may not be able to get back on for a week...so, I guess I will be back later.

Any help greatly appreciated.

Gilbert

Hmmm did you tried using Display() to check with the variables' values?

Also, try declaring cindex and tindex globally, and see if it's some weird problem happening.

monkey0506

I tried to comment out the line that cleared the text for that option "Dialog[dialog].SetHalfText(option, "")" and it created the same error further up with a Dialog[...].GetText(...) call...which I'm done working with this for now.  I will be going to Oregon tomorrow, coming back Monday, but then I'll be leaving straight from the airport to my sister's house for another week...so it will be about 2 weeks before I have a chance to work with this again.

The wierd thing is that I don't see any reason for it not to be updating.  It is repetetive with a call like SetHalfText(option, ""), but it should only last 200 loops.  So I don't see why it keeps failing.  So, yes, Gilbot, I would assume "it's some weird problem happening".

Gilbert

I just wrote similar stuff and it didn't give me an error.
Can you please check the value of option when the function first starts? (Display("%d",option); ) and try really displaying the indices in the loops.


Theme

maybe the
StrGetCharAt(text, tindex);
is putting a char in a invalid
index of this.HalfText[cindex]
and setting
cindex
to a lower number

o/

monkey0506

Okay, I did get a chance to test it.  So here's the results of trying to display the value of cindex:

0 through 200 displayed.  0 displayed (it skipped?).
0 - 399 (skip) 200.
200 - 599 - 400
400 - 799 - 600
600 - 999 - 800
800 - 1999 - 1000
1000 - 1399 - 1200
1200 - 1599 - 1400
1400 - 1799 - 1600
1600 - 1999 - 1800
1800 - 2199 - 2000
2000 - 2399 - 2200
2200 - 2599 - 2400
2400 - 2799 - 2600
2600 - 2999 - 2800
2800 - 3199 - etc.

I'm sure you have picked up on the pattern by this point.  So had I.  So, I gave up and figured I would just crash the game since the abort key didn't work.  Little did I realize just how many loops 150000 really is.  So, I was holding it for some time, and then, it got in the range of 6000-ish:

5400 - 5799 - 5600
5600 - 5999...

Then, it skipped back to 0.

5600 - 5999 - 0.

I'm not sure that this is exactly where it skipped, but I suppose that it is based on the pattern of the previous values.  From this point the pattern picked back up at the beginning:

0 - 200 - 0
0 - 399 - 200
...etc...

I put the "Display("%d", cindex)" statement in the "while (cindex < strstart + 200)" loop, on the first line.  How cindex is updating I don't know.  The display statement excluded, the code above is the exact code in my scripts.  I don't understand why an integer would go from 200 to 0 because of a "++" command.  Or 399 to 200.  I eventually ended up exiting the game with Alt+F4...

Gilbert

Odd. Didn't fail on me when I tried similar thing.

Though it's a small chance, can you check if the prototype of the function in the declaration of the struct matches what is here in the function code ? (Well shouldn't be causing problem, as cindex is internal to the function)

Also, since you have tindex which starts from 0, the loop can actually be simplified to:
while (tindex<200) instead of using cindex (but shouldn't be causing problem either).

My final guess was that it may possibly be a memory bug that only appear if your game consumes large amount of memory with lots of variable defined (if it's the case). So I'll recommend you try starting a new game and test if that function works for a relatively tiny and fresh game.


For example, I tried this (with a fresh new "game") and it did work for me (from your codes with small modifications):
Header:
Code: ags
struct ScrollingDialog {
  char HalfText[6000];
  char str[200];
  import void SetHalfText(int option, string tex);
  import void GrabText(int option);
  };


Global Script:
Code: ags
void ScrollingDialog::SetHalfText(int option, string tex) {  
  readonly int strstart = option * 200;
  int cindex = strstart;
  int tindex = 0;
  while (cindex < strstart + 200) {
    this.HalfText[cindex] = StrGetCharAt(tex, tindex);
    cindex++;
    tindex++;
    }
  }

void ScrollingDialog::GrabText(int option) {  
  readonly int strstart = option * 200;
  int cindex = strstart;
  int tindex = 0;
  while (cindex < strstart + 200) {
    this.str[tindex]=this.HalfText[cindex];
    cindex++;
    tindex++;
    }
  }


Then in the starting room:
Code: ags
ScrollingDialog strr[50];
#sectionstart room_a  // DO NOT EDIT OR REMOVE THIS LINE
function room_a() {
  // script for Room: Player enters screen (after fadein)
  strr[4].SetHalfText(0, "HAHAHA");
  strr[4].SetHalfText(1, "XAXA");
  strr[4].SetHalfText(2, "");
  strr[4].GrabText(0);
  Display(strr[4].str);
  strr[4].GrabText(1);
  Display(strr[4].str);
  strr[4].GrabText(2);
  Display(strr[4].str);
}
#sectionend room_a  // DO NOT EDIT OR REMOVE THIS LINE

And the strings were shown correctly.

monkey0506

Okay...well...I don't have access to the code or the game at least until Monday, so I will let you know then what I can find...but seeing as our code is virtually the same I don't see what the problem is.  Thanks for...uh...trying to help.

Pumaman

Can you provide the script definition of your  ScrollingDialog  struct so that we can look into it?

monkey0506

#9
First let me say that I've been trying to keep this definition under wraps because I was embarassed about the last method I tried.  Previously I had tried implementing one struct within another by putting one inside a header first...but then I needed several layers of depth, making it insanely messy to work with.  Strazer suggested this a while back and I ignored it until recently, when in combination with a suggestion from RickJ, it seemed plausible to work...and I'm happily sad to say it's doing pretty good thus far.

Also, I have made several changes today, so I may have somehow worked the bug out...I haven't tested it yet today.

This being said:

Code: ags
struct ScrollingDialog {
  /* protected enumerated types */
  /*protected*/ ScrollingDialogOptionState State[ScrollingDialog_MAX_OPTS]; /* option state */
  /*protected*/ ScrollingDialogOptionHalfState HalfState[ScrollingDialog_MAX_OPTS]; /* state of option halves */
  
  /* protected standard types */
  /*protected*/ char Text[ScrollingDialog_STR_SIZE]; /* the strings of text in the current dialog */
  /*protected String Text[ScrollingDialog_MAX_OPTS];*/
  /*protected*/ char HalfText[ScrollingDialog_STR_SIZE]; /* the potential second halves */
  /*protected String HalfText[ScrollingDialog_MAX_OPTS];*/
  /*protected*/ int Width[ScrollingDialog_MAX_OPTS]; /* width of options in font ScrollingDialog_DLG_FONT */
  /*protected*/ int HalfWidth[ScrollingDialog_MAX_OPTS]; /* width of option halves */
  /*protected*/ int ID;
  
  /* protected member functions */
  /*protected*/ import void SetHalfText(int option, const string text);
  /* [-- deleted --] */
    /* sets the text of option halves */
  /*protected*/ import void SetText(int option, const string text);
  /* [-- deleted --] */
    /* sets the text of options */
  
  /* public standard types */
  
  /* public static member functions */
  import static void RunDialogOption(int dialog, int option); /* run dialog interaction for an option of specified dialog */
  
  /* public member functions */
  import void End(); /* calls RunningDialog.End() */
  import void Run(); /* run a dialog -- replaces SetupDialog(int dialog) */
  import void Initialize(); /* initialize values */
  import int GetHalfWidth(int option);
    /* returns the width of option halves */
  import ScrollingDialogOptionHalfState GetHalfState(int option);
    /* returns the state of option halves */
  import void GetHalfText(int option, string buffer);
  /* import String GetHalfText(const int option); */
    /* stores the text of option halves in string buffer */
  import int GetWidth(int option); /* returns the width of an option */
  import ScrollingDialogOptionState GetState(int option); /* returns an option state */
  import void GetText(int option, string buffer); /* stores option text in buffer */
  /* import String GetText(int option); */
  /*protected*/ import void SetHalfState(int option, ScrollingDialogOptionHalfState state);
    /* changes the state of an option half */
  import void SetState(int option, ScrollingDialogOptionState state);
    /* sets the state of an option */
  import void RunOption(int option); /* run dialog interaction for an option */
  };

/*protected*/ void ScrollingDialog::SetHalfText(int option, const string text) {
  if ((option < 0) || (option > ScrollingDialog_MAX_OPTS))
    AbortGame("Invalid parameter to function ScrollingDialog::SetHalfText parameter 'option'.  Range from 0 to %d, value %d.", ScrollingDialog_MAX_OPTS, option);
  readonly int strstart = option * 200;
  int cindex = strstart;
  int tindex = 0;
  while (cindex < strstart + 200) {
    Display("%d", cindex);
    this.HalfText[cindex] = StrGetCharAt(text, tindex);
    cindex++;
    tindex++;
    }
  }

/*protected*/ void ScrollingDialog::SetText(int option, const string text) {
  if ((option < 0) || (option > ScrollingDialog_MAX_OPTS))
    AbortGame("Invalid parameter to function ScrollingDialog::SetText parameter 'option'.  Range from 0 to %d, value %d.", ScrollingDialog_MAX_OPTS, option);
  readonly int strstart = option * 200;
  int cindex = strstart;
  int tindex = 0;
  while (cindex < strstart + 200) {
    this.Text[cindex] = StrGetCharAt(text, tindex);
    cindex++;
    tindex++;
    }
  }

void ScrollingDialog::GetText(int option, string buffer) {
  if ((option < 0) || (option > ScrollingDialog_MAX_OPTS))
    AbortGame("Invalid parameter to function ScrollingDialog::GetText parameter 'option'.  Range from 0 to %d, value %d.", ScrollingDialog_MAX_OPTS, option);
  readonly int strstart = option * 200;
  int cindex = strstart;
  int tindex = 0;
  StrCopy(buffer, "");
  while (cindex < strstart + 200) {
    StrFormat(buffer, "%s%c", buffer, this.Text[cindex]);
    cindex++;
    tindex++;
    }
  }

void ScrollingDialog::Initialize() {
  /* initialize dialog variables -- not possible with protected members */
  int option = 0;
  while (option < ScrollingDialog_MAX_OPTS) {
    RunningDialog.State[option] = eDialogOptionOffForever;
    RunningDialog.HalfState[option] = eDialogOptionHalfOff;
    RunningDialog.Width[option] = -1;
    RunningDialog.HalfWidth[option] = -1;
    if (option < ScrollingDialog_NUM_LBLS) RunningDialog.Options[option] = -1;
    /*
    [-- add --]
    RunningDialog.Text[option] = "";
    RunningDialog.HalfText[option = "";
    */
    option++;
    }
  StrCopy(RunningDialog.Text, "");
  /* [-- deleted --] */
  StrCopy(RunningDialog.HalfText, "");
  /* [-- deleted --] */
  RunningDialog.ID = -1;
  
  /**** DIALOG 0 ****/
  Dialog[0].SetText(0, "My name's Guybrush Threepwood!  Prepare to die!");
  Dialog[0].SetText(1, "So...How did you get up there?");
  Dialog[0].SetText(2, "I'll just be running along now.");
  /*
  Dialog[0].Text[0] = "My name's Guybrush Threepwood!  Prepare to die!";
  Dialog[0].Text[1] = "So...How did you get up there?";
  Dialog[0].Text[2] = "I'll just be running along now.";
  */
  
  /**** DIALOG 1 ****/
  Dialog[1].SetText(0, "I can't believe the resemblance between us.");
  Dialog[1].SetText(1, "What did you say your last name was?");
  Dialog[1].SetText(2, "How long have you been up there?");
  Dialog[1].SetText(3, "Have you ever moved from that spot?");
  Dialog[1].SetText(4, "How's the view up there?");
  Dialog[1].SetText(5, "Do you get a lot of visitors on this deserted island?");
  Dialog[1].SetText(6, "It must get pretty dull just sitting there all day.");
  Dialog[1].SetText(7, "Want to hear a knock-knock joke?");
  Dialog[1].SetText(8, "I'm sorry, I think I hear my wife calling...");
  
  int dialog = 0;
  while (dialog < ScrollingDialog_MAX_DLGS) {
    option = 0;
    while (option < ScrollingDialog_MAX_OPTS) {
      if (option < ScrollingDialog_NUM_LBLS) Dialog[dialog].State[option] = eDialogOptionOn;
      else Dialog[dialog].State[option] = eDialogOptionOffByScrolling;
      Dialog[dialog].HalfState[option] = eDialogOptionHalfOff;
      string text;
      Dialog[dialog].GetText(option, text);
      /* String text = Dialog[dialog].Text[option]; */
      Dialog[dialog].Width[option] = GetTextWidth(text, ScrollingDialog_DLG_FONT);
      if (Dialog[dialog].Width[option] >= gDialog.Width) {
        string half;
        /* String half = ""; */
        StrCutByWidth(text, gDialog.Width, ScrollingDialog_DLG_FONT, text, half);
        Dialog[dialog].SetText(option, text);
        /* Dialog[dialog].Text[option] = text */
        Dialog[dialog].SetHalfText(option, half);
        /* Dialog[dialog].HalfText[option] = half; */
        Dialog[dialog].Width[option] = GetTextWidth(text, ScrollingDialog_DLG_FONT);
        Dialog[dialog].HalfWidth[option] = GetTextWidth(half, ScrollingDialog_DLG_FONT);
        }
      else {
        Dialog[dialog].SetHalfText(option, "");
        /* Dialog[dialog].HalfText[option] = ""; */
        Dialog[dialog].HalfWidth[option] = 0;
        }
      option++;
      }
/*    Dialog[dialog].ID = dialog;*/
    dialog++;
    }
  }

void ScrollingDialog::GetHalfText(int option, string buffer) {
  if ((option < 0) || (option > ScrollingDialog_MAX_OPTS))
    AbortGame("Invalid parameter to function ScrollingDialog::GetHalfText parameter 'option'.  Range from 0 to %d, value %d.", ScrollingDialog_MAX_OPTS, option);
  readonly int strstart = option * 200;
  int cindex = strstart;
  StrCopy(buffer, "");
  while (cindex < strstart + 200) {
    StrFormat(buffer, "%s%c", buffer, this.HalfText[cindex]);
    cindex++;
    }
  }


Edit:  I've deleted the scripts I found that seemed to not have anything to do with the problem (except for the inverse functions of the two that are crashing the game) (read my below post). (end edit)

Thanks for looking into it for me though.

Edit:  I tested it now, and out of the above code, the following crashes the game, "SetHalfText" and "GetText".

Edit:  Based on some of the most recent testing that I have done, I tried changing the definition of SetHalfText to:

Code: ags
void ScrollingDialog::SetHalfText(int option, const string text) {
  int something = 0;
  while (something < 400) { something++; }
  }


And it still crashes.  Also, just to clarify SetText and GetHalfText work but GetText and SetHalfText do not.  Although the definitions are near identical.

Edit:  This seems to be some sort of corruption I have formed within the editor.  I say this because I copied all of the text into a new game, saved, and then the game at some point imported SetHalfText even though I had commented it out before saving the game (if I typed "Set" then the AutoComplete menu would display SetHalfState as well as SetHalfText neither of which is global btw).  So, I deleted the commented part that declared it, and it un-imported itself.  Then I uncommented the definition, recompiled, and it no longer crashes while running SetHalfText...so...I have no idea how I did it, but I hope this helps to get it fixed (if it was even something wrong with AGS and not something my computer did somehow).

monkey0506

As noted above I found that several of my functions had somehow become corrupted and were being AutoCompleted as global functions, and I fixed it by deleting the functions, recompiling the game, then putting the functions back.  However, now I think it may not have anything to do with that.  I have found that two functions, SetHalfText and GetText seem to be crashing whenever called from the function ScrollingDialog.Initialize().  I did the following in game_start:

Code: ags
    Dialog[0].SetHalfText(0, "this is option 0");
    Dialog[0].SetHalfText(1, "this is option 1");
    Dialog[0].SetHalfText(2, "this is option 2");
    Dialog[0].SetHalfText(3, "this is option 3");
    Dialog[0].SetHalfText(4, "");
    string opt0, opt1, opt2, opt3, opt4;
    Dialog[0].GetHalfText(0, opt0);
    Dialog[0].GetHalfText(1, opt1);
    Dialog[0].GetHalfText(2, opt2);
    Dialog[0].GetHalfText(3, opt3);
    Dialog[0].GetHalfText(4, opt4);
    Display("option 0: \"%s\"; option 1: \"%s\"; option 2: \"%s\"; option 3: \"%s\"; option 4: \"%s\"", opt0, opt1, opt2, opt3, opt4);
    Dialog[0].SetText(0, "this is option 0");
    Dialog[0].SetText(1, "this is option 1");
    Dialog[0].SetText(2, "this is option 2");
    Dialog[0].SetText(3, "this is option 3");
    Dialog[0].SetText(4, "");
    Dialog[0].GetText(0, opt0);
    Dialog[0].GetText(1, opt1);
    Dialog[0].GetText(2, opt2);
    Dialog[0].GetText(3, opt3);
    Dialog[0].GetText(4, opt4);
    Display("option 0: \"%s\"; option 1: \"%s\"; option 2: \"%s\"; option 3: \"%s\"; option 4: \"%s\"", opt0, opt1, opt2, opt3, opt4);


And it compiled and ran perfectly, and gave the appropriate output.  However, when I tried to replace this with "ScrollingDialog.Initialize()" (note:  I made this a static function. previously I had made use of the keyword this, but it is no longer used) the game crashes when running said functions.

Pumaman

OK, I think it's because you have this:

while (dialog < ScrollingDialog_MAX_DLGS) {
    option = 0;
    while (option < ScrollingDialog_MAX_OPTS) {

and then the SetHalfText calls also have loops within them and so on.

I don't know what your ScrollingDialog_MAX_OPTS contants are defined to, but the issue is that if 150000 while loop iterations are run without a screen update, the error occurs. In this case, because you have several nested loops, it's probably inadvertantly reaching this limit.

I guess I need to add an option for you to disable the while loop checking when you need large loops like these.

monkey0506

#12
I believe that it is:

Code: ags
#define ScrollingDialog_MAX_DLGS 500
#define ScrollingDialog_MAX_OPTS 30


I'm guessing that it goes like this:

Code: ags
while (dialog < ScrollingDialog_MAX_DLGS) { /* 500 loops */
  option = 0;
  while (option < Scrolling Dialog_MAX_OPTS) { /* 30 loops - for each of the 500 */
    /*...*/
    Dialog[...].SetHalfText(..., ""); /* or whatever it was */
    option++;
    }
  dialog++;
  }


And the SetHalfText contains a loop which runs 200 times:

500 (Initialize() outer loop) * 30 (Initialize() inner loop) * 200 (SetHalfText(..., ...) loop) = 3000000 loops - Hence the crash.

I guess that explains why it was only crashing when running Initialize() and not just SetHalfText(..., ...) by itself.

I can work without the Initialize() function for now, but it will be essential to ms SM when I finish everything else.  So, is this going to be a high priority fix (please)?  Or if you could make it so I can use Strings within my struct, then I could do away with the huge array, which would mean I would only have to run 15000 loops (I'm not saying to do away with the option to disable while loop checking, but perhaps this could be a higher priority alternative).

Or I can just wait to release my SM (by which point the dialog system will probably get updated because that's the way my life works...).


SMF spam blocked by CleanTalk