 |
|  |
 |
|
E
|
 |
July 24,2005 Ctp2 Tiles in sig!
May 1999 time: 21:29
|
|
Martin has been helping me (in the other forum) on how to code Cities that can only settle on specific types of terrain. I might be almost done with that, so my next attempt is along the same lines. Its to add a flag that makes it so that the player can only build terrain improvements on tiles with certain goods. I feel this will give the modder the ability to add some unique improvements and add different bonuses to a game.
I know I have to add a spot in the terrutil.cdb, but terrainutil.cpp will be my coding challenging
code:
bool terrainutil_CanPlayerBuildAt(const TerrainImprovementRecord *rec, sint32 pl, const MapPoint &pos)
{
sint32 i;
I think I need to define a variable here
Assert(rec != NULL);
if(rec == NULL)
return false;
Assert(pl >= 0);
Assert(pl < k_MAX_PLAYERS);
if(pl < 0 || pl >= k_MAX_PLAYERS)
return false;
Assert(g_player[pl]);
if(!g_player[pl])
return false;
Cell *cell = g_theWorld->GetCell(pos);
Assert(cell);
if(!cell)
return false;
if(cell->GetOwner() == -1) {
if(rec->GetIntBorderRadius()) {
if(!g_player[pl]->IsVisible(pos)) {
return false;
}
} else {
return false;
}
}
if(cell->GetOwner() >= 0 && cell->GetOwner() != pl)
{
bool haveAlliance = AgreementMatrix.s_agreements.HasAgreement(pl, cell->GetOwner(), PROPOSAL_TREATY_ALLIANCE);
if(cell->GetOwner() > 0 && haveAlliance) {
if(rec->GetClassRoad() ||
(g_player[pl]->GetGaiaController() && g_player[pl]->GetGaiaController()->GaiaControllerTileImp(rec->GetIndex()))) {
} else {
return false;
}
} else {
return false;
}
}
if(g_theWorld->GetCity(pos).IsValid())
return false;
if(rec->GetClassTerraform()) {
sint32 terr;
if(!rec->GetTerraformTerrainIndex(terr))
return false;
if(cell->GetTerrain() == terr)
return false;
const TerrainRecord *tfrom = g_theTerrainDB->Get(cell->GetTerrain());
const TerrainRecord *tto = g_theTerrainDB->Get(terr);
if(tfrom->GetRemoveAdvanceIndex() < 0 || tto->GetAddAdvanceIndex() < 0)
return false;
if(!g_player[pl]->HasAdvance(tfrom->GetRemoveAdvanceIndex()) ||
!g_player[pl]->HasAdvance(tto->GetAddAdvanceIndex())) {
return false;
}
} else {
const TerrainImprovementRecord::Effect *eff;
eff = terrainutil_GetTerrainEffect(rec, cell->GetTerrain());
if(!eff)
return false;
if(!g_player[pl]->HasAdvance(eff->GetEnableAdvanceIndex()))
return false;
sint32 a;
for(a = 0; a < eff->GetNumObsoleteAdvance(); a++) {
if(g_player[pl]->HasAdvance(eff->GetObsoleteAdvanceIndex(a))) {
return false;
}
}
I think this is the code I should base it on:
for(i = 0; i < rec->GetNumCantBuildOn(); i++) {
if(rec->GetCantBuildOnIndex(i) == cell->GetTerrain()) {
return FALSE;
}
}
}
but something like this:
for(r = 0; r < g_theResourceDB->Get(resource); r++) {
if(rec->GetBuildGoodOnIndex(r) == cell->GetTerrain()) {
return FALSE; //changed, thanks J
}
}
return true;
}
this is just my working start, but comment if interested....
Last edited by E on 21-01-2005 at 21:52
|
|
|  |
 |
|
Martin Gühmann
|
 |
