If condition nesting

OurJud
I still can't get my head around nesting complex 'if' scripts :x

I want to force my player to take 'take' two items before a command to leave the room will trigger.

I set the command pattern (leave; go out; out, etc) and then run the following script, but it doesn't work and typically, I can't see what I need to do in order to fix it.

if (Got(address book)) {
}
else if (Got(ePad)) {
MoveObject (player, kitchen)
}
else {
if (not Got(address book)) {
msg ("You decide it would be better to take the address book.<br/>")
}
else if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad.<br/>")
}
}


I then tried this, and initially thought I had it, but this allows me to leave, if I take just one of the objects.

if (Got(address book)) {
}
if (Got(ePad)) {
MoveObject (player, kitchen)
}
else {
if (not Got(address book)) {
msg ("You decide it would be better to take the address book.<br/>")
}
else if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad.<br/>")
}
}

jaynabonne
You almost had it. Since you want both conditions to be true, you need to check for them together, in the positive form you have:

if (Got(address book) and Got(ePad)) {
MoveObject (player, kitchen)
} else {
if (not Got(address book)) {
msg ("You decide it would be better to take the address book.<br/>")
} else if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad.<br/>")
}
}

The other way to do it is to handle the exception cases first. Then the good case falls out at the bottom:

  if (not Got(address book)) {
msg ("You decide it would be better to take the address book.<br/>")
} else if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad.<br/>")
} else {
// Must have both.
MoveObject (player, kitchen)
}

OurJud
Now you see, your first example uses something I wished the 'if' scripts had.. and it seems they do! The 'and' condition. Where on earth is this is the UI??

Anyway, thank you :)

HegemonKhan
you could also do it this way (sometimes it makes the nesting 'and~or~not' logic operators easier; especially compared to trying to get multiple 'ands' and 'ors' working on the same single line, lol):

if (Got(address book)) {
if (Got(ePad)) {
MoveObject (player, kitchen)
} else if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad.<br/>")
}
} else if (not Got(address book)) {
msg ("You decide it would be better to take the address book.<br/>")
}


or (had to massively adjust for logic, yet it still feels~seems wrong,... this is a very poor ordering-structure to use, as hopefully can be seen below):

if (Got(address book)) {
if (Got(ePad)) {
MoveObject (player, kitchen)
}
}
if (not Got(address book)) {
if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad and the address book.<br/>")
} else {
msg ("You decide it would be better to take the address book.<br/>")
}
} else if (not Got(epad)) {
("You decide it would be better to take the ePad.")
}

OurJud
Thanks, HK, I like the logic of the second, with the 'ePad and the address' condition.

Actually, I've just discovered another logic problem with this.

You see, the two items are on the body of a person you've just shot, and you only know they're there if you search the body, meaning that if the player tries to leave without searching the body first, they will still get the message "You decide it would be better to take the ePad." which would confuse them and make them wonder what ePad the game was referring to.

So, I set a flag on the player once they've searched the body, but I can't figure out how to include the 'if player has/has not got flag' into the script Jay provided.

If the player tries to leave before searching the body, it needs to say something like: "You turn to leave, but stop, convinced there must be something here than can help you."

HegemonKhan
using mine (too lazy to use Jay's lol):

using now 3 layers that you posed on how to do:

(in this case) you add it to the top layer (the least indented layer), see below and see if you see what I did (lol, lots of 'sees' used)
or, to say it in more detail:
the more left (less indented) the layer, the more it's an outer (top) layer. The more to the right (more indented), the more it's an inner (bottom) layer.

if (xxx.searched = true) {
if (Got(address book)) {
if (Got(ePad)) {
MoveObject (player, kitchen)
} else if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad.<br/>")
}
} else if (not Got(address book)) {
msg ("You decide it would be better to take the address book.<br/>")
}
} else if (xxx.searched = false) {
msg ("You search the body.")
xxx.searched = true
}


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

see if you can figure it out with Jay's on your own...
.
.
.
.
.
.
answer:

if (xxx.searched = true) {
if (Got(address book) and Got(ePad)) {
MoveObject (player, kitchen)
} else {
if (not Got(address book)) {
msg ("You decide it would be better to take the address book.<br/>")
} else if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad.<br/>")
}
}
} else if (xxx.searched = false) {
msg ("You should search xxx more closely before you go to the next room.")
xxx.searched = true
}

The Pixie
jaynabonne wrote:
  if (not Got(address book)) {
msg ("You decide it would be better to take the address book.<br/>")
} else if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad.<br/>")
} else {
// Must have both.
MoveObject (player, kitchen)
}

I think this second way is generally better.

Think about why the player should not be able to do something (he does not have this, that is not open, he does not know the combination). You through each one and test to see if that is the case, and if it is, give an appropriate message. You can generally avoid "and", which the GUI does not readily support, and nesting too. If you realise you have another condition, just insert an extra else if

