Jump to content

Bitwise Operators Problem


Rastor

Recommended Posts

I am trying to change the kit usability of a few items in BG2: ToB using the bitwise operators. Thus far, I have had limited success.

 

Here the the code that I am using to make some items usable by wizard slayers.

 

COPY_EXISTING ~PLAT06.ITM~ ~override~ // Ankheg Plate Mail +2
      ~BELT10.ITM~ ~override~ // Belt of Inertial Barrier
      ~CLCK05.ITM~ ~override~ // Cloak of Balduran
      ~CLCK26.ITM~ ~override~ // Cloak of Mirroring
      ~RODS01.ITM~ ~override~ // Rod of Absorption
      ~MISC3L.ITM~ ~override~ // Horn of Silence
      ~AMUL19.ITM~ ~override~ // Amulet of 5% Magic Resistance
      ~AMUL25.ITM~ ~override~ // Amulet of Spell Warding
      ~AMUL20.ITM~ ~override~ // Kaligun's Amulet of Magic Resistance
      ~MISC3E.ITM~ ~override~ // Black Spider Figurine
      ~MISC3I.ITM~ ~override~ // Silver Horn of Valhalla
      ~POTN11.ITM~ ~override~ // Potion of Invulnerability
      ~POTN33.ITM~ ~override~ // Potion of Magic Blocking
      ~POTN34.ITM~ ~override~ // Potion of Magic Protection
      ~POTN35.ITM~ ~override~ // Potion of Magic Shielding
      ~RING34.ITM~ ~override~ // Ring of Spell Turning
      ~WAND18.ITM~ ~override~ // Wand of Spell Striking
      ~MISC3H.ITM~ ~override~ // Horn of Blasting
      ~POTN42.ITM~ ~override~ // Potion of Invulnerability
      ~MISC72.ITM~ ~override~ // The Claw of Kazgaroth
      ~CLCK03.ITM~ ~override~ // Cloak of Displacement
      ~MISC3A3.ITM~ ~override~ // The Book of Infinite Spells (True Seeing)
      ~MISC3A5.ITM~ ~override~ // The Book of Infinite Spells (Spell Turning)
      ~MISC9Y.ITM~ ~override~ // Brine Potion
      ~POTN21.ITM~ ~override~ // Potion of Clarity
      ~POTN45.ITM~ ~override~ // Potion of Freedom
      ~POTN46.ITM~ ~override~ // Potion of Stone Form
      ~RING09.ITM~ ~override~ // Ring of Free Action
      ~RING39.ITM~ ~override~ // Ring of Gaxx
      ~RING33.ITM~ ~override~ // Ring of the Ram
READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BOR "0b00000010")
BUT_ONLY_IF_IT_CHANGES

 

When WeiDU runs that code, however, nothing happens. I will install that portion of the tp2, then load up the item in NI and see that it is still not useable by wizard slayers.

 

Along the same vein, there are some items that I am trying to make not useable by wizard slayers. I am using this code to do it:

 

COPY_EXISTING ~CHAN20.ITM~ ~override~ // White Dragon Scale
      ~WA2HELM.ITM~ ~override~ // Vhailor's Helm
      ~HELM16.ITM~ ~override~ // Helm of Brilliance
      ~MISC9W.ITM~ ~override~ // Drow Piwafwi Cloak
      ~SW1H16.ITM~ ~override~ // Ilbratha +1
READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BOR "0b11111101")
BUT_ONLY_IF_IT_CHANGES

 

I get the same result as above. Absolutely nothing changes.

 

Could someone please give me a hand in resolving this issue?

Link to comment

First, look to the bitwise tutorial in the WeiDU read me.

 

Anyway, it all looks harder than it seems. Let's say we want to make an item usable by wizard slayers. The field in BG2 items defines the following:

bit0 - berserker
bit1 - wizard slayer
bit2 - kensai
bit3 - cavalier
bit4 - inquisitor
bit5 - undead hunter
bit6 - abjurer
bit7 - conjurer

