Author Topic: Can someone explain Flags to me?  (Read 3306 times)

0 Members and 1 Guest are viewing this topic.

Offline Doan Sephim

Can someone explain Flags to me?
« on: June 11, 2019, 11:35:48 AM »
In the past, I've used Global variables for TRUE/FALSE situations like "the first time you enter a room." While it works, it does produce a hefty main.sc which limits what I can do in other rooms/regions. Since then, I've heard a bit about using Flags in the place of global variables for those kinds of uses. The direction given was to look through the QfG1 decompiles, but after having spent some time looking through the forums and scripts, I'm not sure I understand how to implement this.

I'm not a native programmer, so things often go over my head. Can someone point this out to me?


Artificial Intelligence Competition

Offline EricOakford

Re: Can someone explain Flags to me?
« Reply #1 on: June 11, 2019, 11:54:11 AM »
Here's how event flags work, using code from my SCI01 Template:
Code: [Select]
(procedure (Btst flagEnum)
;Test a boolean game flag
(& [gameFlags (/ flagEnum 16)] (>> $8000 (mod flagEnum 16)))
)

(procedure (Bset flagEnum  &tmp oldState)
;Set a boolean game flag
(= oldState (Btst flagEnum))
(|= [gameFlags (/ flagEnum 16)] (>> $8000 (mod flagEnum 16)))
oldState
)

(procedure (Bclr flagEnum  &tmp oldState)
;Clear a boolean game flag
(= oldState (Btst flagEnum))
(&= [gameFlags (/ flagEnum 16)] (~ (>> $8000 (mod flagEnum 16))))
oldState
)

(procedure (SolvePuzzle flag points)
;Adds an amount to the player's current score. A flag (one used with
;Bset, Bclr, and Btst) is used so that a score is only added once.
(if (not (Btst flag))
(theGame changeScore: points)
(Bset flag)
)
)

They refer to a global variable array:
Code: [Select]
[gameFlags 10] ;each global can have 16 flags. 10 globals * 16 flags = 160 flags. If you need more flags, just increase the array!
The SolvePuzzle procedure checks if a flag is set, and if it's not, it awards the specified points to your score.

The flags are enumerated and defined in your GAME.SH file.

This is much more efficient than having one global per TRUE/FALSE situation, so that you only need separate global variables for situations with multiple states.
My SCI templates
SCI0 SCI0.1 SCI1.0 SCI1.1

Offline NilG

Re: Can someone explain Flags to me?
« Reply #2 on: June 11, 2019, 12:16:13 PM »
Awesome!  I just counted and I've got 70 global binary variables in what's probably a little less than a quarter of the full game.  I can shift quite a few local variables over this way as well, which could help trim the necessary logic from some of the main rooms into the specific room/input scripts.  My heap's shifting further from nightmare to comfortable with each trick you all pass on.

Might not be bad to compile some article on the Wiki for heap management tricks like these for some of us more amateur programmer types.  Perhaps I'll take some time to at least start on something like that; it'd be nice to contribute for sure in content if not coding and ideas.

Offline Doan Sephim