Berlin, Germany
Mar 2001 time: 06:29
|
|
quote: Originally posted by J Bytheway
If you do things that way around you must remember to return false if the program gets through the whole for loop without returning true. |
E, John means the return after the for loop not within the for loop. And by the way the function should return a bool and not a BOOL, these are two different things, even if they can be converted into each other easiliy. Nevertheless that is at least a bad style of programming. At least Activision is to blame in this case.
quote: Originally posted by E
I know I have to add a spot in the terrutil.cdb, but terrainutil.cpp will be my coding challenging |
Actual the file is called terrimprove.cdb, there is no terrutil.cdb.
Another thing I wonder about, is why the function does not contain Fromafar's changes.
Now let's come to the for loop you have added. The counting variable is called r. Why do you use an additional counting variable if the the counting variable i is already there and is not needed to store its value. And I see again Activision did it like that in the code as well. However it wastes a little bit of memory, for bytes to be precise.
What really wrong with your for loop is, is that it tries to go through the whole good database. But now you access the BuildGoodOn array, not a good idea if the good database has less entries then your BuildGoodOn array.
So you have to figure out the size of the BuildGoodOn array.
Another question is how to assure backwards compatibility. What happens if your new flag is not present. Actual I would name it IsRestrictedToGood, your name sounds to me like the good is built on an improvement. This is more clear, as it means that you can only build it on the given good.
However there is still a problem in the logic.
quote: Originally posted by E
BigMC you know where the code is? just checking before I run a HasGood search in XP.... |
You would already know it, if you have done it. But of course you can guess where you find it, but of course I don't tell you this. 
But still we have to think about the logic, it should return true; if all the original critera are met, and your new flag is not present in the database record, if it is present, it should only return true if the previous critera are met and the good at the location is the right one. However the function does not do this right now.
-Martin
|
|
|  |
 |
|
Martin Gühmann
|
 |
Berlin, Germany
Mar 2001 time: 06:29
|
|
quote: Originally posted by The Big Mc
you got the one from slicfunc.cpp then. |
Actual it is not the one you can find in slicfunc.cpp. Actual it even doesn't exist. But I would go for the one in HasGood slic function as well.
However this function returns TRUE or FALSE whether there is a good on the given position. To retrieve the good's index you have use the variable that you passed as second argument to the function, in the example called "good". This good variable is passed to the function by reverence instead by value. You see this in the function definition, that includes the ampersand "&" in front of the parameter name.
So you have to call the GetGood function first and then check whether the index stored in the good variable is the same as the current GetIsRestrictedToGoodIndex.
And of course you only have to access the good's db index once, that means that you call the GetGood function before the for loop once.
Now to the logic, the function still returns true whether the tile improvement is restricted to a certain good or not. So you have to put it into a contitioned if block, that is only entered if the size of the RestrictedToGood array is greater than zero. And of course if the for loop is finished without returning true and given it has been entered before, the function should return false, so another return false; belongs into the conditioned if block after the for loop.
And another remark about the layout, actual I only talked about open braces, not about closing braces. The closing braces should have the same indetion like the coresponding if or for or while, so that you don't have to search for them, for the open ones that is clear that they are close to the accoring if, for etc.
-Martin
|
|
|  |
 |
|
E
|
 |
