Author Topic: Migraine Door Challenge!  (Read 956 times)

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
Migraine Door Challenge!
« on: April 13, 2012, 05:33:45 pm »


               Up for a boggler? 

Imagine, if you will, 6 square areas, each area has doors at uniform intervals on all sides.

The areas are arranged as if they were faces on a cube.

In the center of each area, is a switch that when triggered, theoretically rotates the area the switch is in, although only the door/transitions would change targets.

Furthermore, some switches would cause the unoccupied faces of the cube to 'rotate'.

Now, what is required for this? 

I am thinking of a matrix that is the underlying 'cube', with the location of each door interface marked by a node, and given a unique identity. Those unique nodes would carry 2 variables, the identies of the doors that interface to it.

Then, as areas 'rotate', the door ID variables stored with each of the 'nodes' is changed accordingly.  Each switch would have a list of nodes that it influenced, so the managing script would know which nodes 'rotate' door ID's for.

Sadly, I know how I would do all this on a Commodore 64 using BASIC, but that doesn't really help me in NWN.

I will conceed, that the use of the intermediate nodes may not be a hard requirement to make this particular concept work, but there is another layer to this onion that requires the nodes.
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #1 on: April 13, 2012, 05:50:08 pm »


               <shouting...>

Tesseract! The heart of Greenvenom's lair in the Iron Mountain is a tesseract =)

A bit more complicated than 6 faces, and requires a Klein bottle to... <boss!>
Uh, right. can't cross that Teaser line, can we?

Your node framework makes sense to me.
Each node belongs to two faces.
Each face has 4 nodes.
Each door references a node.
On transition, the node is polled to determine the matching door *at that moment*, and a jump to wp moves the party. When switch is pulled, the 4 doors for that face rotate node references (placeholder=a=b=c=d=placeholder).
The other half of each door-node-door set is unchanged.

What would be *really* tricky (spoiler) is to have 4 versions of each face rotated by 90 degrees so that the compass directions swing wildly about...

<...tesseract horripilations!>
               
               

               


                     Modifié par Rolo Kipp, 13 avril 2012 - 05:08 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #2 on: April 13, 2012, 06:12:53 pm »


               Doors can be difficult. If you used triggers, then all you would have to do is update local variables upon rotation.
               
               

               
            

Legacy_PlasmaJohn

  • Full Member
  • ***
  • Posts: 150
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #3 on: April 13, 2012, 06:23:53 pm »


               Don't link the doors, use the OnAreaTransitionClick event then have the script choose the jump target.
               
               

               
            

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #4 on: April 13, 2012, 07:32:09 pm »


               

...
Your node framework makes sense to me.
Each node belongs to two faces.
Each face has 4 nodes.
Each door references a node.
On transition, the node is polled to determine the matching door *at that moment*, and a jump to wp moves the party. When switch is pulled, the 4 doors for that face rotate node references (placeholder=a=b=c=d=placeholder).
The other half of each door-node-door set is unchanged.


Just so... except I have no clue how to implement such a tangle in NWN.

What would be *really* tricky (spoiler) is to have 4 versions of each face rotated by 90 degrees so that the compass directions swing wildly about...


I am totally disinterested in the compass... In a tesseract, with space bending in on itself, I doubt magnetic forces would fair much better.

Unless there is a script to disable or disorient the compass, it's probably best just to ignore it.

I don't think knowing which side of the map was 'up' when it was drawn will do anybody much good if the map keeps getting cut up, spun around, and reoriented... particularly if the map is a legitimate labyrinth in it's own right.
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #5 on: April 13, 2012, 07:43:18 pm »


               

PlasmaJohn wrote...

Don't link the doors, use the OnAreaTransitionClick event then have the script choose the jump target.


Got it, then these functions ought to work perfectly no matter how you do the transition.

For this script to work each side transition tag must be of the form FACEPREFIX + "_" +  SIDE# and the local variable (on the module) for that tag should designate the tag of the target object.  Also set the number of sides for each face using the local integer (on the module) designated by the face prefix.

object GetTargetForTransition()
{
return GetObjectByTag(GetLocalString(GetModule(), GetTag(OBJECT_SELF)));
}

void RotateFaces(string sFacePrefix, int nShift = 1)
{
int nSidesOnFace = GetLocalInt(GetModule(), sFacePrefix);
int n = nSidesOnFace +1;
int nSide = 1;
int nPosition;
string sSide1;
string sSide2;
while(--n)
  {
  sSide1 = sFacePrefix + "_" + IntToString(n);
  nPosition = 1 + FindSubString(sSide1, "_");
  nSide = StringToInt(GetSubString(sSide1, nPosition, GetStringLength(sSide1) - nPosition));
  nSide = ((nSide + nShift - 1) % nSidesOnFace) + 1;
  sSide2 = GetLocalString(GetModule(), GetStringLeft(sSide1, nPosition) + IntToString(nSide));
  DelayCommand(0.5, SetLocalString(GetModule(), sSide2, sSide1));
  DelayCommand(0.5, SetLocalString(GetModule(), sSide1, sSide2));
  }
}

