Contents Back Forward |
9. Global Thread |
9.1 Global Thread overview In the last chapter we've seen how Wonders Thread works. Here we'll analyze deeply another thread: the Global Thread. The Global thread scan continuosly Tot memory searching for Global informations about game, executing at the same time GlbCheck function; the CSPL designer projects his global-related events just changing the GlbCheck function, leaving untouched the main structure of Global Thread. There are a lot of differences between Global Thread and other Threads in CSPL: The exact source-code of Global Thread cannot be reported because it is very complex and uses some of inner CSPL features. Anyway from an external view the Global Thread works exactly as other Threads, so don't worry too much. | 9.2 Global functions In CSPL i've defined several functions to manage global variables:
It reports the number of turns passed since the game started; it can be used as a CSPL replacement of the macro-language TURN turn=x command. byte GetDifficulty() This function returns the difficulty level choosen on game start. Iīve defined the following costants for address difficulty level:
byte SetDifficulty(int Level) This function, as the name itself says, is the opposite of the previous function, it sets the difficulty level in game to Level passed as parameter. byte GetBarbarianActivity() This functions returns the level of Barbarian activity, this level range from "Villages Only" to "Raging Hordes" Again, i've defined some costants to help designers:
byte SetBarbarianActivity(byte Activity) Again, this function is the opposite of the previous function, it sets the difficulty level in game to Level passed as parameter. BOOL TestCiv(int ID) this functions takes as parameter a Civ ID (we saw them here) and returns TRUE if that Civ is still in game, FALSE otherwise byte GetCurrentCiv() This function returns the ID value of the civ currently playing his turn. WORD GetCurrentUnit() This function returns the ID value of the Unit currently selected on screen. Notice that if no unit is currently selected this function returns 0xFFFF. byte GetCivsInPlay() Returns a byte showing (when read as binary number) all civs currently in game; this is exactly the byte 46 in section 2 of Allard's doc: enumeration of all civs still in play [binary]Nothing else to add. void CreateCiv(int ID) This function allows designer to add a new civ to the game (WARNING:you should give manually some units or cities to the new civ in order to see it), Just call CreateCiv passing as parameter ID the ID of the civ you want to add. In case selected civ is already present in the game this function don't do anything. byte GetHumanPlayer() Returns a byte showing (when read as binary number) which civs are currently human controlled; this is exactly the byte 47 in section 2 of Allard's doc: human player played (can be more than one) [binary] void SetHumanPlayer(byte Civs) This function is the opposite of the previous function, it can set human player while the game is running. WARNING: It takes as parameter NOT the ID of civs to be human controlled, but the humancivs byte as described in the previous function So, if you just want to add a human civ you should do the following:
While if we want to set human controlled civ to a particular one (with id ID) we shoulf do the following:
byte ReadCurrentPollution() This function returns the current world pollution level. Let's quote Allard's documentation on this value: 7F is maximum, and will certainly cause globalHere obvioulsy Allard talks about hex values, this means 7F is 127 decimal while FF is 255 decimal. void WriteCurrentPollution(byte Level) Again, this function is the opposite of the previous function, it sets the pollution level in game to Level passed as parameter. byte PeaceTurns() Returns the number of (global) peace turns in current game |
9.3 Example 8 : SwitchRuler In this example we will try to realize an event which switch player civ after 10 turns. This effect can be used to simulate civil wars with the player starting to control a new faction, or you can use this effect in multi-protagonist scenarios (play the first half with one civ, the second half with the other) and a lot of other interesting effects (scenarios designed with companies instead of civs, where player is hired by one company or by another one etc...). In the following let's say that player starts with white civ and, at turn 10, the player controlled civ became the green one. PHASE 0: CREATING A NEW PROJECTAs we've learned in the previous chapters the first step towards CSPL compilation is the project creation (usually done with CSPLCompanion);again create a new project called SwitchRuler. PHASE 1: UNDERSTANDING WHAT WE NEEDThe first thing a CSPL designer should think is : "which thread i need?"Our choise is simple, since we want to play with human civs and so on, only GlobalThread is required. PHASE 2: DESIGNING THE EVENTThe next thing we have to do is to design the "skeleton" of our event:From the first chapter we know that event is made of HEAD (Trigger Statement) and BODY (Action Statement): In this case HEAD is "Current turn is 10." while BODY is "Change human controlled civ." WARNING:We should find a way to make sure that change happens only once. PHASE 3: CODING THE EVENTWe should check continuosly for current turn value, when it is equals to 10, we simply call SetHumanPlayer to change human controlled civ, all should be done inside the GlbCheck function:Itīs time to write a bit of code:
Notice a couple of things: pwr(CIV_GREEN): this is a function i implemented to calculate in a fast way (without including math lib) 2^CIV_GREEN. Why SetHumanPlayer needs 2^CIV_GREEN as parameter? well, because SetHumanPlayer is very simple, it writes the parameter in Tot memory byte which controls HumanPlayer (check Allard documentation for more info). Refresh(): this is a function which forces Tot to repaint the screen, this is useful in a lot of situation because when Tot repaint screen it also check a lot of global variables and redesign the screen according to them; in our example, without Refresh call, ruler switching will happen but the player won't notice it 'till he tries to move a unit or something similar. We should also (but it's not necessary) to warn player of what has happened, we will use the MessageCSPL function to obtain this result:
And that's all, quite simple, isn't it? But, as i said before, if you try to compile the source, on turn 10 CSPL program goes to loop, it shows you the messagebox and, when you click ok, it shows you the box again (this is due to the fact that turn is still 10 'till the player press EndTurn key). How to avoid this? it's easy, we just need to add a global boolean variable, when the game starts this flag will be false and it will be set to true ONLY when the messagebox is displayed (obviously the messagebox will be displayed ONLY if flag is false). so, let's write the code: in Csplclient.h we should define the global Flag variable:
Now we should modify the code of GlbCheck:
PHASE 4: MERGING THE RESULTING SOURCE CODENow it's time to merge all source code we've written:Editing CSPLClient.h: In CSPLClient.h we need to activate the Global thread: BYTE ACTIVITY_FLAG=ACTIVATE_GLOBAL; And we've finished with CSPLClient.h . Editing CSPLClient.csp: The only thing we've to do here is to edit the GlobalCheck function as descrived in previous phase:
PHASE 5: COMPILING AND LINKING THE SOURCE CODEAt this point save CSPLClient.h and CSPLClient.csp files and use CSPLCompanion to compile and link SwitchRuler;you should obtain a CSPLClient executable in SwitchRuler directory, To test this example you should start a game with human-controlled white civ (but, since we never wrote that human start civ should be white we can also start with blue, orange, but the MessageCSPL text will seem strange); start CSPLClient.exe and play your game, if all goes well after ten turns of play you should receive a message informing you of your "Green civ election" from there onwards you should keep playing as ruler of green civ. Notice that this example is far from a finished CSPL event, you should think to change also civ information as change green ruler name to reflect your "election" and change white ruler name to a different one, and maybe also change mood between your new country and old one |