Random Monsters in Turn Based Events

JenniferKline
05 Jul 2017, 11:35

Heya all,

I'm currently starting out with Pixie's combat library, although I haven't figured everything out and gone all the way through. Right now, I've just been setting up an example monster and have been wondering about randomness. For a starter, I want to be able to generate/respawn monsters as I go.

I don't plan on the player ever having to fight more than one monster at once, so a Goblin, a Group of Goblins and a Horde of Goblins would all be one object with different stats. My general idea is that there are safe areas, i.e 'The Inside of your Starship' and there are unsafe areas 'The Glassland wastes'. You can use a script to 'Explore The Glassland Wastes' and then you get a % of loot, of getting skill points, of finding random events, or of finding a foe.

So in this case, the player would go out, find a Goblin and face off against it. I need to consider some way to 'isolate' the player and ignite turn-based combat until the encounter is over, but that's not why I'm here. That's all rambling context in case anyone has suggestions.

Right! Main point.

I saw something mooching through old threads at was about a zombie game. They'd got something in the description like obj.look = ProcessText("A " + obj.alias + ", {random:maggotridden:missing arm:one dangling eye}.")

I'm wondering if there is some kind of combat that is rolling in turns, i.e the player takes a turn against a Goblin, the Goblin makes a turn back - would the random word still be the same? Or would it create a new random message each time the player looks? (Which is what I assume?)

I wrote a brief text for a monster just to test.

You’re facing off against a small creature with {random:greyish-green:blackish-blue:dark yellowy} skin and large, dark eyes that almost seem to glisten. It’s wearing what appears to be the {random:ripped and torn:tattered:slightly burnt:faintly bloody} remains of a {random:crimson red:brown-tan:iron grey:dark blue} woollen jacket, streaked with dust and grime from crawling around the plains. Little hobnail boots make its feet look rather clunky and a variety of {random:steel:copper:bronze:bone} piercings line its long, batlike ears. 
“Shinies!” Its voice has a shrill, monstrous screetch to it as it holds its mace up high and gives it a firm, threatening swing. “Shiny! Shinies!” It’s clear the creature’s not going to get away without a fight.

Could I format this in a way so it's set for a monster, consistently, until it's respawned? I assume I could set each 'factor' as an attribute and roll the attributes each time, but its a way to try and make the randomly spawned monsters feel like there's a bit more... Randomness to them.


The Pixie
05 Jul 2017, 13:09

The trick is in the ProcessText function.... which is not yet in Quest. It will do the text processor stuff straightaway, so the modified string is used for the attribute. Every time the player looks, the attribute will be the same.

Until Quest 5.7 comes out, you can add ProcessText to your game. Have it return a string, and a single parameter "text", and paste in this code:

    data = NewDictionary()
    dictionary add (data, "fulltext", text)
    text = ProcessTextSection(text, data)
    return (Replace(Replace(text, "@@@open@@@", "{"), "@@@close@@@", "}"))

I would suggest creating clones of goblins, and setting the look attribute when the clone is created.


JenniferKline
05 Jul 2017, 16:35

How can I manipulate clones? I've not really used them much, but I mean - they're made when the game is running. Then again, I wonder if I'll need to clone them at all. I know I'll be using objects, but with only one monster on screen at once, recycling and changing the same one, dragging it out of its room for combat and throwing it back in when done, that might be easier.

Also, adding on your answer, how do I have something return a string? I don't think I've come across this yet. Is there a full tutorial for ProcessText?


The Pixie
05 Jul 2017, 16:50

How can I manipulate clones?

See here (which just happens to be about cloning goblins).

Also, adding on your answer, how do I have something return a string? I don't think I've come across this yet. Is there a full tutorial for ProcessText?#

There is a page on creating functions here, but basically you select "string" from the Returntype drop down list,


DarkLizerd
06 Jul 2017, 04:08

So... You want your text to read like this:
You’re facing off against a small creature with {monster.skin} skin and large, dark eyes that almost seem to glisten. It’s wearing what appears to be the {monster.jacket1} remains of a {monster.jacket2} woollen jacket, streaked with dust and grime from crawling around the plains. Little hobnail boots make its feet look rather clunky and a variety of {monster.piercings} piercings line its long, batlike ears.
“Shinies!” Its voice has a shrill, monstrous screetch to it as it holds its mace up high and gives it a firm, threatening swing. “Shiny! Shinies!” It’s clear the creature’s not going to get away without a fight.

