Contents
Back
Forward

8. Wonders Thread


8.1 Wonders Thread overview

In the last chapter we've seen how Civ Thread works.
Here we'll analyze another thread in greater depth, the Wonders Thread.
The wonders thread continuously scans the wonder list in memory and continuously executes the WonderCheck function. The CSPL designer protects his civ-related events by just changing the WonderCheck function, leaving untouched the main structure of Wonders Thread.
There is a big difference between Wonders Thread and the other Threads we saw in previous chapters, as Wonders Thread doesn't use a ReadNextWonder function.
The exact source-code of Wonders Thread is the following:

void WonderCycle()
{
while(true)//Starts a continuous cycle
    {
    WonderCheck();//Call WonderCheck function continuously
    Sleep(1);//Wait a bit (just to avoid freezing ToT)
    }
}




8.2 Wonders functions
In CSPL I've defined several functions to manage wonders:
  • GetCityWonder : Gets the city containing a particular wonder.
  • SetCityWonder : Creates a particular Wonder in a particular city.
  • DestroyWonder : Destroy a particular Wonder (it cannot be built another time).
  • DeleteWonder : Delete a particular Wonder (it can be built another time).
Wonders are identified using pre-defined constants:
WONDER NAME CONSTANT DEFINED
Pyramids ID_WOND_PYRAMIDS
Hanging Gardens ID_WOND_HANGINGARDEN
Colossus ID_WOND_COLOSSUS
Lighthouse ID_WOND_LIGHTHOUSE
Great Library ID_WOND_GREATLIBRARY
Oracle ID_WOND_ORACLE
Great Wall ID_WOND_GREATWALL
Sun Tzu's War Academy ID_WOND_SUNTZU
King Richard's Crusade ID_WOND_KINGRICHARD
Marco Polo's Embassy ID_WOND_MARCOPOLO
Michelangelo's Chapel ID_WOND_MICHELANGELO
Copernicus Observatory ID_WOND_COPERNICUSOBS
Magellan's Expedition ID_WOND_MAGELLAN
Shakespeare's Theatre ID_WOND_SHAKESPEARE
Leonardo's Workshop ID_WOND_LEONARDO
J. S. Bach's Cathedral ID_WOND_JSBACH
Isaac Newton's College ID_WOND_NEWTONCOLLEGE
Adam Smith's Trading Co. ID_WOND_ADAMSMITH
Darwin's Voyage ID_WOND_DARWINVOYAGE
Statue of Liberty ID_WOND_STATUELIBERTY
Eiffel Tower ID_WOND_EIFFELTWR
Women's Suffrage ID_WOND_WOMENSUFFRAGE
Hoover Dam ID_WOND_HOOVERDAM
Manhattan Project ID_WOND_MANHATTANPRJ
United Nations ID_WOND_UN
Apollo Program ID_WOND_APOLLO
SETI Program ID_WOND_SETI
Cure for Cancer ID_WOND_CURECANCER

