Looping a script, but pausing for user input

Hey all, I'm creating a simplified combat system that uses menus. I'd like for this script to loop repeatedly, but wait for the user to make a selection before running another iteration of the script.

The script is activated by a verb, which simply does...

do (this, "combat_script")

The script I currently have (an attribute on the creature that spawns), looks like this...

x = ToString (GetRandomInt(1, DictionaryCount(this.combat_library)))
this.runscript = ScriptDictionaryItem(this.combat_library, x)
do (this, "runscript")
do (this, "combat_script")

It references a script library, which contains several scripts (with numerical indices, i.e. 1, 2, 3, etc...) An example of one of the scripts might be...

msg ("The " + this.alias + " is charging right at you!")
this.combat_commands = NewStringList()
list add (this.combat_commands, "Dodge Left")
list add (this.combat_commands, "Dodge Right")
list add (this.combat_commands, "Do Nothing")
ShowMenu ("Commands:", this.combat_commands, true) {
  if (result = "Dodge Left") {
    // Dodge left result
  }
  if (result = "Dodge Right") {
    // Dodge right result
  }
  if (result = "Do Nothing") {
    // Do nothing result
  }
}

Unfortunately, if I put 'do (this, "combat_script")' at the end of the script, it causes and infinite loop, and quest crashes. If I put 'do (this, "combat_script")' inside one of the menu result scripts, it doesn't recognise what 'this' means. I can't reference a specific object in this case, because the attributes belong to a cloned object, and I don't know what the name will be. I also don't want to use a turn script, because I want the player to make a choice before running the script again.

Any thoughts on how I could achieve this?

