 |
|  |
 |
|  |
 |
|
Martin Gühmann
|
 |
Berlin, Germany
Mar 2001 time: 06:16
|
|
Well that wasn't so difficuilt, let's set up something that can be more called as a challenge for training purposes of course.  
Extendet trade acces. A function that returns the number of trade route at a specific location. The syntax would be like this:
int_t TradeRoutes(location_t)
Some other trade specifix functions would be:
void_t GetTradeRouteByIndex(location_t, int_t, traderoute_t)
First parameter the location that contains a trade route, second an index and third a parameter that is filled with a specific trade route. The only little problem with this is that we have no traderoute_t thing that has to be implemented. And this is necessary to allow the trade route specific events called from slic.
void_t GetTradePartners(traderoute_t, city_t, city_t)
With the traderoute_t thing we coult retrive from it the start and endpoint of a trade route.
int_t GetTradeGood(traderoute_t)
Get the index of the good that is traded by the give route.
The first function shouldn't be too difficuilt, maybe not all indrigents are found in the slicfunc.cpp, but Cell.cpp and Cell.h should help you.
For fixing ContinentBiggerThan I have no idea it is somewhere in the underlying functions outside slic, by the way what in particular does not work about this function, what are the symptoms?
-Martin
|
|
|  |
 |
|  |
 |
|  |
 |
|
The Big Mc
|
 |
Of the universe / England
Oct 2001 time: 05:16
|
|
code: SFN_ERROR Slic_Addslaves::Call(SlicArgList *args)
{
if(args->m_numArgs != 2)
return SFN_ERROR_NUM_ARGS;
Unit city;
BOOL res;
res = args->GetCity(0, city);
if(!res) {
return SFN_ERROR_TYPE_ARGS;
}
sint32 count;
if(!args->GetInt(1, count))
return SFN_ERROR_TYPE_ARGS;
MapPoint pos;
city.GetPos(pos);
sint32 i;
if(count > 0) {
for (i=0; iAddEvent(GEV_INSERT_Tail, GEV_MakePop,
GEA_City, city.m_id,
GEA_End);
ChangeSpecialists(POP_SLAVE, +1);
}
} else {
for(i = count; i < 0; i++) {
}
}
sint32 delta_martial_law;
CityData *cd = city.GetData()->GetCityData();
cd->GetHappy()->CalcHappiness(*cd, FALSE, delta_martial_law, TRUE);
return SFN_ERROR_OK;
}
I hope this is the case but could adding the line in red really make this add slave function working or do i have to link it with something. I can't compile at the moment as id don't have any source files apart from the actocrap ones.
This was made by combining a function that removed slaves in citydate.cpp and the add pop function. In slicfunction.cpp
|
|
|  |
 |
|
E
|
 |
