Extra Doors, NPC Routines, Random NPCs and Manipulating Attributes - lots of silly questions.

Inherited Sin
27 Apr 2017, 10:10

Hi there. Total newbie with some questions, if anyone has the time...

I'm looking at building a game in a haunted mansion/hotel, where you play a Ghost trying to figure out your own murder. As I try to puzzle out the game design, several questions spring to mind:

Layout: Can I put 2 doors on the same wall, so one large room leads to 2 smaller ones? How do I put in stairs, and link to rooms that are on the 2nd floor? Particularly in a hallway where there might be several doors to other rooms as well.

Time: How do I set up a routine for non-player characters, so they show up in certain rooms at certain times, or perhaps show up randomly when not otherwise set to do so? If I set my game in an old hotel, how do I have random guests from a pre-prepared list show up?

Attributes: I'm trying to add an Attribute (Spiritus) to my Ghost, but can't seem to get the game to recognize it. There are several things I'm trying to achieve with it:

  • Tie it to turns, so that every turn - or better every ~10 turns - it reduces by -1 because the Ghost is slowly fading away. If it reaches 0, the game ends.

  • Certain activities, such as interactions with real world objects (like turning on a TV) will cost Spiritus, though some interactions (sucking elemental energy from an open fire) increase it.

  • I want the Ghost to be able to suck Spiritus from the living (I'll add a Corruption Attribute later when I've figured out a bit more). I've posted my attempt to do this below. I started by adding a Verb "enervate" to a non-player Character, then added it as an Attribute to my Ghost and the NPC - but I get a Syntax error:

Error running script: Error compiling expression 'HasAttribute(Spiritus, > 1)': Unknown object or variable 'Spiritus'

Here is my code:

msg ("You cannot rest until you know what happened to you. And if that means feeding on the souls of sleepers, then so be it.")
SetTimeout (2) {
if (HasAttribute(Spiritus, > 1)) {
set (Audrey, Spiritus, - 1)
set (player, Spiritus, +1)
msg ("Your target turns pale as you tap their life energy.")
}
else if (HasAttribute(Spiritus, < 2)) {
set (Audrey, Spiritus, - 1)
set (player, Spiritus, + 1)
msg ("You devour your target's soul in order to cling to the material world a bit longer.")
}
}

My guess is that I'm using: If Object has Attribute wrong, but I don't know. Is there a better way to do what I'm trying to do? Am I simply working in the wrong place on the tree?

If you want an Attribute to stop increasing once it reaches a certain number, how do you do that? E.g: Mortals who lose Spiritus regain 1 per day of rest, but only back to what they started with.

Randomizing: How do you randomize opposed checks between different Attributes, or add a "dice" score on top? E.g: Ghost Willpower + 1d6 vs Reluctant Professor Willpower + 1d6? I want to create an uncertain outcome, or encourage the Ghost to be clever and pick on someone with a lower Willpower.

OK, this is quite needy for a first post so I'll wait and see now...


The Pixie
27 Apr 2017, 11:14

Sounds like an interesting game...

Layout: Can I put 2 doors on the same wall, so one large room leads to 2 smaller ones? How do I put in stairs, and link to rooms that are on the 2nd floor? Particularly in a hallway where there might be several doors to other rooms as well.

Kind of, but as it all works on compass directions, you would have to have one east and one northeast, and make clear they were in the same wall in the description. Or break the hall into two parts and have a door east from the south end and a door east from the north end. The limitation is with the genre really.

Time: How do I set up a routine for non-player characters, so they show up in certain rooms at certain times, or perhaps show up randomly when not otherwise set to do so? If I set my game in an old hotel, how do I have random guests from a pre-prepared list show up?

This will be quite involved, but certainly doable. The simplest way would be with a turn script, set up to count turns (the last but one part of the tutorial says how to do that), and then in the turn script, have something happen at specific turns. If it is turn 10, guess arrives at reception. If turn 12 guess goes up stairs, and so on.

