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 deeply another thread: the Wonders Thread.
The wonders thread scan continuosly wonder list in memory and, continuosly it executes WonderCheck function;
the CSPL designer projects his civ-related events just changing the WonderCheck function, leaving untouched the main structure of Wonders Thread.
There is a big difference between Wonders Thread and other Threads we saw in previous chapters:
Wonders Thread doesn't use a ReadNextWonder function;
The exact source-code of Civ Thread is the following:

void WonderCycle()
{
while(true)//Starts a continuos cycle
    {
    WonderCheck();//Call WonderCheck function continuosly
    Sleep(1);//Wait a bit (just to avoid to freeze 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 designees:WOND_NOT_BUILT and WOND_DESTROYED which maps these values)

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

bool DestroyWonder(int Wonder)
This function is used to destroy a wonder (the wonder passed as parameter)
Destroing a wonder means that the wonder cannot be built again by other civs, and it appears as lost in 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-build state:
it can be built by civs with correct pre-requisites and it doesn't show in wonder screen.



8.3 Example 7 : MovingWonder
From an idea of CyberChrist.
This example is the first to use different threads, so expect it to be a bit more complex than others.
One of the annoyances about Wonders is that they're stucked in cities in which they're built:
In some scenarios it could be interesting to move wonders as units between cities of owner civilization;
imagine a Special King unit which acts as a wonder when stationed in cities (maybe as Shakespeare theatre to calm down citizen 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 create a new project called MovingWonder.

PHASE 1: UNDERSTANDING WHAT WE NEED

The first thing a CSPL designer should think is : "which thread i need?"
In this situation, since we just want to play with wonders AND units, our choise is very easy: we need Wonders Thread and Units Thread, BOTH of them.

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 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 still open:
First of all, there is only one Wonder so we need to ensure that it will be only one Special King Unit in the whole game. This can be done creating King Unit as a special unit, this means fixing prereq to no and giving a single unit to a particular civ (using for example events or giving it to one civ from start).
Another problem is with wonder: we must ensure that no one will ever build that wonder (again, this can be obtained with no prereq)
Another problem: what we should do while King is in transit between cities? in my opinion wonder should be destroyed and re-established when King units enters in a new city.
In that way, if the King is killed while moving, the wonder effect is lost forever.
Now we've cleared a couple of things about the event we should realize and we can start develping it

PHASE 4: CODING THE EVENT

We should check continuosly for King unit position, then we've to check if there is a city at that position and, if the answer is yes, we should set wonder to that city, while if the answer is no, we should destroy the wonder.
First of all we need to identify King unit.
If the King unit is present from start we can extract the ID number and call UnitID to obtain infos about King unit; 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 let's consider 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 it is 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 King coordinates and its infos are stored in Temp variable
now we've to do two things, if there isn't a city we need to destroy the wonder (BTW i chose Shakespeare's theatre), else we need to set this wonder into Temp city.
This can be done by 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 it is 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 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've finished with CSPLClient.h .

Editing CSPLClient.csp:
The only thing we've to do here is to edit the WonderCheck function as descrived in 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 it is 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 CSPLClient.h and CSPLClient.csp files and use CSPLCompanion to compile and link MovingWonder;
you should obtain a CSPLClient executable in MovingWonder directory,
To test this example you should create a game with a couple of cities, and then adds a Mech. Inf. unit (remember our hypothesis of using MechInf type as King unit); start CSPLClient.exe and move Mech. Inf. unit between your cities, check frequently Wonder screen and if all goes well you should see the Shakespeare's Theatre moving with the King (Mech. Inf.) unit.
Notice that this example is far from an efficient CSPL program 'cause the same info about city presence on King tile can be obtained looking directly to map structure (using the city bit, read the Map Thread chapter for more details); we still have to call CityAt to obtain City informations but ONLY if city is present, 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