Checking Lua outside of the game (MS-Windows)

whoward69

DLL Minion
Joined
May 30, 2011
Messages
8,697
Location
Near Portsmouth, UK
ModBuddy's support for Lua is not great. Most people write Lua and then start up the game to test it - which is a poor way to find syntax errors.

There are several alternatives, mine is

1) Download and install "Lua for Windows"
2) From the Lua option now in the main menu, select SciTE
3) From the File, Open ... dialog in SciTE, browse into the "~Documents\Firaxis ModBuddy" sub-directory, then into the sub-directory that's your mod
4) In that sub-directory you should have three further sub-directories "Build", "Packages" and one named as your mod, browse into that one
5) Browse into any sub-directories you use to organise files (LUA in my case) and Open the file you want to check - eg "C:\Users\{username}\Documents\Firaxis ModBuddy\Resolutions - Political Voting MP\Resolutions - Political Voting MP\LUA\ResolutionsPoliticalVoting.lua"
6) On the toolbar, click the blue right pointing arrow head (the mouse over hover reads "Run Program")
7) Correct any syntax errors, save the changes and click the blue arrow again - repeat until you have no syntax errors
8) At some point you will get an error about GameInfo, GameInfoTypes, GameEvents or include() - this is the Lua environment looking for CivV globals and failing to find them.
9) As you have been making changes directly to the Lua file(s) as ModBuddy reads them, rebuild the mod from within ModBuddy to deploy the changed files into the mod used by the game

At this point your Lua syntax is correct and you can proceed with testing in-game - knowing that you are now only looking for logic errors (or typos related to game objects/methods)

W
 
Nice. This will save an enormous amount of time currently being lost from loading a mod into a game only to see one of those 'line 587: near = no )' sort of error messages in the lua log.
 
I probably should have posted this two years ago when I was using it to write/test/debug the river connection code.

If you have some complex code to test, it may be quicker to create fake CivV Lua objects and test entirely within SciTE and only use the game for final acceptance tests - the spoiler has the code for the fake CivV objects needed to initially test the river connection code.

Spoiler :
Code:
--
-- MapSupport.lua
--
-- Bare minimum replacements for the DirectionTypes, Map and Plot objects to support testing of the RiverConnections code
--

--
-- y=4  0   1   2   3   4   5
-- y=3    0   1   2   3   4   5
-- y=2  0   1   2   3   4   5
-- y=1    0   1   2   3   4   5
-- y=0  0   1   2   3   4   5
--

local gMapWidth = 8
local gMapHeight = 5

-- gRiverSegments[y][x][side] indicates if there is a river (not nil) and if so if the flow is clockwise (true) or anti-clockwise (false)
-- only entries for DIRECTION_EAST (1), DIRECTION_SOUTHEAST (2) and DIRECTION_SOUTHWEST (3) are required if not nil (or for padding)
local gRiverSegments = {
  -- y = 0
  {{},					{},					{},					{},						{},					{},						{},				{}},
  -- y = 1
  {{},					{},					{},					{},						{false, false},		{},						{},				{}},
  -- y = 2
  {{},					{true},				{nil, false, false},{nil, false, false},	{nil, false, false},{false, false, false},	{},				{}},
  -- y = 3
  {{},					{nil, nil, false},	{},					{},						{},					{false, false}, 		{},				{}},
  -- y = 4
  {{},					{},					{},					{},						{},					{}, 					{nil, false},	{}}
}

local gLakePlots = {
  -- y = 0
  {false, false, false, false, false, false, false, false},
  -- y = 1
  {false, false, false, false, false, false, false, false},
  -- y = 2
  {false, false, false, false, false, false, false, false},
  -- y = 3
  {false, false, false, false, false, false, false, false},
  -- y = 4
  {false, false, false, false, false, false, false, false}
}

local gSeaPlots = {
  -- y = 0
  {false, false, false, false, false, false, false, false},
  -- y = 1
  {false, false, false, false, false, false, false, false},
  -- y = 2
  {false, false, false, false, false, false, false, false},
  -- y = 3
  {false, false, false, false, false, false, false, false},
  -- y = 4
  {false, false, false, false, false, false, false, true }
}

local gMountainPlots = {
  -- y = 0
  {false, false, false, false, false, false, false, false},
  -- y = 1
  {false, false, false, false, false, false, false, false},
  -- y = 2
  {false, false, false, false, false, false, false, false},
  -- y = 3
  {false, false, false, false, false, false, false, false},
  -- y = 4
  {false, false, false, false, false, false, false, false}
}