Attributes: I'm trying to add an Attribute (Spiritus) to my Ghost, but can't seem to get the game to recognize it. There are several things I'm trying to achieve with it:

Error running script: Error compiling expression 'HasAttribute(Spiritus, > 1)': Unknown object or variable 'Spiritus'

The second line in your code is wrong, should be

if (Audrey.Spiritus > 1) {

Also, the line that starts "else", delete everything apart from the "else" at the start and the "{" at the end (if the attribute is not over 1 then it must be below 2, so that bit is not necessaryu as well as wrong).

If you want an Attribute to stop increasing once it reaches a certain number, how do you do that? E.g: Mortals who lose Spiritus regain 1 per day of rest, but only back to what they started with.

Do the addition, then test if it is greater and set to the original if so.

Audrey.Spiritus = Audrey.Spiritus + 1
if (Audrey.Spiritus > 10) {
  Audrey.Spiritus = 10
}

Randomizing: How do you randomize opposed checks between different Attributes, or add a "dice" score on top? E.g: Ghost Willpower + 1d6 vs Reluctant Professor Willpower + 1d6? I want to create an uncertain outcome, or encourage the Ghost to be clever and pick on someone with a lower Willpower.

I would get a total for each person, and then compare.

total1 = player.Willpower + DiceRoll("1d6")
total2 = Reluctant Professor.Willpower + DiceRoll("1d6")
if (total1 > total2) {
  // do stuff

The Pixie
27 Apr 2017, 11:32

If you want an advanced time tracking and event system, and you are using the desktop version, you might want to look at this library:
https://github.com/ThePix/quest/wiki/Clock-Library


jmnevil54
27 Apr 2017, 20:15

So, are you talking ghost can go through walls, or doors that show up but you can't go through them. 'Cause that would be pretty sweet either way.
I think you can set an attribute to an attribute just by typing it.
player.dead = true
dead.true = something

Also, is your game up? I'd love to play it!


DarkLizerd
28 Apr 2017, 06:14

Layout: Can I put 2 doors on the same wall, so one large room leads to 2 smaller ones? How do I put in stairs, and link to rooms that are on the 2nd floor? Particularly in a hallway where there might be several doors to other rooms as well.

Actually, you can. You can have a single hallway with several doors on either side, that lead back to the central hallway.
Just make the doors Non-directional exits, then describe the doors in the room description. And have the exit from the room one way back to the hall way.
Like this... (if I got this right)

  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="test">
    <gameid>31022ab7-4bf3-43ad-8002-a106c94bf456</gameid>
    <version>1.0</version>
    <firstpublished>2017</firstpublished>
    <start type="script">
      player.fat = 0
    </start>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <description>On the west wall, there are 3 doors, a red door to the north, a blue door in the middle, and a green door south of that.</description>
    <beforeenter type="script"><![CDATA[
      if (player.fat<-2) {
        msg ("looking good!")
      }
    ]]></beforeenter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
      <statusattributes type="stringdictionary" />
    </object>
    <exit name="red door" alias="red door" to="A1" />
    <exit name="blue door" alias="blue door" to="A2" />
    <exit name="green door" alias="green door" to="A3" />
  </object>
  <object name="A1">
    <inherit name="editor_room" />
    <exit alias="east" to="room">
      <inherit name="eastdirection" />
    </exit>
  </object>
  <object name="A2">
    <inherit name="editor_room" />
    <exit alias="east" to="room">
      <inherit name="eastdirection" />
    </exit>
  </object>
  <object name="A3">
    <inherit name="editor_room" />
    <exit alias="east" to="room">
      <inherit name="eastdirection" />
    </exit>
  </object>
</asl>

DarkLizerd
28 Apr 2017, 06:20

If different NPCs have different Spiritus values then do this:
Audrey.Spiritus = Audrey.Spiritus + 1
if (Audrey.Spiritus > Audrey.Spiritus.Maxinums) {
Audrey.Spiritus = Audrey.Spiritus.Maxinums
}

Sam could have 15, and Joe could be 8...
Altho, I'm sure you could just call a function and pass the NPC's name to it and "heal" each player that way once per day...

If you want an Attribute to stop increasing once it reaches a certain number, how do you do that? E.g: Mortals who lose Spiritus regain 1 per day of rest, but only back to what they started with.
Do a check on the ghost just like the NPC healing...
if (player.Spiritus > player.Spiritus.Maxinums) {
player.Spiritus = player.Spiritus.Maxinums
msg("Try as you may, you do not feel any better after doing this.")
}
You could also have a decreasing maximum as well.
Even though you can suck the life out of the NPCs or objects, each day, your maximum decreases so that there is a time where you "die" anyway...
IE: Day 1 after you died, your maximum is 20
Day 2: it is 19.
Day 2: 18
Day 10: 10
day 19: 1
day 20: there is nothing you can do to sustain your after life and you fade away...


DarkLizerd
28 Apr 2017, 06:39

set (Audrey, Spiritus, - 1)
set (player, Spiritus, +1)

I think this will set the value, not increase or decrease it...
I think you want:
DecreaseObjectCounter(Audrey, "Spiritus")
IncreaseObjectCounter (player, "Spiritus")

or use simple math:
Audrey.Spiritus=Audrey.Spiritus-1
player.Spiritus=player.Spiritus+1


Inherited Sin
28 Apr 2017, 09:19

Hello Everyone

Thanks for all the responses, I'm slowly figuring out bits and pieces but I'm currently a long way out of my depth!

Pixie: I tried this...

msg ("You cannot rest until you know what happened to you. And if that means feeding on the souls of sleepers, then so be it.")
SetTimeout (2) {
if (Audrey.Spiritus > 1) {
set (Audrey.Spiritus - 1)
set (player.Spiritus + 1)
msg ("Your target turns pale as you tap their life energy.")
}
else if {
set (Audrey.Spiritus - 1)
set (player.Spiritus + 1)
msg ("You devour your target's soul in order to cling to the material world a bit longer.")
}
}

... and got this:

Error running script: Expected 3 parameter(s) in script 'set (Audrey.Spiritus - 1)' I got the same error trying this instead...

msg ("You cannot rest until you know what happened to you. And if that means feeding on the souls of sleepers, then so be it.")
SetTimeout (2) {
set (Audrey.Spiritus - 1)
set (player.Spiritus + 1)
if (Audrey.Spiritus > 1) {
msg ("Your target turns pale as you tap their life energy.")
}
else if ("You devour your target's soul in order to cling to the material world a bit longer.")
}

What am I doing wrong? Basically I want the Attribute exchange to occur regardless, but if this reduces the NPC to 0 they're dead. So underneath that last message I'll have to figure out how to define a "Dead" flag that stops dialogue with poor Audrey and changes her description to a dessicated corpse. I also noticed the Status window in the game didn't dynamically update the Spiritus Attribute I put in it either.

The thought occurred that looping the Spiritus drain so it kept retrying every 5 seconds until either the NPC's Spiritus hit 0 or the player typed "stop eating" would be cool; but I clearly need to learn more of the basics first!

jmnevil54: Alas I've only really just started, and never done coding before so my game won't be up for a long while. The main hills I seem to need to climb are setting up and manipulating custom Attributes, setting up turns and tying Attribute gain/loss to them, and finally tying events to turns. The tutorials I've looked at so far are really good for a lot of the other things like dynamic dialogue, but I can't seem to get a handle on connecting components together in the GUI. Great point about the walls: perhaps the Ghost should be able to go in any direction whether there's a door in the wall or not!

DarkLizerd: Thanks for the code for different NPC Attributes, though I haven't figured out where I need to attach it to yet. I really am a total noob! I like the idea of extra hallway doors for character, though my brain is in danger of exploding from all the new stuff I'm trying to fit into it...


Inherited Sin
28 Apr 2017, 09:21

Hi DarkLizerd - wrote my reply above before seeing your last one, will try what you suggested - thanks!


Inherited Sin
28 Apr 2017, 10:53

Hello Again

OK, progress at last! After a couple of errors when Audrey got reduced to 1 Spiritus, I managed to finally figure it out when I got this one:

Error running script: Error compiling expression '"You devour your target's soul in order to cling to the material world a bit longer."': RootExpressionElement: Cannot convert type 'String' to expression result of 'Boolean':

Here is what finally worked:

DecreaseObjectCounter (Audrey, "Spiritus")
IncreaseObjectCounter (player, "Spiritus")
if (Audrey.Spiritus > 0) {
msg ("Your target turns pale as you tap their life energy.")
}
else if (Audrey.Spiritus = 0) {
msg ("You devour your target's soul in order to cling to the material world a bit longer.")
}

The Status Attribute for Spiritus updated OK as well. So now I need to set a flag for "Dead", and somehow define it to show a different description ("There is a dead person on the floor"), with no dialogue options and perhaps 1-2 inventory items. It would also be nice to find a way to make the above script run continuously until commanded to stop instead of having to run it over and over.

Phew, I'm beginning to appreciate how much detective work there is in this stuff when you're not a programmer!


Pertex
28 Apr 2017, 11:03
set (Audrey.Spiritus - 1)

The set function requires 3 parameters, you only have one. You can do this

set (Audrey, "Spiritus", Audrey.Spiritus - 1)

The first parameter is the object you want to change, the second parameter is the attribute you want to change and the third parameter is the new value you want to set. If you are using code view you can also do

Audrey.Spiritus = Audrey.Spiritus -1

or

DecreaseObjectCounter (Audrey, "Spiritus ")

DecreaseObjectCounter decreases the value by one.


Inherited Sin
28 Apr 2017, 11:12

Thanks Pertex, that's helping me to wrap my tiny brain around it a bit better...


hegemonkhan
28 Apr 2017, 23:28

to add to Pertex' Post:

when you use such Functions (Set, Do, HasAttribute, GetAttribute, etc), they require these Parameters/Arguments, for example, using 'set' Function:

set (NAME_OF_OBJECT, "NAME_OF_ATTRIBUTE", VALUE)

'NAME_OF_OBJECT' is the Object's name, which is a reference/pointer to that Object, is NEVER enclosed within double quotes. Anything without double quotes is an Object's name, except for the numbers and the special Values reserved for the Boolean Attribute: true/false, as these do NOT have double quotes, but are not mistaken for an Object's name (and no Object can have/be-given the name of 'true' or false', obviously)

'NAME_OF_ATTRIBUTE" is the Attribute's name, which when used as an Argument in a Function, must be enclosed within double quotes, as it is taken as a String by the Argument's Parameter. Anything in double quotes is a String Value to quest.

'VALUE' is your Value, which can be whatever data/Attribute type, so if the Value is a String, then it needs to be encased in double quotes.

for examples:

set (player, "strength_integer_attribute", 100)
set (player, "strength_string_attribute", "strong")
set (player, "right_hand_object_attribute", sword) // 'sword' is an already existing/created Object in our pretend game

string_VARIABLE = GetString (player, "strength_string_attribute")

if (GetString (player, "strength_string_attribute") = "strong") { /* blah scripting / } else if (GetString (player, "strength_string_attribute") = "weak") { / blah scripting / } else { / blah scripting */ }

if (HasString (player, "strength_string_attribute")) { /* blah scripting / } else { / blah scripting */ }


here's a guide on using Attributes and the 'if' Script, the 'bread and butter' of scripting/coding/game-making:

http://textadventures.co.uk/forum/samples/topic/5559/attributes-and-if-script-guide-by-hk