NPC random pathfinding

doubleoathseven
06 Dec 2017, 02:45

So I'm building a game at the moment and have a cleaner droid who moves randomly from room to room among a set range.

I'm quite deliberately moving the object rather than getting it to use exits, simulating the fact that the little fella is using service hatches that the player is too large to fit through, so that it can 'clean' (ie pick up objects under a certain volume left around and drop them off in a specific 'bin' object) rooms that are locked. Note: I'm just working on the pathfinding at the moment and will get to the cleaning scripts later.

So, the game runs this at gamestart:

r21apath = NewObjectList ()
list add = (r21apath, aviary)
list add = (r21apath, courtyard)
list add = (r21apath, dark hall)
list add = (r21apath, the cells)
list add = (r21apath, dungeon)

As well as starting an 8-second BotTimer.

Our little r21a, the cleaner, starts in the courtyard. The courtyard is the third room the player ever enters, so the droid doesn't do anything, in order to guarantee you see it.

But the first time you look at r21a, it sets the BotTimer to the following script :

n = GetRandomInt (0, 4)
if (r21a.parent = player.parent) {
	msg ("r21a leaves " + r21a.parent + "")
}
r21a.parent = ObjectListItem(r21apath, n) 
if (r21a.parent = player.parent) {
	msg ("r21a enters " + r21a.parent + "")
}

Please note I've been busy at work and have been writing this on my phone and haven't really had the chance to put the code into Quest yet.

So my questions (finally), to those coders more proficient than I, are:

  1. Does this look workable?

  2. Would there be a DRY way to implement this as a function? I'd imagine something along the lines of giving the cleaner and other pathfinders a 'pathfinder' flag, running a foreach at game-start to create a list named after each pathfinder. Can you create a list and have its name decided by a script? Could a pathfinder have its visitable rooms set as attributes and then the gamestart foreach could fetch those details to add to the list?

  3. Help?


DarkLizerd
06 Dec 2017, 03:50

Looks good...
And a good idea about a function...
And if the function, or functions includes a map, you could expand where the droid goes...
Like this:
(not real code)
function Droid_move()
If r21a.parent =aviary {
r21apath=("north room, east room,courtyard", ",")
}
if r21a.parent =Courtyard{
r21apath=("aviary,dark hall,the cells,dungeon", ",")
}
if r21a.parent =dark hall {
r21apath=("room1,room2,room3,room4,room5,courtyard", ",")
}
then do this for every room the droid can go to and it allows you to control where it goes.
(someone else will give you a ForEachExit search thingy that will do the same...)

Then you random selected room from the r21apath list

One thing to watch out for is spaces...
r21apath=("room1,room2,room3,room4,room5,courtyard", ",")
is not the same as
r21apath=("room1, room2, room3, room4, room5, courtyard", ",")
Quest sees the space in front of the room names in the list and tells you that room1 is not the same as room1...
(Took a while to find that one!!!)


The Pixie
06 Dec 2017, 08:22

r21apath needs to be attached to an object. Personally, I would give the r21a object an attribute called "path", so it is r21a.path. This answers your point 2; just check if an object has a path attribute.

You could put all the rooms r21a can visit inside another room (one the player cannot access), representing the zone. Then (supposing it is called "cleaning zone"):

r21a.path = GetDirectChildren(cleaning zone)

And you could use PickOneObject to select the next room. Also check if the room actually changed. The then could be (assuming all rooms have aliases).

newRoom = PickOneObject (r21a.path)
if (not newRoom = r21a.parent) {
  if (r21a.parent = player.parent) {
    msg ("r21a leaves " + r21a.parent.alias + ".")
  }
  if (newRoom  = player.parent) {
    msg ("r21a enters " + r21a.parent.alias + ".")
  }
  r21a.parent = newRoom 
}

You could easily put that in a function, just change "r21a" for "npc", and have "npc" as a parameter.

More advanced... If you are using the desktop version, the best way to make it DRY is using types. Have the above as a script on the "robot type", and change "r21a" for "this" ("this" indicates the thing the script is attached to), called "takeaturn". Then have all the robots inherit from the "robot type", which in tirn inherits from the "npc type". Each turn (i.e., 8 seconds), run the "takeaturn" script of all the NPCs; for the robot NPCs, that would be the script above, but other NPCs could have their own script for their own behaviour.