After asking why the fuck they didn't put any of these in logical order (hmm, fighters, paladins, and... 2 mage specialty schools?), we only need to realize that when a bit is on, the item is unusable by that alignment/class/kit, and when the bit is off, it is usable.

 

Looking to the bitwise operators themselves, you get some simple rules:

BAND:
0 BAND 0 = 0
0 BAND 1 = 0
1 BAND 0 = 0
1 BAND 1 = 1
-- only if the leftBit and the rightBit have the particular bit on will this ever return 1

BOR:
0 BOR 0 = 0
0 BOR 1 = 1
1 BOR 0 = 1
1 BOR 1 = 1
-- if either the leftBit or rightBit is on, return 1 (in other words, they both have to be off to return 0)

BXOR (you shouldn't ever need this):
0 BXOR 0 = 0
0 BXOR 1 = 1
1 BXOR 0 = 1
1 BXOR 1 = 0
-- exclusive OR, returns 1 if and only if one of the two bits is on

 

So, you have your items that you want to make usable by wizard slayers. To enable a bit, you'll want to use BAND (because if the bit is on, the item is unusable), since leftBit BAND 0 will always return 0 (and turn the bit off):

READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BAND "0b11111101")

This will turn the wizard slayer bit off (making the item usable), and preserve the existing bits (if any are off, 0 BAND 1 returns 0, leaving the bit off, and if enabled, 1 BAND 1 returns 1 and leaves the bit on).

 

We need the reverse to make an item unusable by wizard slayers (we need to turn the bit on, and BAND won't help us with that), so we turn to BOR. Since leftBit BOR 1 returns 1, we can use it to turn on the bit, regardless of its current value:

READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BOR "0b00000010")

This will turn the wizard slayer bit on (making the item unusable), and preserve the existing bits (if any are off, 0 BOR 0 returns 0, leaving the bit off, and if enabled, 1 BOR 0 returns 1 and leaves the bit on).

Link to comment

Since I brought up BXOR, and am probably the only person using it, here's a little blurb. Say we have the following:

bit0 - berserker - ON (1)
bit1 - wizard slayer - OFF (0)
bit2 - kensai - OFF (0)
bit3 - cavalier - OFF (0)
bit4 - inquisitor - ON (1)
bit5 - undead hunter - OFF (0)
bit6 - abjurer - OFF (0)
bit7 - conjurer - OFF (0)

Now, say we want to turn the berserker bit off (making the item usable by berserkers), and the wizard slayer bit on (making the item unusable by wizard slayers) *in the same patch*, we turn to BXOR. Since BXOR gives us the "one or the other but not both" rule, we can use this to easily toggle multiple bits in the same WRITE action:

READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("usability" BXOR "0b00000011")

Since the value of usability should be "0b00010001," BXORing the value returns "0b00010010" (since 1 BXOR 1 returns 0). Huzzah! Don't ever do this, though, as there's no real way to tell if the bit you want to turn off is actually on (in a single patch action, at least), and BXOR will just turn it on if it's not.

 

EDIT: actually, you could just do something like WRITE_BYTE 0x2f ((usability BAND 0x01) = 0x01) ? "usability" BXOR 0x03 /* turn bit 0 off and bit 1 on */ : "usability" BOR 0x02 /* bit 0 already off, turn bit 1 on */. Huzzah! It is now safe to use BXOR.

 

Once you get more familiar with the bitwise operators, you can adopt some practices that make it much simpler to read and write. Since individual bits will always give us decimal powers of 2 (0b0001 = 1, 0b0010 = 2, 0b0100 = 4, etc.), there's no reason at all to use binary notation with the bitwise operators:

bit0 = 2^0 = 1 = 0x01
bit1 = 2^1 = 2 = 0x02
bit2 = 2^2 = 4 = 0x04
bit3 = 2^3 = 8 = 0x08
bit4 = 2^4 = 16 = 0x10
bit5 = 2^5 = 32 = 0x20
bit6 = 2^6 = 64 = 0x40
bit7 = 2^7 = 128 = 0x80

