First time using LUA, need help

Putmalk

Deity
Joined
Sep 26, 2010
Messages
2,652
Location
New York
Hello everyone. This is my first time entering LUA coding; mostly, I've been using XML to create my mods.

The goal of my LUA is simple. I want to:
  1. Identify all preplaced Greek cities on my map.
  2. When the capital (Athens) is captured, the captor receives 500 Gold and 1 free Social Policy.
  3. When a regular Greek city is captured, the captor receives 50 Gold for each city.
  4. Identify Carthage and Rome on the map.
  5. When Carthage is captured, it checks to see if the captor was Rome, and if it is, Rome wins a Domination victory.
  6. When Rome is captured, it checks to see if the captor was Carthage, and if it is, Carthage wins a Domination victory.

Here is my code so far. It only checks to see if Athens was captured (as of now). I adopted most of it from the Korea and Mongol scenarios.
Code:
GreeceCities = {
	{ -- Athens
		X = 57,
		Y = 21,
	},
	{ -- Sparta
		X = 56,
		Y = 25,
	},
	{ -- Delphi
		X = 54,
		Y = 20,
	},
	{ -- Pylos
		X = 53,
		Y = 26,
	},
	{ -- Elis
		X = 52,
		Y = 22,
	},
	{ -- Ambracia
		X = 49,
		Y = 16,
	},
	{ -- Pharsalos
		X = 55,
		Y = 15,
	},
	{ -- Philippi
		X = 58,
		Y = 13,
	},
};

local iGreeceCitiesStart = 1;
local iGreeceCitiesEnd = 10;
local iAthensIndex = 1;
local iCarthageX = 32;
local iCarthageY = 24;
local iRomeX = 37;
local iRomeY = 12;
--------------------------------------------------------------
-- CaptureCapitals
--------------------------------------------------------------
GameEvents.CityCaptureComplete.Add(function(iOldOwner, bIsCapital, iX, iY, iNewOwner)
	--local popupInfo = {
		--Data1 = 500,
		--Type = ButtonPopupTypes.BUTTONPOPUP_TEXT,
	--}

	local plot = Map.GetPlot(iX, iY);
	local cCity = plot:GetPlotCity();
	local iNewOwner = cCity:GetOwner();

	-- Was this capital Athens?
	if (iX == GreeceCities[iAthensIndex].X and iY == GreeceCities[iAthensIndex].Y) then

		Players[iNewOwner]:ChangeGold(500);
		--popupInfo.Text = Locale.ConvertTextKey("TXT_KEY_SCENARIO_ATHENS_FALLEN", 500);
		Players[iNewOwner]:ChangeNumFreePolicies(1);
		
	end
end);

When I run my map, I capture Athens and nothing happens. It just takes the city as normal.

Specific questions:

  1. Are there any syntax errors in the script?
  2. How would I place the script into my mod? So far, I opened Content and added: Type: InGameUIAddin, FileName: LUA/VictoryConditions.lua. Is this it? VFS set to true. Is there more to it?

Thank you for any help you can provide!
 
Hello everyone. This is my first time entering LUA coding; mostly, I've been using XML to create my mods.

Welcome to the Dark Side! It's not all bad here; we DO have cupcakes.

Sorry, but your Lua just isn't really going to work in the way you wrote it. Try this:

Code:
function MyFunction(playerID, bCapital, iX, iY, newPlayerID)
  if( playerID ~= nil and bCapital ~= nil and iX ~= nil and iY ~= nil and newPlayerID ~= nil ) then
    pPlayer = Players[playerID];
    nPlayer = Players[newPlayerID];
    if ( pPlayer:IsAlive() and not pPlayer:IsMinorCiv() and not pPlayer:IsBarbarian() and nPlayer:IsAlive() and not nPlayer:IsMinorCiv() and not nPlayer:IsBarbarian() ) then
-- Don't want this to trigger if one of the two participants is a minor civ or barbarian.
-- If you're okay with that, remove the later parts of the above IF, but leave the IsAlive() checks.
      pCivType = pPlayer:GetCivilizationType();
      nCivType = nPlayer:GetCivilizationType();

      for pCity in pPlayer:Cities() do
        cX = pCity:GetX();
        cY = pCity:GetY();
        if ( cX == iX and cY == iY ) then
          cName = pCity:GetName();
--          cID = pCity:GetID();
--          cCity = pCity;
        end
      end
-- Now, we have the name, ID, and structure of the city.  I'm only storing the Name, because that's all you really needed for what you described, but if you ever decide you want to do other things to the cities, just uncomment the "cCity" bit above.
      if ( pCivType == GameInfoTypes.CIVILIZATION_GREECE ) then
        if ( cName == "Athens" ) then
          nPlayer:ChangeGold(500);
          nPlayer:ChangeNumFreePolicies(1);
        else
          nPlayer:ChangeGold(50);
        end
      else
-- Someone other than the Greeks.
        if ( cName == "Carthage" ) then
          if ( nCivType == GameInfoTypes.CIVILIZATION_ROME ) then
            Game:SetWinner( GameInfoTypes.VICTORY_DOMINATION, nPlayer:GetID() );
          end
        elseif ( cName == "Rome" ) then
          if ( nCivType == GameInfoTypes.CIVILIZATION_CARTHAGE ) then
            Game:SetWinner( GameInfoTypes.VICTORY_DOMINATION, nPlayer:GetID() );
          end
        end
      end
    end
  end
end
GameEvents.CityCaptureComplete.Add(MyFunction)

The syntax might be slightly off, but that should do all you've asked for. I'm at work, so I can't actually check what I wrote there, but it'll be pretty close to what's needed.
 
