Tying pretend physical strings together and getting different results.

I have 7 wires.

  • red wire
  • orange wire
  • yellow wire
  • green wire
  • blue wire
  • indigo wire
  • violet wire

I want the player to be able to tie them all together (that's the easy part).
I also want the player to be able to tie the red wire to the indigo wire. Or the green wire to the blue wire and the orange wire.
See where I'm going with this?

If the player ties the red and orange wire together he/she would end up with one wire that's red AND orange (and twice as long)
and so on....

There's quite a lot(!) of different possibilities and I can't figure out how to script it.
Any takers?


(filler for getting my edited post, updated/posted)
(again, filler for getting my edited post, updated/posted)


this will create/format a string, like so (for examples):

red wire
red-blue-yellow wire
red-blue-yellow-green-purple-orange wire

(it can handle/do all/any combinations -- if not, let me know, as I thus made mistakes in the code and need to fix them up)

(total combinations for your 7 items/colors/values = 7 x 6 x 5 x 4 x 3 x 2 = 5040 --- if I did the math/calculation right, lol)


this code can NOT handle your wire color values having spaces in them (if you add more, or change the/your, wire color values: they can NOT have spaces in them)

(I can adjust my code, if you want/need to be able to put spaces into your wire color values, it'll just take a little bit more added code and only very trivial work on my part)


the 'done' Value in the wire color stringlist attribute is required for the code to work, so you can't take it out or nor re-name it (well, you can re-name it if you want to, actually: if you need help on what you need to change in the code, then just ask me for help)


to use/implement my code within your game (within some Element that does scripting: Verb, Command, Object's Script Attribute, Turnscript, Timer, Function):

invoke (wire_object.wire_script_attribute)

<library>

  <delegate name="wire_delegate" type="string" />

  <object name="wire_object">

    <attr name="previous_wire_string_attribute" type="string">unknown</attr>

    <attr name="wire_string_attribute" type="string">unknown</attr>

    <wire_color_stringlist_attribute type="stringlist">
      <value>done</value>
      <value>red</value>
      <value>orange</value>
      <value>yellow</value>
      <value>green</value>
      <value>blue</value>
      <value>indigo</value>
      <value>violet</value>
    </wire_color_stringlist_attribute>

    <attr name="wire_script_attribute">
      this.previous_wire_string_attribute = this.wire_string_attribute
      this.wire_string_attribute = ""
      this.wire_buffer_stringlist_attribute = NewStringList ()
      foreach (string_variable, this.wire_color_stringlist_attribute) {
        list add (this.wire_buffer_stringlist_attribute, string_variable)
      }
      on ready {
        string_variable = RunDelegateFunction (this, "wire_handling_script_attribute")
        // -------------------------
        // (you can change below for how/what you want to do with the colored wire string), the below example, is just a quick display code line of the colored wire string:
        msg ("You created a " + string_variable)
        msg ("You created a " + wire_object.wire_string_attribute)
        // --------------------------
      }
    </attr>

    <attr name="wire_handling_script_attribute" type="wire_delegate">
      if (ListCount (this.wire_buffer_stringlist_attribute) = 1) {
        string_variable = RunDelegateFunction (this, "wire_string_formatting_script_attribute")
        return (string_variable)
      } else {
        show menu ("Select choice", this.wire_buffer_stringlist_attribute, false) { // or if you want random selection: result = PickOneString (this.wire_buffer_stringlist_attribute)
          this = wire_object
          if (result = "done") {
            string_variable = RunDelegateFunction (this, "wire_string_formatting_script_attribute")
            return (string_variable)
          } else {
            list remove (this.wire_buffer_stringlist_attribute, result)
            this.wire_string_attribute = this.wire_string_attribute + result + " " + RunDelegateFunction (this, "wire_handling_script_attribute")
          } 
        }
      }
    </attr>

    <attr name="wire_string_formatting_script_attribute" type="wire_delegate">
      string_variable = this.wire_string_attribute
      RTrim (string_variable) // this might return the trimmed string, so: string_variable = RTrim (string_variable)
      string_variable = Replace (string_variable, " ", "-")
      string_variable = string_variable + " wire"
      this.wire_string_attribute = string_variable
      return (string_variable)
    </attr>

  </object>

</library>

I just wrote/typed this code as a post here... so let me know if it doesn't work... lol

(I made this as a library file, if you need help on how to add it to (use it with) your game, and/or also need more help on how to implement/use my code within your game, let me know, and I'll help you)


P.S.

if you need to also work with a length amount of your created colored wire, my code can easily accomadate (can't spell, lol) it/that, so just let me know, and I'll adjust my code for being able to give your created colored wire strings a length amount as well.


Sheez Hege, that's beautiful! Thank you for taking the time to help me with this!

I've added the Lib to the game but I'm not sure what to do with this: invoke (wire_object.wire_script_attribute)
Is that supposed to go in a "tie strings together" type script?

Edit: Ah, and I get this when running the game:

Failed to load game.
The following errors occurred:
Error: Error adding script attribute 'script' to element 'k7': Function not found: 'RTrim'

I still run 5.7.2 of the desktop version. Might that have something to do with it? =)


that hopefully should be all you need... ya, you'd put it into whataver code you're using...

some quick (multiple -- you wouldn't be using them all together as like I did below) examples (just using a Script Attribute, Command, and Function as some of the multiple types of examples):

<asl version="550">

  <include ref="English.aslx" />
  <include ref="Core.aslx" />

  <include ref="wire_library.aslx" />

  <game name="example">

    <attr name="start" type="script">
      invoke (wire_object.wire_script_attribute)
      // or:
      wire_function
    </attr>

  </game>

  <function name="wire_function">
    invoke (wire_object.wire_script_attribute)
  </function>

  <command name="wire_command">
    <pattern>wire;test;w;t</pattern>
    <script>
     invoke (wire_object.wire_script_attribute)
     // or:
     wire_function
    </script>
  </command>

</asl>

P.S.

don't thank me yet... not until my code is actually fully working and working correctly, lol

P.S.S.

this was actually fun code to do for me, as I needed more practice with using recursion, lol. And, also, the working on the String Manipulation/Formatting was pretty fun too.


hmm... 'RTrim' has been around a long time... maybe the new version changed it... or... I got some mistake in my code...


maybe... RTrim... returns the trimmed string...

(also, 'Replace' does return a string... spotted another mistake in my code... lol)

try this code:

<library>

  <delegate name="wire_delegate" type="string" />

  <object name="wire_object">

    <attr name="previous_wire_string_attribute" type="string">unknown</attr>

    <attr name="wire_string_attribute" type="string">unknown</attr>

    <wire_color_stringlist_attribute type="stringlist">
      <value>done</value>
      <value>red</value>
      <value>orange</value>
      <value>yellow</value>
      <value>green</value>
      <value>blue</value>
      <value>indigo</value>
      <value>violet</value>
    </wire_color_stringlist_attribute>

    <attr name="wire_script_attribute">
      this.previous_wire_string_attribute = this.wire_string_attribute
      this.wire_string_attribute = ""
      this.wire_buffer_stringlist_attribute = NewStringList ()
      foreach (string_variable, this.wire_color_stringlist_attribute) {
        list add (this.wire_buffer_stringlist_attribute, string_variable)
      }
      on ready {
        string_variable = RunDelegateFunction (this, "wire_handling_script_attribute")
        // -------------------------
        // (you can change below for how/what you want to do with the colored wire string), the below example, is just a quick display code line of the colored wire string:
        msg ("You created a " + string_variable)
        msg ("You created a " + wire_object.wire_string_attribute)
        // --------------------------
      }
    </attr>

    <attr name="wire_handling_script_attribute" type="wire_delegate">
      if (ListCount (this.wire_buffer_stringlist_attribute) = 1) {
        string_variable = RunDelegateFunction (this, "wire_string_formatting_script_attribute")
        return (string_variable)
      } else {
        show menu ("Select choice", this.wire_buffer_stringlist_attribute, false) { // or if you want random selection: result = PickOneString (this.wire_buffer_stringlist_attribute)
          this = wire_object
          if (result = "done") {
            string_variable = RunDelegateFunction (this, "wire_string_formatting_script_attribute")
            return (string_variable)
          } else {
            list remove (this.wire_buffer_stringlist_attribute, result)
            this.wire_string_attribute = this.wire_string_attribute + result + " " + RunDelegateFunction (this, "wire_handling_script_attribute")
          } 
        }
      }
    </attr>

    <attr name="wire_string_formatting_script_attribute" type="wire_delegate">
      string_variable = this.wire_string_attribute
      string_variable = RTrim (string_variable)
      string_variable = Replace (string_variable, " ", "-")
      string_variable = string_variable + " wire"
      this.wire_string_attribute = string_variable
      return (string_variable)
    </attr>

  </object>

</library>

oops... I just spotted that I used 'this' within the 'show menu' Function... whoopsy...

new fixed code:

<library>

  <delegate name="wire_delegate" type="string" />

  <object name="wire_object">

    <attr name="previous_wire_string_attribute" type="string">unknown</attr>

    <attr name="wire_string_attribute" type="string">unknown</attr>

    <wire_color_stringlist_attribute type="stringlist">
      <value>done</value>
      <value>red</value>
      <value>orange</value>
      <value>yellow</value>
      <value>green</value>
      <value>blue</value>
      <value>indigo</value>
      <value>violet</value>
    </wire_color_stringlist_attribute>

    <attr name="wire_script_attribute">
      this.previous_wire_string_attribute = this.wire_string_attribute
      this.wire_string_attribute = ""
      this.wire_buffer_stringlist_attribute = NewStringList ()
      foreach (string_variable, this.wire_color_stringlist_attribute) {
        list add (this.wire_buffer_stringlist_attribute, string_variable)
      }
      on ready {
        string_variable = RunDelegateFunction (this, "wire_handling_script_attribute")
        // -------------------------
        // (you can change below for how/what you want to do with the colored wire string), the below example, is just a quick display code line of the colored wire string:
        msg ("You created a " + string_variable)
        msg ("You created a " + wire_object.wire_string_attribute)
        // --------------------------
      }
    </attr>

    <attr name="wire_handling_script_attribute" type="wire_delegate">
      if (ListCount (this.wire_buffer_stringlist_attribute) = 1) {
        string_variable = RunDelegateFunction (this, "wire_string_formatting_script_attribute")
        return (string_variable)
      } else {
        show menu ("Select choice", this.wire_buffer_stringlist_attribute, false) { // or if you want random selection: result = PickOneString (this.wire_buffer_stringlist_attribute)
          this = wire_object
          if (result = "done") {
            string_variable = RunDelegateFunction (this, "wire_string_formatting_script_attribute")
            return (string_variable)
          } else {
            list remove (this.wire_buffer_stringlist_attribute, result)
            this.wire_string_attribute = this.wire_string_attribute + result + " " + RunDelegateFunction (this, "wire_handling_script_attribute")
          } 
        }
      }
    </attr>

    <attr name="wire_string_formatting_script_attribute" type="wire_delegate">
      string_variable = this.wire_string_attribute
      string_variable = RTrim (string_variable)
      string_variable = Replace (string_variable, " ", "-")
      string_variable = string_variable + " wire"
      this.wire_string_attribute = string_variable
      return (string_variable)
    </attr>

  </object>

</library>

This seems a horribly complex way to approach a simple problem. Is there a reason for using delegates? Is there a reason the wires aren't objects?


@mra To me all ways (in this matter) feels horribly complex :)


main operations:

'wire_script_attribute':

  1. store the previous colored wire string (just in-case you'd have a need for it) // if you have a need to store multiple previous colored wire strings, that can be easily coded in (we just need to use a String List Attribute, instead of a String Attribute)
  2. copy wire color list (as we'll remove the wire color choices from this copy list, so we don't mess with the list of wire colors)

'wire_handling_script_attribute':

  1. string concatenation + looping/tail-recursion + wire color selection (via menu selection using our copy list), to build our colored wire string. (And, as we select wire colors, remove those wire colors from our copy list)

'wire_string_formatting_script_attribute':

  1. if/when you choose 'done' from the menu selection or if you selected all of the wire colors (no more wire colors to choose from: the copy list only has 1 item, the 'done' choice, remaining) from #3 operation above: finish formatting the colored wire string for use

I would probably have done something more like a stacking system; where the wires are objects that can be carried around, and can be tied together to make a single object.

Not sure from the OP which kind of wires you'd prefer.

Here's a first attempt (typing code in the forum, so no guarantees it'd work) of the kind of structure I'd use:

code

This was half written on my phone, and hasn't been tested at all. It still has issues. I figured that you might want the player to be able to tie wires onto a wire that's poking out of a machine or something, so didn't limit it to the inventory. But as it currently stands, the "tie" command puts the completed wire in the same place as its *first" argument, and doesn't check if the others can be taken/dropped. This is fixable, but will make the code a bit longer and may be awkward if any of your wires have take/drop scripts.

<type name="wire">
  <attr name="update_attributes" type="script">
    if (HasAttribute (this, "wireparts")) {
      colourlist = NewStringList()
      wirelength = 0
      foreach (wire, this.wireparts) {
        if (HasString (wire, "wirecolour")) {
          list add (colourlist, wire.wirecolour)
        }
        if (HasInt (wire.wirelength)) {
          wirelength = wirelength + wire.wirelength
        }
      }
      this.wirelength = wirelength
      this.longcolour = FormatList (colourlist, ", ", ", and", "no")
      colourlist = ListCompact (colourlist)
      this.wirecolour = Join (colourlist, "/")
    }
    this.alias = this.wirecolour + " " + this.wiretype
  </attr>
  <look type="string">{either HasAttribute(this, "wireparts"):A length of {this.wiretype}, made of smaller {this.longcolour} pieces knotted together.:A piece of {this.wirecolour} {this.wiretype}.}</look>
  <wirelength type="int">1</wirelength>
  <wiretype type="string">wire</wiretype>
  <wirecolour type="string">plain</wirecolour>
  <inventoryverbs type="listextend">Tie;Untie</inventoryverbs>
  <take/>
  <drop/>
</type>

<command name="untie">
  <pattern>^untie (?<object>.+)$</pattern>
  <changecommandscope type="script"><![CDATA[
    // Allow the player to untie a single wire from its parts, even if the single wire isn't in scope
    i = 0
    while (i < ListCount (items)) {
      obj = ListItem (items, i)
      if (HasAttribute (obj, "wireparts")) {
        foreach (subwire, obj.wireparts) {
          list add (items, subwire)
        }
      }
      i = i + 1
    }
  ]]></changecommandscope>
  <script>
    if (ListContains (ScopeReachable(), object)) {
      if (HasAttribute (object, "wireparts")) {
        foreach (part, object.wireparts) {
          part.parent = object.parent
        }
        msg ("You untie the knots, and separate the "+object.wiretype+" into "+ListCount(object.wireparts)+" pieces.")
      }
      else if (DoesInherit (object, "wire")) {
        msg ("It isn't tied to anything,")
      }
      else {
        msg ("You can't untie that.")
      }
    }
    else if (ListContains (ScopeReachable(), object.parent) and DoesInherit (object.parent, "wire")) {
      knot = object.parent
      pos = IndexOf (knot.wireparts, object)
      switch (pos) {
        case (-1) {
          // This shouldn't happen
        }
        case (0) {
          list remove (knot.wireparts, object)
        }
        case (ListCount(knot.wireparts) - 1) {
          list remove (knot.wireparts, object)
        }
        case (1) {
          list remove (knot.wireparts, object)
          endpiece = ListItem (knot.wireparts, 0)
          list remove (knot.wireparts, endpiece)
          endpiece.parent = knot.parent
        }
        case (ListCount(knot.wireparts) - 2) {
          list remove (knot.wireparts, object)
          endpiece = ListItem (knot.wireparts, ListCount(knot.wireparts) - 1)
          list remove (knot.wireparts, endpiece)
          endpiece.parent = knot.parent
        }
        default {
          list remove (knot.wireparts, object)
          newknot = GetUniqueElementName("wire")
          create (newknot, "wire")
          newknot = GetObject (newknot)
          newknot.parent = knot.parent
          newknot.wireparts = NewObjectList()
          while (ListCount (knot.wireparts) > pos) {
            part = ListItem (knot.wireparts, pos)
            list remove (knot.wireparts, part)
            list add (newknot.wireparts, part)
            part.parent = newknot
          }
          do (newknot, "update_attributes")
        }
      }
      object.parent = knot.parent
      if (ListCount (knot.wireparts) = 1) {
        part = ListItem (knot.wireparts, 0)
        part.parent = knot.parent
        destroy (knot.name)
      }
      else {
        do (knot, "update_attributes")
      }
    }
    else {
      msg ("I can't reach that.")
    }
  </script>
</command>

<command name="tie">
  <pattern>^tie (?<object>.+?)( together| to (?<object2>.+)|)$</pattern>
  <allow_all />
  <changecommandscope type="script"><![CDATA[
    // restricts scope to just wires
    i = 0
    while (i < ListCount (items)) {
      item = ListItem (items, i)
      if (DoesInherit (item, "wire")) {
        i = i + 1
      }
      else {
        list remove (items, i)
      }
    }
  ]]></changecommandscope>
  <script><![CDATA[
    wires = NewObjectList()
    if (IsDefined("object")) {
      if (EndsWith (TypeOf (object), "list")) {
        wires = object
      }
      else {
        list add (wires, object)
      }
    }
    if (IsDefined("object2")) {
      if (EndsWith (TypeOf (object2), "list")) {
        wires = ListCombine (wires, object2)
      }
      else {
        list add (wires, object2)
      }
    }
    wires = ListCompact (wires)
    if (ListCount (wires) < 2) {
      allwires = FilterByType (ScopeReachable(), "wire")
      if (ListCount (allwires) = 2) {
        wires = ListCompact (ListCombine (wires, allwires))
      }
      else {
        msg ("You need at least two wires to tie together.")
        if (ListCount (allwires) > 2) {
          message = "What would you like to tie"
          if (ListCount (wires) = 1) message = message + " it to"
          this.disambiguation_wires = wires
          ShowMenu (message+"?", ListExclude (allwires, wires), true) {
            wires = tie.disambiguation_wires
            list add (wires, result)
            do (tie, "script", QuickParams ("object", wires))
          }
        }
      }
    }
    else {
      // We've got enough wires.
      knot = null
      tied = NewStringList()
      foreach (wire, wires) {
        if (not ListContains (ScopeReachable(), wire)) {
          msg ("You can't get the "+GetDisplayAlias(wire)+".")
        }
        else if (HasAttribute (wire, "wireparts")) {
          list add (tied, GetDisplayName (wire))
          if (knot = null) {
            knot = wire
          }
          else {
            foreach (subwire, wire.wireparts) {
              list add (knot.wireparts, subwire)
              MoveObject (subwire, knot)
            }
            destroy (wire.name)
          }
        }
        else {
          list add (tied, GetDisplayName (wire))
          if (knot = null) {
            knot = GetUniqueElementName("wire")
            create (knot, "wire")
            knot = GetObject (knot)
            knot.parent = wire.parent
            knot.wireparts = NewObjectList()
          }
          list add (knot.wireparts, wire)
          MoveObject (wire, knot)
        }
      }
      if (knot = null) {
        msg ("Something went wrong.")
      }
      else if (LengthOf (knot.wireparts) < 2) {
        msg ("You couldn't tie ir.")
        foreach (wire, knot.wireparts) {
          MoveObject (wire, knot.parent)
        }
        destroy (knot.name)
      }
      else {
        do (knot, "update_attributes")
        msg ("You tie "+FormatList(tied, ", ", ", and", "nothing")+" together.")
      }
    }
  ]]></script>
</command>

With this, you should be able to create wires easily enough. Something like:

<object name="redwire">
  <inherit name="wire"/>
  <wirecolour>red</wirecolour>
  <wirelength>3</wirelength>
</object>

The player can enter commands like tie red wire to blue wire, or tie red wire, green wire, and blue wire, or tie all together. Not entirely sure on the format of lists it will accept, as I've not done much with multiple commands. This will create a new wire with an alias like "red/green/blue wire".
If you have some command where the player is using a wire, and you want to check if it includes the red one, you can use Contains (someobject, redwire), or Instr (someobject.wirecolour, "red") > 0.


You both have given me a lot to think about.
The wires are indeed physical game objects. The player can find them in different places... so maybe MrA's way is more suiting for me in this case?
There's a lot of code and I'm at work now so I can't really check it until tonight.
Either way, again, thanks for taking the time guys!


Edited mine, the first prototype of something that might work, but still has a few issues. Most notably, if the wires aren't all in the same place, it should check that they can be taken or dropped before tying them together.


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums