Author Topic: Arrays  (Read 2243 times)

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Arrays
« Reply #15 on: July 02, 2011, 08:01:32 pm »


               

FunkySwerve wrote...

Lightfoot8 wrote...

I will try and answer this.  I hop CID does not ming me butting in. 

Most of the work for paeceing a string has alrady been done for you in the x3_inc_string include.

Those functions are essentially the same as the ones I posted...though not as cleanly written (look at the include above, though I think I might've left out our StringReplace function). I'm curious to see what CID is advocating.

Funky


It is just a simple example.   I wrote it before I seen you post for a request of a GetFirst/Next without use of struct's, Well it uses no structures. The principals behind it can be made as simple or as complex as you like.   I myself do not even think the functions are needed in my example just use of the StringParse and StringRemoveParsed functions in the script where needed would do the trick for parsing through the string.  

Before we really know what the OP is looking for all we are really doing at this point is cluttring up his thread. 
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Arrays
« Reply #16 on: July 02, 2011, 09:45:27 pm »


               

CID-78 wrote...

you can simply use space as a delimiter and check each word against a keyword list. and execute accordingly

FunkySwerve wrote...
Just a space-separated string using FindSubString or one of the functions I provided will do the trick. I'd elaborate, but without knowing more specifics, any number of ways could be best. You could allow multiple acceptable passwords with FSS != -1, for example, or randomly changing passes with GetRandomSubString, or any number of other possibilities.

thats not the full solution, this part is clear even to OP, but what next, how to set up the conversation and key words and how to show them and speak them etc etc.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Arrays
« Reply #17 on: July 02, 2011, 10:10:51 pm »


               He asked to be 'enlightened' about pseudoarrays. He was. He also mentioned you were helping him. At least two of us have asked for more information before rendering help. If you disagree, or know more than we do about what he wants from speaking with him, how about helping him instead of complaining about us? LF is right, the thread is getting cluttered enough - I'm waiting for him to post.

Funky
               
               

               
            

Legacy_TrekSL

  • Newbie
  • *
  • Posts: 35
  • Karma: +0/-0
Arrays
« Reply #18 on: July 02, 2011, 10:32:39 pm »


               OK guys a big thank you - (I've just got back from work) I'll give you  some insight here:

The idea for me is to construct a learning game. The scripting that I intended was to have a simple game that relied on correctly typed phrases to proceed through locked doors for example. The reason behind this was that I could just make all of this in the bog standard clickable dialogue boxes, but that would be far too easy - so I wanted a text parser for the job. ShadoOoW has shown me how and I have adapted the code to suit. However, what I have is so far storing a single phrase. I can expand here, I could use integers or strings to store more of these phrases but, to quote my java teacher 'these are not elegant solutions'. I have just seen the pseudo arrays by funky and lightfoot. You are all very accomplished coders on this forum (I'm just starting out, I wish I had a fraction of the technical know-how you do!!!) but for the time being I do feel intimidated by the complexity of getting it working - so the less elegant may be my best option at the moment!

To continue my example though: Say you have a locked door. You can't open it until you have correctly typed the conjugation of haben in german. In order, these are 'habe' 'hast' 'hat' 'haben' 'habt' 'haben' (Ich, Du, Er, Wir, Ihr, Sie/ I, you, he/she/it, we, you(pl) you(formal))
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Arrays
« Reply #19 on: July 02, 2011, 11:17:47 pm »


               Well first off I do not think you need to use an array for this.  Arrays my be great for full languages. in NWN script however they often add a complexity that you do not need. 

Second I see no need to use the OnPlayerChat event.   It looks like that is what you are currently using but also trying to fire the same event from a trigger also.  That just makes any strings you get from the OnPCChat event functions unreliable without a bunch of extra code in the Chat event.   It is often better to stick with what was desined into the game instead of stepping out and desinging a new sub system.  Agreed there are time when you have not choice but to design a new system, but I do not think it is needed in this case.

To me your solution is to let the door listen for the answers useing SetListeningPatern for each of the strings that are a possiable answer to its question. Now at lot of people will chime in here and start saying that it can not be done that way because the door does not have a OnConversation event.  That is where the well hidden part of this comes into play.  even though the door does not have a OnConversation event. you can make one.   When the door is set to listening (SetListening(oDood)'<img'>  It will fire the default OnConversation Event Script. nw_g0_conversat.  You make your event by modifing the script to run a UserDefined Event on the door.  making it to where you can use that event to put your code for what the door is listening for and what to do when it hears it.

I outlined that process in the thread titled.SetListening() . . is it only for NPCs? Of cource you will want to change the OBJECT_TYPE_PLACEABLE  to OBJECT_TYPE_DOOR or a conjunction of the two according to your needs.

After that you just need to define unique ID numbers for each of you listening patterns to use in the OnUserDefined event for the door. I guess you could do all of that with arrays but I eally do not see the need in nwn script since you would assign them as single patterns anyway.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Arrays
« Reply #20 on: July 03, 2011, 01:15:23 am »


               

TrekSL wrote...
To continue my example though: Say you have a locked door. You can't open it until you have correctly typed the conjugation of haben in german. In order, these are 'habe' 'hast' 'hat' 'haben' 'habt' 'haben' (Ich, Du, Er, Wir, Ihr, Sie/ I, you, he/she/it, we, you(pl) you(formal))

then its easy, just store the "multistring" in format ich|du|er|etc| and then get chat message, lowercase it (beware that characters like Ü and other special characters cannot be lowercased!) add "|" and then try if you findsubstring position

like this:

string sPattern = GetLocalString(OBJECT_SELF,"PHRASES");
string sMessage = GetPCChatMessage();
sMessage = GetStringLowercase(sMessage)+"|";
 if(FindSubString(sPattern, sMessage) > -1)
 {
  //one of the correct phrases, lets do some stuff
 }


LF8: The system I provided him contains only 1variable check in OnChat, with additional 3commands if the variable is set and is reliable. Im doing it this way as having a listener when you want to use it on doors/trigger is a bit silly and this way it dont mess with onchat event (its completely the same as tagbased scripting).':wub:'
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Arrays
« Reply #21 on: July 03, 2011, 02:31:48 am »


               I prefer Lightfoot's solution - despite over 25,000 lines of code in our chat scripts (yes, really), we generally rely on listeners for area-, location-, and speaker-dependant things - modularity. I guess the one thing standing in its way is the question: do you want them to have to speak them one after the other, or all at once?

I would be inclined to track progress with a space-separated (or semi-colon, if some of the answers will have spaces) local string on the door itself, if you want them to answer one after the other. Then, you could just get the first substring, compare it to what they said, and snip it off from the later conjugations, or open the door if they're on the last.

There are going to be endless ways to do this, though. If you prefer to use what code Shad has already given you, I can adapt to that.

Also, if you dislike the listening event aspect, and/or want to have a central include which lists all your answers, you could simply tag all riddle doors the same thing, check for GetNearestObjectByTag, to find the nearest door, and mark each door with a unique local int: Door int 1, Door int 2, and so on. Then, in the master include, you could pull up the full answer list simply by use of a switch statment, and track only progress on the door using locals, rather than setting the answer there to begin with.

I understand you're looking for an elegant solution. To me, that may mean something a little different, so let's clarify your goals. For me, I would want:
a) A central include holding all questions and answers - for easier data filling .If you're comfortable with databases, that's what I'd normally suggest if you're using MySQL on a server, since databases are made for this stuff. If you want to be able to readily read and append, though, the bioware database is not so hot, so maybe the best solution is in fact a scripted include, if this is for single player use.
'B)' Minimal setup on individual doors - drop a door in from the palette, change a single variable, and it's ready
c) Ability to reset/relock doors, and to shuffle questions and answers at random, so that you don't have to make a zillion doors. Heck, maybe even a circle they have to walk around a number of times before a cetral door opens.

So, my questions are, aside from the initial one about how you want the riddles spoken:
1) how many conjugations are we talking
2) how do you want to handle randomization, if at all?
3) how many doors, in what configuration, in how many areas?