Welcome to the Dark Side! It's not all bad here; we DO have cupcakes.

Sorry, but your Lua just isn't really going to work in the way you wrote it. Try this:

Code:
function MyFunction(playerID, bCapital, iX, iY, newPlayerID)
  if( playerID ~= nil and bCapital ~= nil and iX ~= nil and iY ~= nil and newPlayerID ~= nil ) then
    pPlayer = Players[playerID];
    nPlayer = Players[newPlayerID];
    if ( pPlayer:IsAlive() and not pPlayer:IsMinorCiv() and not pPlayer:IsBarbarian() and nPlayer:IsAlive() and not nPlayer:IsMinorCiv() and not nPlayer:IsBarbarian() ) then
-- Don't want this to trigger if one of the two participants is a minor civ or barbarian.
-- If you're okay with that, remove the later parts of the above IF, but leave the IsAlive() checks.
      pCivType = pPlayer:GetCivilizationType();
      nCivType = nPlayer:GetCivilizationType();

      for pCity in pPlayer:Cities() do
        cX = pCity:GetX();
        cY = pCity:GetY();
        if ( cX == iX and cY == iY ) then
          cName = pCity:GetName();
--          cID = pCity:GetID();
--          cCity = pCity;
        end
      end
-- Now, we have the name, ID, and structure of the city.  I'm only storing the Name, because that's all you really needed for what you described, but if you ever decide you want to do other things to the cities, just uncomment the "cCity" bit above.
      if ( pCivType == GameInfoTypes.CIVILIZATION_GREEK ) then
        if ( cName == "Athens" ) then
          nPlayer:ChangeGold(500);
          nPlayer:ChangeNumFreePolicies(1);
        else
          nPlayer:ChangeGold(50);
        end
      else
-- Someone other than the Greeks.
        if ( cName == "Carthage" ) then
          if ( nCivType == GameInfoTypes.CIVILIZATION_ROME ) then
            Game:SetWinner( GameInfoTypes.VICTORY_DOMINATION, nPlayer:GetID() );
          end
        elseif ( cName == "Rome" ) then
          if ( nCivType == GameInfoTypes.CIVILIZATION_CARTHAGE ) then
            Game:SetWinner( GameInfoTypes.VICTORY_DOMINATION, nPlayer:GetID() );
          end
        end
      end
    end
  end
end
GameEvents.CityCaptureComplete.Add(MyFunction)

The syntax might be slightly off, but that should do all you've asked for. I'm at work, so I can't actually check what I wrote there, but it'll be pretty close to what's needed.

Thanks a lot! I'll test and see if this works.

How come what I wrote wouldn't work? The Korea scenario did it to perfection.

And cupcakes sounds nice. :)
 
Actually, looking at it, it doesn't look bad. I generally dislike coding things with set positions, hence the method I'd given, but it SHOULD have worked.

To activate it you do the InGameUIAddin, but you do NOT use VFS. VFS is for two things:
> Altering Lua or non-gamedata XML in the vanilla game's database
> New art assets.

New lua, like this, keeps VFS=false and uses the InGameUIAddin to load.

So since it's not working, let's check something else. How did you get the X, Y values in that table? The thing is, the game has two separate X,Y systems that don't align very well. So there's a "Hex" X and Y and a "Plot" X and Y, which can have very different values. WorldBuilder's X and Y values are generally the Hex type, but most Lua functions use the Plot type.

The easy way to tell is to go into FireTuner, set it to InGame mod (you should lock it in this state anyway), and type

for index, pPlayer in pairs (Players) do print( pPlayer:GetID(), pPlayer:GetName() ) end

Find the ID value for greece. Write that down. Then type:

for pCity in Players[N]:Cities() do print( pCity:GetName(), pCity:GetX(), pCity:GetY() ) end

where N is the ID value for Greece from the previous command. That'll tell you the X and Y positions of each city; make sure they match what's in your tables.

EDIT:
There's a third situation where you use VFS=true: Lua "utility" functions that will be called by other routines through an "include" statement at the top of the file; these files use VFS=true, and NOT the InGameUIAddin. But the point remains, any Lua function that you'll be setting to trigger on an Event or GameEvent does not use VFS.
 
The script didn't work. Is there any way to debug it? I know about logging, but I checked the Lua log and nothing really showed up....

Okay you forgot to put a ";" at the end of the script. I put it in and I'll see if it works. Hopefully. <crosses fingers>
 
If there was an error, then FireTuner should have had a line starting with "RuntimeError". But most Lua debugging involves adding print statements at various points and seeing what they report.

But anyway, first try your original function with VFS turned off. Then try the FireTuner commands I gave, to see if the X and Y values are correct. If those don't fix it, I'll take a closer look at the code later. (Still at work.)
 
After typing in: "for index, pPlayer in pairs (Players) do print( pPlayer:GetID(), pPlayer:GetName() ) end", my game just crashed. (I got Alexander's ID, however).
 
Yeah, that happens sometimes, if it hits an invalid entry. I think it will crash if a city-state has died, but there might be other bits involved. You can expand it to something that includes an IF check in a lua function, it's just harder to type into the Tuner.

But if you have Alexander's ID, then just start the game back up and type the next command once you're back in. The active player (you) is always ID#0, so you can easily test stuff by starting a game as that civ and using Players[0] for everything.

I'd love to figure this out further, but I just bought Skyrim.
 
Yup. The y values were all wrong. I fixed them to match the LUA script in firetuner, let's see if it works.

Nope. The script doesn't work at all. Honestly, I don't think its firing at all.
 
Back
Top Bottom