ID:803473
 
(See the best response by DarkCampainger.)
Code:
var const
MODE1 = 1
MODE2 = 2
MODE3 = 4

var modes = MODE1 | MODE2 | MODE3 // varies
var tmp/mode = 1 // variable

proc/next_mode()
...


Problem description:
I'm trying to use bit flags and cycle through them in the fashion: 1, 2, 4, 1, 2, 4, etc., depending on the available modes (i.e. if modes = MODE1 | MODE3, the cycle is 1, 4, 1, 4). My concern is, what is the best way to determine if it has reached the final mode? What is the best way to loop it back to the smallest mode?

This could easily be done using a list, but I want to try it with a number instead.
This would work with C++, not sure about BYOND.

If your bits are in order: 1, 2, 4, 8, 16, etc... Then you can simply increase mode by 1 and check if it's not over

var const
MODE1 = 1 << 0
MODE2 = 1 << 1
MODE3 = 1 << 2
MAXMODE = 1 << 3

proc/next_mode(mode)
mode++
if(mode == MAXMODE)
mode = 1
return mode
In response to Zaoshi (#1)
I don't think you understood my question, so I'll explain again.

'mode' is the current mode of the object.
'modes' is the available modes that 'mode' can be.
When next_mode() is called, 'mode' goes to the next available mode.

e.g.
modes = MODE1 | MODE2 | MODE3 == 7
mode = MODE1 == 1
next_mode(): mode == MODE2 == 2
next_mode(): mode == MODE3 == 4
next_mode(): mode == MODE1 == 1

modes = MODE1 | MODE3 == 5
mode = MODE1 == 1
next_mode(): mode == MODE3 == 4
next_mode(): mode == MODE1 == 1

Ideally, modes can be any number of 2^n ORed together.

Using a list makes things simpler to me:
var L[] = list("a", "b", "c")
var item = L[1]

proc/next_item()
. = L.Find(item) + 1
item = L[. <= L.len ? . : 1]

But there could potentially be a lot of lists made, so I don't want to use them.
In response to Zaoshi (#1)
You want to shift the mode (mode << 1), not add to it (or you'll end up with a value like 3, which is a combination of MODE1 and MODE2)
Best response
If you need to be able to skip over flags, this seems to work pretty well:

var/const
flagA = 1<<0
flagB = 1<<1
flagC = 1<<2
flagD = 1<<3
flagE = 1<<4
flagF = 1<<5

proc/cycleBitFlag(v, flags)
// Supports up to 16 bits
ASSERT(v < 65536)

// Check that v is actually in flags
if(!(v & flags))
// Start it at the first value if not
return ( flags & ~(flags-1) )

// Get only the lowest bit (incase multiple flags are in v)
v = ( v & ~(v-1) )

// Create a mask of the current bit and all bits below it
v = v | (v - 1)

// Apply mask to flags "list" to leave only more significant bits than previous value
v = (flags & ~v)

if(v)
// Get only the lowest remaining bit
return ( v & ~(v-1) )
else
// Wrap around
return ( flags & ~(flags-1) )


mob
var/flag = flagA
verb/Test()
flag = cycleBitFlag(flag, flagA | flagC | flagF)
src<<flag


Keep in mind that BYOND only supports emulating up to 16 bits.

<edit>
Thought of much better way to create the mask. Doh. Fixed code.