Re: Can someone explain Flags to me?
« Reply #3 on: June 11, 2019, 03:05:38 PM »
This is quite helpful, thank you.
Follow up: I'm working in an older project, and it is not yet in Sierra script. It'll be translated over in time, but when I run the auto-convert I end up with about 140 or so errors (I'll get around to them eventually ;)
In the meantime, I'm working on the scripts with studio scripting. In the code you provided, there is the mathematical operation of "mod."
I've never seen that operation in studio script and was wondering if anyone knew the symbol for that operation in Studio.
Thanks again for your help with flags. I always suspected there was a better way to do these type of things, but never knew about it until now

Edit: Mod's symbol appears to be % in studio script.
When I'm defining in the game.sc script, does that take up heap space?
« Last Edit: June 11, 2019, 03:33:21 PM by Doan Sephim »
Artificial Intelligence Competition

Offline troflip

Re: Can someone explain Flags to me?
« Reply #4 on: June 11, 2019, 05:59:46 PM »
When I'm defining in the game.sc script, does that take up heap space?

Define's are a compile time thing, they don't take up any extra space.
Check out my website: http://icefallgames.com
Groundhog Day Competition

Offline MusicallyInspired

Re: Can someone explain Flags to me?
« Reply #5 on: June 11, 2019, 11:14:19 PM »
Edit: Mod's symbol appears to be % in studio script.

Yeah, "MOD" is short for "modulus" and returns a remainder from a division operation...right?
Brass Lantern Prop Competition

Offline Kawa

Re: Can someone explain Flags to me?
« Reply #6 on: June 12, 2019, 04:00:35 AM »
Define's are a compile time thing, they don't take up any extra space.
I don't think you're talking about the same kind of defining that Doan Sephim is.
Yeah, "MOD" is short for "modulus" and returns a remainder from a division operation...right?
Correct.

Offline NilG

Re: Can someone explain Flags to me?
« Reply #7 on: June 12, 2019, 05:07:44 AM »
Is $8000 hex?  I know how to convert hex, but I'm a little fuzzy on how it applies here, if so?  I've got no real experience with bitwise operation; I feel like I get the most basic of concepts, but I'm definitely lacking in the applicability department, so I'm kind of slow at translating when it comes up.
« Last Edit: June 12, 2019, 05:10:08 AM by NilG »

Offline lskovlun

Re: Can someone explain Flags to me?
« Reply #8 on: June 12, 2019, 06:03:24 AM »
Is $8000 hex?  I know how to convert hex, but I'm a little fuzzy on how it applies here, if so?  I've got no real experience with bitwise operation; I feel like I get the most basic of concepts, but I'm definitely lacking in the applicability department, so I'm kind of slow at translating when it comes up.
Yup, 215, that is to say, the value you AND something with to isolate the 15th bit (OR to set it).
By shifting it right as here, you get decreasing powers of two which can be used similarly to isolate/set the 14th, 13th, etc. bit.

Offline Kawa

Re: Can someone explain Flags to me?
« Reply #9 on: June 12, 2019, 06:20:44 AM »
What's important is that those functions do the intricate math for you so you don't have to worry. I for one get confused easily when dealing with sub-byte data so I for one am thankful.

Offline Charles

Re: Can someone explain Flags to me?
« Reply #10 on: June 12, 2019, 11:06:55 AM »
It can be fun to learn about bit operations and binary/hex and all of that, but like Kawa said, that's all irrelevant knowledge for the Btst, Bset and Bclr procedures.  They do all the heavy lifting for you.

All you need to remember is that a single variable can hold 16 flags.  So the template game has 10 variables assigned to the gameFlags array. Ergo, 160 flags.  The first flag is flag #0, the last is flag #159. If you need more flags, extend the array; you get 16 more flags for each variable you extend the flag array.

You tell the Btst, Bset and Bclr procedures which flag number you want to test/set/clear.  And you should use an enum to track your flags, just to make things easier to read/follow. The enum's won't use any memory since the compiler will hardcode whatever number the flag is when compiling.

Here's how Btst, Bset, and Bclr compare to similar statements using individual global variables, assuming your global variable is named gVar1 and you want to replace it with a flag defined as FLAG1:
Code: [Select]
(Btst FLAG1)
(== gVar1 TRUE)

(Bset FLAG1)
(= gVar1 TRUE)

(Bclr FLAG1)
(= gVar1 FALSE)

Offline Doan Sephim

Re: Can someone explain Flags to me?
« Reply #11 on: June 12, 2019, 11:27:38 AM »
The flags are enumerated and defined in your GAME.SH file.
Do you define them in the Game.sh file or enumerate them (or does it even matter which?)
I apologize for the hand-holding needed with this, but what does it look like in the subheader?

This is what I see in the Template, but I'm confused on how it relates to the gameFlags:
Code: [Select]
;Event flags
;Example: fBabaFrog (original Sierra naming)
« Last Edit: June 12, 2019, 11:44:54 AM by Doan Sephim »
Artificial Intelligence Competition

Offline EricOakford

Re: Can someone explain Flags to me?
« Reply #12 on: June 12, 2019, 12:11:38 PM »
The flags are enumerated and defined in your GAME.SH file.
Do you define them in the Game.sh file or enumerate them (or does it even matter which?)
I apologize for the hand-holding needed with this, but what does it look like in the subheader?

This is what I see in the Template, but I'm confused on how it relates to the gameFlags:
Code: [Select]
;Event flags
;Example: fBabaFrog (original Sierra naming)

It doesn't really matter; using "enum" is just a simpler way to list defines in numerical order. The compiler recognizes them in the exact same way.

As an example, here are the event flags from R44QSCI:
Code: [Select]
; Event flags
(enum
fFoyerLightOn
fMetJohan
fJohanHasTie
fJohanAtReception
fMetNiels
fNielsSleeping
fTookJar
fTookGarbage
fOpenedStoveHood
fTookFilter
fTookTie
fFellDownStairs
fTookShowerGel
fSavedJinwo
fMetRinze
fGaveRinzeBeer
fTookPen
fTookNote
fWroteNote
fJosineDumped
fJosineGotNote
fCanEnterErikRoom
fJinwoHasKey
fCanEnterJosineRoom
fErikWantsFood
fEnteredJosineRoom
fTookRyeBread
fWearingFilter
fSawErikDead
)

If you want to start an enum at a specific number, just type that number after "enum".

Oh yeah, I forgot to mention a bit of trivia earlier - KQ4 and LSL2, the first two SCI games, didn't use the "Btst/Bset/Bclr" trio at all - they just used global variables for every event. Since that's a waste of heap space, PQ2 implemented the much more efficient bit-based event flag procedures. These became a standard part of SCI games ever since.
« Last Edit: June 12, 2019, 12:21:45 PM by EricOakford »
My SCI templates
SCI0 SCI0.1 SCI1.0 SCI1.1

Offline Charles

Re: Can someone explain Flags to me?
« Reply #13 on: June 12, 2019, 12:14:07 PM »
You can put them wherever. You can define then, or use enums. Enums are actually a bit easier to manage.  I mean, heck, if you wanted you could just use numbers for everything and keep it in your head.  Defines and Enums make no difference to the compiled code. They're only for making your code easier to read.  When they get compiled, the compiler will basically just do a find/replace with the defined or enumerated value.  They both have their place.  Defines are great for one-off values. Enums are great if you're defining a bunch of sequential values, like flags.

You could put enums in a seperate .sh file and include that in game.sh (although if you do that, the tooltip may not properly show up in SCICompanion when you hover over it).

I'll show you the more complicated example, and let you pare down as necessary. So if you have 160 flags to play with (as in the template game default), you can make those flags be whatever you want. Let's say your game has 40 rooms, and you want to know if ego has visited any room before. Then you have another 120 flags for game states or puzzle points.  You can break those up into multiple enums for easier readability.

in Game.sh:
Code: [Select]
;;; Sierra Script 1.0 - (do not remove this comment)
;put the Sierra Script comment at the top, so we can use sierra script in the header file
(include gameEnumVisited.sh)

create a new file called gameEnumVisited.sh:
Code: [Select]
;;; Sierra Script 1.0 - (do not remove this comment)
(enum    ;the default starting point is 0, although you can specify another)
   FLAG_VISITED_ROOM1    ;this is given a value of 0
   fVisitedRoom2                 ;this is given a value of 1
   VISITED_RM3                 ;this is given a value of 2
   ;... continue for as many as needed
   ;NOTE, flags can be called whatever you want, but being consistent with your naming will make your code easier to read.
)

