Contents
Back
Forward

Appendix A: Using binary operators


A.1 Why binary operators?

ToT uses a lot of information coded using binary mask. For example, living civilizations in a particular game are represented by a binary
number. Thus the number 11010001 (209 decimal) means that in that game only 4 civilizations are active and particularly the first
(barbarian), the fifth , the seventh and the eighth.
This kind of code appeared often in Civ2 data (read Allard Höfelt's HexEditing document to see for yourself), and if you want to fully utilize
CSPL you should have confidence with this kind of code.
Without getting too far into the details, I'll describe operations commonly used to manage these binary numbers. If you only want to see the final formulae just look below at the conclusion section of this appendix.



A.2 AND operator

The AND operator works exactly as it works in logic (if you consider 0=FALSE and 1=TRUE)
So
0 AND 0 = 0 (FALSE AND FALSE = FALSE)
0 AND 1 = 0 (FALSE AND TRUE = FALSE)
1 AND 0 = 0 (TRUE AND FALSE = FALSE)
1 AND 1 = 1 (TRUE AND TRUE = TRUE)

The important thing to understand about this operator is that if the first operand is TRUE then the result is exactly the second operand
while if the first operand is FALSE then the result will be always FALSE (and vice versa)

If we have a set of bits (for example a byte) we can use the AND operator bit-to-bit
Example:
byte1 = 01010101 AND
byte2 = 00001111
-----------------------
result = 00000101

In C++ the AND operator is expressed by '&' character.



A.3 OR operator

Also the OR operator works as in logic:

0 OR 0 = 0 (FALSE OR FALSE = FALSE)
0 OR 1 = 1 (FALSE OR TRUE = TRUE)
1 OR 0 = 1 (TRUE OR FALSE = TRUE)
1 OR 1 = 1 (TRUE OR TRUE = TRUE)

The important thing to understand about this operator is that if the first operator is FALSE then the result is exactly the second
operator while if the first operator is TRUE the result will be always TRUE (and vice versa)

If we have a set of bits (for example a byte) we can use the OR operator bit-to-bit
Example:
byte1 = 01010101 OR
byte2 = 00001111
-----------------------
result = 01011111

In C++ the OR operator is expressed by '|' character.


A.4 XOR operator

The XOR operator is not well known in logic, where it is called "eXclusive OR":
It works exactly as OR but when the first operand and the second one are TRUE the answer is FALSE instead of TRUE as in the OR operand (it
translate the phrase "the first OR the second but not both")

0 XOR 0 = 0 (FALSE XOR FALSE = FALSE)
0 XOR 1 = 1 (FALSE XOR TRUE = TRUE)
1 XOR 0 = 1 (TRUE XOR FALSE = TRUE)
1 XOR 1 = 0 (TRUE XOR TRUE = FALSE)

If we have a set of bits (for example a byte) we can use the XOR operator bit-to-bit
Example:
byte1 = 01010101 XOR
byte2 = 00001111
-----------------------
result = 01011010      columns different with respect to OR operator

In C++ the XOR operator is expressed by '^' character.



A.5 Yeah, but why do I need this in Civ?

Ok, it's time to come back to our preferred game:
When do you need to use these things?
Let's say you want to trigger a particular event ONLY if the fourth Civ is still alive:
How can you translate this request in C++ code?

You know that CSPL gives you a function called GetCivInPlay, which returns a byte which represents civs still active in the following way:
The n-th bit in the byte is 0 if n-th civ is dead or 1 if n-th civ is alive; so 11010001 means that only civs nr 1,5,7 and 8 are alive
(remember civ 1 is barbarian).
So assuming you are just interested in the fourth bit of the byte, how can you extract this information in a simple way?
The easiest way is to use the AND operator, putting the result of function GetCivInPlay in AND with the bit mask 00010000. See if you can follow:

                        5th civ is alive    5th civ is dead
GetCivInPlay result:     11010001   AND      11000001   AND
bit mask                 00010000   =        00010000   =
--------------------    ----------------    ----------------
result                   00010000 (!=0)      00000000 (=0)

If the fifth civ is dead the result will be 0 while if the fourth civ is alive the result will be a number != 0

As you can imagine if we were interested in the first civ (barbarians) the bit mask to use would be 00000001 (1 decimal), while if we were interested in the second civ the bit mask to use is 00000010 (2 decimal) and so on. In C++ code you'll have:

{

if (!(GetCivInPlay()&16)) //16 is decimal for 00010000
{/*Civ nr 5 is dead!*/}
else
{/*Civ nr 5 is alive!*/}

}

For an example of the use of OR operator keep using the GetCivInPlay function. Let's say we don't want to test if a particular civ is active but that we want to resurrect a civ (if it is dead). The problem here is quite different. First we want to SET a particular bit:

                        5th civ is dead          5th civ is dead
GetCivInPlay result:     11000001   OR            10100101   OR
bit mask                 00010000   =             00010000   =
---------------------   ----------------        -----------------
result                   11010001                 10110101
                      5th civ is now alive      5th civ is now alive

As you can see the result of OR operator is exactly the GetCivInPlay result with the fifth bit set. This ensures that CSPL will not touch other Civilizations, it will just add the fifth one to the game.

For an example of the use of XOR operator keep using GetCivInPlay function. Let's say we want to destroy an existing civilization without touching the other civs. The problem is easily solved with the XOR operator:

5th civ is alive 5th civ is alive
                        5th civ is dead            5th civ is dead
GetCivInPlay result:    11010001   XOR              10110101   XOR
bit mask                00010000   =                00010000   =
------------------     -------------------       --------------------
result                  11000001                    10100101
                       5th civ is now dead        5th civ is now dead

As you can see the result of XOR operator is exactly the GetCivInPlay result with the fifth bit unset, thus ensuring that CSPL will not touch any other Civilizations. It just eliminates the fifth one from the game.



A.6 Conclusions

OK, here I'll briefly discuss the use of the binary operator in CSPL structures:

  1. If you want to check just one bit in a bit set:
    Use AND with a bit mask.
  2. If you want to set just one bit in a bit set:
    Use OR with a bit mask.
  3. If you want to unset just one bit in a bit set:
    Use XOR with a bit mask.
The bit mask you must use depends upon which bit you want to test/set/unset (if it's the first bit you should use 00000001, if it's the second you should use 00000010, etc…)




Contents / Introduction
Chapter I / Chapter II / Chapter III / Chapter IV / Chapter V / Chapter VI / Chapter VII
Chapter VIII / Chapter IX / Chapter X / Chapter XI / Chapter XII / Chapter XIII
Appendix A / Appendix B / Appendix C