EDIT: Ugh I thought I could avoid using 'this' inside a menu (which I'm having trouble getting to work) but I don't think I can.

The combat system I'm planning has a set of random mini-scenarios, which the player can react to. Some of the actions in some of these scenarios need to carry over into other scenarios. For example, one script might result in the player breaking an enemy's shield. Once their shield is broken, other scripts inside the script library need to be able to recognise that this.shield_broken = True.

In other words, I can't really avoid using 'this' inside a menu for the system I have planned.


I believe this is what you're looking for http://docs.textadventures.co.uk/quest/scripts/on_ready.html

Otherwise you might try storing the local object 'this' inside another attribute, it may get around 'this' no longer existing within the scope of the menu. Not actually sure that would work but that would be my first guess.

After testing I could not store 'this' in a local variable inside the script but you can save it to another static object ie: 'game.this = this' then use 'game.this' to reference your object inside the menu

Also I'd have to ask what is the function of the randomize combat library scripts? If you're pulling encounter specific data at that point you could probably go all the way an make the encounter always use the same object but change it's attributes each time in which case you'd no longer need to reference it with 'this'.


"Unfortunately, if I put 'do (this, "combat_script")' at the end of the script, it causes and infinite loop, and quest crashes (scrim)"


you need a way to stop/end/terminate a loop, so it's not infinite/endless.

a simple way in general would be to use a 'if (BOOLEAN or STRING)' checking, for an example:

<verb>
  <property>fight</property>
  <pattern>fight</pattern>
  <defaultexpression>You can't fight that!</defaultexpression>
</verb>

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

<object name="player">
  <attr name="parent" type="object">room</attr>
  <attr name="life" type="int">999</attr>
  <attr name="damage" type="int">50</attr>
</object>

<object name="orc">
  <attr name="parent" type="object">room</attr>
  <attr name="life" type="int">500</attr>
  <attr name="damage" type="int">25</attr>
  <attr name="dead" type="boolean">false</attr>
  <attr name="displayverbs" type="listextend">fight</attr>
  <attr name="fight" type="script"><![CDATA[
    if (orc.dead) {
      msg ("The orc is already dead, silly.")
    } else {
      orc.life = orc.life - player.damage
      msg ("You attack the orc for " + player.damage + " damage, leaving it with only " + orc.life + " life left.")
      if (orc.life < 1) {
        orc.dead = true
        msg ("Your attack fatally wounded the orc, killing it dead.")
      } else {
        player.life = player.life - orc.damage
        msg ("The orc attacks you for " + orc.damage + " damage, leaving you with only " + player.life + " life left.")
        if (player.life < 1) {
          msg ("The orc fatally wounded you, killing you dead.")
          msg ("GAME OVER")
          finish
        } else {
          do (orc, "fight") // or: invoke (orc.fight)
          // this loops/iterates/does the fight over and over until the orc dies or you die
        }
      }
    }
 ]]></attr>
</object>

also, this combat code of mine (using Pertex' combat code design and his/her help too) is old and poor (this was when I was first learning to code combat), but hopefully you can understand it and get some ideas from it that you can use to help yourself with combat:

http://textadventures.co.uk/forum/quest/topic/3348/noobie-hks-help-me-thread#22483
http://textadventures.co.uk/forum/quest/topic/3348/noobie-hks-help-me-thread#22486 (key/legend --- be warned, I got my elemental damage/defense/resistances accidentally mixed up wrongly a bit in my code --- I've learned since to NEVER use abrevs ever again, lol)


I think it would make things much easier for you, if you used Functions, as you can use Parameters and have a return type, so, you can still use your Command if you need to, but then use/have (create) Functions (with your needed combat scripting in them) for your Command's scripting (via the 'call function' Script). You can use Objects and their Script Attributes too, but then you got to learn how to use Delegates, in order to be able to use Parameters and have a return type with them. Easier to just use Functions instead for now.


Thanks guys. I've been having some computer troubles, so I'm only looking at this code now.

I've attempted the boolean method, but I haven't been able to get it to work now. Now I'm giving the 'on ready' method a try and... It doesn't seem to work! Everything inside the on ready brackets runs anyway, without waiting for input. I'm not sure why... Any ideas?

EDIT: Damnit. I can get on ready to work, but only when it's at the same level as the menu. Meaning that it doesn't recognise 'this' any more. This is incredibly annoying!


your desired action scripting (scripts) needs to be within an 'if' block (there's 4 types of 'if' blocks: if, if-else, if-else if, if-else if-else), for example:

if (NAME_OF_OBJECT.NAME_OF_BOOLEAN_ATTRIBUTE) { // if TRUE
  // your desired action scripts
}
// implied: if FALSE: nothing happens (no scripts are done, as no scripts exist because we're only testing if the Boolean Attribute = 'true')

------

if (not NAME_OF_OBJECT.NAME_OF_BOOLEAN_ATTRIBUTE) { // if FALSE
  // your desired action scripts
}
// implied: if TRUE: nothing happens (no scripts are done, as no scripts exist because we're only testing if the Boolean Attribute = 'false')

-----

if (NAME_OF_OBJECT.NAME_OF_BOOLEAN_ATTRIBUTE) { // if TRUE
  // your desired action scripts here, or... (blah scripts here and below)
}
else { // if FALSE
  // your desired action scripts here, or... (blah scripts here and above)
}

-----

if (not NAME_OF_OBJECT.NAME_OF_BOOLEAN_ATTRIBUTE) { // if FALSE
  // your desired action scripts here, or... (blah scripts here and below)
}
else { // if TRUE
  // your desired action scripts here, or... (blah scripts here and above)
}

---

the 'not' (negation: opposite) operation/operator can be used for the below examples with String Attributes, but not showing/explaning all of these combinations --- too much work, lol)

----

if (NAME_OF_OBJECT.NAME_OF_STRING_ATTRIBUTE = "VALUE") { // if TRUE
  // your desired action scripts
}

----

if (NAME_OF_OBJECT.NAME_OF_STRING_ATTRIBUTE = "VALUE") { // if TRUE
  // your desired action scripts here, or... (blah scripts here and below)
}
else { // if FALSE
  // your desired action scripts here, or... (blah scripts here and above)
}

----

if (NAME_OF_OBJECT.NAME_OF_STRING_ATTRIBUTE = "VALUE_1") { // if TRUE
  // your desired action scripts here, or... (blah scripts here and below)
}
else if (NAME_OF_OBJECT.NAME_OF_STRING_ATTRIBUTE = "VALUE_2") { // if TRUE
  // your desired action scripts here, or... (blah scripts here and above)
}
// optionally, more 'else ifs', as you need/want

-----

if (NAME_OF_OBJECT.NAME_OF_STRING_ATTRIBUTE = "VALUE_1") { // if TRUE
  // your desired action scripts here, or... (blah scripts here)
}
else if (NAME_OF_OBJECT.NAME_OF_STRING_ATTRIBUTE = "VALUE_2") { // if TRUE
  // your desired action scripts here, or... (blah scripts here)
}
// optionally, more 'else ifs', as you need/want
else { // if FALSE
  // your desired action scripts here, or... (blah scripts here)
}

P.S.

in the GUI/Editor, it is very frustrating in trying to figure out which 'add new script' circle button you click on for the correct nesting/indenting layer/level of scripting (one of the reasons, I learned quickly to code with quest, lol), and nesting/indenting is extremely important, as it is the 'order of operations' of your scripting, and a wrong order can even cause an error. Scripting in the GUI/Editor is a bit clunky... but the worst is when you have to delete a part of your scripting... so easy to lose all that hard work in scripting (if you got a massive scripting block), if not careful, lol


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

Support

Forums