A little help with lua - please

skodkim

Deity
Joined
Jan 16, 2004
Messages
2,497
Location
Denmark
Hi

I'm fooling around with making a random event that places a resource (wheat) on certain conditions. One condition is that the plot should have either grass or plains terrain or flood plains.

If I run the "condition line" in parts (e.g. one condition line for plains, one for grass and one for flood plains) it works like a charm for all three.

I do have some trouble trying to combine the conditions on one line. More specifically it works with grass and plains but not with flood plains.

If anyone can have a quick look at the following and give me a solution I would be grateful.

Spoiler :
return city and (plot:GetTerrainType() == GameInfo.Terrains[ "TERRAIN_GRASS" ].ID or plot:GetTerrainType() == GameInfo.Terrains[ "TERRAIN_PLAINS" ].ID or plot:GetFeatureType() == GameInfo.Features[ "FEATURE_FLOOD_PLAINS" ].ID) and not plot:IsCity() and plot:GetFeatureType() == -1 and plot:GetResourceType() == -1 and plot:IsFlatlands();


\Skodkim
 
Your conditional has "and plot:GetFeatureType() == -1" near the end of it which means it'll only work for tiles that have no feature; since flood plains is a feature, it can't trigger there.
 
Your conditional has "and plot:GetFeatureType() == -1" near the end of it which means it'll only work for tiles that have no feature; since flood plains is a feature, it can't trigger there.

Of course! I missed that one when I combined the conditions into one line. I would however like it to be either grass/plains without features or flood plains, so I guess I'll either make a more complex condition or break it up in two.

Thanks!

\Skodkim
 
Which turned out to be really easy.

Spoiler :
return city and ((plot:GetTerrainType() == GameInfo.Terrains[ "TERRAIN_GRASS" ].ID or plot:GetTerrainType() == GameInfo.Terrains[ "TERRAIN_PLAINS" ].ID and plot:GetFeatureType() == -1) or plot:GetFeatureType() == GameInfo.Features[ "FEATURE_FLOOD_PLAINS" ].ID) and not plot:IsCity() and plot:GetResourceType() == -1 and plot:IsFlatlands();


On a another matter I was messing around with making a script that adds buildings to a city. For example I know you can add features through the "plot:SetFeatureType( GameInfo.Features[ "FEATURE_###" ].ID );" call but is there a similar way of adding buildings and possibly removing them. If the latter can you check whether the city have the building first?

Thanks in advance!

\Skodkim
 
A good reference point would be the City object methods and/or the "selected city" panel in the Tuner. The latter uses pCity:GetNumRealBuilding(building.ID) to check for a building and pCity:SetNumRealBuilding(building.ID, 1/0) to add/remove them. You can access Building IDs through GameInfo.Buildings similar to what you did with features.
 
A good reference point would be the City object methods and/or the "selected city" panel in the Tuner. The latter uses pCity:GetNumRealBuilding(building.ID) to check for a building and pCity:SetNumRealBuilding(building.ID, 1/0) to add/remove them. You can access Building IDs through GameInfo.Buildings similar to what you did with features.

Great

I'll give it a go!

\Skodkim
 
Hmm

I just don't seem to get this and I'm not even trying to check if the building is in the city already yet. Just trying to add a building - harcoded to Monument right now to begin with. My script goes:
Spoiler :
--[[ New Building ]]--
-- condition function
function NewBuildingCond( player, city, unit, plot )
-- valid only on in cities
return city and plot:IsCity();
end
-- effect function
function NewBuildingEffect( player, city, unit, plot )
local iBuildingID = GameInfo.Buildings["BUILDING_MONUMENT"].ID
-- add Building to the plot
pCity:SetNumRealBuilding(iBuildingID, 1);
-- display the message
_UserEventMessage( Locale.ConvertTextKey( "TXT_USER_EVENT_NEW_BUILDING_EFFECT" ) );
end
-- enable the event
UserEventAdd{
id = "NEW_BUILDING",
probability = 0.99,
options = {
OPTION1 = { order = 1, condition = NewBuildingCond, effect = NewBuildingEffect }
}
};
--[[ / New Building ]]--


But when the event runs the message button hangs. Tried disabling the event line (pCity:SetNumRealBuilding(iBuildingID, 1); ) and it runs but of course with no effect.

Also tried finding help on the Wiki (which is hard due to lack of experience and examples on the page) and from other mods but haven't cracked it yet.

Sorry to ask, but any help would be much appreciated.

\Skodkim
 
Your parameters for NewBuildingEffect are ( player, city, unit, plot ) but you use pCity in the SetNumRealBuilding call.

If "city" is a city object, then just use city:SetNumRealBuilding(). If "city" is just an ID, then you need to use that id to initialize pCity to point to the city object first.
 
Hmm
Seems using other mods as inspiration isn't that easy for me after all with my limited skills.

"City as an object" meaning that its a variable I have set, right? But how do I use that id to initialize pCity to point to the city object first??

I tried using some lines from the Random Events to randomly select a city but with no luck.

I guess I'll leave it alone for a while and concentrate on playing with what I've got.

Thanks for the help.

\Skodkim
 
If you have an ID number for a city you can use Player:GetCityByID to retrieve the city object. It all comes down to what exactly are the arguments which are being passed to NewBuildingEffect?

If city is an object, you could use city:SetNumRealBuilding().

If city is an ID but player is an object, you could use player:GetCityByID(city):SetNumRealBuilding().

If both player and city are IDs you could use Players[player]:GetCityByID(city):SetNumRealBuilding().

Although the above examples gloss over any potential error-checking that should be done.

If you're new to this sort of modding, it might be useful to read through a Tutorial like the one on the wiki, then load a game and run the Fire Tuner and just start trying stuff in the console.
 
Although the above examples gloss over any potential error-checking that should be done.

And definitely don't forget that error-checking. You should check the player object to make sure it's good before extracting the city, and you also might want to ensure the player in question is still alive and HAS cities.

Also, I personally prefer intermediate steps, instead of chaining the variables together so much. Something like:
Code:
if(iPlayer >= 0 and iCity >= 0) then
  local pPlayer = Players[iPlayer];
  if(pPlayer ~= nil and pPlayer:IsAlive() and not pPlayer:IsBarbarian() ) then
    local pCity = pPlayer:GetCityByID(iCity);
    
    pCity:SetNumRealBuilding(whatever);
  end
end
This has the advantage that you can expand this routine to do other things with pCity, without having to screw around with Players[iPlayer] again. It's especially good if, instead of passed-in iPlayer and iCity values, you're using a loop over all cities owned by each player. But it's a little slower than doing it all at once.
 
Back
Top Bottom