WORD GetCityWonder(int Wonder)
It scans Wonders list for wonder passed as parameter and returns the ID number of city in which wonder is located
(it returns 0xFFFF if wonder has not been built yet while it returns 0xEFFF if wonder has been destroyed, I've coded two constants to help CSPL designers: WOND_NOT_BUILT and WOND_DESTROYED which maps these values)

bool SetCityWonder(WORD CityID,int Wonder)
This function sets Wonder passed as parameter as built in city with ID equals to CityID passed as parameter.

bool DestroyWonder(int Wonder)
This function is used to destroy a wonder (the wonder passed as parameter)
Destroying a wonder means that the wonder cannot be built again by other civs, and it appears as "lost" in the wonder screen.

bool DeleteWonder(int Wonder)
This function is used to delete a wonder (the wonder passed as parameter).
Deleting a wonder means that the wonder is restored to a pre-built state.
It can be built by civs with the correct pre-requisites and it doesn't show in the wonder screen.



8.3 Example 7 : MovingWonder
(From an idea first presented by CyberChrist.)
This example is the first to use different threads, so expect it to be a bit more complicated than the others.
One of the annoyances about Wonders is that they're stuck in the cities in which they're built. In some scenarios it could be interesting to move wonders as units between cities of the owner civilization, almost as if they were units.
Imagine a Special King unit which acts as a wonder when stationed in cities (maybe as Shakespeare theatre to calm down the citizenry or as King Richard's crusade to boost production in the city) or an Einstein unit which acts as a moving Copernicus observatory. This is exactly what we're trying to do in this example.

PHASE 0: CREATING A NEW PROJECT

As we've learned in the previous chapters the first step towards CSPL compilation is the project creation (usually done with CSPLCompanion);
Again, begin by creating a new project called MovingWonder.

PHASE 1: UNDERSTANDING WHAT WE NEED

The first thing a CSPL designer should think is : "which thread do I need?"
In this situation, since we want to play with wonders AND units, our choice is very easy. We need BOTH the Wonders Thread and the Units Thread.

PHASE 2: DESIGNING THE EVENT

The next thing we have to do is to design the "skeleton" of our event:
From the first chapter we know that each event is made of HEAD (Trigger Statement) and BODY (Action Statement):
In this case HEAD is "The King Unit is in a city"
while BODY is "Set wonder as built in that city."

PHASE 3: FIXING UP SECONDARY PROBLEMS

The event designed in phase 2 leaves a lot of problems unresolved:
First of all, there is only one Wonder so we need to ensure that there will be only one Special King Unit in the whole game. This can be done creating the King Unit as a special unit, which means setting the prereq to "no" and giving a single unit to a particular civ (either give it to one civ from start or deliver it later via events).
Another problem is the wonder itself, as we must ensure that no one will ever be able to build that wonder (again, this can be achieved with the "no" prereq).
Another question is what should we do while the King is in transit between cities? In my opinion, the wonder should be destroyed and re-established when the King unit enters a new city. Thus if the King is killed while moving, the wonder effect is lost forever.
Now that we've cleared up these issues, we can start developing the event.

PHASE 4: CODING THE EVENT

We should continuously check the King unit's position and likewise check if there is a city at that position. If the answer is yes, we should place the wonder in that city, while if the answer is no we must destroy the wonder.
First of all we need to identify the King unit.
If the King unit is present from the start we can extract the ID number and call UnitID to obtain information about this special unit, or else we can use UnitType called with King type as parameter to obtain the same info (notice that obviously there must be only one unit of King type in the game).
Let's say we don't need Mech. Inf. unit in our medieval scenario and so we'll use the mech inf type as our King type.
It's time to write a bit of code:

Unit King;

bool StillAlive=UnitType(UNIT_MECHINF,0,&King);
//Now we've the first (and only) King type unit in King structure and
//from StillAlive we know if the King unit is active or dead


Then we have to detect if unit is inside a city or not:
if (StillActive)
{
City Temp;

bool IsThereACity=CityAt(King.pos.x,King.pos.y,King.pos.z,0,&Temp);
}

If IsThereACity is true than a city is present at the King coordinates and its information is stored in the Temp variable.
Now we've got to do two things. If there isn't a city we need to destroy the wonder (BTW I chose Shakespeare's theatre for this example), otherwise we need to set this wonder into Temp city.
This is done with the following code:

if (IsThereACity)
SetCityWonder(Temp.ID,ID_WOND_SHAKESPEARE);
else DestroyWonder(ID_WOND_SHAKESPEARE);

As we said above the code we've written should be placed in WonderCheck:

void WonderCheck()
{
Unit King;

bool StillAlive=UnitType(UNIT_MECHINF,0,&King);
//Now we've the first (and only) King type unit in King structure and
//from StillAlive we know if the King unit is active or dead

if (StillActive)
   {
    City Temp;

    bool IsThereACity=CityAt(King.pos.x,King.pos.y,King.pos.z,0,&Temp);
    //Now we've the first (and only) city placed at King coordinates in Temp data structure
    //If IsThereACity is true then a city exists at King coordinates else no city exists at King coordinates

    if (IsThereACity)
    SetCityWonder(Temp.ID,ID_WOND_SHAKESPEARE);
    else DestroyWonder(ID_WOND_SHAKESPEARE);
   }
else DestroyWonder(ID_WOND_SHAKESPEARE);
}

PHASE 5: MERGING THE RESULTING SOURCE CODE

Now it's time to merge all the source code we've written:

Editing CSPLClient.h:
In CSPLClient.h we need to activate the wonders thread:

BYTE ACTIVITY_FLAG=ACTIVATE_WONDER;

And we're finished with CSPLClient.h .

Editing CSPLClient.csp:
The only thing we need to do here is edit the WonderCheck function as described in the previous phase:

void WonderCheck()
{
Unit King;

bool StillAlive=UnitType(UNIT_MECHINF,0,&King);
//Now we've the first (and only) King type unit in King structure and
//from StillAlive we know if the King unit is active or dead

if (StillActive)
   {
    City Temp;

    bool IsThereACity=CityAt(King.pos.x,King.pos.y,King.pos.z,0,&Temp);
    //Now we've the first (and only) city placed at King coordinates in Temp data structure
    //If IsThereACity is true then a city exists at King coordinates else no city exists at King coordinates

    if (IsThereACity)
    SetWonder(Temp.ID,ID_WOND_SHAKESPEARE);
    else DestroyWonder(ID_WOND_SHAKESPEARE);
   }
else DestroyWonder(ID_WOND_SHAKESPEARE);
}

PHASE 6: COMPILING AND LINKING THE SOURCE CODE

At this point save the CSPLClient.h and CSPLClient.csp files and use CSPLCompanion to compile and link MovingWonder. This will create a CSPLClient executable in MovingWonder directory.
To test this example you should create a game with a couple of cities, and then add a Mech Inf unit (remember our hypothesis of using the Mech Inf type as the King unit). Start CSPLClient.exe and move the Mech. Inf. unit between your cities. Frequently open the Wonder screen, and if all goes well you should see Shakespeare's Theatre moving from city to city with the King (Mech. Inf.) unit.
Notice that this example is far from an efficient CSPL program because the same info about city presence on the King tile can be obtained by looking directly to the map structure (using the city bit, read the Map Thread chapter for more details). We would still have to call CityAt to obtain the City information but ONLY if a city is present, thus saving a lot of precious CPU time.



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