DirectionTypes = {
	NO_DIRECTION = -1,
	DIRECTION_NORTHEAST = 0,
	DIRECTION_EAST = 1,
	DIRECTION_SOUTHEAST = 2,
	DIRECTION_SOUTHWEST = 3,
	DIRECTION_WEST = 4,
	DIRECTION_NORTHWEST = 5,
	NUM_DIRECTION_TYPES = 6
}

function Vector4(x, y, z, w)
  return {x=x, y=y, z=z, w=w}
end

Map = {
  rows = {},

  init = function()
    local self = Map

    for y = 0, gMapHeight-1, 1 do
	  self.rows[y] = {}

	  for x = 0, gMapWidth-1, 1 do
	    self.rows[y][x] = Plot:new(x, y, gRiverSegments[y+1][x+1])
	  end
	end
  end,


  GetNumPlots = function()
    local self = Map

    return #self.rows * #self.rows[1]
  end,

  GetPlotByIndex = function(iPlotIndex)
    local self = Map

    return self.GetPlot(iPlotIndex % #self.rows[1], math.floor(iPlotIndex / #self.rows[1]))
  end,

  GetPlot = function(iPlotX, iPlotY)
    local self = Map

    return self.rows[iPlotY] and self.rows[iPlotY][iPlotX]
  end,

  PlotDirection = function(iPlotX, iPlotY, iDirection)
    local self = Map

    local iDeltaX = 0
	local iDeltaY = 0

    if (iDirection == DirectionTypes.DIRECTION_EAST) then
	  iDeltaX = 1
	  iDeltaY = 0
    elseif (iDirection == DirectionTypes.DIRECTION_NORTHEAST) then
	  iDeltaX = (iPlotY % 2)
	  iDeltaY = 1
    elseif (iDirection == DirectionTypes.DIRECTION_SOUTHEAST) then
	  iDeltaX = (iPlotY % 2)
	  iDeltaY = -1
    elseif (iDirection == DirectionTypes.DIRECTION_SOUTHWEST) then
	  iDeltaX = (iPlotY % 2) - 1
	  iDeltaY = -1
    elseif (iDirection == DirectionTypes.DIRECTION_WEST) then
	  iDeltaX = -1
	  iDeltaY = 0
    elseif (iDirection == DirectionTypes.DIRECTION_NORTHWEST) then
	  iDeltaX = (iPlotY % 2) - 1
	  iDeltaY = 1
	end

	return self.GetPlot(iPlotX+iDeltaX, iPlotY+iDeltaY)
  end,
}


Plot = {
  new = function(self, iX, iY, segments)
    local me = {}
    setmetatable(me, self)
    self.__index = self

	me.iX = iX
	me.iY = iY

	me.segments = segments

    return me
  end,

  toString = function(self)
    return string.format("Plot: %i, %i", self.iX, self.iY)
  end,

  GetPlotIndex = function(self)
    return self.iY * gMapWidth + self.iX
  end,

  GetX = function(self)
    return self.iX
  end,

  GetY = function(self)
    return self.iY
  end,

  IsWOfRiver = function(self)
    return self:IsRiverCrossing(DirectionTypes.DIRECTION_EAST)
  end,

  IsNWOfRiver = function(self)
    return self:IsRiverCrossing(DirectionTypes.DIRECTION_SOUTHEAST)
  end,

  IsNEOfRiver = function(self)
    return self:IsRiverCrossing(DirectionTypes.DIRECTION_SOUTHWEST)
  end,

  IsRiverCrossing = function(self, iDirection)
    return (self.segments[iDirection] ~= nil)
  end,

  IsRiverCrossingFlowClockwise = function(self, iDirection)
    return self.segments[iDirection]
  end,

  IsWater = function(self)
    return gSeaPlots[self.iY+1][self.iX+1] or self:IsLake()
  end,

  IsLake = function(self)
    return gLakePlots[self.iY+1][self.iX+1]
  end,

  IsMountain = function(self)
    return gMountainPlots[self.iY+1][self.iX+1]
  end,

  IsImpassable = function(self)
    return false
  end,
}

Map.init()

--riverManager = RiverManager:new()
--route = riverManager:getRiverRoute(1, 5, 1, 1, 3, false)
 
Top Bottom