B Tutorial Module System MBScript and Bitfields

Currently viewing this thread:


Sergeant at Arms
Best answers
Bitfields are a convenient way to pass around pieces of ON/OFF flag data. A bit field is simply a string of 1s and 0s that represent different flags being on or off, expressed as an integer. M&B make heavy use of them for any of the flags, as anyone who has poked around the in header files can attest. Using the bitwise operations (store_and, store_or, val_and, val_or) modders can make use of custom bitfields for their own mods. Onin no Ran make heavy use of them in the economy model and in quests. Prior to having the bitwise operations, I had hacked together a bin->int and int->bin converter, which was bug prone and ugly. So I asked for them, and received (yay Armagan and dev team!):


How to use:

store_or,<dest>,<op1>,<op2> -> dest = op1 | op2
This operation stores the bitwise OR of op1 and op2 into dest. This operation is used to set a particular bit (or set of bits if chained with other store_or or val_or calls)
(assign,':bit1',0x1), # lowest bit in a bit field, in hex, equals 0b0001
(assign,':bit2',0x2), # next lowest bit, equals 0x0010
(assign,':bit3',0x4), # and so on, 0x0100
(assign,':bit4',0x8), # you get the idea, 0b1000
(store_or,':flag',':flag',':bit3'), # this sort of pseudo-recursion is legal, you could use val_or also: (val_or,':flag',':bit3'), result is flag = 4
(val_or,':flag',':bit4'), # result is flag = 12
store_and,<dest>,<op1>,<op2> -> dest = op1 & op2
This operation is used to test whether a particular bit has been set:

# flag is currently set = 12
(store_and,':test',':flag',':bit3'), # test = 3, if the returned value is > 0, the bit is set,
(store_and,':test',':flag',':bit1'), # test = 0, which makes testing easy (either = or != to 0)
val_and is slightly different, since it is equivalent to dest = dest & op. Let's start with some basic binary math, using the above definitions:

flag = 12 # same as 0b1100
flag = flag & bit1 # 0b1100 & 0b0001, result = 0
flag = 12
flag = flag & bit3 # 0b1100 & 0b0100, result = 4, 0b0100
Note how this is a slightly shorter path, with fewer variables to deal with. Assuming a quest with a custom bitfield defined:

(val_and,':flag',custom_quest_flag_foo), # where custom_quest_flag_foo is defined in module_constants.py
(gt,':flag',0), # if flag > 0, custom_quest_flag_foo is set to ON (or HIGH, or 1, however you choose to think of it). If custom_quest_flag_foo were set to 0, 
<continue with script> # then flag = 0 and the script would fail.
To unset a bit, there is no MBScript opcode equivalent to XOR ( 0b1100 XOR 0b0100 = 0b1000). However, the integer equivalent is subtraction: 12 (0b1100) - bit3 (0b0100) = 8 (0b1000). Thus, to unset a bit:

(quest_get_slot,':flag',':quest_number',slot_quest_custom_flags), # using the above, flag = 12 (0b1100)
(val_sub,':flag',custom_quest_flag_foo), # assuming custom_quest_flag_foo = 4 (0b0100), flag = 12 (0b1100) - 4 (0b0100) = 8 (0b1000)
(quest_set_slot,':quest_number',slot_quest_custom_flags,':flag'), # store the new flag, with custom_quest_flag_foo set to 0, back to the quest object
Hopefully this has shed some light on bitwise operations on MBScript. Questions?