Edit fixed a script problem by resetting n, (should have used for loop to avoid this) .
Second edit, I feel ashamed for having to resort to delay command, but I really didn't want to redo this from scratch again with another parameter stored, so I have inserted delayed commands.
               
               

               


                     Modifié par WhiZard, 13 avril 2012 - 07:13 .
                     
                  


            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #6 on: April 13, 2012, 08:08:58 pm »


               <quickly drawing...>

Sweet! And elegant. I like it!

Wait... <looking confused>

WhiZard wrote...


object GetTargetForTransition()
{
return GetObjectByTag(GetLocalString(GetModule(), GetTag(OBJECT_SELF)));
}

void RotateFaces(string sFacePrefix, int nShift = 1)
{
int nSidesOnFace = GetLocalInt(GetModule(), sFacePrefix);
int n = nSidesOnFace +1;
int nSide = 1;
int nPosition;
string sSide1;
string sSide2;
while(--n)
  {
  sSide1 = sFacePrefix + "_" + IntToString(n);
  nPosition = 1 + FindSubString(sSide1, "_");
  nSide = StringToInt(GetSubString(sSide1, nPosition, GetStringLength(sSide1) - nPosition));
  nSide = ((nSide + nShift - 1) % nSidesOnFace) + 1;
  sSide2 = GetLocalString(GetModule(), GetStringLeft(sSide1, nPosition) + IntToString(nSide));
  SetLocalString(GetModule(), sSide2, sSide1);
  SetLocalString(GetModule(), sSide1, sSide2);
  }
}
Edit fixed a script problem by resetting n, (should have used for loop to avoid this) .


nShift is the number of sides to rotate?