(define FLAG_ROOM4  3)  ;we've explicitly given this a value of 3. We could have also made this the next line in the enum

;game states are called out here
(enum 40  ;we're starting this enum at 40, for the game state flags.
    fEgoIsJumping  ; has a value of 40. For when ego's jumping off a massive cliff.
    FLAG_BABAFROG ; has a value of 41. For when ego has turned Baba Yaga into a frog.
)

;puzzle points are defined here, so the user doesn't double-dip on points.
(enum 120
    POINTS_JUMPED ;120.  User jumped. Yay. Give yourself 5 points.
)

Then in each room's script, in the dispose code you would add the following
Code: [Select]
(method (dispose)
(Bset FLAG_VISITED_ROOM1) ; sets flag#0 to 1 (i.e. turns it on, or sets as TRUE)
                ;we'll also give the user some points, because the had to jump to leave the room
                (AddToScore POINTS_JUMPED 5) ;the AddToScore procedure will only add points if the POINTS_JUMPED flag is 0. 
                ;So no other checking is required. The user will only get 5 points once.
(super dispose:)
)

Keep in mind that you can still use Btst to check if points have been awarded. It's still just a flag.

Offline Doan Sephim

Re: Can someone explain Flags to me?
« Reply #14 on: June 12, 2019, 01:34:00 PM »
Thanks Eric and Charles! I only have one question remaining (I hope!) - the thing I don't understand is how the enums in the subheader relate to the variable and the procedure that references that variable. The enumerated list seems to be unconnected to the variable and procedures. I'm guessing they're connected by something in the procedure, but I don't get it, and it makes me feel like I'm missing something.


SMF 2.0.14 | SMF © 2017, Simple Machines
Simple Audio Video Embedder

Page created in 0.162 seconds with 24 queries.