Contents Back Forward |
5. Unit Thread |
5.1 Unit Thread overview In the first chapter we've seen how CSPL structure is divided in threads. Here we'll analyze deeply one of these threads: the Unit Thread. The unit thread scan continuosly the unit list in memory and, for each unit it executes UnitCheck function; the CSPL designer projects his unit events just changing the UnitCheck function, leaving untouched the main structure of Unit Thread The exact source-code of Unit Thread is the following: Unit Temp; while(true) //Starts a continuous cycle { while(ReadNextUnit(&Temp)) //Select following unit in the list {UnitCheck(Temp);} //Call UnitCheck function on current unit ResetUnit(); //Reset Unit Pointer GlobalCheck(); //Update Global data (nr of units particularly) Sleep(1); //Wait a bit (just to avoid to freeze Tot) } | 5.2 Units functions In CSPL i've defined several functions to manage units:
void DeleteUnit() Delete last unit read from the unit list (from the game). void WriteUnit(Unit Temp) Replace last unit read from Tot memory with Temp unit passed as parameter. bool ReadNextUnit(Unit* unita) This function should not be used by CSPL programmers since it is intended for internal library use only, anyway it can be used to scan unit list outside from Units thread (to see how this function should be used look at section 5.1) bool CreateUnit(Unit Temp) This function insert the Temp unit passed as parameter inside the unit list (inside the Tot game). bool UnitAt(DWORD x,DWORD y,DWORD z,DWORD Offset,Unit* Temp) This function searches for units placed at x,y,z (passed as parameter) and places it (if any) in Temp unit structure; if there is no unit at x,y,z the function returns FALSE. Offset parameter is used when you have different units in the stack, first you call UnitAt with Offset 0 and youŽll get the first unit at x,y,z, then call UnitAt with Offset 1 and youŽll get the second unit at x,y,z, etc. when no more units are present at x,y,z this function returns FALSE. bool UnitType(DWORD Type,DWORD Offset,Unit* Temp) This function returns TRUE if a unit of type Type is found in memory (and places its data in Temp unit structure) elsewhere it returns FALSE. Offset is used if multiple units of type Type are present in the game; Offset=0 will find the first unit, Offset=1 will found the second and so on. It is intended to be used with special units (Ex: Where is Wellington unit right now? Is it still alive? and so on) bool UnitID(DWORD Id,Unit* Temp) This function returns TRUE if a unit with ID equals to Id (passed as parameter) is found (and its data are placed in Temp unit structure). UnitID is used to find a particular unit in the unit list; if you are interested in a particular unit you should save its ID when the game starts and then call UnitID with the saved ID to find that particular unit late in the game. bool ReWriteUnit(Unit Prova,DWORD Id) The ReWriteUnit function is used to write Temp unit (passed as parameter) in a particular position in the game list (position identified by Id function parameter); As its name says, this function should be used in quick read-write cycles as the following: - Read Unit (Using UnitID, UnitType, UnitAt or other functions). - Change something on this unit. - Write back the unit calling ReWriteUnit with this unit ID as Id parameter. void ResetUnit() This function is intended for internal use only, anyway it reset internal unit pointer: while each call to ReadNextUnit function reads the next unit in unit list, calling ResetUnit will reset unit pointer so that the next call to ReadNextUnit will read the first unit. |
5.3 Example 4 : WorldLink In this example we will see how to link two Tot maps east-west. This effect is impossible to obtain without CSPL while in CSPL it became quite easy. 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), this step is so basic that i refuse to call it phase 1, this is why it is called phase 0;again create a new project called WorldLink. PHASE 1: UNDERSTANDING WHAT WE NEEDThe first thing a CSPL designer should think is : "which thread i need?"In this situation, since we just want to move some units from a position to another position, our choise is very easy: we need the Unit Thread. 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 "we have an unit on the map border" while BODY is "move that unit on the other side of the map" If we imagine to merge maps at x=0 column we have the following situation: ![]() As you can see, since Tot uses a very strange kind of coordinates (odd,odd or even,even), the x=0 column is made up of (0,0) (1,1) (0,2) (1,3) (0,4) (1,5) ... This means that a unit is on the left border if its x coordinate is 0 OR 1 and, for the same reason, a unit is on the right border if its x coordinate is XDim-1 OR XDim-2 (where XDim is width of the map in tiles) PHASE 3: CODING THE EVENTNow it's time to write a couple of lines of code,'till now we know that: if (Unit.pos.x==0 || Unit.pos.x==1) MoveUnitLeft; else if (Unit.pos.x==XDim-1 || Unit.pos.x=XDim-2) MoveUnitRight; Where || is the OR operator in C/C++ that function must be repeated for each unit in unit list and continuosly; it seems that we need to rewrite the UnitCheck function void UnitCheck(Unit Temp) { if (Temp.pos.x==1 || Temp.pos.x==0) MoveLeft(Temp); else if (Temp.pos.x==XDim-1 || Temp.pos.x==XDim-2) MoveRight(Temp); } Obviously compiling that will produce a lot of errors because MoveLeft and MoveRight are not defined in CSPL nor are user-defined; These functions simply don't exist. Since you've read all C/C++ tutorial i suggested you, now you know how to define new functions and procedures in a C/C++ program and this is the case. PHASE 4: CODING AUXILIARY USER-DEFINED FUNCTIONSWe need two functions MoveLeft(Unit) which takes a unit as parameter and changes its position so it appears on the left border of the other map,and MoveRight(Unit) which takes a unit as parameter and changes its position so it appears on the right border of the other map. void MoveLeft(Unit Temp) { Temp.pos.z=1-Temp.pos.z //Change map (this can be done this way only because we have 2 maps, MAP_0 and MAP_1!) if (Temp.pos.x==0) Temp.pos.x=XDim-4; //Change X coord. if x was 0 if (Temp.pos.x==1) Temp.pos.x=XDim-3; //Change X coord. if x was 1 WriteUnit(Temp); //Write back unit in memory RefreshMap(); //Refresh Screen } The same happens for MoveRight: void MoveRight(Unit Temp) { Temp.pos.z=1-Temp.pos.z //Change map (this can be done this way only because we have 2 maps, MAP_0 and MAP_1!) if (Temp.pos.x==XDim-1) Temp.pos.x=3; //Change X coord. if x was Max (XDim-1) if (Temp.pos.x==XDim-2) Temp.pos.x=2; //Change X coord. if x was Max-1 ((XDim-1)-1) WriteUnit(Temp); //Write back unit in memory RefreshMap(); //Refresh Screen } To understand CSPL function RefreshMap() look at MISCELLANEOUS FUNCTIONS PHASE 5: 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 units thread: BYTE ACTIVITY_FLAG=ACTIVATE_UNIT; Then we need to register new user defined functions: void MoveLeft(Unit Temp); void MoveRight(Unit Temp); And we've finished with CSPLClient.h . Editing CSPLClient.csp: The first step is to edit the UnitCheck function: void UnitCheck(Unit Temp) { if (Temp.pos.x==1 || Temp.pos.x==0) MoveLeft(Temp); else if (Temp.pos.x==XDim-1 || Temp.pos.x==XDim-2) MoveRight(Temp); } Then we have to add user defined functions: void MoveLeft(Unit Temp) { Temp.pos.z=1-Temp.pos.z; //Change map if (Temp.pos.x==0) Temp.pos.x=XDim-4; //Change x coord if (Temp.pos.x==1) Temp.pos.x=XDim-3; //Change x coord WriteUnit(Temp); //Write back unit RefreshMap(); //Refresh Screen } void MoveRight(Unit Temp) { Temp.pos.z=1-Temp.pos.z; //Change map if (Temp.pos.x==XDim-1) Temp.pos.x=3; //Change x coord if (Temp.pos.x==XDim-2) Temp.pos.x=2; //Change x coord WriteUnit(Temp); //Write back unit RefreshMap(); //Refresh Screen } PHASE 6: COMPILING AND LINKING THE SOURCE CODEAt this point save CSPLClient.h and CSPLClient.csp files and use CSPLCompanion to compile and link WorldLink;you should obtain a CSPLClient executable in WorldLink directory, launch TOT, start a game (with 2 worlds!), identify the x=0 column and put a ship (if it is sea) or a fast ground unit (if it is land) near this column (for example on 3,3 tile), start CSPLClient.exe and try moving the unit at (3,3) toward (3,1), asap the unit will enter in (3,1) it should be transferred on the right border of the second map. Notice that this example is far from a complete and working CSPL program 'cause there is no check if starting tile and arriving tile are of the same kind (sea or land), so it's possible to have a ship transferred on land tiles and viceversa, tanks transferred in the middle of the ocean on the second map. This problem can be solved designing carefully the two maps with the x=0 and adjacent columns full of sea or full of land, to avoid jumping from sea to land and viceversa; a more difficult way to solve this problem consist in checking the arrival tile type and comparing it with unit which should be moved, and move it ONLY if this is feasible. |