So while there are still sides to do (n)
  assemble the name of the face_side (sFacePrefix + _ +(n))
  Find out where the underscore is so you can extract the number part (What am I missing? Wouldn't this be n?)
  ...

Where are you retreiving the sSide1 target from the local variable (module)? Er, I mean the sSide2 to swap into sSide1?

<...a map> 
               
               

               
            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #7 on: April 13, 2012, 08:16:39 pm »


               

Rolo Kipp wrote...

Where are you retreiving the sSide1 target from the local variable (module)? Er, I mean the sSide2 to swap into sSide1?

<...a map> 


The local variables would all be set from the module so that each variable name (tag of transition) links it to the tag of the target transition. 

I did make a second edit above, because I found that the shift would displace the sides I had already set further down the loop, and didn't want any compounding problems.
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #8 on: April 13, 2012, 08:38:22 pm »


               

WhiZard wrote...

PlasmaJohn wrote...

Don't link the doors, use the OnAreaTransitionClick event then have the script choose the jump target.


Got it, then these functions ought to work perfectly no matter how you do the transition.

For this script to work each side transition tag must be of the form FACEPREFIX + "_" +  SIDE# and the local variable (on the module) for that tag should designate the tag of the target object.  Also set the number of sides for each face using the local integer (on the module) designated by the face prefix.

object GetTargetForTransition()
{
return GetObjectByTag(GetLocalString(GetModule(), GetTag(OBJECT_SELF)));
}

void RotateFaces(string sFacePrefix, int nShift = 1)
{
int nSidesOnFace = GetLocalInt(GetModule(), sFacePrefix);
int n = nSidesOnFace +1;
int nSide = 1;
int nPosition;
string sSide1;
string sSide2;
while(--n)
  {
  sSide1 = sFacePrefix + "_" + IntToString(n);
  nPosition = 1 + FindSubString(sSide1, "_");
  nSide = StringToInt(GetSubString(sSide1, nPosition, GetStringLength(sSide1) - nPosition));
  nSide = ((nSide + nShift - 1) % nSidesOnFace) + 1;
  sSide2 = GetLocalString(GetModule(), GetStringLeft(sSide1, nPosition) + IntToString(nSide));
  DelayCommand(0.5, SetLocalString(GetModule(), sSide2, sSide1));
  DelayCommand(0.5, SetLocalString(GetModule(), sSide1, sSide2));
  }
}


So for face D and side 1 of a 6 sided cube...

While 1 is more than 0:
  sSide1 = "D+ "_" + "1" //sSide1 = "D_1"
  nPosition = 1+1 //nPosition = 2
  nSide = StringToInt(GetSubString("D_1", nPosition, GetStringLength("D_1")-nPosition) // nSide =1
  nSide = ((1+nShift-1)%nSidesOnFace+1 //nSide = 1%7 ? Not understanding this line... :-(
  sSide2 = Get the string stored in the variable "D_" + (1%7)
  Swap sSide1 ("D_1") into the variable "D_" + (1%7) //Are you storing the variable name for sSide1 into sSide2?
  Swap sSide2 ("D_" + 1%7) into variable named "D_1"

I can *feel* this script is right, but I'm just not following it :-(
               
               

               
            

Legacy_Rolo Kipp

  • Hero Member
  • *****
  • Posts: 4349
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #9 on: April 13, 2012, 08:45:25 pm »


               <following...>

WhiZard wrote...
The local variables would all be set from the module so that each variable name (tag of transition) links it to the tag of the target transition. 

I did make a second edit above, because I found that the shift would displace the sides I had already set further down the loop, and didn't want any compounding problems.

Right. Got that far. The transition tags would be paired up, and changing the tags when a face rotates is what we are talking about.

But somehow my brain is frazzling with that middle bit in there. Isn't the modulus operator going to give strange integers when dividing by the number of faces + 1? I.e. 1%7 is 1428571428571429 (depending on precision). How does that give us the new side tag?

Edit, the 1 is added after the modulus... duh! But still (1%6) + 1 = 1.1666...

<...bread crumbs>
               
               

               


                     Modifié par Rolo Kipp, 13 avril 2012 - 07:47 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #10 on: April 13, 2012, 08:54:23 pm »


               Here we are without the delayed command.  I managed to do it with a second loop.

EDIT:Redid the second loop what was there before worked only when the shift amount and number of sides were relatively prime.  Thus a shift of 2 on 4 sides did not work as only half of the sides would make it through the second loop.  Now this should work without delayed command as it uses the "#Temp" designation as a deletable placeholder.

object GetTargetForTransition()
{
return GetObjectByTag(GetLocalString(GetModule(), GetTag(OBJECT_SELF)));
}

void RotateFaces(string sFacePrefix, int nShift = 1)
{
int nSidesOnFace = GetLocalInt(GetModule(), sFacePrefix);
int n = nSidesOnFace + 1;
int nSide = 1;
int nPosition;
string sSide1;
string sSide2;
while(--n)
  {
  sSide1 = sFacePrefix + "_" + IntToString(n);
  nPosition = 1 + FindSubString(sSide1, "_");
  nSide = StringToInt(GetSubString(sSide1, nPosition, GetStringLength(sSide1) - nPosition));
  nSide = ((nSide + nShift - 1) % nSidesOnFace) + 1;
  sSide2 = GetLocalString(GetModule(), GetStringLeft(sSide1, nPosition) + IntToString(nSide));
  SetLocalString(GetModule(), sSide2, sSide1);
  SetLocalString(GetModule(), sSide1 + "#Temp", sSide2);
  }
while(++n <= nSidesOnFace)
  {
  sSide1 = sFacePrefix + "_" + IntToString(n);
  SetLocalString(GetModule(), sSide1, GetLocalString(GetModule(), sSide1 + "#Temp"));
  DeleteLocalString(GetModule(), sSide1 + "#Temp");
  }
}
               
               

               


                     Modifié par WhiZard, 13 avril 2012 - 08:13 .
                     
                  


            

Legacy_WhiZard

  • Hero Member
  • *****
  • Posts: 2149
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #11 on: April 13, 2012, 08:57:11 pm »


               

Rolo Kipp wrote...
But still (1%6) + 1 = 1.1666...

<...bread crumbs>


1%6 is 1 and 7%6 is 1.  The operation returns an integer.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #12 on: April 13, 2012, 09:29:00 pm »


               

WhiZard wrote...

Rolo Kipp wrote...
But still (1%6) + 1 = 1.1666...

<...bread crumbs>


1%6 is 1 and 7%6 is 1.  The operation returns an integer.


1%6 is 0 and 7%6 is 1.  The operation returns an integer.
  

Edit:  sorry long day.  
               
               

               


                     Modifié par Lightfoot8, 13 avril 2012 - 08:44 .
                     
                  


            

Legacy_Leurnid

  • Sr. Member
  • ****
  • Posts: 473
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #13 on: April 13, 2012, 09:42:50 pm »


               *boggles*

Ok, I am running on 2 hours of sleep and a second pot of coffee, but I can't really blame that, you guys have blown right past the 6 scripting tutorials I have choked down so far.

I see the rotation for the switch taking place, but what is being modified by that, and how do you stitch it all together for the desired effect?

It seems that you will need to modify the node associated with the door, as well as modify the rotated door associated with the node, so that coming back from the other side, you land in the right place, not just land in the right place on the outbound trip. Then of course, a script will need to stitch the door to the node (and on to the door), or maybe that can all be handled by just having a generic call from the door, and let the node management script handle it all?!  

Ok, I have tied my synapses into a knot again.  I am going to get more coffee, or maybe a nap, and let the experts handle this.  Carry on and disregard me.
               
               

               
            

Legacy_Lightfoot8

  • Hero Member
  • *****
  • Posts: 4797
  • Karma: +0/-0
Migraine Door Challenge!
« Reply #14 on: April 13, 2012, 09:48:55 pm »


               Questions:

1  Do all doors on the outside of the 6x6 square head out of the square?
 
2  Is this for multi-player or single player?  If it is single player, You could do it all with just two areas. if all the areas look alike.