Funky
               
               

               


                     Modifié par FunkySwerve, 03 juillet 2011 - 01:33 .
                     
                  


            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Arrays
« Reply #22 on: July 03, 2011, 02:53:12 am »


               Yes, Shadow I remember your system now.  It is still a matter of prefferance.  I myself find having the door listening more usefull then routing it through the OnChat event.  For one there is no way to tell if the door that you want listening is even in range to hear the spoken words without extra code added.   Two there is no direct link to the door without adding a search for it within the code.  

With the door itself listening there is no question that it heard the PC speak, there is also no need to search for the door since it is OBJECT_SELF the event is running on it after all.  there is no problem finding the PC who spoke the words either just use oPC=GetLastSpeaker();  There is no extra code needed to have firm links between the objects in questions.  You can also set the entire search set up to one listening patern.  

SetListenPattern(oDoor,"habe|hast|hat|haben|habt|haben", 150);

or if the was wanting them all spoken in order on the same line.

SetListenPattern(oDoor,"habe**hast**hat**haben**habt**haben", 150);

or all spoken on the same line with nothing else by white space include.
SetListenPattern(oDoor,"(habe)*w(hast)*w(hat)*w(haben)*w(habt)*w(haben)", 150);

or single checks with multipal checks.
SetListenPattern(oDoor," (habe|erste|ein) **(habe|erste|ein)", 150);