July 24,2005 Ctp2 Tiles in sig!
May 1999 time: 21:29
|
|
code:
const TerrainImprovementRecord::Effect *eff;
eff = terrainutil_GetTerrainEffect(rec, cell->GetTerrain());
if(!eff)
return false;
if(!g_player[pl]->HasAdvance(eff->GetEnableAdvanceIndex()))
return false;
sint32 a;
for(a = 0; a < eff->GetNumObsoleteAdvance(); a++) {
if(g_player[pl]->HasAdvance(eff->GetObsoleteAdvanceIndex(a))) {
return false;
}
}
sint32 good;
if(cell->GetGood(good)>0 {
(g_theWorld->GetGood(good)&& g_theWorld->GetGood(rec->GetIndex(good))
} else {
return false; }
if (i >0; i < rec->GetNumIsRestrictedToGood(); i++) {
if(rec->GetIsRestrictedToGoodIndex(i) != GetGood(good)) {
return false;
}
}
for(i = 0; i < rec->GetNumCantBuildOn(); i++) {
if(rec->GetCantBuildOnIndex(i) == cell->GetTerrain()) {
return false;
}
}
}
return true;
}
The [b]bold[/b[ stuff is the only thing I changed. My thinking here is:
I defined the variable good, then checked to see if the tile has a good. And then get the index for that good. Then I used the variable 'i' to get the index to see if the improvement is restricted to that type of good. If they are NOT equal then it retuns false and then checks the CantBuildOn...
Is this right? Do goods have an index number, how do I define names (I remember the txt uses Desert_Good_One or something like that)
Last edited by E on 25-01-2005 at 10:25
|
|
|  |
 |
|  |
 |
|
Martin Gühmann
|
 |
Berlin, Germany
Mar 2001 time: 06:29
|
|
code:
} else {
const TerrainImprovementRecord::Effect *eff;
eff = terrainutil_GetTerrainEffect(rec, cell->GetTerrain());
if(!eff)
return false;
if(!g_player[pl]->HasAdvance(eff->GetEnableAdvanceIndex()))
return false;
sint32 a;
for(a = 0; a < eff->GetNumObsoleteAdvance(); a++) {
if(g_player[pl]->HasAdvance(eff->GetObsoleteAdvanceIndex(a))) {
return false; }}
for(i = 0; i < rec->GetNumCantBuildOn(); i++) {
if(rec->GetCantBuildOnIndex(i) == cell->GetTerrain()) {
return false; }}
for(i = 0; i < rec->GetNumIsRestrictedToGood(); i++) {
if(rec->GetIsRestrictedToGoodIndex(i) == cell->GetGood()) {
return true; }}
}
return true;
}
Better start from here again, of course afterwards you got the indention right . Now you have to make sure that your new code is executed if and only if the tile improvement is restricted at least to one good. You should know how to get this number, as you use it in your new code. And to achieve this if and only if condition you surround your new code by braces, one open brace before '{' and one closing brace '{' afterwards. And before the open brace you put an if with the according condition.
And before the for loop you have to retrieve the good's database index that you can find on the terrain, and to do this you use the GetGood function from the world object. And in slic you have an instance how it is used:
code:
SlicFunc.cpp
SFN_ERROR Slic_HasGood::Call(SlicArgList *args)
{
if(args->m_numArgs != 1)
return SFN_ERROR_NUM_ARGS;
MapPoint pos;
if(!args->GetPos(0, pos))
return SFN_ERROR_TYPE_ARGS;
sint32 good;
if(!g_theWorld->GetGood(pos, good)) {
m_result.m_int = -1;
} else {
m_result.m_int = good;
}
return SFN_ERROR_OK;
}
The GetGood function gets two arguments, a map point and an integer, both arguments are passed by refference not by value. That means the good variable used inside the function is the same instead of a copy, like outside the function, that means the function can assign a value to the good variable that can be used outside, quasi a second return value.
So first thing you have to do here is to retrieve the good's index. Maybe you should also check the return value of the GetGood function and if it is false you should leave the function with a return false.
And finally once you have done the for loop in your new and it didn't return true, the function must return false, but only if it executed your new code.
-Martin
Last edited by Martin Gühmann on 12-02-2005 at 21:10
|
|
|  |
 |
|
E
|
 |
July 24,2005 Ctp2 Tiles in sig!
May 1999 time: 21:29
|
|
from terrainutil.cpp terrainutil_CanPlayerBuildAt
code:
sint32 good;
if(cell->GetGood(good)>0 {
(g_theWorld->GetGood(good)&& g_theWorld->GetGood(rec->GetIndex(good))
} else {
return false;
}
Cell *c = GetCell(pos);
if (c->GetGoodsIndex(good)) {
good= g_theTerrainDB->Get(c->m_terrain_type)->GetResourcesIndex(good);
return true;
} else {
return false;
}
if (i = 0; i < rec->GetNumIsRestrictedToGood(); i++) {
if(rec->GetIsRestrictedToGoodIndex(i) == GetGoodsIndex(good)) {
return true;
}
}
for(i = 0; i < rec->GetNumCantBuildOn(); i++) {
if(rec->GetCantBuildOnIndex(i) != cell->GetTerrain()) {
return true;
}
}
}
return false;
}
In BOLD is my code as usual.
1) I used the GetGood function to identify if the spot the player is trying to build has a good or not. I have to admit here that its kind of fuzzy how the system checks here, I really don't "see" in the code how the system knows which tilethe player is building on, is that an event or something?
2) I created a variable good and if the tilehas a good it returns its index value, if not false. This is another C++ question, I don't have the braces around the other code will the progran stop running at the first false or check all conditions?
3)In the GetGoodIndex part if it returns true for a value good, will it stop runing the program or run to the next function? Should I remove the else {return false} and make it that if it returns true it does the nex function?
4) finally I have it check for the value in GetRestiictedtoGood value and if it equals the same as good value its true. This is similar to my last code so I think thats close (my only dount is on the good variable)
5) Finally, if the IsRestrictedtoGood flag is not there how do I know it will still run the program?
Sorry for the questions this time but I'm trying to get a bit more of an understanding...
Last edited by E on 14-02-2005 at 09:52
|
|
|  |
 |