July 24,2005 Ctp2 Tiles in sig!
May 1999 time: 21:16
|
|
is there a function
GetTileOwner
and
ChangeTileOwner?
I was looking to have the ability to change ownership of territory once a unit fortifies (and cause war if it changes from one player to another)
Could this code in cell.cpp be reference for it?
code:
void Cell::SetOwner(sint32 owner)
{
m_playerLandArea[m_cellOwner+1]--;
m_cellOwner = (sint8)owner;
m_playerLandArea[m_cellOwner+1]++;
}
Also:
ChangeCityRadius
to shrink or expand city radius independent of population size (i'm tired of new york city taking up half the US for a scenario)
Last edited by E on 12-01-2005 at 21:41
|
|
|  |
 |
|
Martin Gühmann
|
 |
Berlin, Germany
Mar 2001 time: 06:16
|
|
quote: Originally posted by E
PlayerReceivesTradedGood function?
PlayerSendstradedGood function?
|
Actual this doesn't seem to make sense, according to the names of these functions they can only act when a good is send. And that is covered by the SendGood event. It has three arguments the first an integer an index into the good's database and the second the sender city and the third the receiver city. From the cities you can retrieve the owner.
quote: Originally posted by E
as for the new code, do we need to type something like this?
code:
int_t TradeRoutes(location_t)
{
sint32 p;
if(args->m_numArgs != 1)
return SFN_ERROR_NUM_ARGS;
if(!args->GetPlayer(0, p))
return SFN_ERROR_TYPE_ARGS;
m_result.m_int = g_player[p]->TradeRoutes();
return SFN_ERROR_OK;
}
|
Not quite. At first I gave the here the slic function signature I would expect in fact in the documentation I find something like this:
INT PlayerCityCount(player)
Actual I would now write it like:
INT PlayerCityCount(int_t player)
INT is the return type in this case an integer VOID would mean the function doesn't return anything. int_t is the type of the slic variable in this case it is of type int_t actual a whole number, and player is a description of the meaning of this variable, for simplicity I skipped the variable name in my function description. It isn't used anywhere anyway.
Now to add a new slic function you have to modify three files, slicfunc.cpp, SlicEngine.cpp and SlicFunc.h, note that on a Linux machine in contrast to a windows machine slicfunc.cpp and SlicFunc.cpp are different files. I don't tell you now in which directory you can find these files as you already should have found these files. By the way these files are the same files Solver modified to add the IsOnSameContinent.
To understand how to add such an function look in all these file for IsOnSameContinent or any other slic function.
Let's do a tutorial function and let's suppose we don't have a TradeRoutes already:
In SlicFunc.h we have a long list like this:
code:
SLICFUNC(SFR_INT, StringCompare)
SLICFUNC(SFR_INT, CityNameCompare)
SLICFUNC(SFR_VOID, ChangeGlobalRegard)
SLICFUNC(SFR_VOID, SetAllCitiesVisible)
SLICFUNC(SFR_VOID, SetCityVisible)
SLICFUNC(SFR_INT, IsCivilian)
SLICFUNC(SFR_VOID, FinishImprovements)
SLICFUNC(SFR_VOID, RemoveAdvance)
SLICFUNC(SFR_INT, PlayerGold)
SLICFUNC(SFR_INT, GetArmyFromUnit)
SLICFUNC (SFR_INT, ClearBattleFlag)
SLICFUNC(SFR_VOID, MinimizeAction)
SLICFUNC(SFR_INT, IsUnitAtHead)
SLICFUNC(SFR_VOID, OpenScenarioEditor)
If there isn't already a TradeRoutes functions there we could add to the list something like this:
code:
SLICFUNC(SFR_INT,TradeRoutes)
Of course if the function should have a different name then we name it differently and we use SFR_INT instead of SFR_VOID as this function should return an integer.
The next thing is to modify SlicEngine.cpp the is a function called void SlicEngine::AddBuiltinFunctions() that registeres all the slic functions so that the game can use them.
There we find also again such a list of functions:
code:
m_functionHash->Add(new Slic_SetUnit);
m_functionHash->Add(new Slic_SetUnitByIndex);
m_functionHash->Add(new Slic_SetCity);
m_functionHash->Add(new Slic_SetCityByIndex);
m_functionHash->Add(new Slic_SetLocation);
m_functionHash->Add(new Slic_MakeLocation);
m_functionHash->Add(new Slic_SetOrder);
m_functionHash->Add(new Slic_Flood);
m_functionHash->Add(new Slic_Ozone);
m_functionHash->Add(new Slic_GodMode);
m_functionHash->Add(new Slic_ExecuteAllOrders);
m_functionHash->Add(new Slic_CatchUp);
m_functionHash->Add(new Slic_Deselect);
m_functionHash->Add(new Slic_Preference);
m_functionHash->Add(new Slic_SetPreference);
m_functionHash->Add(new Slic_AddMovement);
m_functionHash->Add(new Slic_ToggleVeteran);
m_functionHash->Add(new Slic_IsVeteran);
And here at the end of this list we would again add our new function the TradeRoutes if it is already present in this list. Something like this:
code:
m_functionHash->Add(new Slic_TradeRoutes);
And now we have to modify slicfunc.cpp, the best is we look for an empty function that should return an integer copy it to the end of the file and modify it, like this one:
code:
SFN_ERROR Slic_UnitHasFlag::Call(SlicArgList *args)
{
m_result.m_int = 0;
return SFN_ERROR_OK;
}
Now we just need to replace the name with the desired one and we optain:
code:
SFN_ERROR Slic_TradeRoutes::Call(SlicArgList *args)
{
m_result.m_int = 0;
return SFN_ERROR_OK;
}
If we just wanted to add a function then we are finished, we can call this function without even a slic error. The only little problem is that it always return 0. It doesn't matter how we call it in slic, for instance like:
code:
TradeRoutes();
TradeRoutes(city);
TradeRoutes(army);
TradeRoutes(city, army);
TradeRoutes(player, city);
No slic error, it doesn't matter how many arguments we pass to the function or what kind of argument we pass, whether it is a city, whether it is an army or whatever. Let's modify it so that it only accepts one parameter:
code:
SFN_ERROR Slic_TradeRoutes::Call(SlicArgList *args)
{
if(args->m_numArgs != 1)
return SFN_ERROR_NUM_ARGS;
m_result.m_int = 0;
return SFN_ERROR_OK;
}
Our Call function gets an input parameter called args as it is a pointer we can access a member of the SlicArgList like this:
code:
args->m_numArgs
In fact that is the way to figure out the number of arguments our slic function gets, if the number of arguments is different than one we let return the Call function a slic error about wrong number of arguments.
Well now the function complains when the wrong number of arguments is given, but it still accepts wrong types of arguments. Therefore we check the type of an argument.
To do this we can use the GetPlayer function of the SlicArgList object the first argument is the index of that element in the argument list we want to access in that case it is the first argument and it is indexed with 0. The second argument is a variable that is filled by the GetPlayer function. The GetPlayer function returns whether the according argument can be interpreted as player. In that case it is a player index and the variable should be declared locally before, we do it like this:
SFN_ERROR Slic_TradeRoutes::Call(SlicArgList *args)
{
sint32 p;
if(args->m_numArgs != 1)
return SFN_ERROR_NUM_ARGS;
if(!args->GetPlayer(0, p)) {
return SFN_ERROR_TYPE_ARGS;
}
m_result.m_int = 0;
return SFN_ERROR_OK;
}
Now the function exspects the right arguments, but still it doesn't anything accept returning 0. So here now comes the more difficuilt part we have to access the rest of the program and have to assign m_result.m_int something nice. As we want to access something from the player we use the global player array g_player and use the index p we have optained from GetPlayer to access the pth player. In the Player class we find the right function for it that gives us the number of trade routes a player has, GetNumTradeRoutes. Since g_player is an array of pointers we have to use the arrow operator (->) to use the function. And now our code looks like this:
code:
SFN_ERROR Slic_TradeRoutes::Call(SlicArgList *args)
{
sint32 p; // Declare the variable p of type sint32
if(args->m_numArgs != 1) // Check the number
//of arguments
return SFN_ERROR_NUM_ARGS;
// Return wrong number of argument slic
// error if the number of arguments are unequal one.
if(!args->GetPlayer(0, p)) { // Optain the player
//index from the first argument.
return SFN_ERROR_TYPE_ARGS; // Return wrong type
//of argument of slic error
// if the first argument
// cannot be interpreted
// as player index.
}
m_result.m_int = g_player[p]->GetNumTradeRoutes();
// Assign the result, after retriving the players
// number of trade routes.
return SFN_ERROR_OK; // Return that there was no slic error.
}
Note that this level of commentation in normal program code that is not intended for teaching is called overcommented. For a programmer it should be obviously what is here done.
If this function is not already in the source code we could add it now. But actual we want also such a function that tells us how many trade routes a you can priate for instance on a tile.
Therefore we overload this slic function, basicly overloading means the function accepts more then one set of parameters. The sets of parameters can differ in size and in the order of types.
Now we want such a function that with the same name but with a location as first argument. In c++ we could just do a second function with another parameter.
But here we take the same function and extend the parameter checking. As we still just want to accept one parameter, we don't need to alter the number of argument checking, but we have to alter the type checking:
code:
SFN_ERROR Slic_TradeRoutes::Call(SlicArgList *args)
{
sint32 p;
if(args->m_numArgs != 1)
return SFN_ERROR_NUM_ARGS;
if(args->GetPlayer(0, p)) {
m_result.m_int = g_player[p]->GetNumTradeRoutes();
return SFN_ERROR_OK;
}
return SFN_ERROR_TYPE_ARGS;
}
First we change the instruction flow. If GetPlayer can fill p successfully we jump into the if block within the braces {}. That is done by removing the exclamation mark, the exclamation mark is a boolean operator and is the negator of a statement. For instance this
code:
!true
means in word: not true. And of course not true is of course false, and the way around.
As the behavour of the slic function should not be changed, we switch the statements inside the if block and the following ones.
Now the function still does everthing it did before, but only diffrently then before. But this is to our advance. Now we can add another Argument type checking.
code:
SFN_ERROR Slic_TradeRoutes::Call(SlicArgList *args)
{
sint32 p;
if(args->m_numArgs != 1)
return SFN_ERROR_NUM_ARGS;
if(args->GetPlayer(0, p)) {
m_result.m_int = g_player[p]->GetNumTradeRoutes();
return SFN_ERROR_OK;
}
MapPoint pos;
if(!args->GetPos(0, pos)) {
return SFN_ERROR_TYPE_ARGS;
}
return SFN_ERROR_TYPE_ARGS;
}
Now we have to test whether the first argument could contain a location, therefore we look how they did this in the CellOwner function for instance and copy the necessary code.
In the CellOwner function we see that they used the GetPos function, we just copy it, it works like the GetPlayer function except that its second argument must be a MapPoint opject. So far this returns nevertheless a wrong type of argument slic error even if the first argument is a location, therefore we replace the last:
code:
return SFN_ERROR_TYPE_ARGS;
with
code:
return SFN_ERROR_OK;
So that everything again is ok.
From the CellOwner function there is a retrievel of a Cell object and such a cell object we need as well.
So we add the according code again:
code:
SFN_ERROR Slic_TradeRoutes::Call(SlicArgList *args)
{
sint32 p;
if(args->m_numArgs != 1)
return SFN_ERROR_NUM_ARGS;
if(args->GetPlayer(0, p)) {
m_result.m_int = g_player[p]->GetNumTradeRoutes();
return SFN_ERROR_OK;
}
MapPoint pos;
if(!args->GetPos(0, pos)) {
return SFN_ERROR_TYPE_ARGS;
}
Cell *cell = g_theWorld->GetCell(pos);
if(!cell) {
return SFN_ERROR_OUT_OF_RANGE;
}
return SFN_ERROR_OK;
}
There is still a little problem, the case the first argument is a location the function returns something, to prevent this we add to the start something like this:
code:
m_result.m_int = 0;
But there is still a problem if the first argument is a location it returns 0, that is ok if the first argument is a unit.
So we have to add the result assignemnt. From the CellOwner function we have something like this:
code:
m_result.m_int = cell->GetOwner();
Actual we don't want to optain the Owner of that location, but we want the number of trade routes in that location we can pirate, fortunatly the Cell object has something like this:
code:
m_result.m_int = cell->GetOwner();
code:
m_result.m_int = GetNumTradeRoutes();
Finally our code looks like this:
code:
SFN_ERROR Slic_TradeRoutes::Call(SlicArgList *args)
{
m_result.m_int = 0;
sint32 p;
if(args->m_numArgs != 1)
return SFN_ERROR_NUM_ARGS;
if(args->GetPlayer(0, p)) {
m_result.m_int = g_player[p]->GetNumTradeRoutes();
return SFN_ERROR_OK;
}
MapPoint pos;
if(!args->GetPos(0, pos)) {
return SFN_ERROR_TYPE_ARGS;
}
Cell *cell = g_theWorld->GetCell(pos);
if(!cell) {
return SFN_ERROR_OUT_OF_RANGE;
}
m_result.m_int = cell->GetNumTradeRoutes();
return SFN_ERROR_OK;
}
This is now the overloaded slic function that returns if the first argument is a player the number of trade routes that the player owns and if it is a location it returns the number of trade routes you find on the according tile.
So that should it be how to do a slic function, the trickiest part is to fill the m_result.m_int thingy.
-Martin
Last edited by Martin Gühmann on 12-01-2005 at 21:20
|
|
|  |
All times are GMT. The time now is 05:16. Apolyton Time is 00:16. |
top of page
|
|
|
Forum Rules:
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
|
HTML code is ON
vB code is ON
Smilies are ON
[IMG] code is ON
|
|
|
|
|
|