would match things like:..... hmm german is a little more complex.  The translator is changing the words on me.  lol.  let me do this as an english example

SetListenPattern(oDoor," (habe|first|one) **(habe|first|one)", 150);
wold match things like:
The first is habe
and
habe is number one
unfortantly with the way I have it written it would also match.
one is the first.

So yes with the tools availiable with the listening patterns I like it better then channeling through the player chat event.  Perhaps that is avaliable in the Chat event also, I dont know. I have not looked that close.  Still there is the problem with seperating out what is doing the listening. with the old listening pattern system there is no problem there or even with having several objects listening at the same time, something I do not think your system handles very well.  

Just my opinon, We all have our own preferances and it realy does not matter what system the OP picks as long as it works for him and he is happy with it.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Arrays
« Reply #23 on: July 03, 2011, 03:05:51 am »


               for setting up your listening patterns here is a quote.

From Noel (Bioware):
** will match zero or more characters
*w one or more whitespace
*n one or more numeric
*p one or more punctuation
*a one or more alphabetic
| is or
( and ) can be used for blocks

- setting a creature to listen for "**" will match any string
- telling him to listen for "**funk**" will match any string that contains the word "funk".
- "**(bash|open|unlock)**(chest|door)**" will match strings like "open the door please" or "he just bashed that chest!" 


               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
Arrays
« Reply #24 on: July 03, 2011, 04:52:33 am »


               

Lightfoot8 wrote...

for setting up your listening patterns here is a quote.

From Noel (Bioware):
** will match zero or more characters
*w one or more whitespace
*n one or more numeric
*p one or more punctuation
*a one or more alphabetic
| is or
( and ) can be used for blocks

- setting a creature to listen for "**" will match any string
- telling him to listen for "**funk**" will match any string that contains the word "funk".
- "**(bash|open|unlock)**(chest|door)**" will match strings like "open the door please" or "he just bashed that chest!" 

You got a point Lightfoot8, I totally forgot about SetListenPattern function. Thats especially suitable for this issue. However using this function is really quite complicated as you have to use creature, special onspawn and special OnConversation script. Its the way to do that for sure, maybe even better, but my solution has its advantages too. Well, lets see what will OP prefer now.:innocent:
               
               

               
            

Legacy_CID-78

  • Sr. Member
  • ****
  • Posts: 261
  • Karma: +0/-0
Arrays
« Reply #25 on: July 03, 2011, 07:22:12 am »


               Lightfoot got my drift. I never said that you didn't have the pieces, I just said that you should do away with the struct layer. or only use specific struct function for specific uses ie if you want to build complex rule addons.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Arrays
« Reply #26 on: July 03, 2011, 08:19:18 am »


               Lightfoot copied the x3 string include, which is, if anything, a more poorly-written version of some of the functions in the include I posted. He didn't address the functionality of the functions you objected to at all, like IntList. I'd still like to see some code, please, or SOME basis for your having called those functions 'awful'.