|
Martin Gühmann
|
 |
Berlin, Germany
Mar 2001 time: 06:29
|
|
Well E the code is something else then I told you...
quote: Originally posted by E
1) I used the GetGood function to identify if the spot the player is trying to build has a good or not. I have to admit here that its kind of fuzzy how the system checks here, I really don't "see" in the code how the system knows which tilethe player is building on, is that an event or something? |
That's simple check the parameter list of the function you are modifying, it is the parameter const MapPoint &pos. And you don't need to understand the logic inside the function you just need to know what you can do with these functions. And actual I already told you that you only need the GetGood function from the world and no GetGoodsIndex function, this function is used of the GetGood function, there is no need to mess around with it.
quote: Originally posted by E
2) I created a variable good and if the tilehas a good it returns its index value, if not false. This is another C++ question, I don't have the braces around the other code will the progran stop running at the first false or check all conditions? |
That's stupid the function should return true if the player is allowed to build the given tarrain improvement at the given place and false if he isn't allowed to do so. There is no room for an index there. However it doesn't return there anything because it doesn't has a return statement and the final colon is missing. And this first if-else pair causes the function to return false if there is no good at the place always.
quote: Originally posted by E
3)In the GetGoodIndex part if it returns true for a value good, will it stop runing the program or run to the next function? Should I remove the else {return false} and make it that if it returns true it does the nex function? |
You should remove this GetGoodsIndex function alltogether, you don't need it at all as I said above.
quote: Originally posted by E
4) finally I have it check for the value in GetRestiictedtoGood value and if it equals the same as good value its true. This is similar to my last code so I think thats close (my only dount is on the good variable) |
I still have no idea what you want with this if-for-loop hybrid synthax. That doesn't do anything it even doesn't compile. However once you changed this if-for-hybrid stuff into a real for loop you have to compare each RestrictedToGood index to the good index you have retrieved before and stored in the good variable, don't use this GetGoodsIndex function, it doesn't even compile since it is a member of Cell.
quote: Originally posted by E
5) Finally, if the IsRestrictedtoGood flag is not there how do I know it will still run the program? |
That is a pretty good question and if I remember correctly the answer is in this thread, but here again: You have this GetNumIsRestrictedToGood function. This function returns the number of goods to that your improvement is restricted. For a tile improvement without any restrictions it returns 0. So all you have to do is to use an
if(){
}
statement. If this function I refered above returns a number bigger than 0 then your new code is executed. otherwise it isn't executed. And of course leave the original code as it is, don't mess with this around and of course you new code is insereted after the original code.
-Martin
|
|
|  |
 |
|
E
|
 |
July 24,2005 Ctp2 Tiles in sig!
May 1999 time: 21:29
|
|
code:
sint32 good;
if (g_theWorld->GetGood(pos, good)){
for(i = 0; i < rec->GetNumIsRestrictedToGood(); i++) {
if(rec->GetIsRestrictedToGood(i) == good) {
return true;
}
}
}
for(i = 0; i < rec->GetNumCantBuildOn(); i++) {
if(rec->GetCantBuildOnIndex(i) == cell->GetTerrain()) {
return false;
}
}
}
return true;
}
just a quick correction and I'll come back to the rest of your message for the last changes
Last edited by E on 28-02-2005 at 07:11
|
|
|  |
All times are GMT. The time now is 05:29. Apolyton Time is 00:29. |
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
|
|
|
|
|
|