help fixing an error and help making cat behaviour?

TiberianEuanOfficialYT
27 Sept 2020, 11:09https://snipboard.io/JxAfmL.jpg
Look above at the link.
(PS: I solved the error, just need cat script.)
mrangel
27 Sept 2020, 14:38The cat should be a fairly simple turnscript. My usual approach is to work from the top down; taking the most general case first.
I'll do this step by step rather than throwing a block of code at you, because hopefully that makes it easier to understand for the purpose of fixing problems.
So…
and not move to other rooms while being held by the player
You probably don't need to worry about this. Most NPC movement scripts just look for exits in the current room. If the cat's current room is the inventory, there aren't any exits there, so it won't move.
i need it to walk around the ship too
This is simple enough. First, find an exit from the room the cat is currently in:
exit = PickOneUnlockedExit (cat.parent)
Then we need to check if the exit is valid. If the player is holding the cat, or if all the exits are locked, then exit
will be null
. We need to check that before moving the cat:
exit = PickOneUnlockedExit (cat.parent)
if (not exit = null and HasObject (exit, "to")) {
MoveObject (cat, exit.to)
}
The exit's to
attribute points to the room on the other side. I check that to
exists before moving, because it's possible to have an exit that doesn't go anywhere and runs a script instead, and you don't want the cat to follow these.
However, at this point I have a thought. In my experience, cats tend to spend a lot of time sitting in front of closed doors, waiting for someone to open them. So maybe it would be better to have the cat pick an exit at random, and then if that exit is closed, don't move. That's an easy change to make:
exit = PickOneExit (cat.parent)
if (not exit = null and HasObject (exit, "to") and not GetBoolean (exit, "locked")) {
MoveObject (cat, exit.to)
}
If you want the cat to only go through certain doors, or you want to make the cat only move every other turn or something, you could add an extra and
expression to that line
With most NPCs, you would also want to tell the player if a someone has moved into or out of the room they're in. Cats can be quiet, so you might not want this (the cat will just appear in the sidebar), but I'll assume you do.
So, you want to check if the cat is in the player's room, and if the destination is the player's room. Something like:
exit = PickOneExit (cat.parent)
if (not exit = null and HasObject (exit, "to") and not GetBoolean (exit, "locked")) {
if (cat.parent = game.pov.parent) {
msg ("The cat wanders off to the " + GetDisplayAlias (exit.to) + ".")
}
if (exit.to = game.pov.parent) {
msg ("Your {object:cat} walks in from the " + GetDisplayAlias (cat.parent) + ".")
}
MoveObject (cat, exit.to)
}
(I'm assuming you know the names of the rooms. Using GetDisplayAlias (exit)
to get something like "north" would be another alternative, depending on the atmosphere you want to create)
follow the player at random
Actually following the player ends up being more complex than you think. However, there's an easier way – just give the cat a higher chance of walking into the room where the player is if they're in adjacent rooms. This could be as simple as:
exit = PickOneExit (cat.parent)
if (RandomChance (75)) {
follow = GetExitByLink (cat.parent, game.pov.parent)
if (TypeOf (follow) = "string") {
exit = GetObject (follow)
}
}
if (not exit = null and HasObject (exit, "to") and not GetBoolean (exit, "locked")) {
if (cat.parent = game.pov.parent) {
msg ("The cat wanders off to the " + GetDisplayAlias (exit.to) + ".")
}
if (exit.to = game.pov.parent) {
msg ("Your {object:cat} walks in from the " + GetDisplayAlias (cat.parent) + ".")
}
MoveObject (cat, exit.to)
}
GetExitByLink
finds an exit between two rooms if there is one. If the exit exists, it returns the name of the exit, which we can use GetObject
on to get the actual exit. If there is no exit between those rooms, it returns null
. so we check that the returned value is a string before doing anything with it.
take the items
and not take items in the same room as the player
You can put this in the same turnscript. You can put it before or after the cat moves. Or if you don't want the cat to move and pick up an object and move on the same turn, you could use an 'else' clause.
I'll use the object's take
attribute, which says whether it can be picked up. If you want to have a separate attribute to determine what objects the cat can pick up, just use that instead.
if (RandomChance (35)) {
objects = FilterByAttribute (GetDirectChildren (cat.parent), "take", true)
list remove (objects, cat)
obj = PickOneObject (objects)
MoveObject (obj, cat)
cat.hidechildren = true
}
I'd suggest making the cat a "Surface" (On the 'Container' tab), which means that the player can take objects away from it, and can see what it's holding by looking at it. In this case, hidechildren
causes the object(s) in the cat to be hidden until the player looks at it.
You can change the description for an object's contents on the container tab somewhere, so that instead of "Containing:" it says "Carrying:" or "Playing with:" once the player has looked at it.
after some time it should drop the item in the room it's in
That's simple enough. If the cat can only hold one item, then I'd give it a simple percentage chance of either picking up or dropping an object (use the same dice roll for both, it's more efficient).
So it would look like:
if (RandomChance (35)) {
objectheld = PickOneObject (GetDirectChildren(cat))
if (objectheld = null) {
objects = FilterByAttribute (GetDirectChildren (cat.parent), "take", true)
if (ListCount (objects) > 1) {
list remove (objects, cat)
obj = PickOneObject (objects)
MoveObject (obj, cat)
cat.hidechildren = true
}
}
else {
MoveObject (objectheld, cat.parent)
}
}
If you want to use different probabilities, you could just rearrange that a little:
objectheld = PickOneObject (GetDirectChildren(cat))
if (objectheld = null) {
// chance of picking up:
if (RandomChance (35)) {
objects = FilterByAttribute (GetDirectChildren (cat.parent), "take", true)
if (ListCount (objects) > 1) {
list remove (objects, cat)
obj = PickOneObject (objects)
MoveObject (obj, cat)
cat.hidechildren = true
}
}
}
else {
// chance of dropping
if (RandomChance (20)) {
MoveObject (objectheld, cat.parent)
}
}
not take items in the same room as the player
That's simple enough. I'll assume that you also don't want it to take items from the player if they're carrying the cat. So I use Contains
(which is faster than most of the Scope functions) to check if the cat is in the player's room. This includes cases when the cat is in the room, the cat is in the inventory, or the cat is in a box in the same room, whether or not the box is closed)
if (not Contains (game.pov.parent, cat)) {
objectheld = PickOneObject (GetDirectChildren(cat))
if (objectheld = null) {
// chance of picking up:
if (RandomChance (35)) {
objects = FilterByAttribute (GetDirectChildren (cat.parent), "take", true)
if (ListCount (objects) > 1) {
list remove (objects, cat)
obj = PickOneObject (objects)
MoveObject (obj, cat)
cat.hidechildren = true
}
}
}
else {
// chance of dropping
if (RandomChance (20)) {
MoveObject (objectheld, cat.parent)
}
}
}
If the cat can drop objects near the player but not pick them up, you could just move the if statement around.
But if the cat is being carried and drops an item, you probably want to let the player know, so it would become:
objectheld = PickOneObject (GetDirectChildren(cat))
if (objectheld = null) {
// chance of picking up:
if (not Contains (game.pov.parent, cat) and RandomChance (35)) {
objects = FilterByAttribute (GetDirectChildren (cat.parent), "take", true)
if (ListCount (objects) > 1) {
list remove (objects, cat)
obj = PickOneObject (objects)
MoveObject (obj, cat)
cat.hidechildren = true
}
}
}
else {
// chance of dropping
if (RandomChance (20)) {
if (cat.parent = game.pov) {
msg ("The cat spits out something, and you look down in time to see " + GetDisplayName(objectheld) + " hit the floor.")
MoveObject (objectheld, game.pov.parent)
}
else {
MoveObject (objectheld, cat.parent)
}
}
}
the player should not be able to see the object for a while until they step on it or look at their cat
Not entirely sure what you mean by 'step on it'. Do you mean that after the cat drops the object, it continues to be hidden for some length of time? I'd probably do that by making the object into scenery temporarily.
I'd add 2 lines after the cat drops an object:
objectheld.scenery = true
objectheld.lost = true
Then add a section to the beginning of the turnscript that lets the player 'find' these objects again. Something like:
randomobj = PickOneObject (GetDirectChildren (game.pov.parent))
if (not randomobj = null and GetBoolean (randomobj, "lost")) {
msg ("You almost trip over " + GetDisplayName (randomobj) + " that your cat has left lying around.")
randomobj.scenery = false
randomobj.lost = false
}
This picks an object in the same room as the player, and if it's lost finds it again. It means that the more stuff is in a room, the longer it takes to find something by chance.
If you want to make it a little easier on the player, you could make it so that when they deliberately look around the room (by typing look
) they find any objects the cat has been playing with. Adding something like this to the beginning of the turnscript:
if (game.pov.currentcommandpattern = look) {
found = FilterByAttribute (ScopeVisible(), "lost", true)
if (ListCount (found) > 0) {
msg ("While you are looking around, you find " + FormatList (found, ", ", ", and", "") + " lying around on the floor.")
foreach (obj, found) {
obj.lost = false
obj.scenery = false
}
}
}
(Using game.pov.currentcommandpattern
is a weird way for a turnscript to find out the last command that the player used. In this case, it's a relatively easy way to do things)
You could also add a little tweak to change the message when the player takes the object from the cat. Because the cat currently won't pick up objects that run a script when they are taken, you could add one like this (modifying the 'pick up/drop' part of the cat's script):
objectheld = PickOneObject (GetDirectChildren(cat))
if (objectheld = null) {
// chance of picking up:
if (not Contains (game.pov.parent, cat) and RandomChance (35)) {
objects = FilterByAttribute (GetDirectChildren (cat.parent), "take", true)
if (ListCount (objects) > 1) {
list remove (objects, cat)
obj = PickOneObject (objects)
MoveObject (obj, cat)
cat.hidechildren = true
obj.take => {
this.take = true
if (RandomChance (30)) {
msg ("You try to take the {object:" + this.name + "}, but the {object:cat} bats it into the far corner of the room.")
MoveObjectHere (obj)
obj.lost = true
obj.scenery = true
}
else {
msg ("With some effort, you persuade the {object:cat} to let go of {cat.possessive} toy.")
AddToInventory (this)
}
}
}
}
}
else {
// chance of dropping
if (RandomChance (20)) {
if (cat.parent = game.pov) {
msg ("The cat spits out something, and you look down in time to see " + GetDisplayName(objectheld) + " hit the floor.")
MoveObject (objectheld, game.pov.parent)
}
else {
MoveObject (objectheld, cat.parent)
objectheld.lost = true
objectheld.scenery = true
objectheld.take = true
}
}
}
So with all those bits, you'd have a turnscript whose script is:
if (game.pov.currentcommandpattern = look) {
found = FilterByAttribute (ScopeVisible(), "lost", true)
if (ListCount (found) > 0) {
msg ("While you are looking around, you find " + FormatList (found, ", ", ", and", "") + " lying around on the floor.")
foreach (obj, found) {
obj.lost = false
obj.scenery = false
}
}
}
else {
randomobj = PickOneObject (GetDirectChildren (game.pov.parent))
if (not randomobj = null and GetBoolean (randomobj, "lost")) {
msg ("You almost trip over " + GetDisplayName (randomobj) + " that your cat has left lying around.")
randomobj.scenery = false
randomobj.lost = false
}
}
exit = PickOneExit (cat.parent)
if (RandomChance (75)) {
follow = GetExitByLink (cat.parent, game.pov.parent)
if (TypeOf (follow) = "string") {
exit = GetObject (follow)
}
}
if (not exit = null and HasObject (exit, "to") and not GetBoolean (exit, "locked")) {
if (cat.parent = game.pov.parent) {
msg ("The cat wanders off to the " + GetDisplayAlias (exit.to) + ".")
}
if (exit.to = game.pov.parent) {
msg ("Your {object:cat} walks in from the " + GetDisplayAlias (cat.parent) + ".")
}
MoveObject (cat, exit.to)
}
objectheld = PickOneObject (GetDirectChildren(cat))
if (objectheld = null) {
// chance of picking up:
if (not Contains (game.pov.parent, cat) and RandomChance (35)) {
objects = FilterByAttribute (GetDirectChildren (cat.parent), "take", true)
if (ListCount (objects) > 1) {
list remove (objects, cat)
obj = PickOneObject (objects)
MoveObject (obj, cat)
cat.hidechildren = true
obj.take => {
this.take = true
if (RandomChance (30)) {
msg ("You try to take the {object:" + this.name + "}, but the {object:cat} bats it into the far corner of the room.")
MoveObjectHere (obj)
obj.lost = true
obj.scenery = true
}
else {
msg ("With some effort, you persuade the {object:cat} to let go of {cat.possessive} toy.")
AddToInventory (this)
}
}
}
}
}
else {
// chance of dropping
if (RandomChance (20)) {
if (cat.parent = game.pov) {
msg ("The cat spits out something, and you look down in time to see " + GetDisplayName(objectheld) + " hit the floor.")
MoveObject (objectheld, game.pov.parent)
}
else {
MoveObject (objectheld, cat.parent)
objectheld.lost = true
objectheld.scenery = true
objectheld.take = true
}
}
}
mrangel
27 Sept 2020, 15:13Edit:
I realise that using scenery like this might result in some odd behaviour. If the cat plays with an object then puts it back in the same room, then the player picks it up by typing the command (because they knew where they left it and didn't notice that it was missing from the list), they'll be able to clear the scenery
flag but the lost
flag will still be there.
In this case, it might be advantageous to use the take
script again to clear up any confusion:
if (game.pov.currentcommandpattern = look) {
found = FilterByAttribute (ScopeVisible(), "lost", true)
if (ListCount (found) > 0) {
msg ("While you are looking around, you find " + FormatList (found, ", ", ", and", "") + " lying around on the floor.")
foreach (obj, found) {
obj.lost = false
obj.scenery = false
obj.take = true
}
}
}
else {
randomobj = PickOneObject (GetDirectChildren (game.pov.parent))
if (not randomobj = null and GetBoolean (randomobj, "lost")) {
msg ("You almost trip over " + GetDisplayName (randomobj) + " that your cat has left lying around.")
randomobj.scenery = false
randomobj.lost = false
randomobj.take = true
}
}
exit = PickOneExit (cat.parent)
if (RandomChance (75)) {
follow = GetExitByLink (cat.parent, game.pov.parent)
if (TypeOf (follow) = "string") {
exit = GetObject (follow)
}
}
if (not exit = null and HasObject (exit, "to") and not GetBoolean (exit, "locked")) {
if (cat.parent = game.pov.parent) {
msg ("The cat wanders off to the " + GetDisplayAlias (exit.to) + ".")
}
if (exit.to = game.pov.parent) {
msg ("Your {object:cat} walks in from the " + GetDisplayAlias (cat.parent) + ".")
}
MoveObject (cat, exit.to)
}
objectheld = PickOneObject (GetDirectChildren(cat))
if (objectheld = null) {
// chance of picking up:
if (not Contains (game.pov.parent, cat) and RandomChance (35)) {
objects = FilterByAttribute (GetDirectChildren (cat.parent), "take", true)
if (ListCount (objects) > 1) {
list remove (objects, cat)
obj = PickOneObject (objects)
MoveObject (obj, cat)
cat.hidechildren = true
obj.take => {
if (RandomChance (30)) {
msg ("You try to take the {object:" + this.name + "}, but the {object:cat} bats it into the far corner of the room.")
MoveObjectHere (obj)
this.lost = true
this.scenery = true
this.take => {
if (RandomChance (80)) {
msg ("You manage to find the " + GetDisplayAlias (this) + " where the cat had left it.")
this.lost = false
this.scenery = false
this.take = true
AddToInventory (this)
}
else {
msg ("The " + GetDiaplayAlias (this) + " isn't anywhere to be seen. The cat must have moved it, and you might need to {command:look} around to find it.")
}
}
}
else {
msg ("With some effort, you persuade the {object:cat} to let go of {cat.possessive} toy.")
AddToInventory (this)
}
}
}
}
}
else {
// chance of dropping
if (RandomChance (20)) {
if (cat.parent = game.pov) {
msg ("The cat spits out something, and you look down in time to see " + GetDisplayName(objectheld) + " hit the floor.")
MoveObject (objectheld, game.pov.parent)
}
else {
MoveObject (objectheld, cat.parent)
}
objectheld.lost = true
objectheld.scenery = true
objectheld.take => {
if (RandomChance (80)) {
msg ("You manage to find the " + GetDisplayAlias (this) + " where the cat had left it.")
this.lost = false
this.scenery = false
this.take = true
AddToInventory (this)
}
else {
msg ("The " + GetDiaplayAlias (this) + " isn't anywhere to be seen. The cat must have moved it, and you might need to {command:look} around to find it.")
}
}
}
}
I've also got thoughts about cats and their tendency to climb into any open boxes they see, which would make the script a little more complex. Let me know if you'd like to try that.

Mataeus
27 Sept 2020, 16:42I can't believe you wrote that entire thing for the developer. That's above and beyond!
mrangel
28 Sept 2020, 13:29Now I'm looking at the 'getting into boxes' thing.
Think it might be interesting to give some objects a 'cat behaviour' thing. Like, you can give objects a verb that the cat can use.
So the cat picks an object at random in the room it ends the turn in.
If that object has a 'catdoes' verb, run the script. If it's a message, print the message only if the player is in the room. So you can have the cat scratching at things, or sniffing things, which has no effect but gives the player a sense that the cat is a real thing.
Otherwise, if the object is an open box (or a surface) the cat gets in/on it.
Otherwise, if the object can be taken, the cat isn't carrying anything, and the player isn't present, the cat picks it up.
If you have a verb that you don't want the player to use (makes it easier in the editor, especially using the web editor), you can put something like dictionary remove (game.verbattributeslookup, "catdoes")
, list remove (game.verbattributes, "catdoes")
, and destroy ("catdoes")
in the start script to remove that verb at the start of the game.
mrangel
30 Sept 2020, 14:10Here's a revised cat turnscript. A little different, but this is probably how I'd do it if it were my game.
Click here for code
NOTE: This was written off the top of my head on the forum, not tested, and I haven't tried it in Quest. So there may be typos. May also be logic errors, especially as my mum walked into the room and started rearranging the furniture behind me about twenty minutes ago. If you need help making it work, let me know.EDIT: Modified to include the part about letting the player find stuff the cat has hidden. Now, it will find any objects that the player has typed the name of in their command, anything that somehow got into the inventory without being found, as well as testing one random object in the room. Using the "look" command will still find everything.
result = ""
object = cat
params = NewDictionary()
// check if the player is messing with the cat
cat.interact = Contains (game.pov, cat)
if (HasAttribute(game.pov, "currentcommandresolvedobjects")) {
if (ListContains (game.pov.currentcommandresolvedobjects, cat)) {
cat.interact = true
}
}
else {
game.pov.currentcommandresolvedobjects = NewObjectList()
}
dictionary add (params, "interact", cat.interact)
// first, the stuff for finding objects that the cat has hidden
if (game.pov.currentcommandpattern = look) {
found = ScopeVisible()
}
else {
found = ListCombine (ScopeInventory(), game.pov.currentcommandresolvedobjects)
list add(found, PickOneObject (GetDirectChildren (game.pov.parent)))
list add(found, PickOneObject (ScopeReachableNotHeld()))
}
found = ListCompact (found)
found = FilterByAttribute (found, "lost", true)
showfound = NewObjectList()
if (ListCount (found) > 0) {
foreach (obj, found) {
obj.lost = false
obj.scenery = false
obj.take = true
if (GetBoolean (obj, "visible") and not Contains (game.pov, obj)) {
list add (showfound, obj)
}
}
}
if (ListCount (found) > 0) {
msg ("While you are looking around, you find " + FormatList (found, ", ", ", and", "") + " lying around on the floor.")
}
// Only have the cat do stuff if it's awake
if (HasInt (cat, "sleeping")) {
cat.sleeping = cat.sleeping - GetRandomInt (-3, 12)
// cat has more chance of waking up if the player used a command on it
if (cat.interact) {
if (game.pov.currentcommandpattern = lookat) {
cat.sleeping = cat.sleeping - GetRandomInt (0,5)
}
else {
cat.sleeping = cat.sleeping - GetRandomInt (15,25)
cat.startled = true
}
}
else if (GetBoolean (cat, "startled") and RandomChance (20)) {
cat.startled = false
}
if (cat.sleeping < 0) {
cat.sleeping = null
if (Contains (game.pov.parent, cat)) {
result = cat.wakemessage
}
}
}
else if (HasObject (cat, "parent")) {
// cat is awake and has not been RemoveObject'ed
// First, we get a list of everything the cat could interact with
objects = ListCombine (GetDirectChildren(cat.parent), ScopeExitsForRoom(cat.parent))
list add (objects, cat.parent)
if (HasObject (cat, "carrying")) {
list add (objects, cat.carrying)
list add (objects, cat.carrying)
}
options = NewStringList()
foreach (obj, objects) {
if (HasString (obj, "catactions")) {
obj.catactions = Split (obj.catactions)
}
if (HasScript (obj, "catactions")) {
list add (options, obj.name + ":catactions")
}
else if (HasAttribute (obj, "catactions") and GetBoolean (obj, "visible")) {
if (not ListContains (obj.catactions, "ignore")) {
foreach (action, obj.catactions) {
digits = 0
while (IsInt (Left (action, digits))) digits = digits + 1
if (digits = 0) {
count = 1
}
else {
count = ToInt (Left (action, digits))
action = Mid (action, digits + 1)
}
list add (options, obj.name + ":" + action)
}
}
}
}
// choose an action, and split it up into action and messages
action = PickOneString (options)
parts = TSplit(action + ":::")
action = Trim(ListItem (parts, 0))
object = ListItem (parts, 0)
list remove (parts, object)
object = GetObject (object)
if (action = "") {
list remove (parts, "")
}
if (IsRegexpMatch("^(go|carry|message|sleep\d*)$", action) or HasScript (object, action) or HasString (object, action)) {
list remove (parts, action)
}
else if (DoesInherit (object, "defaultexit") or DoesInherit (object, "container_base")) {
action = "go"
}
else if (GetBoolean (object, "take") or GetBoolean (object, "drop") or object = cat.carrying) {
action = "take"
}
else {
action = "message"
}
mesg = ListItem (parts, 0)
failmsg = ListItem (parts, 1)
dictionary add (params, "action", action)
dictionary add (params, "message", mesg)
dictionary add (params, "failmessage", failmsg)
cat.here = Contains (cat.parent, game.pov)
cat.seen = ListContains (ScopeVisible(), cat)
dictionary add (params, "here", cat.here)
dictionary add (params, "seen", cat.seen)
dictionary add (params, "carrying", cat.carrying)
// Now we actually do the thing
switch (action) {
case ("go") {
if (DoesInherit (object, "defaultexit")) {
if (GetBoolean (object, "locked") or not HasObject (object, "to")) {
if (Contains (game.pov.parent, cat) or game.pov.parent = object.to) {
result = failmsg
}
}
else {
if (Contains (game.pov.parent, cat) or game.pov.parent = object.to) {
result = mesg
}
cat.parent = object.to
}
}
else {
// it's a container
if (GetBoolean (object, "isopen")) {
if (Contains (game.pov.parent, cat)) {
result = mesg
}
if (Contains (object, cat)) {
cat.parent = object.parent
}
else {
cat.parent = object
}
}
else if (Contains (game.pov.parent, cat)) {
result = failmesg
}
}
}
case ("carry") {
if (object = cat.carrying) {
if (cat.parent = game.pov) {
if (ListCount (parts) > 2) {
result = ListItem (parts, 2)
else {
result = mesg
}
MoveObject (object, game.pov.parent)
}
else {
MoveObject (object, cat.parent)
if (Contains (game.pov.parent, cat)) {
result = mesg
}
}
cat.carrying = null
object.lost = true
object.scenery = true
object.take => {
if (RandomChance (80)) {
msg ("You manage to find the " + GetDisplayAlias (this) + " where the cat had left it.")
this.lost = false
this.scenery = false
this.take = true
AddToInventory (this)
}
else {
msg ("The " + GetDiaplayAlias (this) + " isn't anywhere to be seen. The cat must have moved it, and you might need to {command:look} around to find it.")
}
}
}
else if (HasObject (cat, "carrying")) {
// cat is carrying something else
if (Contains (game.pov.parent, cat) and ListCount (parts) > 3) {
result = ListItem (parts, 3)
}
}
else if (ListContains (ScopeVisible(), cat)) {
result = failmsg
}
else if (GetBoolean (object, "take")) {
// picked up an item
cat.carrying = object
}
}
case ("sleep") {
if (ListContains (ScopeVisible(), cat)) {
result = mesg
cat.sleeping = 80
cat.wakemessage = failmsg
cat.startled = false
}
}
case ("message") {
if (Contains (game.pov.parent, cat)) {
result = mesg
}
else {
result = failmsg
}
}
default {
result = GetAttribute (object, action)
}
}
}
// And show the result
switch (TypeOf(result)) {
case ("string") {
if (LengthOf (result) > 0) {
game.text_processor_this = object
game.text_processor_variables = params
result = Trim (ProcessText (result))
if (LengthOf (result) > 0) {
msg (result)
}
}
}
case ("script") {
dictionary add (params, "this", object)
invoke (result, params)
}
}
This assumes that each object the cat can interact with has an attribute catactions
, which can either be a script, string, or stringlist. Default options, such as "the cat paces around the room" or "the cat has fallen asleep in the doorway" can be added to the cat itself, or the room. In the case of a string or stringlist, the format is something like: action:message:failmessage
For example, 3go:The cat wanders through the door {either here:to the kitchen:from the lounge}.:You can {either seen:see:hear} your cat scrabbling at the closed {either here:kitchen:lounge} door, eager to get through.
Actions can be go
(exits and containers), carry
(which the player never sees, so the message is the cat dropping the item. The failmessage is if it can't pick up while the player is watching; the 3rd and 4th messages are for if it drops an item while being carried, or if it examines an item while already carrying something else), message
(display a message if the player is in the room; the second message is for if the player isn't present, so you can have the cat making noise), sleep
(the fail message is for when it wakes up), or the name of a script attribute on the object. If there's a number stuck to the beginning of the action, like 6sleep
, that makes the action 6 times more likely to be chosen.
If the action is omitted, we'll assume go
for exits and containers, carry
for moveable objects, and message
otherwise.
Adding ignore
to an objects action list will cause the cat to ignore that object completely.
The attribute cat.here
(or the parameter here
) can be used in the text processor to check if the cat was in the same room as the player at the start of its action. This will be false if the cat is trying to go through a door into the player's current room, or is trying to get out of a box.
Similarly, you can use cat.startled
in the wake-up message to see if the cat woke prematurely because the player disturbed it.