jaynabonne
You can tremendously simplify all that (and make it more readable and easier to understand) simply by getting rid of the redundant checks in the elses. Not only is it much more of a pain to put in with the GUI, it's absolutely unnecessary.

If you have an "if (condition)", then there is absolutely no point to using "else if (not condition)" after it since the only way it gets to the else anyway is if the opposite condition is true. You're checking something which is *always true*. Why would you check something that is always true? Just use an "else".

OurJud
HegemonKhan wrote:
answer:

if (xxx.searched = true) {
if (Got(address book) and Got(ePad)) {
MoveObject (player, kitchen)
} else {
if (not Got(address book)) {
msg ("You decide it would be better to take the address book.<br/>")
} else if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad.<br/>")
}
}
} else if (xxx.searched = false) {
msg ("You should search xxx more closely before you go to the next room.")
xxx.searched = true
}

This sounds like what I want, HK, but I'm not clear on the 'xxx.searched - true' bit.

Are you saying I put the object's name in place of 'xxx' ?

And also, how does it know that 'xxx.searched = true' refers to the body? I feel like I need to do something else, other than just insert this code, but you don't say what?

Okay, I tried putting 'lance.searched = true' (Lance being the name of the dead guy) but when I tested it in-game, I got the error:

Error running script: Error compiling expression 'lance.searched = true': CompareElement: Operation 'Equal' is not defined for types 'Object' and 'Boolean

OurJud
Done it!!

I just went back to setting a flag on the player when he searches the body, then checked for that instead of using 'if (xxx.searched = true) {'

Thanks, everyone.

For reference, the working script code is:

if (GetBoolean(player, "lancesearched")) {
if (Got(address book) and Got(ePad)) {
MoveObject (player, kitchen)
}
else {
if (not Got(address book)) {
msg ("You decide it would be better to take the address book as its probably full of useful information.<br/>")
}
else if (not Got(ePad)) {
msg ("You decide it would be better to take the ePad as its probably full of useful information..<br/>")
}
}
}
else if (not GetBoolean(player, "lancesearched")) {
msg ("You turn to leave, but stop, convinced there must be <i>something</i> here that can help you.")
}

jaynabonne
Just to beat a dead horse, you can change this:

else if (not GetBoolean(player, "lancesearched")


to this:

else

If the "if" is not true, then you already know GetBoolean(player, "lancesearched") is false, so there is no need to check for it again. It can't be anything but.

HegemonKhan
@OurJud:

my bad, I should have explained, but I assumed you understood, and so I didn't do so.

ya, change the 'xxx' to whatever the Object's 'name' is that is involved, and also, change 'searched' to whatever you want as (or what is) the 'name' of (or that you choosen for) your Boolean Attribute (SetObjectFlagOn~Off).

I used the 'xxx' and 'searched' as I don't know what your words that you're using for them, are. I wasn't thinking, as I should have used 'xxx' also, instead of 'searched' to convey to fill it in with what you're using for your Boolean Attribute's 'name', lol.

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

GetBoolean (object_name, "attribute_name")
GetBoolean (xxx, "xxx") // my laziness as 'xxx' is quicker than: 'object_name' and 'attribute_name', lol
ie: GetBoolean (player, "lancesearched")

is the same as:

object_name.attribute_name = true
xxx.xxx = true
ie: player.lancesearched = true

----

not GetBoolean (object_name, "attribute_name")
not GetBoolean (xxx, "xxx") // my laziness as 'xxx' is quicker to write~type in than: 'object_name' and 'attribute_name', lol
ie: not GetBoolean (player, "lancesearched")

is the same as:

object_name.attribute_name = false
xxx.xxx = false
ie: player.lancesearched = false

OurJud
jaynabonne wrote:Just to beat a dead horse, you can change this:

else if (not GetBoolean(player, "lancesearched")


to this:

else

If the "if" is not true, then you already know GetBoolean(player, "lancesearched") is false, so there is no need to check for it again. It can't be anything but.

Understood, Jay.

Thanks, HK, but out of interest why did you choose to use 'true/false' values instead of the 'has/has not flag' ?

I think sometimes the reason I find your instructions so difficult to follow is because you code rather than use the UI, so there's always differences. When you supply a block of code to answer a question I've asked, it more often than not means nothing because it looks so different to the code I see when switching to it from the UI. You also seem to prefer using attributes and variables, rather than the conventional UI functions. Not that those functions aren't there in the UI, but I never use them as so far I've been able to do the things I need with 'ifs', flags, etc.

HegemonKhan
well... the:

if (orc.dead = false) {

is faster+shorter to type than:

if (HasBoolean (orc, "dead") = true) {

or shortened to (as Jay prefers): if (HasBoolean (orc, "dead")) {

HK is VERY LAZY! :D

also though, in coding, this uses the generic~universal syntax structure, so again, it's faster.

Object.Attribute = Value_or_Expression

orc.dead = false

which can be quickly switched to any other Attribute Type, as this (Object.Attribute=Value_or_Expression) is the generic~universal syntax structure:

orc.dead = true
orc.strength = 100
orc.skin_color = "green"
orc.equipment_list = split ("sword;mail;shield", ";")

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

as to why I add the unneccessary '=true' and 'else if (=false)' is because I need to do so, to know what is going on and~or to line it up with its upper line.

Jay hates this though. (when~if I become as good a coder as Jay, then I'll hate it too, lol)

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

yep, lol:

90% of everything that you want to do in your game uses just 2 (SUPER) Scripts:

1. the 'if' Script

2. the 'set a variable or attribute' Script (your use of 'quest:flags' of 'SetObjectFlagOn~Off' is just merely a different way of setting a Boolean Type Attribute, which the 'set a variable or attribute' Script does, along with all the other types of attributes too, compared to just being able to set boolean attributes)

jaynabonne
HK, first I think you mean GetBoolean instead of HasBoolean. The former returns the value; the latter checks if a boolean attribute exists, and has very rare uses.

GetBoolean can actually be ultimately less to type, because then you don't need to create an attribute - and creating an attribute takes more typing! (I am lazy as well, and True Laziness requires looking at it from all angles. lol) Also, you might want do only define a flag on an object when the flag is actually relevant. It can be cleaner to only actually set a flag when you're using it, rather than defining 20 possible flags on an object, the vast majority of which may be clutter.

if (orc.dead = false) {

requires you to actually create a "dead" attribute and set it to false. Otherwise, you'll get a script error about "dead" not existing.

if (GetBoolean (orc, "dead")) {

will return false if orc.dead is false *or* if it doesn't exist. It can be more convenient (and safer and more expedient).

I'm not saying always use GetBoolean. If you know for sure an attribute will exist, then the direct method is fine. But GetBoolean has its uses because it's behaviorally different (in other words: they are *not* totally equivalent).

The Pixie
jaynabonne wrote:if (HasBoolean (orc, "dead")) {

will return false if orc.dead is false *or* if it doesn't exist.

just a type, I am sure, but that should be GetBoolean. HasBoolean will return true if orc.dead is false, because the attribute exists.

An issue with GetBoolean is that it takes no account of typos. GetBoolean(orc, "deaad") will return false, whether the orc is dead or not. On the other hand, orc.deaad will throw an error, making the problem much easier to spot and correct.

jaynabonne
Thanks. And ironic, given what I was saying two paragraphs above. :)

Your point about typos is valid. Direct binding is definitely preferred, if the attribute is guaranteed to exist.

HegemonKhan
good points, thank you, and ya, I meant GetBoolean (pretending that I realized the difference between them which you just explained, lol).

so... each have their pros and cons basically, sometimes 'Object.Attribute=Value' should be used, sometimes 'GetAttribute' should be used, and sometimes 'HasAttribute' should be used, sometimes 'Set (Object, "Attribute", Value) should be used.

------

(correct me if wrong) to me it seems like the 'Has', 'Get', and 'Set' are more useful when you're a more advanced coder, using advanced parsing (and~or concatinating ~ can't spell) coding, whereas for me, since I usually do have those Attributes existing~created on the Objects initially, then the 'Object.Attribute=Value' works well for me.

jaynabonne
We've been talking about getting values. Setting is a different story. For one thing, assignment always works, even if the attribute doesn't yet exist. So "object.attribute=value" has little wrong with it. The only reason I'd use "set" over simply assigning is if "attribute" is a variable (e.g. you want to compute the name of the attribute to set). Otherwise, I always just assign.

And the other Get methods besides GetBoolean are almost useless (short of the more advanced variable name case). At least GetBoolean returns a decent default if there is no attribute defined (which is at least of boolean type). The others return null. So if you have something like:

n = GetInt(object, attribute)

despite "n" possibly being equal to null, you can't actually compare it to null, as that check will cause a Quest exception if n happens to be an integer. So basically, GetInt returns a value that you can't check for. There's no way to use the null return value in any useful way. The bottom line is that calling GetInt on a missing attribute will always cause a Quest error at some point, just as simply referencing it directly does.

I would love GetInt to return a default value of the correct type as GetBoolean does (maybe 0). Then you could easily implement things like counters without having to actually set the initial value - it would just return 0 the first time you queried it. The same thing with GetString: returning an empty string instead of null would be much more useful.

The Has methods are definitely advanced. They have limited use, but when you need them, you need them. There's no other way to do what they do. :)

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

Support

Forums