Seriously, how would you do the IntList functionality, without all those ebil structs? Since you claim to always value efficiency and nothing else, your code must be incredibly difficult to read, what with all the reused declarations. Do you actually have any practical experience working with these kinds of functions? If so, why not just post the way you would do it? You can demonstrate just how much more efficient your code is. Surely it would be a massive improvement over those 'awful' functions. '<img'>

Funky
               
               

               
            

Legacy_CID-78

  • Sr. Member
  • ****
  • Posts: 261
  • Karma: +0/-0
Arrays
« Reply #27 on: July 03, 2011, 09:03:45 am »


               A list would be a loop where i get one "list entry" (this can be one or more data entries) at a time and evaluate what I want todo with it and do that then i continue my loop to the next "list entry". Depending on how i want to process the list the script would look diffrently. No struct. just simple loading from the string into the variables in question. and for each loop i will forget the values i don't need from the previous iteration. the pseudoarray would just pull the values for me either as a enumerator system (first/next) or by request(index). As a scripter i know what i type of information i stored so i can get it back the same way.

I recently reinstalled NWN on my new laptop and all my old nwscripting is located on my old desktop. which is stuffed away in storage by now. So i don't have anything unless i write a pseudo array from scratch. And i am not going to spend that time to prove my point. go ahead and use your system if you like.

what i thought was awful is the fact that you use a switch to populate a struct. and in the main script i would guess that the user would do the opposent ie having to use a switch to read each entry.
The substring part was okay.
               
               

               
            

Legacy_FunkySwerve

  • Hero Member
  • *****
  • Posts: 2325
  • Karma: +0/-0
Arrays
« Reply #28 on: July 03, 2011, 09:35:59 am »


               

CID-78 wrote...
I recently reinstalled NWN on my new laptop and all my old nwscripting is located on my old desktop. which is stuffed away in storage by now. So i don't have anything unless i write a pseudo array from scratch. And i am not going to spend that time to prove my point. go ahead and use your system if you like.

In other words, you're completely unable or unwilling to back up your criticism with code. Go figure. I'm tempted to write a switchless version to demonstrate the insignificant difference in speed. It wouldn't take me very long. With your clearly superior skillz, surely it'd take you no time at all...right?

what i thought was awful is the fact that you use a switch to populate a struct. and in the main script i would guess that the user would do the opposent ie having to use a switch to read each entry.
The substring part was okay.

You don't HAVE to guess. I posted two different examples, in which no switch is used to read entries. You either didn't read or don't understand the code I posted, but are perfectly willing to argue its merits with me regardless. Pure champion stuff there.

Funky
               
               

               


                     Modifié par FunkySwerve, 03 juillet 2011 - 08:36 .
                     
                  


            

Legacy_CID-78

  • Sr. Member
  • ****
  • Posts: 261
  • Karma: +0/-0
Arrays
« Reply #29 on: July 03, 2011, 12:00:45 pm »


               unwilling would be the word. I am experienced enough to ignore young cooky (usually student) who think they are best until proven otherwise. Why should a waste a hour on you? if i would spend time to prove how to script Apllication X or script Y. I would never finish my own projects and they would exploit me for resources.

But i can comment your code or the authors code, because your spending alot of time defending some one else work.

okay let start from the beginning with what you first posted:

struct IntList {
   int size;

   int i0,  i1,  i2,  i3,  i4;
   int i5,  i6,  i7,  i8,  i9;
};

/*CID-78: Fixed sized array struct with ten entries, it can obviously only handle arrays with size 1-10,
it kind of kill the meaning of a pseudo array, which really should act as a vector.
ie you shouldn't need to care how many entries it has. */

struct StringList {
   int size;

   string s0,  s1,  s2,  s3;
   string s4,  s5,  s6,  s7;
   string s8,  s9,  s10, s11;
   string s12, s13, s14, s15;
};
/*CID-78: Fixed sized array struct with 15 entries, same as above but like above your locking yourself down to a type and size*/

struct SubString {
   string first, rest;
};
/*CID-78: okay this one can be usefull*/

/*snip away some okay code*/

