Arrays
#1
Posté 01 juillet 2011 - 11:18
object oDoor = GetObjectByTag("door");//This is the door to open. Need a global variable
void StartListening(object oPlayer, string sScript)//Two functions here, start listening setting a string on the player
{
SetLocalString(oPlayer,"START_LISTENING",sScript);
}
void StopListening(object oPlayer)
{
DeleteLocalString(oPlayer,"START_LISTENING");
}
void main()
{
int nEvent = GetLocalInt(GetModule(),"GetRunningEvent()");
if(nEvent == 15)//check whether the onchat event Module integer exists when the player enters the trigger
{
object oPC = OBJECT_SELF;//set PC up as oPC
string sMessage = GetPCChatMessage();//sMessage will be whatever is written in chat
SetPCChatMessage();//<--Can be commented out- avoids what the player has typed from appearing onscreen
StopListening(oPC);//disable further listening
if(sMessage == "habe")//<-- this is a simple german learning game, hence the word, nested if statement.
{
SetLocked(oDoor, FALSE);//Unlock my door
}
}
else//script fired from trigger
{
object oPC = GetEnteringObject();
if(!GetIsPC(oPC))return;
StartListening(oPC,"secrettest");//start listen the player
FloatingTextStringOnCreature("You may now speak",oPC);
}
}
#2
Posté 01 juillet 2011 - 11:33
ie name|str|int|cha could be treated as a pseudo array with four strings in it.
#3
Posté 01 juillet 2011 - 04:48
struct IntList {
int size;
int i0, i1, i2, i3, i4;
int i5, i6, i7, i8, i9;
};
struct StringList {
int size;
string s0, s1, s2, s3;
string s4, s5, s6, s7;
string s8, s9, s10, s11;
string s12, s13, s14, s15;
};
struct SubString {
string first, rest;
};
/* Return the substring at the given index nIndex of sString, separating
* sString with sSep. */
string GetStringSubString (string sString, int nIndex, string sSep=" ");
/* Return the number of substrings sString would have if it were separated
* by sSep. */
int GetStringSubStrings (string sString, string sSep=" ");
/* Return a random string of sString separated by sSep. */
string GetRandomSubString (string sString, string sSep=" ");
/* Return a SubString struct containing the first substring of sString
* separated by sSep, as well as the remainder of sString. The idiom
* would be:
*
* struct SubString ss;
*
* ss.rest = sString;
*
* while (ss.rest != "") {
* ss = GetFirstSubString(ss.rest);
*
* (do things here)
* }
*/
struct SubString GetFirstSubString (string sString, string sSep = " ");
/* Return a StringList struct containing strings extracted from sString
* separated by sSep. */
struct StringList GetStringList (string sString, string sSep=" ", int nLimit=16);
/* Return an IntList struct containing integers extracted from sString
* separated by sSep. */
struct IntList GetIntList (string sString, string sSep=" ", int nLimit=10);
string GetStringSubString (string sString, int nIndex, string sSep=" ") {
int nSep, nStart = 0, nSkip = GetStringLength(sSep);
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));
}
int GetStringSubStrings (string sString, string sSep=" ") {
int nCount = 1, nStart = 0;
int nSep = FindSubString(sString, sSep);
int nSkip = GetStringLength(sSep);
if (nSkip < 1)
return 1;
while (nSep >= 0) {
nCount++;
nSep = FindSubString(sString, sSep, nSep + nSkip);
}
return nCount;
}
string GetRandomSubString (string sString, string sSep=" ") {
int nCount = GetStringSubStrings(sString, sSep);
return GetStringSubString(sString, Random(nCount), sSep);
}
struct SubString GetFirstSubString (string sString, string sSep = " ") {
struct SubString ret;
int nSep = FindSubString(sString, sSep);
if (nSep < 0) {
ret.first = sString;
ret.rest = "";
return ret;
}
ret.first = GetStringLeft(sString, nSep);
ret.rest = GetStringRight(sString, GetStringLength(sString) - (nSep + GetStringLength(sSep)));
return ret;
}
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;
}
Funky
Modifié par FunkySwerve, 01 juillet 2011 - 04:50 .
#4
Posté 02 juillet 2011 - 05:04
#5
Posté 02 juillet 2011 - 09:16
a) None of those are fixed length arrays. Some of them are limited in the number of array components. If you think that's pointless, your argument is not with me, but with the professional coders of the world. Think resref (16), VARCHAR (255), and so on.
if (nAddCount) {
sAddedDescription = "=====\\nEnchantment Quantity: " + GetEnchantmentQuantity(nAddCount) + " (+" +
IntToString(nAddCount) + ")\\n" + C_LIGHT_GREEN + "Added:\\n";
for (ss = GetFirstSubString(sAdded, " "); ss.first != ""; ss = GetFirstSubString(ss.rest, " ")) {
il = GetIntList(ss.first, ",");
if (GetIsItemPropertyStacking(il.i0, il.i1)) {
if (il.i0 == ITEM_PROPERTY_ARCANE_SPELL_FAILURE){
//do special asf encoding
if (il.i3 < 10) {
nX = 10-il.i3;//encode 'asf good 1-10)
AddLocalInt(oItem, "RIPStack_84_0", nX);
}
else {//fake subtype for bad spell fail prop
nX = il.i3-9;//encode 'asf bad 1-10)
AddLocalInt(oItem, "RIPStack_84_1", nX);
}
}
else
AddLocalInt(oItem, "RIPStack_"+IntToString(il.i0)+"_"+IntToString(il.i1), il.i3);
} else {
sAssemble = IntToString(il.i0)+","+IntToString(il.i1)+","
+IntToString(il.i2)+","+IntToString(il.i3)+","
+IntToString(il.i4)+","+IntToString(il.i5);
sTempString = GetLocalString(oItem, "TempPropString");
if (sTempString != "")
sTempString += " ";
sTempString += sAssemble;
SetLocalString(oItem, "TempPropString", sTempString);
}
if (GetIsItemPropertyImmunity(il.i0))
il.i3 = GetCostValueFromPercentImmune(il.i3);
sAddedDescription += C_LIGHT_GREEN + " " + GetItemPropertyInfoDirect(il.i0, il.i1, il.i2, il.i3, il.i4, il.i5) + "\\n";
}
}
Funky
Modifié par FunkySwerve, 02 juillet 2011 - 09:17 .
#6
Posté 02 juillet 2011 - 10:34
And I cant see any good algorhytm to make it, thats why I sent him there. Does anyone have any idea?
#7
Posté 02 juillet 2011 - 11:31
funky:
No your adding a unnecissary layer on your system, that isn't the optimal way of doing arrays, especially not if you want to emulate how arrays work in C and C++. It also make the code harder to read.
you want to work as close to the memory as you can. and you want to have clean code. The only reason i can see todo things your way is if you got alot of similar structs but with diffrent names, and you want to save some code space. Normally you want to work directly towards the pseudostring and not against an struct which you can't build loop with.
if you skip the struct layer you got what you need.
#8
Posté 02 juillet 2011 - 01:19
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.ShaDoOoW wrote...
Anyway OP want to make a chat based conversation with key words aka morrowind or where it was? maybe in Wizardry.
And I cant see any good algorhytm to make it, thats why I sent him there. Does anyone have any idea?
Funky
#9
Posté 02 juillet 2011 - 01:38
If it is just a single NPC that this chat is happening with, The old set listening pattern could do away with the need for arrays.
If it is a module wide system using On PC chat event. Then the packed string sounds like a good option.
But more information on the system is needed.
#10
Posté 02 juillet 2011 - 02:13
You just called them fixed length arrays, and now you want to lecture me on optimization? Lol. First of all, this isn't my code. It was written by a professional - acaos. Secondly, I never said it was the 'optimal' way to do arrays. Without pointers, I'm not really sure that any one way is much better than another, frankly. Those functions were NOT, however, written with only speed in mind, but also convenience. The more you code, the more you realize that the 'best' code is not just the fastest - there are many other concerns to consider, like modularily, readability (and they most certainly do NOT make the code harder to read, they make it easier - you yourself mention saving on code space below), and convenience. And, while we're at it, part of the usefulness of those functions IS PRECISELY that you can treat arrays in more C-like fashion - by pointing directly to a member of the array in your code. See, e.g., the code I posted above.CID-78 wrote...
funky:
No your adding a unnecissary layer on your system, that isn't the optimal way of doing arrays, especially not if you want to emulate how arrays work in C and C++. It also make the code harder to read.
If you want to run some speed tests against your method, by all means, have at it - the differences were talking about are miniscule, for considerable gains in the other departments.
The concept of working close to the memory is sort of inane when applied to nwscript. It's not like we're doing mallocs or worrying about packing our arrays into nice tidy sections here. Maybe with nwnx plugins. As for clean code, that's part of the motivation for these functions, as I noted above.you want to work as close to the memory as you can. and you want to have clean code.
No, not just structs. These are pseudoarray functions. IntList, by way of example, is used all over the place in our mod, for schlepping up numerical data in string into ready-to-use format. It can handle an enormous variety of things, from dynamically applied var-based weapon onhits (yes, it's quite fast enough for that, and then some), to our quest-system data, to parsing chat commands with multiple numeric inputs. I'm getting the impression that you really don't understand how we're using these, so here's another example (var-based weapon onhits able to apply any effect/s with just about any conditions - they're used for nearly all our npcs' onhits and for a fair number of pc-based abilities, all running from a single script, the intelligent weapon onhit):The only reason i can see todo things your way is if you got alot of similar structs but with diffrent names,
/*
* OnHitDamages format:
* TYPE,DICE,SIDES,BONUS[,RACEMASK]
*
* OnHitEffects format:
* DYNEFFECT[|CHECK[|CHECK...]]
*
* DYNEFFECT format:
* LINKEFFECT[;LINKEFFECT...][:SECONDS[+RANDOM]][:E|S]][/VFX][#SPELLID]
*
* LINKEFFECT format:
* EFFECTID[,PARAM...]
*
* CHECK format:
* CHECKTYPE:PARAM[:PARAM...][/NAME]
*
* CHECKTYPES
* 1 - percent chance (param is percentage chance)
* 2 - saving throw (params are type, dc, random dc, subtype, feedback)
* 3 - ability check (params are ability, dc, random dc, feedback, auto)
* 4 - skill check (params are skill, dc, random dc, feedback, auto)
* 5 - favored enemy check (param is a favored enemy mask)
* 6 - spell resistance check (param is spell penetration)
*
* & - last check was successful (and)
* ^ - last check failed (exclusive or)
*
* OnHitBreach (integer)
* if > 0 will breach that many spells
* if < 0 will act as a dispel of level = abs(OnHitBreach)
*
*/
*snip*
/* apply special on-hit effects */
if (sEffects != "") {
int nPos, nDurType, nSubType, bPetrify, bSelf, bLast = FALSE;
float fDur;
string sDur;
effect eLink;
struct IntList il;
struct SubString css;
ss.rest = sEffects;
/* parse each effect in turn */
while (ss.rest != "") {
ss = GetFirstSubString(ss.rest);
css = GetFirstSubString(ss.first, "|");
/* if the effect has any pre-effect checks (e.g. random chance, saving throw),
* make them before applying the effect */
if (css.rest != "") {
ss.first = css.first;
if (css.rest == "&") {
if (!bLast)
continue;
} else if (css.rest == "^") {
if (!(bLast = !bLast))
continue;
} else {
bLast = !(CheckDynamic(css.rest, oTarget, OBJECT_SELF) > 0);
/* CheckDynamic returns TRUE if they pass; we invert it above so
* bLast is 'did the last effect go through' */
if (!bLast)
continue;
}
}
if ((nPos = FindSubString(ss.first, "#")) >= 0) {
nSpellId = StringToInt(GetStringRight(ss.first, GetStringLength(ss.first) - (nPos + 1)));
ss.first = GetStringLeft(ss.first, nPos);
if (GetHasSpellEffect(nSpellId, oTarget))
continue;
} else
nSpellId = -1;
/* check if the effect has an associated visual */
if ((nPos = FindSubString(ss.first, "/")) >= 0) {
nVis = StringToInt(GetStringRight(ss.first, GetStringLength(ss.first) - (nPos + 1)));
ss.first = GetStringLeft(ss.first, nPos);
} else
nVis = 0;
nSubType = 0;
bPetrify = FALSE;
bSelf = FALSE;
/* check if the effect has a duration parameter specified; if so, apply it;
* otherwise, determine the duration of the effect automatically */
if ((nPos = FindSubString(ss.first, ":")) >= 0) {
sDur = GetStringRight(ss.first, GetStringLength(ss.first) - (nPos + 1));
ss.first = GetStringLeft(ss.first, nPos);
/* check if a subtype was specified */
if ((nPos = FindSubString(sDur, ":")) >= 0) {
string sSub = GetStringRight(sDur, 1);
if (sSub == "E")
nSubType = SUBTYPE_EXTRAORDINARY;
else if (sSub == "S")
nSubType = SUBTYPE_SUPERNATURAL;
sDur = GetStringLeft(sDur, nPos);
}
if ((nPos = FindSubString(sDur, "+")) >= 0) {
int nRandDur = StringToInt(GetStringRight(sDur, GetStringLength(sDur) - (nPos + 1)));
fDur = StringToFloat(GetStringLeft(sDur, nPos)) + Random(nRandDur);
} else
fDur = StringToFloat(sDur);
if (fDur < 0.0) {
fDur = 0.0;
nDurType = DURATION_TYPE_PERMANENT;
} else if (fDur == 0.0)
nDurType = DURATION_TYPE_INSTANT;
else
nDurType = DURATION_TYPE_TEMPORARY;
int bFirst = TRUE;
struct SubString sss;
sss.rest = ss.first;
while (sss.rest != "") {
sss = GetFirstSubString(sss.rest, ";");
il = GetIntList(sss.first, ",");
if (bFirst) {
bFirst = FALSE;
eLink = EffectDynamic(il.i0, il.i1, il.i2, il.i3, il.i4, il.i5, il.i6);
} else
eLink = EffectLinkEffects(eLink, EffectDynamic(il.i0, il.i1, il.i2, il.i3, il.i4, il.i5, il.i6));
}
} else {
il = GetIntList(ss.first, ",");
if (il.i0 < 100) {
fDur = 6.0;
nDurType = DURATION_TYPE_TEMPORARY;
} else {
fDur = 0.0;
nDurType = DURATION_TYPE_INSTANT;
}
if (il.i0 == EFFECT_TYPE_HEAL)
bSelf = TRUE;
else if (il.i0 == EFFECT_TYPE_PETRIFY)
bPetrify = TRUE;
eLink = EffectDynamic(il.i0, il.i1, il.i2, il.i3, il.i4, il.i5, il.i6);
}
if (bSelf) {
if (GetCurrentHitPoints(oCaster) < GetMaxHitPoints(oCaster)) {
if (nVis > 0)
ApplyVisualToObject(nVis, oCaster);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eLink, oCaster);
}
} else {
if (nVis > 0)
ApplyVisualToObject(nVis, oTarget);
else if (nVis < 0)
eLink = EffectLinkEffects(eLink, EffectVisualEffect(-nVis));
if (nSubType == SUBTYPE_EXTRAORDINARY)
eLink = ExtraordinaryEffect(eLink);
else if (nSubType == SUBTYPE_SUPERNATURAL)
eLink = SupernaturalEffect(eLink);
if (nSpellId >= 0)
SetEffectSpellId(eLink, nSpellId);
if (bPetrify)
ApplyPetrifyEffect(nDurType, eLink, oTarget, fDur);
else
ApplyEffectToObject(nDurType, eLink, oTarget, fDur);
}
}
}
Again, I'm not sure you understand how GetFirstSubString works. It uses a struct with two strings to loop through a given string evaluating substrings. Check the comments above it.Normally you want to work directly towards the pseudostring and not against an struct which you can't build loop with.
Funky
Modifié par FunkySwerve, 02 juillet 2011 - 02:16 .
#11
Posté 02 juillet 2011 - 03:06
I just say that you can do it better if you skip structs, because you rarely need structs in nwscript.
they are certainly not good for lists. which is the most common use for arrays. and list are often used in loops where you only need to see one entry or two at a time. not the whole array at the same time
and when i talk about as close to memory i obviously mean as close that you can get in nwscript ie. the string itself. the more you nest and build layer the slower will each operation become.
#12
Posté 02 juillet 2011 - 03:20
#13
Posté 02 juillet 2011 - 05:16
Khuzadrepa wrote...
Can you give an example of how you would do it, CID-78? I'm trying to follow your logic, but it would be easier with something to compare against the code Funky provided.
I'll second that. I'm especially curious to see how you write a function with GetFirstSubString's functionality without using a struct.
Funky
#14
Posté 02 juillet 2011 - 06:03
Khuzadrepa wrote...
Can you give an example of how you would do it, CID-78? I'm trying to follow your logic, but it would be easier with something to compare against the code Funky provided.
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.
here is a simple example for adding a get first/next functionality to it. allong with a simple script to show/test the use. Of cource it would be better to just make the top two functions along with the one declaired global string as an include file.
#include "x3_inc_string"
string sParse; // This string if for use by GetFirst/Next only
// It is a place holder for the itorator.
// it is global to both functions.
// sArray is a string with space delimited tokens as array elements.
string GetFirstToken(string sArray)
{
string sToken = StringParse(sArray);
sParse = StringRemoveParsed(sArray,sToken);
return sToken;
}
// the token string used by this function is the one set in the GetFirstToken function.
//therefore it has no arguments.
string GetNextToken()
{
return GetFirstToken(sParse);
}
void main()
{
string Array = "Red Blue Green";
float fDelay=1.0;
string sSpeak = GetFirstToken(Array );
while (sSpeak != "")
{
DelayCommand(fDelay,SpeakString(sSpeak));
fDelay += 1.0;
sSpeak = GetNextToken();
}
}
Edited to correct spacing.
Modifié par Lightfoot8, 02 juillet 2011 - 06:17 .
#15
Posté 02 juillet 2011 - 06:43
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.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.
Funky
Modifié par FunkySwerve, 02 juillet 2011 - 06:44 .
#16
Posté 02 juillet 2011 - 07:01
FunkySwerve wrote...
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.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.
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.
#17
Posté 02 juillet 2011 - 08:45
CID-78 wrote...
you can simply use space as a delimiter and check each word against a keyword list. and execute accordingly
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.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.
#18
Posté 02 juillet 2011 - 09:10
Funky
#19
Posté 02 juillet 2011 - 09:32
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))
#20
Posté 02 juillet 2011 - 10:17
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)
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.
#21
Posté 03 juillet 2011 - 12:15
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 positionTrekSL 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))
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).
#22
Posté 03 juillet 2011 - 01:31
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.
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 .
#23
Posté 03 juillet 2011 - 01:53
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.
#24
Posté 03 juillet 2011 - 02:05
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!"
#25
Posté 03 juillet 2011 - 03:52
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: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!"





Retour en haut