All you need to do is pre-randomize the variables before hand:
monster.skin= {random:greyish-green:blackish-blue:dark yellowy}
monster.jacket1=random:ripped and torn:tattered:slightly burnt:faintly bloody}
monster.jacket2={random:crimson red:brown-tan:iron grey:dark blue}
monster.piercings= {random:steel:copper:bronze:bone}
or:
S=Split("greyish-green:blackish-blue:dark yellowy" , ":")
J1=Split(":ripped and torn:tattered:slightly burnt:faintly bloody", ":")
J2=Split("crimson red:brown-tan:iron grey:dark blue", ":")
P=Split("steel:copper:bronze:bone", ":")
Then:
r=GetRandomInt(1,3)
monster.skin=stringListItem(S, r)
r=GetRandomInt(1,4)
monster.skin=stringListItem(J1, r)

(then the same for the rest of the variables)
This way, each new creature will be different, but, the same until a new one is generated.


JenniferKline
06 Jul 2017, 17:18

Yeah, that's what I was considering beforehand, but that little text bit got me wondering if it was possible to just do it in text. Using attributes would probably be the easiest method, but it's good to have the ProcessText there just in case it comes in handy some other time.


The Pixie
06 Jul 2017, 17:51

The advantage of DarkLizerd's way is you could refer to the trait in other places, saying that you hack into its {monster.skin} skin, for example, and it would be consistent.

The diaadvantage is your cannot do that with clones using the text processor (because the clone willhave a different name), but if you are not using clones, that is not a problem.


hegemonkhan
06 Jul 2017, 22:24

"For a starter, I want to be able to generate/respawn monsters as I go (JK)"