foreach (npc, FilterByType(AllObjects(), "npc type")) {
  do(npc, "takeaturn")
}

Not relevant in this case, but for completeness Quest does have PickOneExit and PickOneUnlockedExit for when you want an NPC to use exits.


doubleoathseven
06 Dec 2017, 12:54

Pixie, thanks!

I worked through that and made a few minor adjustments - both because of a few different gameplay elements that I had that were were interfering and also because I likely made errors in code entry (my pc has no internet connection, so I didn't have the option of copying and pasting your code).

I've edited the lookat command so that it sets a lookedat flag and coded that into the timer as if (GetBoolean(object, "lookedat")){ expression. Mainly because I want the player to encounter the NPCs in specific rooms - bit of a hassle if they wander off before you even get there.

I'll post the code when I can plug the computer in again.

As a quick side note, how would you deal with NPCs that share some but not all of their paths? Logically it seems to me that the overlapping rooms would have to both be nested inside two uber-rooms. I didn't think Quest could do that.


mrangel
09 Dec 2017, 11:18

If they share some but not all rooms in their paths, you might have to explicitly create the path attribute as you did in your first example.

I'd probably have done this using exits anyway, but had the NPC not check if the exit is locked or visible (so you can use an invisible exit to indicate a path NPCs can take but the player can't).


Doctor Agon
13 Dec 2017, 09:45

Hi, apologies to doubleoathseven for hijacking the thread, but I have a similar issue in my game.

I'd like my npc character to either follow a pre-determined path between 5 rooms for example;
room1 => room2 => room3 => room2 => room4 => room5, then reverse direction back to room1 then repeat.

Or to randomly select it's route based on the exits available between those 5 rooms.

There would be other rooms off these 5 where the npc character wouldn't go/patrol, so an attribute would be attached to these 5 rooms, eg. 'patrol route'.

Not sure yet which option to go with, but also unsure how to go about coding either option.
I've looked at previous threads but can't seem to find a solution unless I've missed something.
Can anyone help.


hegemonkhan
13 Dec 2017, 19:53

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


@ Dr. Agon:


For your 'non-random' method, you're asking for doing a recursion operation, hehe:

(in trying to do this, I realized that direct recursion couldn't work, so I had to create an indirect recursion effect/operation, lol)

(hopefully this does work... been working on this a long time... and I'm still not really comfortable with recursion, as I've not really done much work/practice with it. I'm sure Pixie and/or mrangel can create much more efficient coding, as I'm still a noob at this type, recursion or whatever design, of coding, as it's advanced coding design for me, I really struggled with this code of mine. Been working on this post/code for some hours now, sighs)

(I'll try to explain it / walk you through it, if you can't follow/understand it, just let me know)

(I can add more scalable/dynamic scripting, but this is just an example, let me know if you want or need help with more scalability/dynamic-ness of it)

<delegate name="recursion_delegate" parameters="object_parameter" />

<game name="example_game">
</game>

<object name="room_data_object">

  <object name="room">
  </object>

  <object name="npc_1_room_data_object">

    <object name="room_1">
    </object>

    <object name="room_2">
    </object>

    <object name="room_3">
    </object>

    <object name="room_4">
    </object>

    <object name="room_5">
    </object>

  </object>

  <object name="npc_2_room_data_object">

    <object name="room_6">
    </object>

    <object name="room_7">
    </object>

    <object name="room_8">
    </object>

    <object name="room_9">
    </object>

    <object name="room_10">
    </object>

  </object>

</object>

<object name="player">

  <attr name="parent"> type="object">room</attr>

  <attr name="changedparent" type="script">
    rundelegate (recursion_object, "recursion_script_attribute", npc_1)
    rundelegate (recursion_object, "recursion_script_attribute", npc_2)
  </attr>

</object>

<object name="recursion_object">

  <attr name="recursion_script_attribute" type="recursion_delegate">
    if (not object_parameter.recursion_boolean_attribute) {
      list add (object_parameter.recursion_objectlist_attribute, object_parameter.parent)
      object_parameter.parent = ObjectListItem (object_parameter.patrol_objectlist_attribute, ListCount (object_parameter.recursion_objectlist_attribute))
      if (ListCount (object_parameter.recursion_objectlist_attribute) = ListCount (object_parameter.patrol_objectlist_attribute) - 1) {
        object_parameter.recursion_boolean_attribute = true
      }
    } else {
      object_parameter.parent = ObjectListItem (object_parameter.patrol_objectlist_attribute, ListCount (object_parameter.recursion_objectlist_attribute) - 1)
      list remove (object_parameter.recursion_objectlist_attribute, ListCount (object_parameter.recursion_objectlist_attribute) - 1)
      if (ListCount (object_parameter.recursion_objectlist_attribute) = 0) {
        object_parameter.recursion_boolean_attribute = false
      }
    }
  </attr>

</object>

<object name="npc_data_object">

  <object name="npc_1">

    <attr name="parent" type="object">room_1</attr>

    <attr name="recursion_boolean_attribute" type="boolean">false</attr>

    <attr name="recursion_objectlist_attribute" type="objectlist">
    </attr>

    <attr name="patrol_objectlist_attribute" type="objectlist">
      <value>room_1</value>
      <value>room_2</value>
      <value>room_3</value>
      <value>room_4</value>
      <value>room_5</value>
    </attr>

  </object>

  <object name="npc_2">

    <attr name="parent" type="object">room_6</attr>

    <attr name="recursion_boolean_attribute" type="boolean">false</attr>

    <attr name="recursion_objectlist_attribute" type="objectlist">
    </attr>

    <attr name="patrol_objectlist_attribute" type="objectlist">
      <value>room_6</value>
      <value>room_7</value>
      <value>room_8</value>
      <value>room_9</value>
      <value>room_10</value>
    </attr>

  </object>

</object>

<!--
Note to self:

I can move the, 'recursion_objectlist_attribute' and 'recursion_boolean_attribute', over to the 'recursion_object' (instead of redundantly having every npc have it, YUCK! lol), and just remember that it'd have to be cleared/overwritten (and for the boolean, set it back to default value: false) when done, so it's blank for the next time its used with different rooms.

(too tired/exhausted to go ahead and adjust my code right now, lol. I need a break, sighs)
-->

randomization of what room to go to is very easy....


randomization + (recursive) retracing of the randomized sequence is much more difficult (surely, but I've not even tried to think of doing it, as I'm tired from just getting my code above done, sighs)


actually... I couldn't help from thinking about it as I wrote this part of my post, lol....

and I think... my code will be able to easily incorporate/adapt to adding in a randomized sequence... hopefully... otherwise... it'll be very difficult for me to do, lol.


K.V.
13 Dec 2017, 20:14

HK,

You did almost the same thing I did, but you made it a little longer than I did before giving up for the night.

NOTE: This will do nothing at the moment.

<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Pathfinding NPC">
    <gameid>fb4843e9-acc1-4079-922f-99301c91ccea</gameid>
    <version>1.0</version>
    <firstpublished>2017</firstpublished>
    <start type="script">
      NPC.roomlist = NewObjectList()
      list add (NPC.roomlist, room1)
      list add (NPC.roomlist, room2)
      list add (NPC.roomlist, room3)
      list add (NPC.roomlist, room4)
      list add (NPC.roomlist, room5)
    </start>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="north" to="room1">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="room1">
    <inherit name="editor_room" />
    <exit alias="south" to="room">
      <inherit name="southdirection" />
    </exit>
    <exit alias="north" to="room2">
      <inherit name="northdirection" />
    </exit>
    <object name="NPC">
      <inherit name="editor_object" />
      <usedefaultprefix type="boolean">false</usedefaultprefix>
      <prefix>an</prefix>
      <turnscript name="NPC_pathfinding_turnscript">
        <script>
          if (not HasAttribute(NPC, "lastvisited")) {
            NPC.lastvisited = NewObjectList()
          }
          if (ListCount(NPC.lastvisited=2)) {
            lastroom = NPC.lastvisited[0]
            list remove (NPC.lastvisited, NPC.lastvisited[0])
          }
          list add (NPC.lastvisited, NPC.parent)
          i = 0
          foreach (room, NPC.roomlist) {
            if (lastroom = room) {
              if (NPC.roomlist[i+1] = NPC.parent) {
              // Yawn.  Stretch.  I'll finish this tomorrow!
              }
            }
          }
        </script>
      </turnscript>
    </object>
  </object>
  <object name="room2">
    <inherit name="editor_room" />
    <exit alias="north" to="room3">
      <inherit name="northdirection" />
    </exit>
    <exit alias="south" to="room1">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="room3">
    <inherit name="editor_room" />
    <exit alias="north" to="room4">
      <inherit name="northdirection" />
    </exit>
    <exit alias="south" to="room2">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="room4">
    <inherit name="editor_room" />
    <exit alias="south" to="room3">
      <inherit name="southdirection" />
    </exit>
    <exit alias="north" to="room5">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="room5">
    <inherit name="editor_room" />
    <exit alias="south" to="room4">
      <inherit name="southdirection" />
    </exit>
  </object>
</asl>

hegemonkhan
13 Dec 2017, 20:20

ah, so KV is already capable/understanding of, recursion / this-type of, advanced design/logic ...

sorry for not including you in the list with pixie and mrangel who can probably do more efficient coding, didn't know you were already at this level of coding ability. (I was hoping you hadn't advanced to understanding this type of advanced coding, meh, you're really smart to be getting/learning/understanding such advanced coding/concepts/designs so quickly, sighs. You've already surpassed me in coding)

HK will now (hopefully) remember to include you amongst pixie and mrangel (and pertex and etc --- though they don't post that often)


K.V.
13 Dec 2017, 20:43

Hey, how about this?

(It seems to work when I test it.)

EDITED: Added USE verb to button and made it switch from random to ...um... not random when pressing or using it.

<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Pathfinding NPC">
    <gameid>fb4843e9-acc1-4079-922f-99301c91ccea</gameid>
    <version>1.2</version>
    <firstpublished>2017</firstpublished>
    <appendobjectdescription />
    <start type="script">
      NPC.roomlist = NewObjectList()
      list add (NPC.roomlist, room1)
      list add (NPC.roomlist, room2)
      list add (NPC.roomlist, room3)
      list add (NPC.roomlist, room4)
      list add (NPC.roomlist, room5)
    </start>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="north" to="room1">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="room1">
    <inherit name="editor_room" />
    <enter type="script">
      EnableTurnScript (NPC_pathfinding_turnscript)
    </enter>
    <exit alias="south" to="room">
      <inherit name="southdirection" />
    </exit>
    <exit alias="north" to="room2">
      <inherit name="northdirection" />
    </exit>
    <object name="NPC">
      <inherit name="editor_object" />
      <inherit name="namedmale" />
      <usedefaultprefix type="boolean">false</usedefaultprefix>
      <prefix>an</prefix>
      <look>The NPC is tidying up from room to room.</look>
      <inroomdescription>{once:The NPC sees you looking at him and gets back to work,}{notfirst:The NPC is passing through here while} tidying up from room to room.</inroomdescription>
    </object>
    <object name="random button">
      <inherit name="editor_object" />
      <take />
      <press type="script">
        if (not NPC.move_randomly) {
          NPC.move_randomly = true
          msg ("The NPC is now moving randomly.")
        }
        else {
          NPC.move_randomly = false
          msg ("The NPC is no longer moving randomly.")
        }
      </press>
      <feature_usegive />
      <use type="script">
        invoke (this.press)
      </use>
    </object>
  </object>
  <object name="room2">
    <inherit name="editor_room" />
    <exit alias="north" to="room3">
      <inherit name="northdirection" />
    </exit>
    <exit alias="south" to="room1">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="room3">
    <inherit name="editor_room" />
    <exit alias="north" to="room4">
      <inherit name="northdirection" />
    </exit>
    <exit alias="south" to="room2">
      <inherit name="southdirection" />
    </exit>
  </object>
  <object name="room4">
    <inherit name="editor_room" />
    <exit alias="south" to="room3">
      <inherit name="southdirection" />
    </exit>
    <exit alias="north" to="room5">
      <inherit name="northdirection" />
    </exit>
  </object>
  <object name="room5">
    <inherit name="editor_room" />
    <exit alias="south" to="room4">
      <inherit name="southdirection" />
    </exit>
  </object>
  <turnscript name="NPC_pathfinding_turnscript">
    <script><![CDATA[
      firsttime {
        NPC.moves = 0
        NPC.moveup = true
        NPC.move_randomly = false
      }
      if (NPC.moves = ListCount(NPC.roomlist)-1) {
        NPC.moveup = false
      }
      if (NPC.moves = 0) {
        NPC.moveup = true
      }
      if (NPC.moveup) {
        if (NPC.moves < ListCount(NPC.roomlist)-1) {
          NPC.moves = NPC.moves + 1
        }
        else if (NPC.moves = ListCount(NPC.roomlist)-1) {
          NPC.moveup = false
          NPC.moves = NPC.moves -1
        }
      }
      if (not NPC.moveup) {
        if (NPC.moves > 0) {
          NPC.moves = NPC.moves - 1
        }
        else if (NPC.moves = 0) {
          NPC.moveup = true
          NPC.moves = NPC.moves * 1
        }
      }
      // For debugging:
      msg (NPC.roomlist[NPC.moves])
      if (NPC.move_randomly) {
        NPC.moves = GetRandomInt(0,ListCount(NPC.roomlist)-1)
      }
      MoveObject (NPC, NPC.roomlist[NPC.moves])
    ]]></script>
  </turnscript>
  <verb>
    <property>press</property>
    <pattern>press;push</pattern>
    <defaultexpression>"You can't press;push " + object.article + "."</defaultexpression>
  </verb>
</asl>

DarkLizerd
13 Dec 2017, 20:46

OK, So I am a Basic programmer and not an object programmer...
so, this is how I would see the solution:
(Setup)
NPC.room=1
NPC.direction=1
NPC.roomlist=Split("room1, room2, room3, room4, room5", ",")
And for the NPC move:
NPC.room=NPC.room +NPC.direction
if NPC.room=4 {
NPC.Direction=-1
}
if NPC.room=0 {
NPC.direction=1
}
msg("NPC is in room: " +NPC.roomlist(NPC.room) +".")

Then loop it for every time the NPC moves...
Or, make it a function and pass the NPC stats and have the function move it, then any NPC could have it's own path and movement list.
And, if you add a NPC.roommax then you can have any number of path lengths...
And for random selection... A d4 works... 1=move left, 2=move right, 3 and 4=stay in the room.


K.V.
13 Dec 2017, 20:54

HK,

You're cool. I don't like being on lists, anyway. (Hehehe.)

...and I learned the recursion directly from you, so I don't know why you say you're not good at it. (I'm watching you.)

I do appreciate your kind words, but not as much as all your help.


DL,

Hey!

That looks like it will work, too.

I used a boolean instead of an integer for the direction, but it looks pretty similar besides that.


HK,

I still have no clue about delegates, if that makes you feel any better.


hegemonkhan
13 Dec 2017, 21:01

@ Dark Lizard:

I'd definitely would include you too as great programmer, though quest is mostly programming using Objects (and etc higher language stuff/structures: Lists, Dictionaries, Object Types, etc) and its design/logic is based off of it, and I don't think you've yet come as far as KV with Object programming and its design/logic, yet.

If quest was assembly language (or other early/lower languages like basic) program, you'd definitely be one of the top coders!


as you know, modern high level languages, are very different mindset/design/logic/structure, than low level or early/lower-level languages.

I started with modern high level languages, so I'm more familiar with it, whereas, without Jay's help, I'd never even begin to be able to understand assembly language. they're completely different ways of thinking... due to their different structures/functionalities

Whereas, you started with basic, and thus are more familiar with it and low level languages, whereas, these modern high level languages are still new to you. they're completely different ways of thinking... due to their different structures/functionalities


hegemonkhan
13 Dec 2017, 21:10

Dark Lizard's method is most efficient, as it's not using the overhead of all the stuff we're using.

However, the high level overhead stuff makes it more scalable and human-friendly, which is why most programming is high level programming.

Lots of people can learn high level coding, but the low level coding stuff that Dark Lizard does, is much harder for us, who've been exposed first to high level programming.

learning low level programming is not something everyone can learn on their own. You got to be really smart to learn low level coding, and even if you're being taught/helped in learning low level programming... it's still very challanging/confusing... sighs.

lots of people can do at least basic high level coding/scripting, but much fewer people can do assembly language


hegemonkhan
13 Dec 2017, 21:43

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


@ KV:

it took me awhile to understand delegates, but they're actually pretty simple...

you could definitely understand them quickly, I can try to help you (I'm not the best at helping though, Pixie or whoever is much better), if you're interested in learning them. (err, see below, lol)


Delegate's just turn a Script Attribute basically into a Function, but you're using a Script Attribute, which means its attached to an Object, which makes it much more useful (just in terms of organization/structure, let alone other applications) than Functions.

<delegate name="example_delegate" parameters="param" />
// or:
<delegate name="example_delegate" type="string" />
// or:
<delegate name="example_delegate" parameters="param" type="string" />

see how this (see above) is the exact same as a Function's header/signature code line (see below)?

<function name="example_function" parameters="param">
// or:
<function name="example_function" type="string">
// or:
<function name="example_function" parameters="param" type="string">

and whatever Script Attribute(s) which will use the Delegate, act as the Function's body/content/scripting (see below):

(note that for the Script Attribute's: type="xxx", you put in the NAME_OF_THE_DELEGATE that you want the Script Attribute to use, instead of: type="script")

<delegate name="example_delegate" parameters="param" />

<object name="example_object">
  <attr name="example_script_attribute" type="example_delegate">
    msg (param)
  </attr>
</object>

is the same as:

<function name="example_function" parameters="param">
  msg (param)
</function>

---------

// to call/use/do them, there's a bit more to remember with Delegates, than compared to normal Script Attributes and Functions

--------

// if your delegate ONLY has parameters, then you use 'rundelegate (OBJECT, "SCRIPT ATTRIBUTE", ARGS/PARAMS)' :

<delegate name="example_delegate" parameters="param" />

<game name="example_game">
  <attr name="start" type="script">
    rundelegate (example_object, "example_script_attribute", "hi")
  </attr>
</game>

<object name="example_object">
  <attr name="example_script_attribute" type="example_delegate">
    msg (param)
  </attr>
</object>

1. param (of '<delegate name...>') <==== "hi" (from 'rundelegate')

2. the '<attr name="xxx" type="NAME_OF_DELEGATE"...>' is telling that Script Attribute to use that Delegate, and thus:

3. the 'example_script_attribute' then uses 'param' (which is storing "hi") as a variable in its scripting, just as a Function does.

------------------------------------------

// if your delegate returns a value (regardless of: with or without parameters), then you got to use 'RunDelegateFunction (OBJECT, "SCRIPT ATTRIBUTE", ARGS/PARAMS/TYPE, TYPE)' :

========
there's NO difference in whether, type="xxx" or 'parameters="xxx", (this is the same with a Function's header/signature) comes first, if you're having both of them:

<delegate name="example_2_delegate" type="string" parameters="param" />
// is the same as:
<delegate name="example_2_delegate" parameters="param" type="string"  />

just as with Functions (and Commands)

what does matter is the placement matching (if you got multiple PARAMS/ARGS you're using) of the PARAMS with the ARGS

though, don't forget that the delegate requires the Object and the Script Attribute as well (in the order/placement shown below) within its call/usage/doing:

rundelegate (OBJECT, "SCRIPT ATTRIBUTE", ARGS/PARAMS)
// or:
RunDelegateFunction (OBJECT, "SCRIPT ATTRIBUTE")
// or:
RunDelegateFunction (OBJECT, "SCRIPT ATTRIBUTE", ARGS/PARAMS)

which is like using/doing/calling/running a normal Script Attribute:

do (OBJECT, "SCRIPT ATTRIBUTE")
// or:
do (OBJECT, "SCRIPT ATTRIBUTE", DICTIONARY ARGS/PARAMS)

but unlike a Function:

example_function
// or:
example_function (ARGS/PARAMS)
=========

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

<game name="example_game">
  <attr name="start" type="script">
    string_variable = RunDelegateFunction (example_object, "example_script_attribute")
    msg (string_variable)
  </attr>
</game>

<object name="example_object">
  <attr name="example_script_attribute" type="example_2_delegate">
    return ("hi")
  </attr>
</object>

// or:

<delegate name="example_3_delegate" parameters="param" type="string" />

<game name="example_game">
  <attr name="start" type="script">
    string_variable = RunDelegateFunction (example_object, "example_script_attribute", "hi")
    msg (string_variable)
  </attr>
</game>

<object name="example_object">
  <attr name="example_script_attribute" type="example_3_delegate">
    return ("give me a " + param + "gh five if you were able to understand delegates from this post of mine!")
  </attr>
</object>

hegemonkhan
13 Dec 2017, 22:41

@ DL:

looked more closely at your code, really ingenius using the 'direction (+/-)' mechanism!

in hindsight, you're basically doing 'shifting', but still I think it's ingenius, as I'd never think to use 'shifting', lol.


DarkLizerd
14 Dec 2017, 09:43

When I learned Basic... It was just about as high of a language as you could get... (3 or 4 decades ago!!!)
Well, there were a few other "learning" languages... Logo for one (forgot another one I was just thinking about...)
But, from what I am picking up here, I can understand HTML programming better, Not that I will be doing any HTML programming, but it may get me started into looking a little bit deeper into VB.net...
Quest is cool for writing text adventure games. It is built for that. It has a lot of power for building very good works of art...
By combining my knowledge of Basic, with Quest, I can see stuff that "you guys" would overlook because "Quest and OOP (Object Orientated Programming) does it differently...
But, I'm getting there...


hegemonkhan
14 Dec 2017, 20:28

It's not easy, older people have a hard time with modern high level programming languages, as these didn't exist back then for them, thus, they had to work with less built-up functionality, and thus learned more of lower level languages and their various techniques. Younger people are introduced to the modern high level languages, but have a very hard time with learning the lower level languages and thus have a hard time with working with a lot less functionality.

low level languages build upon computer architecture (hardware/circuitry/logic-gates/machine-language), adding more functionality/control'ability to the human user, and then that enabled high level languages to be built-on top of the low level languages, adding even more functionality/control'ability to the human user, and high level languages have continued to build upon what has already been built. This makes it ever harder to learn about and use a computer, as it's just too much stuff for people to know and understand.

The cause of this building of more functionality/control'ability is technological advancement. Hardware was limited in the past, so programming languages were very simple in their functionality, you had to be really creative and efficient to get done what you wanted. Imagine trying to work with literally only 256 bytes of memory compared to what we've got now (tera bytes and more).

think of having a house that is only like 10x10x10 feet, you're a lot more limited in what you can have in your house. compared to having a house that is like 1000x1000x1000 feet. With the 10x10x10 feet house, you're dealing with HOW to put what you need into it, and NOT what you need to put into it. With the 1000x1000x1000 feet house, you're dealing with WHAT things to put into it, and NOT how to put those things into it, lol.

also, imagine having only a chisel and a hammer, compared to having a multitude of hydrolic construction vehicles and etc tools/equipment.


however, with more and more building up of functionality/ccontrol'ability for the human user... came a new demand of it: complex design/structure, management/logic/understanding, and etc... which really pushes our brains (at least mine, lol) to the limit.

OOP/OOD is very different than assembly/low/early programming

take the 'chisel and hammer' vs 'modern construction vehicles/tools/equipment/technology':

with only a chisel and hammer, you're using your intelligence to figure out how to do what you want to do with only that chisel and hammer. You're not using intelligence to figure out how to most effectively use that chisel and hammer together, lol. There's no complexity in using a chisel and hammer... the hammer is used to hit the chisel, and that is all, lol.

when you got the plethera of modern construction vehicles/tools/equipment/technology at your disposal... you can do whatever you want to do, that's NOT the problem! The problem is what is the best way to use what you got available to use, you're dealing with how to use all that stuff/options that is your vehicles/tools/equipment/technology/etc, but NOT with how to do what you want to do, as you got the total means to do whatever you want to do. But what's the best way to go about it with those means.

see, it's complete opposite challenges/mindset, and why it's so hard to cross-over from either side. High-Level vs Low-Level.


Doctor Agon
14 Dec 2017, 23:31

@DL, looking at your code and also HK comment about shifting, I was reminded of an adventure game, I programmed when I was younger, back in my BASIC days. The adventure operated on a 6x5 grid, east or west (+1 or -1), north or south (+5 or -5), moved the player. Up or Down (+30 or -30).


mrangel
15 Dec 2017, 15:21

@Dr Agon
That reminds me of a programming exercise regarding a tray full of Tetris blocks; the challenge being to find the most memory-efficient method of determining whether a certain block would fit into a certain grid. Various programmers tried representing the tray as various kinds of arrays, but were rejected. The correct solution was to represent the tray as a long long int (64-bit integer to represent an 8x8 grid of blocks).


DarkLizerd
15 Dec 2017, 18:51

"Correct"? Maybe, maybe not... But it was the simplest or smallest solution...

(But I think we are sliding off topic here... and maybe confusing a few people...)