string GetStringSubString (string sString, int nIndex, string sSep=" ") {
   int nSep, nStart = 0, nSkip = GetStringLength(sSep); /*CID-78: be happy that nwscript set all variables to zero otherwise would nSep be unknown here*/

   while (nIndex-- > 0) {
       nSep = FindSubString(sString, sSep, nStart);

       if (nSep < 0)
           return "";

       nStart = nSep + nSkip;
   }

   if ((nSep = FindSubString(sString, sSep, nStart)) < 0)
       nSep = GetStringLength(sString);

   return GetSubString(sString, nStart, (nSep - nStart));
}

/*snip away some okay code*/

/*CID-78 the two following functions are what i thought was awfull*/
/*CID-78 1) You got a parameter that defines a Limit which obviously only can be 16 or smaller because of your fixed struct.
/*CID-78 2) the purpouse of struct is to collect and identify it's content. in your case it seem to be alot of the same.

struct StringList GetStringList (string sString, string sSep=" ", int nLimit=16) {
   int nCount = 0, nSep = 0, nStart = 0;
   int nSkip = GetStringLength(sSep);
   int nLen = GetStringLength(sString);
   struct StringList sl;

   if (nSkip < 1) {
       sl.size = 0;
       return sl;
   }

   while (nSep < nLen && nCount < nLimit) {
       nSep = FindSubString(sString, sSep, nStart);
       if (nSep < 0)
           nSep = nLen;

       switch (nCount & 1) {
           case 0: switch (nCount++) {
               case  0: sl.s0  = GetSubString(sString, nStart, (nSep - nStart)); break;
               case  2: sl.s2  = GetSubString(sString, nStart, (nSep - nStart)); break;
               case  4: sl.s4  = GetSubString(sString, nStart, (nSep - nStart)); break;
               case  6: sl.s6  = GetSubString(sString, nStart, (nSep - nStart)); break;
               case  8: sl.s8  = GetSubString(sString, nStart, (nSep - nStart)); break;
               case 10: sl.s10 = GetSubString(sString, nStart, (nSep - nStart)); break;
               case 12: sl.s12 = GetSubString(sString, nStart, (nSep - nStart)); break;
               case 14: sl.s14 = GetSubString(sString, nStart, (nSep - nStart)); break;
           }
           break;

           case 1: switch (nCount++) {
               case  1: sl.s1  = GetSubString(sString, nStart, (nSep - nStart)); break;
               case  3: sl.s3  = GetSubString(sString, nStart, (nSep - nStart)); break;
               case  5: sl.s5  = GetSubString(sString, nStart, (nSep - nStart)); break;
               case  7: sl.s7  = GetSubString(sString, nStart, (nSep - nStart)); break;
               case  9: sl.s9  = GetSubString(sString, nStart, (nSep - nStart)); break;
               case 11: sl.s11 = GetSubString(sString, nStart, (nSep - nStart)); break;
               case 13: sl.s13 = GetSubString(sString, nStart, (nSep - nStart)); break;
               case 15: sl.s15 = GetSubString(sString, nStart, (nSep - nStart)); break;
           }
           break;
       }

       nStart = nSep + nSkip;
   }

   sl.size = nCount;

   return sl;
}

struct IntList GetIntList (string sString, string sSep=" ", int nLimit=10) {
   int nCount = 0, nSep = 0, nStart = 0;
   int nLen = GetStringLength(sString);
   int nSkip = GetStringLength(sSep);
   struct IntList il;

   if (nSkip < 1) {
       il.size = 0;
       return il;
   }

   while (nSep < nLen && nCount < nLimit) {
       nSep = FindSubString(sString, sSep, nStart);
       if (nSep < 0)
           nSep = nLen;

       switch (nCount++) {
           case  0: il.i0  = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
           case  1: il.i1  = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
           case  2: il.i2  = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
           case  3: il.i3  = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
           case  4: il.i4  = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
           case  5: il.i5  = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
           case  6: il.i6  = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
           case  7: il.i7  = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
           case  8: il.i8  = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
           case  9: il.i9  = StringToInt(GetSubString(sString, nStart, (nSep - nStart))); break;
       }

       nStart = nSep + nSkip;
   }

   il.size = nCount;

   return il;
}