the trick to this is to have your actual monster Objects as storage/data Objects (aka: not interactive'able by the person playing the game), which you never mess with, and then you can reference them (and thus use them, including cloning them and then using their clones), as an illusion/effect such as that of 'generating/respawning' them.

This is a big concept of (gaming) programming (but also in general with any non-gaming program too):

what seems to be happening/going-on with the person playing the game (or the user for non-gaming programs), is NOT actually what is happening/going-on in the programming, it's something completely different in programming, but which creates the effect/illusion of that thing that the person playing (or user) is thinking is happening/going-on, hehe. You don't program in 'generating/re-spawning' of monsters, but your programming does cause/produce that effect/illusion of 'generating/re-spawning' of monsters for the person playing the game (or user).

AND

"I need to consider some way to 'isolate' the player and ignite turn-based combat until the encounter is over (JK)"

see the scripting example in the code box below (see the 'game.start' and the 'battle_fucntion')


// you'd then use scripting for 'getting' (not technically 'getting/moving') of the monster Objects and/or their clones (that are created through/with this same scripting), but rather referencing of them (and/or of their clones), as we never actually mess with our monster objects, but if we do use clones, we may want to destroy the clones when done, depends on your game design) and doing stuff with them (or their clones) and/or using their stuff (Attributes), which will use List/Dictionary Attribute scripting work as well for this stuff.

// I show an example of such scripting below (see the 'game.start' and the 'battle_function')

<asl version="550">

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

  <game name="example">
    // blah Attributes
    // example scripting (and also see the actual function at very bottom of this code box too):
    <attr name="start" type="script">
      monster_object_variable = ObjectListItem (monster_container.monster_objectlist_attribute, GetRandomInt (0, ListCount (monster_container.monster_objectlist_attribute) - 1))
      msg ("A " + monster_object_variable.alias + " has spawned. You must fight it and win, else die...")
      battle_function (monster_object_variable)
      battle_function (monster_object_variable) // this second line (a second calling/usage/doing of the 'battle_function' after the monster is dead --- if you are dead, the game is frozen as the game is over), is for trying to do this upon a dead monster (the first time, looting it, and addition times saying you're silly as there's nothing to do now  with it, you already looted its corpse), if this example was a full-working game code, usually you'd have a 'fight/battle' Verb/Command, which you can click on (or type-in) again after you already killed the monster, to loot its corpse.
    </attr>
  </game>

  // the storage/data monster Objects, which you never actually mess with (as you're merely referencing them and/or creating clones of them through the scripting), but with the scripting, it creates the illusion/effect of you 'spawning/generating/re-spawning/re-generating' them to the person playing the game:

  <object name="monster_container"> // for organization (especially) if using the GUI/Editor, but also good regardless anyways.
    <attr name="monster_objectlist_attribute" type="objectlist">orc;ogre</attr>
    <object name="orc">
      // blah Attributes
    </object>
   <object name="ogre">
      // blah Attributes
    </object>
   // etc etc etc monster Objects
  </object>

  // example scripting:
  // (it's really bad/redundent scripting, can be made much more concise: put the player's turn as its own function and put the monster's turn as its own function (or best: have a function that can handle the turn regardless of who's turn it is), but this is jsut a quick example)

  <function name="battle_function" parameters="monster_object_parameter">
    <![CDATA[
      if (monster_object_parameter.condition = "dead") {
        firsttime {
          msg ("You loot the dead " + monster_object_parameter.alias + "'s corpse")
          player.current_experience = player.current_experience + monster_object_parameter.experience
          player.current_currency = player.current_currency + monster_object_parameter.currency
          // scripting for getting any items/equipment from the monster (too much work, too lazy to do it here, lol)
        } otherwise {
          msg ("The " + monster_object_parameter.alias + " is still dead, and has already been looted by you, silly.")
        }
      } else { // if monster not dead
        if (player.speed > monster_object_parameter.speed) {
          msg ("You get to go first, having greater speed than the " + monster_object_parameter.alias)
          monster_object_parameter.current_life = monster_object_parameter.current_life - player.damage
          msg ("You do " + player.damage + " damage to the " + monster_object_parameter.alias)
          if (monster_object_parameter.current_life < 1) {
            msg ("You killed the " + monster_object_parameter.alias + "!")
            monster_object_parameter.condition = "dead"
          } else { // if monster still alive
            msg ("The " + monster_object_parameter.alias + " still has " + monster_object_parameter.current_life + " life remaining.")
            msg ("The " + monster_object_parameter.alias + " now attacks you!")
            player.current_life = player.current_life - monster_object_parameter.damage
            msg ("The " + monster_object_parameter.alias + " does " + monster_object_parameter.damage + " damage to you")
            if (player.current_life < 1) {
              msg ("You were killed by the " + monster_object_parameter.alias)
              msg ("GAME OVER")
              finish
            }
          }
        } else if (player.speed < monster_object_parameter.speed) {
          msg ("The " + monster_object_parameter.alias + " gets to go first, having greater speed than you.")
          player.current_life = player.current_life - monster_object_parameter.damage
          msg ("The " + monster_object_parameter " does " + monster_object_parameter.damage + " damage to you")
          if (player.current_life < 1) {
            msg ("You were killed by the " + monster_object_parameter.alias)
            msg ("GAME OVER")
            finish
          } else { // if you're still alive
            msg ("You still have " + player.current_life + " life remaining.")
            msg ("You now attack the " + monster_object_parameter.alias)
            monster_object_parameter.current_life = monster_object_parameter.current_life - player.damage
            msg ("You do " + player.damage + " damage to the " + monster_object_parameter.alias)
            if (monster_object_parameter.current_life < 1) {
              msg ("You killed the " + monster_object_parameter.alias)
              monster_object_parameter.condition = "dead"
            }
          }
        } else if (RandomChance (50)) { // if you and monster have same speed, "flip a coin" (RandomChance(50)), to see who goes first // if TRUE, you go first:
          msg ("You get to go first, having greater speed than the " + monster_object_parameter.alias)
          monster_object_parameter.current_life = monster_object_parameter.current_life - player.damage
          msg ("You do " + player.damage + " damage to the " + monster_object_parameter.alias)
          if (monster_object_parameter.current_life < 1) {
            msg ("You killed the " + monster_object_parameter.alias + "!")
            monster_object_parameter.condition = "dead"
          } else { // if monster still laive
            msg ("The " + monster_object_parameter.alias + " still has " + monster_object_parameter.current_life + " life remaining.")
            msg ("The " + monster_object_parameter.alias + " now attacks you!")
            player.current_life = player.current_life - monster_object_parameter.damage
            msg ("The " + monster_object_parameter.alias + " does " + monster_object_parameter.damage + " damage to you")
            if (player.current_life < 1) {
              msg ("You were killed by the " + monster_object_parameter.alias)
              msg ("GAME OVER")
              finish
            }
          }
        } else { // (you and monster have same speed), "flip a coin" (RandomChance (50)), to see who goes first // if FALSE, the monster gets to go first:
          msg ("The " + monster_object_parameter.alias + " gets to go first, having greater speed than you.")
          player.current_life = player.current_life - monster_object_parameter.damage
          msg ("The " + monster_object_parameter " does " + monster_object_parameter.damage + " damage to you")
          if (player.current_life < 1) {
            msg ("You were killed by the " + monster_object_parameter.alias)
            msg ("GAME OVER")
            finish
          } else { // if you still alive
            msg ("You still have " + player.current_life + " life remaining.")
            msg ("You now attack the " + monster_object_parameter.alias)
            monster_object_parameter.current_life = monster_object_parameter.current_life - player.damage
            msg ("You do " + player.damage + " damage to the " + monster_object_parameter.alias)
            if (monster_object_parameter.current_life < 1) {
              msg ("You killed the " + monster_object_parameter.alias)
              monster_object_parameter.condition = "dead"
            }
          }
        }
        // end of a single battle turn/round (you and monster, have both done your individual fight/attack turns)
        battle_function (monster_object_parameter) // you're stuck in combat with the monster (scripting loop: keep doing battle turns/rounds), until one of you (you or monster) dies (or you can add in more combat action/choices: magic/cast, item, etc, in addition to the effective 'attack' action/option that the scripting is showing/doing here already (just not named as a choice/option as it's the only one in this code example of mine), too, such as specifically for another way of ending the combat looping: flee/escape).
      }
    ]]>
  </function>

</asl>

oops... I should have added the use of cloning (using cloned objects) ... well it won't be too difficult to include the cloning scripting into my example code above... but I'm too tired/lazy to do it now... (took a bit of work to do the example code above, need a rest first).


you can also see this old code of mine too (for seeing how to add in multiple combat options/actions/choices):

(this is super horribly bad code... as this was when I was first learning this stuff)

http://textadventures.co.uk/forum/quest/topic/3348/noobie-hks-help-me-thread#22483

and its key/legend for all of my abrevs (I've learned since to NEVER EVER use abrevs ever again, lol, as I got my 'damage, for example: pd: physical damage' vs 'resistances, for example: pr: physical resistance' mixed up, and I myself was forgoting what my own abrevs stood for, laughs):

http://textadventures.co.uk/forum/quest/topic/3348/noobie-hks-help-me-thread#22486


VERY IMPORTANT:

if the link/download still works, you want to look at Pertex' clean-up of my horrible code:

http://textadventures.co.uk/forum/quest/topic/3348/noobie-hks-help-me-thread#22485

as, my code is horribly bad, and thus has lots of mistakes, making it NOT a good choice for looking at and trying to understand it

if Pertex' link/download doesn't work... ask me and I can help you understand my code... and one of these days (like never as I'm lazy and been saying I'd do this for a long time, lol), I may re-do this combat code of mine, now that I know how to do it correctly

(I do think I have it cleaned up on my computer, but I'd have to find it... too lazy, might be hard to find too...)

(it'd probably be easier for me to just write in the new-correct combat code, than trying to find the cleaned up code on my computer... if I do actually ahve it... as I may not in fact... I think I do... but my memory is often wrong... my organic/brain-cell/synapsis memory is very faulty, I need silicon/whatever memory chips instead, lol)


hegemonkhan
06 Jul 2017, 22:49

"My general idea is that there are safe areas, i.e 'The Inside of your Starship' and there are unsafe areas 'The Glassland wastes'. You can use a script to 'Explore The Glassland Wastes' and then you get a % of loot, of getting skill points, of finding random events, or of finding a foe. (JK)"

see this link (my 'explore' and 'travel' code), though it is old and has some inefficiencies with the 'Listcount - 1' handling stuff (this was back when I was first trying/learning to do this type of stuff: using Lists/Dictionaries):

http://textadventures.co.uk/forum/samples/topic/5138/explore-and-travel-code-sample-by-hk

to have a better chance of understanding/following it:

  1. start with the 'explore_function' (I've only got it coded for exploring the 'homeland' in my sample/example code, but you can add in the additional cases for exploring the other types of lands too. Also I only have a single type of 'explore' event: discover a new type of land that you can now travel to, but you can easily add in other 'explore' events too: get X currency, get random item/equipment/clothing/etc, random monster battle, etc etc etc)

  2. then look at the 'data_object.homeland_events_script_dictionary', which adds the lands to the 'data_object.travel_string_list' for the 'travel_function', so that you can now travel to those lands. Also, once you discover a new type of land, I don't want you to be able to get this event again, as this is to be a one-time event, so I have scripting to handle the removing of this event from the 'homeland_events_string_list' list for the next time you try to 'explore')

  3. last, look at the 'travel_function'

and, just ask for whatever help you need with it, too, of course :D


and here's my guide on using Lists/Dictionaries too:

http://textadventures.co.uk/forum/samples/topic/5137/list-and-dictionary-extensive-guide-by-hk

ask if you need help and/or got any questions on anything


hegemonkhan
06 Jul 2017, 22:50

(sorry, accidental double-mirror post: this post was the same as the post above)

(is there a way for normal users to delete their posts?)