As you can see, you don't even need to know your powers of two to do this in hex: you only need to know the sequence 1->2->4->8 (as you move up the field by multiples of 4, you just add a 0: 0b0001000000000000 is 0x1000). This makes it very easy to cover a wider range of values (if you need to modify two sequential bytes using bitwise operators, a single WRITE_SHORT with hexadecimal values is cooler than two WRITE_BYTEs, and a lot easier on the eyes than using binary notation).

 

Finally, for turning bits off, you'd eventually realize the following are all equivalent:

READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BAND "0b11111101")

READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BAND "0xfd")

READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BAND (BNOT "0x02"))

Since we now know that 0x02 = 2^1 = bit1 = wizard slayer, we know that BNOT 0x02 gives us everything *but* the wizard slayer bit (i.e., all of the above representations -- 0b11111101, 0xfd, and BNOT 0x02 are all just different representations of the decimal value 255 - 2 = 253* -- will turn the wizard slayer bit off, making the item usable by wizard slayers).

 

*Since each byte can hold a maximum of 2^8 = 256 values (ranging from 0 to 255), the value returned from disabling any particular bit is the difference between 255 and the value of the bit(s) disabled. That said, to me, BNOT 0x02 makes clear the association to bit1, whereas I have to think about the difference when using a value like 0xfd (0xff (255) - 0xfd (253) = 0x02 = 2 = bit1).

Link to comment
This will turn the wizard slayer bit on (making the item unusable), and preserve the existing bits (if any are off, 0 BOR 0 returns 0, leaving the bit off, and if enabled, 1 BOR 0 returns 1 and leaves the bit on).

 

The code that you posted to turn the bit on is the exact same code that I posted to turn the bit on. It is not working.

Link to comment

The code you posted to turn the bit off:

 READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BOR "0b00000010")
// this is actually going to turn the bit on if it's off

The code you need to turn the bit off:

READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BAND "0b11111101")
// this is going to turn the wizard slayer bit, and only that bit, off

 

The code you posted to turn the bit on:

READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BOR "0b11111101")
// this is going to turn every bit on *but* the wizard slayer bit

The code you need to turn the bit on:

 READ_BYTE 0x2f "usability"
WRITE_BYTE 0x2f ("%usability%" BOR "0b00000010")
// this is going to turn the wizard slayer bit, and only that bit, on

 

The binary notation (they all look the same) is hiding the fact that you switched the values and need to use BAND to turn the bit off. You can just go ahead and BAND (BNOT 0x02) to turn the bit off and BOR 0x02 to turn it on, if you wish. :)

Link to comment
EDIT: actually, you could just do something like WRITE_BYTE 0x2f ((usability BAND 0x01) = 0x01) ? "usability" BXOR 0x03 /* turn bit 0 off and bit 1 on */ : "usability" BOR 0x02 /* bit 0 already off, turn bit 1 on */. Huzzah! It is now safe to use BXOR.
To save face, even this isn't sufficient. You'll need something like
WRITE_BYTE 0x2f ((flags BAND 0x03) = 0x01) ? flags BXOR 0x03 : (flags BAND 0x01) ? flags BAND (BNOT 0x01) : flags BOR 0x02

This will run through each possible scenario (bit0 off, bit1 off; bit0 on, bit1 off; bit0 off, bit1 on; bit0 on, bit1 on). As with all things binary, the number of conditions increases exponentially as more bits are added into the fray: sample code to toggle the value of three bits in a single byte

((flags BAND 0x49) = 0x48) ? flags BXOR 0x49 : ((flags BAND 0x41) = 0x40) ? flags BXOR 0x41 : ((flags BAND 0x09) = 0x08) ? flags BXOR 0x09 : ((flags BAND 0x48) = 0x48) ? flags BAND (BNOT 0x48) : (flags BAND 0x40) ? flags BAND (BNOT 0x40) : (flags BAND 0x08) ? flags BAND (BNOT 0x08) : flags BOR 0x01

(although, technically, the hope is that this should still be faster than three separate writes).

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...