Skip to content
Snippets Groups Projects
Commit 55ceebe3 authored by Rsge's avatar Rsge
Browse files

Add project files

parent 45f12cfa
No related branches found
No related tags found
No related merge requests found
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
## ##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
#Zip files
*.zip
# User-specific files # User-specific files
*.rsuser *.rsuser
*.suo *.suo
......
--==========================================================
-- CityBannerManager
-- Re-written by bc1 using Notepad++
-- code is common using gk_mode and bnw_mode switches
--==========================================================
Events.SequenceGameInitComplete.Add(function()
include "GameInfoCache" -- warning! booleans are true, not 1, and use iterator ONLY with table field conditions, NOT string SQL query
local GameInfo = GameInfoCache
include "IconHookup"
local IconHookup = IconHookup
local CivIconHookup = CivIconHookup
local Color = Color
local PrimaryColors = PrimaryColors
local BackgroundColors = BackgroundColors
local ColorGreen = Color( 0, 1, 0, 1 )
local ColorYellow = Color( 1, 1, 0, 1 )
local ColorRed = Color( 1, 0, 0, 1 )
local ColorCulture = Color( 1, 0, 1, 1 )
include "CityStateStatusHelper"
local GetCityStateStatusRow = GetCityStateStatusRow
local GetActiveQuestText = GetActiveQuestText
--==========================================================
-- Minor lua optimizations
--==========================================================
local ipairs = ipairs
local floor = math.floor
local max = math.max
local min = math.min
local pairs = pairs
local print = print
local insert = table.insert
local remove = table.remove
local format = string.format
local ButtonPopupTypes = ButtonPopupTypes
local CityUpdateTypes = CityUpdateTypes
local ContextPtr = ContextPtr
local Controls = Controls
local Events = Events
local EventsClearHexHighlightStyle = Events.ClearHexHighlightStyle.Call
local EventsRequestYieldDisplay = Events.RequestYieldDisplay.Call
local EventsSerialEventHexHighlight = Events.SerialEventHexHighlight.Call
local Game = Game
local GridToWorld = GridToWorld
local InStrategicView = InStrategicView
local InterfaceModeTypes = InterfaceModeTypes
local L = Locale.ConvertTextKey
local ToUpper = Locale.ToUpper
local GetPlot = Map.GetPlot
local GetPlotByIndex = Map.GetPlotByIndex
local MinorCivQuestTypes = MinorCivQuestTypes
local Mouse = Mouse
local SendUpdateCityCitizens = Network.SendUpdateCityCitizens
local IsCivilianYields = OptionsManager.IsCivilianYields
local Players = Players
local Teams = Teams
local ToGridFromHex = ToGridFromHex
local ToHexFromGrid = ToHexFromGrid
local UI = UI
local GetUnitPortraitIcon = UI.GetUnitPortraitIcon
local UnitMoving = UnitMoving
local YieldDisplayTypes = YieldDisplayTypes
local MAX_CITY_HIT_POINTS = GameDefines.MAX_CITY_HIT_POINTS
local CITY_PLOTS_RADIUS = GameDefines.CITY_PLOTS_RADIUS
--==========================================================
-- Globals
--==========================================================
local RefreshCityBanner
local gk_mode = Game.GetReligionName ~= nil
local bnw_mode = Game.GetActiveLeague ~= nil
local g_activePlayerID = Game.GetActivePlayer()
local g_activePlayer = Players[ g_activePlayerID ]
local g_activeTeamID = Game.GetActiveTeam()
local g_activeTeam = Teams[ g_activeTeamID ]
local g_cityBanners = {}
--local g_outpostBanners = {}
--local g_stationBanners = {}
local g_svStrikeButtons = {}
local g_scrapTeamBanners = {}
local g_scrapOtherBanners = {}
local g_scrapSVStrikeButtons = {}
local g_WorldPositionOffsetZ = InStrategicView and 35 or 55
local g_cityHexHighlight
--local IsCivBE = Game.GetAvailableBeliefs ~= nil
--local g_CovertOpsBannerContainer = IsCivBE and ContextPtr:LookUpControl( "../CovertOpsBannerContainer" )
--local g_CovertOpsIntelReportContainer = IsCivBE and ContextPtr:LookUpControl( "../CovertOpsIntelReportContainer" )
local g_cityFocusIcons = {
--[CityAIFocusTypes.NO_CITY_AI_FOCUS_TYPE or -1] = "",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_FOOD or -1] = "[ICON_FOOD]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_PRODUCTION or -1] = "[ICON_PRODUCTION]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_GOLD or -1] = "[ICON_GOLD]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_SCIENCE or -1] = "[ICON_RESEARCH]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_CULTURE or -1] = "[ICON_CULTURE]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_GREAT_PEOPLE or -1] = "[ICON_GREAT_PEOPLE]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_FAITH or -1] = "[ICON_PEACE]",
} g_cityFocusIcons[-1] = nil
local g_cityFocusTooltips = {
[CityAIFocusTypes.NO_CITY_AI_FOCUS_TYPE or -1] = L"TXT_KEY_CITYVIEW_FOCUS_BALANCED_TEXT",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_FOOD or -1] = L"TXT_KEY_CITYVIEW_FOCUS_FOOD_TEXT",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_PRODUCTION or -1] = L"TXT_KEY_CITYVIEW_FOCUS_PROD_TEXT",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_GOLD or -1] = L"TXT_KEY_CITYVIEW_FOCUS_GOLD_TEXT",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_SCIENCE or -1] = L"TXT_KEY_CITYVIEW_FOCUS_RESEARCH_TEXT",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_CULTURE or -1] = L"TXT_KEY_CITYVIEW_FOCUS_CULTURE_TEXT",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_GREAT_PEOPLE or -1] = L"TXT_KEY_CITYVIEW_FOCUS_GREAT_PERSON_TEXT",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_FAITH or -1] = L"TXT_KEY_CITYVIEW_FOCUS_FAITH_TEXT",
} g_cityFocusTooltips[-1] = nil
local function IsTurnActive( player )
return player and player:IsTurnActive() and not Game.IsProcessingMessages()
end
local function BannerError( where, arg )
if Game.IsDebugMode() then
local txt = ""
if arg and arg.PlotIndex then
txt = "city banner"
arg = arg and GetPlotByIndex(arg.PlotIndex)
end
if arg and arg.GetPlotCity then
txt = "plot " .. (arg:IsCity() and "with" or "without") .. " city"
arg = arg:GetPlotCity()
end
if arg and arg.GetCityPlotIndex then
txt = "city " .. arg:GetName()
end
print( "glitch", where, txt, debug and debug.traceback and debug.traceback() )
end
end
--==========================================================
-- Clear Hex Highlighting
--==========================================================
local function ClearHexHighlights()
EventsClearHexHighlightStyle( "HexContour" )
EventsClearHexHighlightStyle( "WorkedFill" )
EventsClearHexHighlightStyle( "WorkedOutline" )
EventsClearHexHighlightStyle( "UnlockedFill" )
EventsClearHexHighlightStyle( "UnlockedOutline" )
EventsClearHexHighlightStyle( "OwnedFill")
EventsClearHexHighlightStyle( "OwnedOutline" )
EventsClearHexHighlightStyle( "CityLimits" )
EventsClearHexHighlightStyle( "EnemyFill" )
EventsClearHexHighlightStyle( "EnemyOutline" )
g_cityHexHighlight = false
end
--==========================================================
-- Show/hide the garrison frame icon
--==========================================================
local function HideGarrisonFrame( instance, isHide )
-- Only the active team has a Garrison ring
if instance and instance[1] then
instance.GarrisonFrame:SetHide( isHide )
end
end
--==========================================================
-- Show/hide the range strike icon
--==========================================================
local function UpdateRangeIcons( plotIndex, city, instance )
if city and instance then
local hideRangeStrikeButton = city:GetOwner() ~= g_activePlayerID or not city:CanRangeStrikeNow()
if instance.CityRangeStrikeButton then
instance.CityRangeStrikeButton:SetHide( hideRangeStrikeButton )
end
instance = g_svStrikeButtons[ plotIndex ]
if instance then
instance.CityRangeStrikeButton:SetHide( hideRangeStrikeButton )
end
end
end
--==========================================================
-- Refresh the City Damage bar
--==========================================================
local function RefreshCityDamage( city, instance, cityDamage )
if instance then
local maxCityHitPoints = gk_mode and city and city:GetMaxHitPoints() or MAX_CITY_HIT_POINTS
local iHealthPercent = 1 - cityDamage / maxCityHitPoints
instance.CityBannerHealthBar:SetPercent(iHealthPercent)
instance.CityBannerHealthBar:SetToolTipString( format("%g / %g", maxCityHitPoints - cityDamage, maxCityHitPoints) )
---- Health bar color based on amount of damage
local barColor = {}
if iHealthPercent > 0.66 then
barColor = ColorGreen
elseif iHealthPercent > 0.33 then
barColor = ColorYellow
else
barColor = ColorRed
end
instance.CityBannerHealthBar:SetFGColor( barColor )
-- Show or hide the Health Bar as necessary
instance.CityBannerHealthBarBase:SetHide( cityDamage == 0 )
end
end
--==========================================================
-- Click On City State Quest Info
--==========================================================
local questKillCamp = MinorCivQuestTypes.MINOR_CIV_QUEST_KILL_CAMP
local IsActiveQuestKillCamp
if bnw_mode then
IsActiveQuestKillCamp = function( minorPlayer )
return minorPlayer and minorPlayer:IsMinorCivDisplayedQuestForPlayer( g_activePlayerID, questKillCamp )
end
elseif gk_mode then
IsActiveQuestKillCamp = function( minorPlayer )
return minorPlayer and minorPlayer:IsMinorCivActiveQuestForPlayer( g_activePlayerID, questKillCamp )
end
else
IsActiveQuestKillCamp = function( minorPlayer )
return minorPlayer and minorPlayer:GetActiveQuestForPlayer( g_activePlayerID ) == questKillCamp
end
end
local function OnQuestInfoClicked( plotIndex )
local plot = GetPlotByIndex( plotIndex )
local city = plot and plot:GetPlotCity()
local cityOwner = city and Players[ city:GetOwner() ]
if cityOwner and cityOwner:IsMinorCiv() and IsActiveQuestKillCamp( cityOwner ) then
local questData1 = cityOwner:GetQuestData1( g_activePlayerID, questKillCamp )
local questData2 = cityOwner:GetQuestData2( g_activePlayerID, questKillCamp )
local plot = GetPlot( questData1, questData2 )
if plot then
UI.LookAt( plot )
local hex = ToHexFromGrid{ x=plot:GetX(), y=plot:GetY() }
Events.GameplayFX( hex.x, hex.y, -1 )
end
end
end
local function AnnexPopup( plotIndex )
local plot = GetPlotByIndex( plotIndex )
local city = plot and plot:GetPlotCity()
if city and city:GetOwner() == g_activePlayerID and not( bnw_mode and g_activePlayer:MayNotAnnex() ) then
Events.SerialEventGameMessagePopup{
Type = ButtonPopupTypes.BUTTONPOPUP_ANNEX_CITY,
Data1 = city:GetID(),
Data2 = -1,
Data3 = -1,
Option1 = false,
Option2 = false
}
end
end
local function EspionagePopup( plotIndex )
local plot = GetPlotByIndex( plotIndex )
local city = plot and plot:GetPlotCity()
if city and not Players[city:GetOwner()]:IsMinorCiv() then
ClearHexHighlights()
UI.SetInterfaceMode( InterfaceModeTypes.INTERFACEMODE_SELECTION )
UI.DoSelectCityAtPlot( plot )
else
Events.SerialEventGameMessagePopup{ Type = ButtonPopupTypes.BUTTONPOPUP_ESPIONAGE_OVERVIEW }
end
end
--==========================================================
-- Click on City Range Strike Button
--==========================================================
local function OnCityRangeStrikeButtonClick( plotIndex )
local plot = GetPlotByIndex( plotIndex )
local city = plot and plot:GetPlotCity()
if city and city:GetOwner() == g_activePlayerID then
UI.ClearSelectionList()
UI.SelectCity( city )
UI.SetInterfaceMode( InterfaceModeTypes.INTERFACEMODE_CITY_RANGE_ATTACK )
-- Events.InitCityRangeStrike( city:GetOwner(), city:GetID() )
end
end
--==========================================================
-- Left Click on city banner
--==========================================================
local function OnBannerClick( plotIndex )
local plot = GetPlotByIndex( plotIndex )
local city = plot and plot:GetPlotCity()
if city then
UI.SetInterfaceMode( InterfaceModeTypes.INTERFACEMODE_SELECTION )
local cityOwnerID = city:GetOwner()
local cityOwner = Players[ cityOwnerID ]
-- Active player city
if cityOwnerID == g_activePlayerID then
-- always open city screen, puppets are not that special
ClearHexHighlights()
UI.DoSelectCityAtPlot( plot )
-- Observers get to look at anything
elseif Game.IsDebugMode() or g_activePlayer:IsObserver() then
UI.SelectCity( city )
UI.LookAt( plot )
UI.SetCityScreenUp( true )
-- Other player, which has been met
elseif g_activeTeam:IsHasMet( city:GetTeam() ) then
if cityOwner:IsMinorCiv() then
UI.DoSelectCityAtPlot( plot )
elseif IsTurnActive( g_activePlayer ) then
if cityOwner:IsHuman() then
Events.OpenPlayerDealScreenEvent( cityOwnerID )
elseif not cityOwner:IsBarbarian() then
UI.SetRepeatActionPlayer( cityOwnerID )
UI.ChangeStartDiploRepeatCount(1)
cityOwner:DoBeginDiploWithHuman()
end
end
end
else
BannerError( "OnBannerClick", plot )
end
end
--==========================================================
-- Destroy City Banner
--==========================================================
local function DestroyCityBanner( plotIndex, instance )
-- Release city banner
if instance then
insert( instance[1] and g_scrapTeamBanners or g_scrapOtherBanners, instance )
g_cityBanners[ plotIndex or -1 ] = nil
instance.Anchor:ChangeParent( Controls.Scrap )
end
-- Release sv strike button
instance = g_svStrikeButtons[ plotIndex ]
if instance then
instance.Anchor:ChangeParent( Controls.Scrap )
insert( g_scrapSVStrikeButtons, instance )
g_svStrikeButtons[ plotIndex ] = nil
end
end
--==========================================================
-- City banner mouse over
--==========================================================
local function OnBannerMouseExit()
if not UI.IsCityScreenUp() then
ClearHexHighlights()
-- duplicate code from InGame.lua function RequestYieldDisplay()
local isDisplayCivilianYields = IsCivilianYields()
local unit = UI.GetHeadSelectedUnit()
if isDisplayCivilianYields and UI.CanSelectionListWork() and not( unit and (GameInfo.Units[unit:GetUnitType()] or {}).DontShowYields ) then
EventsRequestYieldDisplay( YieldDisplayTypes.EMPIRE )
elseif isDisplayCivilianYields and UI.CanSelectionListFound() and unit then
EventsRequestYieldDisplay( YieldDisplayTypes.AREA, 2, unit:GetX(), unit:GetY() )
else
EventsRequestYieldDisplay( YieldDisplayTypes.AREA, 0 )
end
end
end
local function OnBannerMouseEnter( plotIndex )
local plot = GetPlotByIndex( plotIndex )
if plot then
local city = plot:GetPlotCity()
g_cityHexHighlight = plotIndex
if city and city:GetOwner() == g_activePlayerID and not( Game.IsNetworkMultiPlayer() and g_activePlayer:HasReceivedNetTurnComplete() ) then -- required to prevent turn interrupt
SendUpdateCityCitizens( city:GetID() )
end
return RefreshCityBanner( city )
end
end
local CityTooltip = LuaEvents.CityToolTips.Call
local TeamCityTooltips = {
CityBannerButton = "EUI_ItemTooltip",
CityBannerRightBackground = "EUI_ItemTooltip",
BuildGrowth = "EUI_ItemTooltip",
CityGrowth = "EUI_ItemTooltip",
-- BorderGrowth = "EUI_ItemTooltip",
CityReligion = "EUI_ItemTooltip",
CityFocus = "EUI_ItemTooltip",
CityQuests = "EUI_ItemTooltip",
CityIsPuppet = "EUI_ItemTooltip",
CityIsRazing = "EUI_ItemTooltip",
CityIsResistance = "EUI_ItemTooltip",
CityIsConnected = "EUI_ItemTooltip",
CityIsBlockaded = "EUI_ItemTooltip",
CityIsOccupied = "EUI_ItemTooltip",
CityIsCapital = "EUI_ItemTooltip",
CityIsOriginalCapital = "EUI_ItemTooltip",
CivIndicator = "EUI_ItemTooltip",
CityProductionBG = "EUI_CityProductionTooltip",
CityPopulation = "EUI_CityGrowthTooltip",
}
local OtherCityTooltips = {
CityBannerButton = "EUI_ItemTooltip",
CityBannerRightBackground = "EUI_ItemTooltip",
-- BuildGrowth = "EUI_ItemTooltip",
-- CityGrowth = "EUI_ItemTooltip",
-- BorderGrowth = "EUI_ItemTooltip",
CityReligion = "EUI_ItemTooltip",
-- CityFocus = "EUI_ItemTooltip",
CityQuests = "EUI_ItemTooltip",
CityIsPuppet = "EUI_ItemTooltip",
CityIsRazing = "EUI_ItemTooltip",
CityIsResistance = "EUI_ItemTooltip",
-- CityIsConnected = "EUI_ItemTooltip",
CityIsBlockaded = "EUI_ItemTooltip",
CityIsOccupied = "EUI_ItemTooltip",
CityIsCapital = "EUI_ItemTooltip",
CityIsOriginalCapital = "EUI_ItemTooltip",
CivIndicator = "EUI_ItemTooltip",
-- CityProductionBG = "EUI_CityProductionTooltip",
-- CityPopulation = "EUI_CityGrowthTooltip",
}
local function InitBannerCallbacks( instance, tooltips )
local button = instance.CityBannerButton
button:RegisterCallback( Mouse.eLClick, OnBannerClick )
button:RegisterCallback( Mouse.eMouseEnter, OnBannerMouseEnter )
button:RegisterCallback( Mouse.eMouseExit, OnBannerMouseExit )
-- instance.CityName:SetColor( Color( 0, 0, 0, 0.5 ), 1 ) -- #1 = shadow color
-- instance.CityName:SetColor( Color( 1, 1, 1, 0.5 ), 2 ) -- #2 = soft color
instance.CityDiplomat:RegisterCallback( Mouse.eLClick, EspionagePopup )
instance.CitySpy:RegisterCallback( Mouse.eLClick, EspionagePopup )
-- Setup Tootip Callbacks
for controlID, toolTipType in pairs( tooltips ) do
instance[ controlID ]:SetToolTipCallback( function( control )
control:SetToolTipCallback( function( control ) return CityTooltip( control, GetPlotByIndex( button:GetVoid1() ):GetPlotCity() ) end )
control:SetToolTipType( toolTipType )
end)
end
end
--==========================================================
-- Update banners to reflect latest city info
--==========================================================
function RefreshCityBanner( city )
if city then
local isDebug = Game.IsDebugMode() or g_activePlayer:IsObserver()
local plot = city:Plot()
local plotIndex = plot:GetPlotIndex()
local instance = g_cityBanners[ plotIndex ]
local cityOwnerID = city:GetOwner()
local cityOwner = Players[ cityOwnerID ]
local isActiveType = isDebug or city:GetTeam() == g_activeTeamID
local isActivePlayerCity = cityOwnerID == g_activePlayerID
-- Incompatible banner type ? Destroy !
if instance and isActiveType ~= instance[1] then
DestroyCityBanner( plotIndex, instance )
instance = nil
end
---------------------
-- Create City Banner
if not instance then
local worldX, worldY, worldZ = GridToWorld( plot:GetX(), plot:GetY() )
if isActiveType then
-- create a strike button for stategic view
instance = remove( g_scrapSVStrikeButtons )
if instance then
instance.Anchor:ChangeParent( Controls.StrategicViewStrikeButtons )
else
instance = {}
ContextPtr:BuildInstanceForControl( "SVRangeStrikeButton", instance, Controls.StrategicViewStrikeButtons )
instance.CityRangeStrikeButton:RegisterCallback( Mouse.eLClick, OnCityRangeStrikeButtonClick )
end
instance.Anchor:SetWorldPositionVal( worldX, worldY, worldZ )
instance.CityRangeStrikeButton:SetVoid1( plotIndex )
g_svStrikeButtons[ plotIndex ] = instance
-- create a team type city banner
instance = remove( g_scrapTeamBanners )
if instance then
instance.Anchor:ChangeParent( Controls.CityBanners )
else
instance = {}
ContextPtr:BuildInstanceForControl( "TeamCityBanner", instance, Controls.CityBanners )
instance.CityRangeStrikeButton:RegisterCallback( Mouse.eLClick, OnCityRangeStrikeButtonClick )
instance.CityIsPuppet:RegisterCallback( Mouse.eLClick, AnnexPopup )
InitBannerCallbacks( instance, TeamCityTooltips )
end
instance.CityIsPuppet:SetVoid1( plotIndex )
instance.CityRangeStrikeButton:SetVoid1( plotIndex )
else
-- create a foreign type city banner
instance = remove( g_scrapOtherBanners )
if instance then
instance.Anchor:ChangeParent( Controls.CityBanners )
else
instance = {}
ContextPtr:BuildInstanceForControl( "OtherCityBanner", instance, Controls.CityBanners )
instance.CityQuests:RegisterCallback( Mouse.eLClick, OnQuestInfoClicked )
InitBannerCallbacks( instance, OtherCityTooltips )
end
instance.CityQuests:SetVoid1( plotIndex )
end
instance.CityBannerButton:SetVoid1( plotIndex )
instance.Anchor:SetWorldPositionVal( worldX, worldY, worldZ + g_WorldPositionOffsetZ )
instance[1] = isActiveType
g_cityBanners[ plotIndex ] = instance
end
-- /Create City Banner
---------------------
-- Refresh the damage bar
RefreshCityDamage( city, instance, city:GetDamage() )
-- Colors
local color = PrimaryColors[ cityOwnerID ]
local backgroundColor = BackgroundColors[ cityOwnerID ]
-- Update name
local cityName = city:GetName()
local upperCaseCityName = ToUpper( cityName )
local originalCityOwnerID = city:GetOriginalOwner()
local originalCityOwner = Players[ originalCityOwnerID ]
local otherCivID, otherCivAlpha
local isRazing = city:IsRazing()
local isResistance = city:IsResistance()
local isPuppet = city:IsPuppet()
-- Update capital icon
instance.CityIsCapital:SetHide( not city:IsCapital() or cityOwner:IsMinorCiv() )
instance.CityIsOriginalCapital:SetHide( city:IsCapital() or not city:IsOriginalCapital() )
instance.CityName:SetText( upperCaseCityName )
instance.CityName:SetColor( color, 0 ) -- #0 = main color
-- Update strength
instance.CityStrength:SetText(floor(city:GetStrengthValue() / 100))
-- Update population
instance.CityPopulationValue:SetText( city:GetPopulation() )
-- Being Razed ?
instance.CityIsRazing:SetHide( not isRazing )
-- In Resistance ?
instance.CityIsResistance:SetHide( not isResistance )
-- Puppet ?
instance.CityIsPuppet:SetHide( not isPuppet )
-- Occupied ?
instance.CityIsOccupied:SetHide( not city:IsOccupied() or city:IsNoOccupiedUnhappiness() )
-- Blockaded ?
instance.CityIsBlockaded:SetHide( not city:IsBlockaded() )
-- Garrisoned ?
instance.GarrisonFrame:SetHide( not ( plot:IsVisible( g_activeTeamID, true ) and city:GetGarrisonedUnit() ) )
instance.CityBannerBackground:SetColor( backgroundColor )
instance.CityBannerRightBackground:SetColor( backgroundColor )
instance.CityBannerLeftBackground:SetColor( backgroundColor )
if isActiveType then
instance.CityBannerBGLeftHL:SetColor( backgroundColor )
instance.CityBannerBGRightHL:SetColor( backgroundColor )
instance.CityBannerBackgroundHL:SetColor( backgroundColor )
-- Update Growth
local foodStored100 = city:GetFoodTimes100()
local foodThreshold100 = city:GrowthThreshold() * 100
local foodPerTurn100 = city:FoodDifferenceTimes100( true )
local foodStoredPercent = 0
local foodStoredNextTurnPercent = 0
if foodThreshold100 > 0 then
foodStoredPercent = foodStored100 / foodThreshold100
foodStoredNextTurnPercent = ( foodStored100 + foodPerTurn100 ) / foodThreshold100
if foodPerTurn100 < 0 then
foodStoredPercent, foodStoredNextTurnPercent = foodStoredNextTurnPercent, foodStoredPercent
end
end
-- Update Growth Meter
instance.GrowthBar:SetPercent( max(min( foodStoredPercent, 1),0))
instance.GrowthBarShadow:SetPercent( max(min( foodStoredNextTurnPercent, 1),0))
instance.GrowthBarStarve:SetHide( foodPerTurn100 >= 0 )
-- Update Growth Time
local turnsToCityGrowth = city:GetFoodTurnsLeft()
local growthText
if foodPerTurn100 < 0 then
turnsToCityGrowth = floor( foodStored100 / -foodPerTurn100 ) + 1
growthText = "[COLOR_WARNING_TEXT]" .. turnsToCityGrowth .. "[ENDCOLOR]"
elseif city:IsForcedAvoidGrowth() then
growthText = "[ICON_LOCKED]"
elseif foodPerTurn100 == 0 then
growthText = "-"
else
growthText = min(turnsToCityGrowth,99)
end
instance.CityGrowth:SetText( growthText )
local productionPerTurn100 = city:GetCurrentProductionDifferenceTimes100(false, false) -- food = false, overflow = false
local productionStored100 = city:GetProductionTimes100() + city:GetCurrentProductionDifferenceTimes100(false, true) - productionPerTurn100
local productionNeeded100 = city:GetProductionNeeded() * 100
local productionStoredPercent = 0
local productionStoredNextTurnPercent = 0
if productionNeeded100 > 0 then
productionStoredPercent = productionStored100 / productionNeeded100
productionStoredNextTurnPercent = (productionStored100 + productionPerTurn100) / productionNeeded100
end
instance.ProductionBar:SetPercent( max(min( productionStoredPercent, 1),0))
instance.ProductionBarShadow:SetPercent( max(min( productionStoredNextTurnPercent, 1),0))
-- Update Production Time
if city:IsProduction()
and not city:IsProductionProcess()
and productionPerTurn100 > 0
then
instance.BuildGrowth:SetText( city:GetProductionTurnsLeft() )
else
instance.BuildGrowth:SetText( "-" )
end
-- Update Production icon
local unitProductionID = city:GetProductionUnit()
local buildingProductionID = city:GetProductionBuilding()
local projectProductionID = city:GetProductionProject()
local processProductionID = city:GetProductionProcess()
local portraitIndex, portraitAtlas
local item = nil
if unitProductionID ~= -1 then
item = GameInfo.Units[unitProductionID]
portraitIndex, portraitAtlas = GetUnitPortraitIcon( (item or {}).ID or -1, cityOwnerID )
elseif buildingProductionID ~= -1 then
item = GameInfo.Buildings[buildingProductionID]
elseif projectProductionID ~= -1 then
item = GameInfo.Projects[projectProductionID]
elseif processProductionID ~= -1 then
item = GameInfo.Processes[processProductionID]
end
-- really should have an error texture
instance.CityProduction:SetHide( not( item and
IconHookup( portraitIndex or item.PortraitIndex, 45, portraitAtlas or item.IconAtlas, instance.CityProduction )))
-- Focus?
if isRazing or isResistance or isPuppet then
instance.CityFocus:SetHide( true )
else
instance.CityFocus:SetText( g_cityFocusIcons[city:GetFocusType()] )
instance.CityFocus:SetHide( false )
end
-- Connected to capital?
instance.CityIsConnected:SetHide( city:IsCapital() or not cityOwner:IsCapitalConnectedToCity( city ) )
-- Demand resource / King day ?
local resource = GameInfo.Resources[ city:GetResourceDemanded() ]
local weLoveTheKingDayCounter = city:GetWeLoveTheKingDayCounter()
-- We love the king
if weLoveTheKingDayCounter > 0 then
instance.CityQuests:SetText( "[ICON_HAPPINESS_1]" )
instance.CityQuests:SetHide( false )
elseif resource then
instance.CityQuests:SetText( resource.IconString )
instance.CityQuests:SetHide( false )
else
instance.CityQuests:SetHide( true )
end
-- update range strike button (if it is the active player's city)
UpdateRangeIcons( plotIndex, city, instance )
-- not active team city
else
local isMinorCiv = cityOwner:IsMinorCiv()
if isMinorCiv then
-- Update Quests
instance.CityQuests:SetText( GetActiveQuestText( g_activePlayerID, cityOwnerID ) )
local info = GetCityStateStatusRow( g_activePlayerID, cityOwnerID )
instance.StatusIconBG:SetTexture( info and info.StatusIcon )
instance.StatusIcon:SetTexture( (GameInfo.MinorCivTraits[ (GameInfo.MinorCivilizations[ cityOwner:GetMinorCivType() ] or {}).MinorCivTrait ] or {}).TraitIcon )
-- Update Pledge
if gk_mode then
local pledge = g_activePlayer:IsProtectingMinor( cityOwnerID )
local free = pledge and cityOwner:CanMajorWithdrawProtection( g_activePlayerID )
instance.Pledge1:SetHide( not pledge or free )
instance.Pledge2:SetHide( not free )
end
-- Update Allies
local allyID = cityOwner:GetAlly()
local ally = Players[ allyID ]
if ally then
-- Set left banner icon to ally flag
otherCivAlpha = 1
otherCivID = g_activeTeam:IsHasMet( ally:GetTeam() ) and allyID or -1
end
else
CivIconHookup( cityOwnerID, 45, instance.OwnerIcon, instance.OwnerIconBG, instance.OwnerIconShadow, false, true )
end
instance.CityQuests:SetHide( not isMinorCiv )
instance.StatusIconBG:SetHide( not isMinorCiv )
instance.OwnerIconBG:SetHide( isMinorCiv )
end
if not otherCivID and originalCityOwner and (originalCityOwnerID ~= cityOwnerID) then
-- Set left banner icon to city state flag
if originalCityOwner:IsMinorCiv() then
otherCivAlpha = 4 --hack
instance.MinorTraitIcon:SetTexture( (GameInfo.MinorCivTraits[ (GameInfo.MinorCivilizations[ originalCityOwner:GetMinorCivType() ] or {}).MinorCivTrait ] or {}).TraitIcon )
instance.CityIsOriginalCapital:SetHide( true )
else
otherCivAlpha = 0.5
otherCivID = originalCityOwnerID
end
end
if otherCivID then
CivIconHookup( otherCivID, 32, instance.CivIcon, instance.CivIconBG, instance.CivIconShadow, false, true )
instance.CivIndicator:SetAlpha( otherCivAlpha )
end
instance.MinorCivIndicator:SetHide( otherCivAlpha ~= 4 ) -- hack
instance.CivIndicator:SetHide( not otherCivID )
-- Spy & Religion
if gk_mode then
local spy
local x = city:GetX()
local y = city:GetY()
for _, s in ipairs( g_activePlayer:GetEspionageSpies() ) do
if s.CityX == x and s.CityY == y then
spy = s
break
end
end
if spy then
if spy.IsDiplomat then
instance.CityDiplomat:SetVoid1( spy.EstablishedSurveillance and plotIndex or -1 )
instance.CityDiplomat:LocalizeAndSetToolTip( "TXT_KEY_CITY_DIPLOMAT_OTHER_CIV_TT", spy.Rank, spy.Name, cityName, spy.Rank, spy.Name, spy.Rank, spy.Name )
instance.CityDiplomat:SetHide( false )
instance.CitySpy:SetHide( true )
else
instance.CitySpy:SetHide( false )
instance.CitySpy:SetVoid1( spy.EstablishedSurveillance and plotIndex or -1 )
if isActivePlayerCity then
instance.CitySpy:LocalizeAndSetToolTip( "TXT_KEY_CITY_SPY_YOUR_CITY_TT", spy.Rank, spy.Name, cityName, spy.Rank, spy.Name )
elseif cityOwner:IsMinorCiv() then
instance.CitySpy:LocalizeAndSetToolTip( "TXT_KEY_CITY_SPY_CITY_STATE_TT", spy.Rank, spy.Name, cityName, spy.Rank, spy.Name)
else
instance.CitySpy:LocalizeAndSetToolTip( "TXT_KEY_CITY_SPY_OTHER_CIV_TT", spy.Rank, spy.Name, cityName, spy.Rank, spy.Name, spy.Rank, spy.Name)
end
instance.CityDiplomat:SetHide( true )
end
else
instance.CitySpy:SetHide( true )
instance.CityDiplomat:SetHide( true )
end
local religion = GameInfo.Religions[city:GetReligiousMajority()]
if religion then
IconHookup( religion.PortraitIndex, 32, religion.IconAtlas, instance.CityReligion )
IconHookup( religion.PortraitIndex, 32, religion.IconAtlas, instance.ReligiousIconShadow )
instance.ReligiousIconContainer:SetHide( false )
else
instance.ReligiousIconContainer:SetHide( true )
end
end
-- Change the width of the banner so it looks good with the length of the city name
instance.NameStack:CalculateSize()
local bannerWidth = instance.NameStack:GetSizeX() - 64
instance.CityBannerButton:SetSizeX( bannerWidth + 64 )
instance.CityBannerBackground:SetSizeX( bannerWidth )
instance.CityBannerBackgroundHL:SetSizeX( bannerWidth )
if isActiveType then
instance.CityBannerBackgroundIcon:SetSizeX( bannerWidth )
instance.CityBannerButtonGlow:SetSizeX( bannerWidth )
instance.CityBannerButtonBase:SetSizeX( bannerWidth )
else
instance.CityBannerBaseFrame:SetSizeX( bannerWidth )
instance.CityAtWar:SetSizeX( bannerWidth )
instance.CityAtWar:SetHide( not g_activeTeam:IsAtWar( city:GetTeam() ) )
end
instance.CityBannerButton:ReprocessAnchoring()
instance.NameStack:ReprocessAnchoring()
instance.IconsStack:CalculateSize()
instance.IconsStack:ReprocessAnchoring()
if g_cityHexHighlight == plotIndex then
if not (InStrategicView and InStrategicView()) then
local cityID = city:GetID()
local cityTeamID = cityOwner:GetTeam()
local plot = GetPlot(0,0)
local hexPos
local checkFunc = plot.GetCityPurchaseID or plot.GetWorkingCity
local checkVal = plot.GetCityPurchaseID and cityID or city
for i = 0, city:GetNumCityPlots()-1 do
plot = city:GetCityIndexPlot( i )
if plot then
hexPos = ToHexFromGrid{ x=plot:GetX(), y=plot:GetY() }
-- Show city limits
EventsSerialEventHexHighlight( hexPos, true, nil, "CityLimits" )
if plot:GetOwner() == cityOwnerID then
local isImproved = true
if plot:GetImprovementType()>0 then
isImproved = not plot:IsImprovementPillaged() -- CanHaveImprovement, GetImprovementType, GetRevealedImprovementType, IsImprovementPillaged
else
for improvement in GameInfo.Improvements() do
if plot:CanHaveImprovement( improvement.ID, cityTeamID ) then
isImproved = false
break
end
end
end
if isActiveType and city:IsWorkingPlot( plot ) then
-- worked city plots
if plot:IsCity() or city:IsForcedWorkingPlot( plot ) then
if isImproved then
EventsSerialEventHexHighlight( hexPos , true, nil, "WorkedFill" )
end
EventsSerialEventHexHighlight( hexPos , true, nil, "WorkedOutline" )
else
if isImproved then
EventsSerialEventHexHighlight( hexPos , true, nil, "UnlockedFill" )
end
EventsSerialEventHexHighlight( hexPos , true, nil, "UnlockedOutline" )
end
elseif not city:CanWork( plot ) and ( plot:IsWater() and city:IsPlotBlockaded( plot ) or plot:IsVisibleEnemyUnit( cityOwnerID ) ) then
-- Blockaded water plot or Enemy Unit standing here
EventsSerialEventHexHighlight( hexPos , true, nil, "EnemyFill" )
EventsSerialEventHexHighlight( hexPos , true, nil, "EnemyOutline" )
elseif checkFunc( plot ) == checkVal then
-- city plots that are owned but not worked
if isImproved then
EventsSerialEventHexHighlight( hexPos , true, nil, "OwnedFill" )
end
EventsSerialEventHexHighlight( hexPos , true, nil, "OwnedOutline" )
end
end
end
end
end
if isActiveType then
-- Show plots that will be acquired by culture
local purchasablePlots = {city:GetBuyablePlotList()}
for i = 1, #purchasablePlots do
local plot = purchasablePlots[i]
EventsSerialEventHexHighlight( ToHexFromGrid{ x=plot:GetX(), y=plot:GetY() }, true, ColorCulture, "HexContour" )
end
EventsRequestYieldDisplay( YieldDisplayTypes.AREA, CITY_PLOTS_RADIUS, city:GetX(), city:GetY() )
else
EventsRequestYieldDisplay( YieldDisplayTypes.CITY_OWNED, city:GetX(), city:GetY() )
end
end
end
end
local function RefreshCityBannerAtPlot( plot )
return plot and RefreshCityBanner( plot:GetPlotCity() )
end
--==========================================================
-- Register Events
--==========================================================
------------------
-- On City Created
Events.SerialEventCityCreated.Add( function( hexPos, cityOwnerID, cityID, cultureType, eraType, continent, populationSize, size, fowState )
-- fowState 0 is invisible
if fowState ~= 0 then
return RefreshCityBannerAtPlot( GetPlot( ToGridFromHex( hexPos.x, hexPos.y ) ) )
end
end)
------------------
-- On City Updated
Events.SerialEventCityInfoDirty.Add( function()
-- Don't know which city, so update all visible city banners
for plotIndex in pairs( g_cityBanners ) do
RefreshCityBannerAtPlot( GetPlotByIndex( plotIndex ) )
end
end)
--------------------
-- On City Destroyed
Events.SerialEventCityDestroyed.Add(
function( hexPos ) --, cityOwnerID, cityID, newPlayerID )
local plot = GetPlot( ToGridFromHex( hexPos.x, hexPos.y ) )
if plot then
local plotIndex = plot:GetPlotIndex()
return DestroyCityBanner( plotIndex, g_cityBanners[ plotIndex ] )
end
end)
---------------------
-- On City Set Damage
Events.SerialEventCitySetDamage.Add( function( cityOwnerID, cityID, cityDamage, previousDamage )
local cityOwner = Players[ cityOwnerID ]
if cityOwner then
local city = cityOwner:GetCityByID( cityID )
if city then
return RefreshCityDamage( city, g_cityBanners[ city:Plot():GetPlotIndex() ], cityDamage )
end
end
end)
---------------------------
-- On Specific City changed
Events.SpecificCityInfoDirty.Add( function( cityOwnerID, cityID, updateType )
local cityOwner = Players[ cityOwnerID ]
if cityOwner then
local city = cityOwner:GetCityByID( cityID )
if city then
local plotIndex = city:Plot():GetPlotIndex()
local instance = g_cityBanners[ plotIndex ]
if instance then
if updateType == CityUpdateTypes.CITY_UPDATE_TYPE_ENEMY_IN_RANGE then
return UpdateRangeIcons( plotIndex, city, instance )
elseif updateType == CityUpdateTypes.CITY_UPDATE_TYPE_BANNER or updateType == CityUpdateTypes.CITY_UPDATE_TYPE_GARRISON then
return RefreshCityBanner( city )
end
end
end
end
end)
-------------------------
-- On Improvement Created
Events.SerialEventImprovementCreated.Add( function( hexX, hexY, cultureID, continentID, playerID )--, improvementID, rawResourceID, improvementEra, improvementState )
if playerID == g_activePlayerID then
local plot = GetPlot( ToGridFromHex( hexX, hexY ) )
if plot then
return RefreshCityBanner( plot:GetWorkingCity() )
end
end
end)
---------------------------
-- On Road/Railroad Created
Events.SerialEventRoadCreated.Add( function( hexX, hexY, playerID, roadID )
if playerID == g_activePlayerID then
for city in g_activePlayer:Cities() do
RefreshCityBanner( city )
end
end
end)
--[[
-----------------------
-- On city range strike
Events.InitCityRangeStrike.Add( function( cityOwnerID, cityID )
if cityOwnerID == g_activePlayerID then
local city = g_activePlayer:GetCityByID( cityID )
if city and city == UI.GetHeadSelectedCity() then
UI.SetInterfaceMode( InterfaceModeTypes.INTERFACEMODE_CITY_RANGE_ATTACK )
end
end
end)
--]]
-------------------
-- On Unit Garrison
Events.UnitGarrison.Add( function( unitOwnerID, unitID, isGarrisoned )
if isGarrisoned then
local unitOwner = Players[ unitOwnerID ]
if unitOwner then
local unit = unitOwner:GetUnitByID( unitID )
if unit then
local city = unit:GetGarrisonedCity()
if city then
return HideGarrisonFrame( g_cityBanners[ city:Plot():GetPlotIndex() ], UnitMoving( unitOwnerID, unitID ) )
end
end
end
end
end)
-----------------------------
-- On Unit Move Queue Changed
Events.UnitMoveQueueChanged.Add( function( unitOwnerID, unitID, hasRemainingMoves )
local unitOwner = Players[ unitOwnerID ]
if unitOwner then
local unit = unitOwner:GetUnitByID( unitID )
if unit then
local city = unit:GetGarrisonedCity()
if city then
return HideGarrisonFrame( g_cityBanners[ city:Plot():GetPlotIndex() ], not hasRemainingMoves )
end
end
end
end)
--[[
---------------------------
-- On interface mode change
Events.InterfaceModeChanged.Add( function( oldInterfaceMode, newInterfaceMode )
local disableBanners = newInterfaceMode ~= InterfaceModeTypes.INTERFACEMODE_SELECTION
for _, instance in pairs( g_cityBanners ) do
instance.CityBannerButton:SetDisabled( disableBanners )
instance.CityBannerButton:EnableToolTip( not disableBanners )
end
end)
--]]
---------------------------
-- On strategic view change
Events.StrategicViewStateChanged.Add( function(isStrategicView, showCityBanners)
local showBanners = showCityBanners or not isStrategicView
Controls.CityBanners:SetHide( not showBanners )
return Controls.StrategicViewStrikeButtons:SetHide( showBanners )
end)
-----------------------
-- On fog of war change
Events.HexFOWStateChanged.Add( function( hexPos, fowType, isWholeMap )
if isWholeMap then
-- fowState 0 is invisible
if fowType == 0 then
for plotIndex, instance in pairs( g_cityBanners ) do
DestroyCityBanner( plotIndex, instance )
end
else
for playerID = 0, #Players do
local player = Players[ playerID ]
if player and player:IsAlive() then
for city in player:Cities() do
RefreshCityBanner( city )
end
end
end
end
else
local plot = GetPlot( ToGridFromHex( hexPos.x, hexPos.y ) )
if plot then
-- fowType 0 is invisible
if fowType == 0 then
local plotIndex = plot:GetPlotIndex()
return DestroyCityBanner( plotIndex, g_cityBanners[ plotIndex ] )
else
return RefreshCityBannerAtPlot( plot )
end
end
end
end)
---------------------------
-- On War Declared
Events.WarStateChanged.Add(
function( teamID1, teamID2, isAtWar )
if teamID1 == g_activeTeamID then
teamID1 = teamID2
elseif teamID2 ~= g_activeTeamID then
return
end
for playerID = 0, #Players do
local player = Players[playerID]
if player and player:IsAlive() and player:GetTeam() == teamID1 then
for city in player:Cities() do
if city:Plot():IsRevealed( g_activeTeamID, true ) then
RefreshCityBanner( city )
end
end
end
end
end)
--==========================================================
-- 'Active' (local human) player has changed:
-- Check for City Banner Active Type change
--==========================================================
Events.GameplaySetActivePlayer.Add( function( activePlayerID, previousActivePlayerID )
-- update globals
g_activePlayerID = Game.GetActivePlayer()
g_activePlayer = Players[ g_activePlayerID ]
g_activeTeamID = Game.GetActiveTeam()
g_activeTeam = Teams[ g_activeTeamID ]
ClearHexHighlights()
local isDebug = Game.IsDebugMode() or g_activePlayer:IsObserver()
-- Update all city banners
for playerID = 0, #Players do
local player = Players[ playerID ]
if player and player:IsAlive() then
for city in player:Cities() do
local plot = city:Plot()
local plotIndex = plot:GetPlotIndex()
local instance = g_cityBanners[ plotIndex ]
if plot:IsRevealed( g_activeTeamID, isDebug ) then
RefreshCityBanner( city )
-- If city banner is hidden, destroy the banner
elseif instance then
DestroyCityBanner( plotIndex, instance )
end
end
end
end
end)
--==========================================================
-- Hide Garrisson Ring during Animated Combat
--==========================================================
if gk_mode then
local function HideGarrisonRing( x, y, hideGarrisonRing )
local plot = GetPlot( x, y )
local city = plot and plot:GetPlotCity()
local instance = city and g_cityBanners[ plot:GetPlotIndex() ]
return instance and HideGarrisonFrame( instance, hideGarrisonRing or not city:GetGarrisonedUnit() )
end
Events.RunCombatSim.Add( function(
attackerPlayerID,
attackerUnitID,
attackerUnitDamage,
attackerFinalUnitDamage,
attackerMaxHitPoints,
defenderPlayerID,
defenderUnitID,
defenderUnitDamage,
defenderFinalUnitDamage,
defenderMaxHitPoints,
attackerX,
attackerY,
defenderX,
defenderY,
bContinuation)
--print( "CityBanner CombatBegin", attackerX, attackerY, defenderX, defenderY )
HideGarrisonRing(attackerX, attackerY, true)
HideGarrisonRing(defenderX, defenderY, true)
end)
Events.EndCombatSim.Add( function(
attackerPlayerID,
attackerUnitID,
attackerUnitDamage,
attackerFinalUnitDamage,
attackerMaxHitPoints,
defenderPlayerID,
defenderUnitID,
defenderUnitDamage,
defenderFinalUnitDamage,
defenderMaxHitPoints,
attackerX,
attackerY,
defenderX,
defenderY )
--print( "CityBanner CombatEnd", attackerX, attackerY, defenderX, defenderY )
HideGarrisonRing(attackerX, attackerY, false)
HideGarrisonRing(defenderX, defenderY, false)
end)
end -- gk_mode
--==========================================================
-- The active player's turn has begun, make sure their range strike icons are correct
--==========================================================
Events.ActivePlayerTurnStart.Add( function()
for plotIndex, instance in pairs( g_cityBanners ) do
UpdateRangeIcons( plotIndex, GetPlotByIndex( plotIndex ):GetPlotCity(), instance )
end
end)
Events.SerialEventUnitDestroyed.Add( function( unitOwnerID, unitID )
local unitOwner = Players[ unitOwnerID ]
if unitOwner and g_activeTeam:IsAtWar( unitOwner:GetTeam() ) then
for city in g_activePlayer:Cities() do
local plotIndex = city:Plot():GetPlotIndex()
UpdateRangeIcons( plotIndex, city, g_cityBanners[ plotIndex ] )
end
end
end)
--==========================================================
-- Initialize all Visible City Banners
--==========================================================
for playerID = 0, #Players do
local player = Players[ playerID ]
if player and player:IsEverAlive() then
for city in player:Cities() do
if city:Plot():IsRevealed( g_activeTeamID, true ) then
RefreshCityBanner( city )
end
end
end
end
end)
--==========================================================
-- City View
-- Re-written by bc1 using Notepad++
-- code is common using switches
-- compatible with Gazebo's City-State Diplomacy Mod (CSD) for Brave New World v21
-- compatible with JFD's Piety & Prestige for Brave New World
-- compatible with GameInfo.Yields() iterator broken by Communitas
--todo: upper left corner
--todo: selection list with all buildable items
--todo: mod case where several buildings are allowed
--==========================================================
Events.SequenceGameInitComplete.Add(function()
local IsCiv5 = InStrategicView ~= nil
local IsCivBE = not IsCiv5
local IsCiv5vanilla = IsCiv5 and not Game.GetReligionName
local IsCiv5BNW = IsCiv5 and Game.GetActiveLeague ~= nil
include "UserInterfaceSettings"
local UserInterfaceSettings = UserInterfaceSettings
include "GameInfoCache" -- warning! booleans are true, not 1, and use iterator ONLY with table field conditions, NOT string SQL query
local GameInfo = GameInfoCache
include "IconHookup"
local IconHookup = IconHookup
local CivIconHookup = CivIconHookup
local ColorCulture = Color( 1, 0, 1, 1 )
include "StackInstanceManager"
local StackInstanceManager = StackInstanceManager
include "ShowProgress"
local ShowProgress = ShowProgress
include "SupportFunctions"
local TruncateString = TruncateString
if IsCiv5BNW then
include "GreatPeopleIcons"
end
local GreatPeopleIcons = GreatPeopleIcons
if IsCivBE then
include "IntrigueHelper"
end
--==========================================================
-- Minor lua optimizations
--==========================================================
local ipairs = ipairs
local abs = math.abs
local ceil = math.ceil
local floor = math.floor
local max = math.max
local min = math.min
local sqrt = math.sqrt
local pairs = pairs
local tonumber = tonumber
local tostring = tostring
local unpack = unpack
local concat = table.concat
local insert = table.insert
local sort = table.sort
local ButtonPopupTypes = ButtonPopupTypes
local CityAIFocusTypes = CityAIFocusTypes
local CityUpdateTypes = CityUpdateTypes
local ContextPtr = ContextPtr
local Controls = Controls
local Events = Events
local EventsClearHexHighlightStyle = Events.ClearHexHighlightStyle.Call
local EventsRequestYieldDisplay = Events.RequestYieldDisplay.Call
local EventsSerialEventHexHighlight = Events.SerialEventHexHighlight.Call
local Game = Game
local GameDefines = GameDefines
local GameInfoTypes = GameInfoTypes
local GameMessageTypes = GameMessageTypes
local GameOptionTypes = GameOptionTypes
local HexToWorld = HexToWorld
local InStrategicView = InStrategicView or function() return false end
local KeyEvents = KeyEvents
local Keys = Keys
local L = Locale.ConvertTextKey
local Locale = Locale
local eLClick = Mouse.eLClick
local eRClick = Mouse.eRClick
local eMouseEnter = Mouse.eMouseEnter
local Network = Network
local NotificationTypes = NotificationTypes
local OptionsManager = OptionsManager
local Players = Players
local PopupPriority = PopupPriority
local TaskTypes = TaskTypes
local ToHexFromGrid = ToHexFromGrid
local UI = UI
local GetHeadSelectedCity = UI.GetHeadSelectedCity
local GetUnitPortraitIcon = UI.GetUnitPortraitIcon
local YieldDisplayTypesAREA = YieldDisplayTypes.AREA
local YieldTypes = YieldTypes
local ORDER_TRAIN = OrderTypes.ORDER_TRAIN
local ORDER_CONSTRUCT = OrderTypes.ORDER_CONSTRUCT
local ORDER_CREATE = OrderTypes.ORDER_CREATE
local ORDER_MAINTAIN = OrderTypes.ORDER_MAINTAIN
--==========================================================
-- Globals
--==========================================================
local g_currencyIcon = IsCiv5 and "[ICON_GOLD]" or "[ICON_ENERGY]"
local g_maintenanceCurrency = IsCiv5 and "GoldMaintenance" or "EnergyMaintenance"
local g_yieldCurrency = IsCiv5 and YieldTypes.YIELD_GOLD or YieldTypes.YIELD_ENERGY
local g_isAdvisor = true
local g_activePlayerID = Game.GetActivePlayer()
local g_activePlayer = Players[ g_activePlayerID ]
local g_finishedItems = {}
local g_workerHeadingOpen = OptionsManager.IsNoCitizenWarning()
local g_worldPositionOffset = { x = 0, y = 0, z = 30 }
local g_worldPositionOffset2 = { x = 0, y = 35, z = 0 }
local g_portraitSize = Controls.PQportrait:GetSizeX()
local g_screenHeight = select(2, UIManager.GetScreenSizeVal() )
local g_leftStackHeigth = g_screenHeight - 40 - Controls.CityInfoBG:GetOffsetY() - Controls.CityInfoBG:GetSizeY()
local g_PlotButtonIM = StackInstanceManager( "PlotButtonInstance", "PlotButtonAnchor", Controls.PlotButtonContainer )
local g_BuyPlotButtonIM = StackInstanceManager( "BuyPlotButtonInstance", "BuyPlotButtonAnchor", Controls.PlotButtonContainer )
local g_GreatWorksIM = StackInstanceManager( "Work", "Button", false )
local g_SpecialistsIM = StackInstanceManager( "Slot", "Button", false )
local g_ProdQueueIM, g_SpecialBuildingsIM, g_GreatWorkIM, g_WondersIM, g_BuildingsIM, g_GreatPeopleIM, g_SlackerIM, g_UnitSelectIM, g_BuildingSelectIM, g_WonderSelectIM, g_ProcessSelectIM, g_FocusSelectIM
local g_queuedItemNumber, g_isDebugMode, g_BuyPlotMode, g_previousCity, g_isButtonPopupChooseProduction, g_isScreenAutoClose, g_isResetCityPlotPurchase
local g_citySpecialists = {}
local g_isViewingMode = true
local g_slotTexture = {
SPECIALIST_CITIZEN = "CitizenUnemployed.dds",
SPECIALIST_SCIENTIST = "CitizenScientist.dds",
SPECIALIST_MERCHANT = "CitizenMerchant.dds",
SPECIALIST_ARTIST = "CitizenArtist.dds",
SPECIALIST_MUSICIAN = "CitizenArtist.dds",
SPECIALIST_WRITER = "CitizenArtist.dds",
SPECIALIST_ENGINEER = "CitizenEngineer.dds",
SPECIALIST_CIVIL_SERVANT = "CitizenCivilServant.dds", -- Compatibility with Gazebo's City-State Diplomacy Mod (CSD) for Brave New World
SPECIALIST_JFD_MONK = "CitizenMonk.dds", -- Compatibility with JFD's Piety & Prestige for Brave New World
SPECIALIST_PMMM_ENTERTAINER = "PMMMEntertainmentSpecialist.dds", --Compatibility with Vicevirtuoso's Madoka Magica: Wish for the World for Brave New World
}
for specialist in GameInfo.Specialists() do
if specialist.SlotTexture then
g_slotTexture[ specialist.Type ] = specialist.SlotTexture
end
end
local g_slackerTexture = IsCivBE and "UnemployedIndicator.dds" or g_slotTexture[ (GameInfo.Specialists[GameDefines.DEFAULT_SPECIALIST] or {}).Type ]
local g_gameInfo = {
[ORDER_TRAIN] = GameInfo.Units,
[ORDER_CONSTRUCT] = GameInfo.Buildings,
[ORDER_CREATE] = GameInfo.Projects,
[ORDER_MAINTAIN] = GameInfo.Processes,
}
local g_avisorRecommended = {
[ORDER_TRAIN] = Game.IsUnitRecommended,
[ORDER_CONSTRUCT] = Game.IsBuildingRecommended,
[ORDER_CREATE] = Game.IsProjectRecommended,
}
local g_advisors = {
[AdvisorTypes.ADVISOR_ECONOMIC] = "EconomicRecommendation",
[AdvisorTypes.ADVISOR_MILITARY] = "MilitaryRecommendation",
[AdvisorTypes.ADVISOR_SCIENCE] = "ScienceRecommendation",
[AdvisorTypes.ADVISOR_FOREIGN] = "ForeignRecommendation",
}
local function GetSelectedCity()
return ( not Game.IsNetworkMultiPlayer() or g_activePlayer:IsTurnActive() ) and GetHeadSelectedCity()
end
local function GetSelectedModifiableCity()
return not g_isViewingMode and GetSelectedCity()
end
----------------
-- Citizen Focus
local g_cityFocusButtons = {
a = Controls.AvoidGrowthButton,
b = Controls.ResetButton,
c = Controls.BoxOSlackers,
d = Controls.EditButton,
}
do
local g_cityFocusControls = {
[ Controls.BalancedFocusButton or -1 ] = CityAIFocusTypes.NO_CITY_AI_FOCUS_TYPE or false,
[ Controls.FoodFocusButton or -1 ] = CityAIFocusTypes.CITY_AI_FOCUS_TYPE_FOOD or false,
[ Controls.ProductionFocusButton or -1 ] = CityAIFocusTypes.CITY_AI_FOCUS_TYPE_PRODUCTION or false,
[ Controls.GoldFocusButton or -1 ] = CityAIFocusTypes.CITY_AI_FOCUS_TYPE_GOLD or CityAIFocusTypes.CITY_AI_FOCUS_TYPE_ENERGY or false,
[ Controls.ResearchFocusButton or -1 ] = CityAIFocusTypes.CITY_AI_FOCUS_TYPE_SCIENCE or false,
[ Controls.CultureFocusButton or -1 ] = CityAIFocusTypes.CITY_AI_FOCUS_TYPE_CULTURE or false,
[ Controls.GPFocusButton or -1 ] = CityAIFocusTypes.CITY_AI_FOCUS_TYPE_GREAT_PEOPLE or false,
[ Controls.FaithFocusButton or -1 ] = CityAIFocusTypes.CITY_AI_FOCUS_TYPE_FAITH or false,
} g_cityFocusControls[-1] = nil
local function FocusButtonBehavior( focus )
local city = GetSelectedModifiableCity()
if city then
Network.SendSetCityAIFocus( city:GetID(), focus )
return Network.SendUpdateCityCitizens( city:GetID() )
end
end
for control, focus in pairs( g_cityFocusControls ) do
if focus then
g_cityFocusButtons[ focus ] = control
control:SetVoid1( focus )
control:RegisterCallback( eLClick, FocusButtonBehavior )
else
control:SetHide( true )
end
end
end
local function HexRadius( a )
return ( sqrt( 1 + 4*a/3 ) - 1 ) / 2
end
local function SetupCallbacks( controls, toolTips, tootTipType, callBacks )
local control
-- Setup Tootips
for name, callback in pairs( toolTips ) do
control = controls[name]
if control then
control:SetToolTipCallback( callback )
control:SetToolTipType( tootTipType )
end
end
-- Setup Callbacks
for name, eventCallbacks in pairs( callBacks ) do
control = controls[name]
if control then
for event, callback in pairs( eventCallbacks ) do
control:RegisterCallback( event, callback )
end
end
end
end
local function ResizeProdQueue()
local selectionPanelHeight = 0
local queuePanelHeight = min( 190, Controls.QueueStack:IsHidden() and 0 or Controls.QueueStack:GetSizeY() ) -- 190 = 5 x 38=instance height
if not Controls.SelectionScrollPanel:IsHidden() then
Controls.SelectionStacks:CalculateSize()
selectionPanelHeight = max( min( g_leftStackHeigth - queuePanelHeight, Controls.SelectionStacks:GetSizeY() ), 64 )
-- Controls.SelectionBackground:SetSizeY( selectionPanelHeight + 85 )
Controls.SelectionScrollPanel:SetSizeY( selectionPanelHeight )
Controls.SelectionScrollPanel:CalculateInternalSize()
Controls.SelectionScrollPanel:ReprocessAnchoring()
end
Controls.QueueSlider:SetSizeY( queuePanelHeight + 38 ) -- 38 = Controls.PQbox:GetSizeY()
Controls.QueueScrollPanel:SetSizeY( queuePanelHeight )
Controls.QueueScrollPanel:CalculateInternalSize()
Controls.QueueBackground:SetSizeY( queuePanelHeight + selectionPanelHeight + 152 ) -- 125 = 38=Controls.PQbox:GetSizeY() + 87 + 27
return Controls.QueueBackground:ReprocessAnchoring()
end
local function ResizeRightStack()
Controls.BoxOSlackers:SetHide( Controls.SlackerStack:IsHidden() )
Controls.BoxOSlackers:SetSizeY( Controls.SlackerStack:GetSizeY() )
Controls.WorkerManagementBox:CalculateSize()
Controls.WorkerManagementBox:ReprocessAnchoring()
Controls.RightStack:CalculateSize()
local rightStackHeight = Controls.RightStack:GetSizeY() + 85
Controls.BuildingListBackground:SetSizeY( max( min( g_screenHeight + 48, rightStackHeight ), 160 ) )
Controls.RightScrollPanel:SetSizeY( min( g_screenHeight - 38, rightStackHeight ) )
Controls.RightScrollPanel:CalculateInternalSize()
return Controls.RightScrollPanel:ReprocessAnchoring()
end
local cityIsCanPurchase
if IsCiv5vanilla then
function cityIsCanPurchase( city, bTestPurchaseCost, bTestTrainable, unitID, buildingID, projectID, yieldID )
if yieldID == g_yieldCurrency then
return city:IsCanPurchase( not bTestPurchaseCost, unitID, buildingID, projectID )
-- bOnlyTestVisible
else
return false
end
end
else
function cityIsCanPurchase( city, ... )
return city:IsCanPurchase( ... )
end
end
--==========================================================
-- Clear out the UI so that when a player changes
-- the next update doesn't show the previous player's
-- values for a frame
--==========================================================
local function ClearCityUIInfo()
g_ProdQueueIM:ResetInstances()
g_ProdQueueIM.Commit()
Controls.PQremove:SetHide( true )
Controls.PQrank:SetText()
Controls.PQname:SetText()
Controls.PQturns:SetText()
return Controls.ProductionPortraitButton:SetHide(true)
end
--==========================================================
-- Selling Buildings
--==========================================================
local function SellBuilding( buildingID )
local city = GetSelectedModifiableCity()
local building = GameInfo.Buildings[ buildingID ]
-- Can this building be sold?
if building and city and city:IsBuildingSellable( buildingID ) then
Controls.YesButton:SetVoids( city:GetID(), buildingID )
Controls.SellBuildingTitle:SetText( building._Name:upper() )
Controls.SellBuildingText:LocalizeAndSetText( "TXT_KEY_SELL_BUILDING_INFO", city:GetSellBuildingRefund(buildingID), building[g_maintenanceCurrency] or 0 )
Controls.SellBuildingImage:SetHide( not IconHookup( building.PortraitIndex, 256, building.IconAtlas, Controls.SellBuildingImage ) )
Controls.SellBuildingStack:CalculateSize()
Controls.SellBuildingFrame:DoAutoSize()
--todo energy
return Controls.SellBuildingConfirm:SetHide( false )
end
end
local function CancelBuildingSale()
Controls.SellBuildingConfirm:SetHide(true)
return Controls.YesButton:SetVoids( -1, -1 )
end
local function CleanupCityScreen()
-- clear any rogue leftover tooltip
g_isButtonPopupChooseProduction = false
Controls.RightScrollPanel:SetScrollValue(0)
return CancelBuildingSale()
end
local function GotoNextCity()
if not g_isViewingMode then
CleanupCityScreen()
return Game.DoControl( GameInfoTypes.CONTROL_NEXTCITY )
end
end
local function GotoPrevCity()
if not g_isViewingMode then
CleanupCityScreen()
return Game.DoControl( GameInfoTypes.CONTROL_PREVCITY )
end
end
local function ExitCityScreen()
--print("request exit city screen")
-- CleanupCityScreen()
return Events.SerialEventExitCityScreen()
end
--==========================================================
-- Key Down Processing
--==========================================================
do
local VK_RETURN = Keys.VK_RETURN
local VK_ESCAPE = Keys.VK_ESCAPE
local VK_LEFT = Keys.VK_LEFT
local VK_RIGHT = Keys.VK_RIGHT
local KeyDown = KeyEvents.KeyDown
ContextPtr:SetInputHandler( function ( uiMsg, wParam )
if uiMsg == KeyDown then
if wParam == VK_ESCAPE or wParam == VK_RETURN then
if Controls.SellBuildingConfirm:IsHidden() then
ExitCityScreen()
else
CancelBuildingSale()
end
return true
elseif wParam == VK_LEFT then
GotoPrevCity()
return true
elseif wParam == VK_RIGHT then
GotoNextCity()
return true
end
end
end)
end
--==========================================================
-- Pedia
--==========================================================
local SearchForPediaEntry = Events.SearchForPediaEntry.Call
local function Pedia( row )
return SearchForPediaEntry( row and row._Name )
end
local function UnitClassPedia( unitClassID )
return Pedia( GameInfo.UnitClasses[ unitClassID ] )
end
local function BuildingPedia( buildingID )
return Pedia( GameInfo.Buildings[ buildingID ] )
end
local function SpecialistPedia( buildingID )
return Pedia( GameInfo.Specialists[ GameInfoTypes[(GameInfo.Buildings[buildingID]or{}).SpecialistType] or GameDefines.DEFAULT_SPECIALIST ] )
end
local function SelectionPedia( orderID, itemID )
return Pedia( (g_gameInfo[ orderID ]or{})[ itemID ] )
end
local function ProductionPedia( queuedItemNumber )
local city = GetHeadSelectedCity()
if city and queuedItemNumber then
return SelectionPedia( city:GetOrderFromQueue( queuedItemNumber ) )
end
end
--==========================================================
-- Tooltips
--==========================================================
local GreatPeopleIcon = GreatPeopleIcons and function (k)
return GreatPeopleIcons[k]
end or function()
return "[ICON_GREAT_PEOPLE]"
end
local function GetSpecialistYields( city, specialist )
local yieldTips = {}
if city and specialist then
local specialistYield, specialistYieldModifier, yieldInfo
local specialistID = specialist.ID
local cityOwner = Players[ city:GetOwner() ]
-- Culture
local cultureFromSpecialist = city:GetCultureFromSpecialist( specialistID )
local specialistCultureModifier = city:GetCultureRateModifier() + ( cityOwner and ( cityOwner:GetCultureCityModifier() + ( city:GetNumWorldWonders() > 0 and cityOwner:GetCultureWonderMultiplier() or 0 ) or 0 ) )
-- Yield
for yieldID = 0, YieldTypes.NUM_YIELD_TYPES-1 do
yieldInfo = GameInfo.Yields[yieldID]
if yieldInfo then
specialistYield = city:GetSpecialistYield( specialistID, yieldID )
specialistYieldModifier = city:GetBaseYieldRateModifier( yieldID )
if yieldID == YieldTypes.YIELD_CULTURE then
specialistYield = specialistYield + cultureFromSpecialist
specialistYieldModifier = specialistYieldModifier + specialistCultureModifier
cultureFromSpecialist = 0
end
if specialistYield ~= 0 then
insert( yieldTips, specialistYield * specialistYieldModifier / 100 .. yieldInfo.IconString )
end
end
end
if cultureFromSpecialist ~= 0 then
insert( yieldTips, cultureFromSpecialist .. "[ICON_CULTURE]" )
end
if IsCiv5 and (specialist.GreatPeopleRateChange or 0) ~= 0 then
insert( yieldTips, specialist.GreatPeopleRateChange .. GreatPeopleIcon( specialist.Type ) )
end
end
return concat( yieldTips, " " )
end
local ShowTextToolTipAndPicture = LuaEvents.ShowTextToolTipAndPicture.Call
local BuildingToolTip = LuaEvents.CityViewBuildingToolTip.Call
local CityOrderItemTooltip = LuaEvents.CityOrderItemTooltip.Call
local function SpecialistTooltip( control )
local buildingID = control:GetVoid1()
local building = GameInfo.Buildings[ buildingID ]
local specialistType = building and building.SpecialistType
local specialistID = specialistType and GameInfoTypes[specialistType] or GameDefines.DEFAULT_SPECIALIST
local specialist = GameInfo.Specialists[ specialistID ]
local tip = specialist._Name .. " " .. GetSpecialistYields( GetHeadSelectedCity(), specialist )
local slotTable = building and g_citySpecialists[buildingID]
if slotTable and not slotTable[control:GetVoid2()] then
tip = L"TXT_KEY_CITYVIEW_EMPTY_SLOT".."[NEWLINE]("..tip..")"
end
return ShowTextToolTipAndPicture( tip, specialist.PortraitIndex, specialist.IconAtlas )
end
local function ProductionToolTip( control )
local city = GetHeadSelectedCity()
local queuedItemNumber = control:GetVoid1()
if city and not Controls.QueueSlider:IsTrackingLeftMouseButton() then
return CityOrderItemTooltip( city, false, false, city:GetOrderFromQueue( queuedItemNumber ) )
end
end
--==========================================================
-- Specialist Managemeent
--==========================================================
local function OnSlackersSelected( buildingID, slotID )
local city = GetSelectedModifiableCity()
if city then
for _=1, slotID<=0 and city:GetSpecialistCount( GameDefines.DEFAULT_SPECIALIST ) or 1 do
Network.SendDoTask( city:GetID(), TaskTypes.TASK_REMOVE_SLACKER, 0, -1, false )
end
end
end
local function ToggleSpecialist( buildingID, slotID )
local city = buildingID and slotID and GetSelectedModifiableCity()
if city then
-- If Specialists are automated then you can't change things with them
if IsCiv5 and not city:IsNoAutoAssignSpecialists() then
Game.SelectedCitiesGameNetMessage(GameMessageTypes.GAMEMESSAGE_DO_TASK, TaskTypes.TASK_NO_AUTO_ASSIGN_SPECIALISTS, -1, -1, true)
Controls.NoAutoSpecialistCheckbox:SetCheck(true)
if IsCiv5BNW then
Controls.NoAutoSpecialistCheckbox2:SetCheck(true)
end
end
local specialistID = GameInfoTypes[(GameInfo.Buildings[ buildingID ] or {}).SpecialistType] or -1
local specialistTable = g_citySpecialists[buildingID]
if specialistTable[slotID] then
if city:GetNumSpecialistsInBuilding(buildingID) > 0 then
specialistTable[slotID] = false
specialistTable.n = specialistTable.n - 1
return Game.SelectedCitiesGameNetMessage( GameMessageTypes.GAMEMESSAGE_DO_TASK, TaskTypes.TASK_REMOVE_SPECIALIST, specialistID, buildingID )
end
elseif city:IsCanAddSpecialistToBuilding(buildingID) then
specialistTable[slotID] = true
specialistTable.n = specialistTable.n + 1
return Game.SelectedCitiesGameNetMessage( GameMessageTypes.GAMEMESSAGE_DO_TASK, TaskTypes.TASK_ADD_SPECIALIST, specialistID, buildingID )
end
end
end
--==========================================================
-- Great Work Managemeent
--==========================================================
local function GreatWorkPopup( greatWorkID )
local greatWork = GameInfo.GreatWorks[ Game.GetGreatWorkType( greatWorkID or -1 ) or -1 ]
if greatWork and greatWork.GreatWorkClassType ~= "GREAT_WORK_ARTIFACT" then
return Events.SerialEventGameMessagePopup{
Type = ButtonPopupTypes.BUTTONPOPUP_GREAT_WORK_COMPLETED_ACTIVE_PLAYER,
Data1 = greatWorkID,
Priority = PopupPriority.Current
}
end
end
local function YourCulturePopup( greatWorkID )
return Events.SerialEventGameMessagePopup{
Type = ButtonPopupTypes.BUTTONPOPUP_CULTURE_OVERVIEW,
Data1 = 1,
Data2 = 1,
}
end
local function ThemingTooltip( buildingClassID, _, control )
control:SetToolTipString( GetHeadSelectedCity():GetThemingTooltip( buildingClassID ) )
end
local function GreatWorkTooltip( greatWorkID, greatWorkSlotID, slot )
if greatWorkID >= 0 then
return slot:SetToolTipString( Game.GetGreatWorkTooltip( greatWorkID, GetHeadSelectedCity():GetOwner() ) )
else
return slot:LocalizeAndSetToolTip( tostring(( GameInfo.GreatWorkSlots[ greatWorkSlotID ] or {}).EmptyToolTipText) )
end
end
--==========================================================
-- City Buildings List
--==========================================================
local function sortBuildings(a,b)
if a and b then
if a[4] ~= b[4] then
return a[4] < b[4]
elseif a[3] ~= b[3] then
return a[3] > b[3]
end
return a[2] < b[2]
end
end
local function SetupBuildingList( city, buildings, buildingIM )
buildingIM:ResetInstances()
sort( buildings, sortBuildings )
local cityOwnerID = city:GetOwner()
local cityOwner = Players[ cityOwnerID ]
local isNotResistance = not city:IsResistance()
-- Get the active perk types for civ BE
local cityOwnerPerks = IsCivBE and cityOwner:GetAllActivePlayerPerkTypes()
local building, buildingID, buildingClassID, buildingName, greatWorkCount, greatWorkID, slotStack, slot, new, instance, buildingButton, sellButton, textButton
for i = 1, #buildings do
building, buildingName, greatWorkCount = unpack(buildings[i])
buildingID = building.ID
buildingClassID = GameInfoTypes[ building.BuildingClass ] or -1
instance, new = buildingIM:GetInstance()
slotStack = instance.SlotStack
buildingButton = instance.Button
sellButton = instance.SellButton
textButton = instance.TextButton
textButton:SetHide( true )
if new then
buildingButton:RegisterCallback( eRClick, BuildingPedia )
buildingButton:SetToolTipCallback( BuildingToolTip )
sellButton:RegisterCallback( eLClick, SellBuilding )
textButton:RegisterCallback( eLClick, YourCulturePopup )
textButton:RegisterCallback( eMouseEnter, ThemingTooltip )
end
buildingButton:SetVoid1( buildingID )
-- Can we sell this building?
if not g_isViewingMode and city:IsBuildingSellable( buildingID ) then
sellButton:SetText( city:GetSellBuildingRefund( buildingID ) .. g_currencyIcon )
sellButton:SetHide( false )
sellButton:SetVoid1( buildingID )
else
sellButton:SetHide( true )
end
--!!!BE portrait size is bigger
instance.Portrait:SetHide( not IconHookup( building.PortraitIndex, 64, building.IconAtlas, instance.Portrait ) )
-------------------
-- Great Work Slots
if greatWorkCount > 0 then
local buildingGreatWorkSlotType = building.GreatWorkSlotType
if buildingGreatWorkSlotType then
local buildingGreatWorkSlot = GameInfo.GreatWorkSlots[ buildingGreatWorkSlotType ]
if city:IsThemingBonusPossible( buildingClassID ) then
textButton:SetText( " +" .. city:GetThemingBonus( buildingClassID ) )
textButton:SetVoid1( buildingClassID )
textButton:SetHide( false )
end
for i = 0, greatWorkCount - 1 do
slot, new = g_GreatWorksIM:GetInstance( slotStack )
slot = slot.Button
if new then
slot:RegisterCallback( eLClick, YourCulturePopup )
slot:RegisterCallback( eMouseEnter, GreatWorkTooltip )
end
greatWorkID = city:GetBuildingGreatWork( buildingClassID, i )
slot:SetVoids( greatWorkID, buildingGreatWorkSlot.ID )
if greatWorkID >= 0 then
slot:SetTexture( buildingGreatWorkSlot.FilledIcon )
slot:RegisterCallback( eRClick, GreatWorkPopup )
else
slot:SetTexture( buildingGreatWorkSlot.EmptyIcon )
slot:ClearCallback( eRClick )
end
end
end
end
-------------------
-- Specialist Slots
local numSpecialistsInBuilding = city:GetNumSpecialistsInBuilding( buildingID )
local specialistTable = g_citySpecialists[buildingID] or {}
if specialistTable.n ~= numSpecialistsInBuilding then
specialistTable = { n = numSpecialistsInBuilding }
for i = 1, numSpecialistsInBuilding do
specialistTable[i] = true
end
g_citySpecialists[buildingID] = specialistTable
end
local specialistType = building.SpecialistType
local specialist = GameInfo.Specialists[specialistType]
if specialist then
for slotID = 1, city:GetNumSpecialistsAllowedByBuilding( buildingID ) do
slot, new = g_SpecialistsIM:GetInstance( slotStack )
slot = slot.Button
if new then
slot:RegisterCallback( eRClick, SpecialistPedia )
slot:SetToolTipCallback( SpecialistTooltip )
end
if IsCiv5 then
slot:SetTexture( specialistTable[ slotID ] and g_slotTexture[ specialistType ] or "CitizenEmpty.dds" )
else
-- todo (does not look right)
IconHookup( specialist.PortraitIndex, 45, specialist.IconAtlas, slot )
slot:SetHide( not specialistTable[ slotID ] )
end
slot:SetVoids( buildingID, slotID )
if g_isViewingMode then
slot:ClearCallback( eLClick )
else
slot:RegisterCallback( eLClick, ToggleSpecialist )
end
end -- Specialist Slots
end
-- Building stats/bonuses
local maintenanceCost = tonumber(building[g_maintenanceCurrency]) or 0
local defenseChange = tonumber(building.Defense) or 0
local hitPointChange = tonumber(building.ExtraCityHitPoints) or 0
local buildingCultureRate = (IsCiv5vanilla and tonumber(building.Culture) or 0) + (specialist and city:GetCultureFromSpecialist( specialist.ID ) or 0) * numSpecialistsInBuilding
local buildingCultureModifier = tonumber(building.CultureRateModifier) or 0
local cityCultureRateModifier = cityOwner:GetCultureCityModifier() + city:GetCultureRateModifier() + (city:GetNumWorldWonders() > 0 and cityOwner and cityOwner:GetCultureWonderMultiplier() or 0)
local cityCultureRate
local population = city:GetPopulation()
local tips = {}
local thisBuildingAndYieldTypes = { BuildingType = building.Type }
if IsCiv5 then
cityCultureRate = city:GetBaseJONSCulturePerTurn()
-- Happiness
local happinessChange = (tonumber(building.Happiness) or 0) + (tonumber(building.UnmoddedHappiness) or 0)
+ cityOwner:GetExtraBuildingHappinessFromPolicies( buildingID )
+ (cityOwner:IsHalfSpecialistUnhappiness() and GameDefines.UNHAPPINESS_PER_POPULATION * numSpecialistsInBuilding * ((city:IsCapital() and cityOwner:GetCapitalUnhappinessMod() or 0)+100) * (cityOwner:GetUnhappinessMod() + 100) * (cityOwner:GetTraitPopUnhappinessMod() + 100) / 2e6 or 0) -- missing getHandicapInfo().getPopulationUnhappinessMod()
if happinessChange ~=0 then
insert( tips, happinessChange .. "[ICON_HAPPINESS_1]" )
end
else -- IsCivBE
cityCultureRate = city:GetBaseCulturePerTurn()
-- Health
local healthChange = (tonumber(building.Health) or 0) + (tonumber(building.UnmoddedHealth) or 0) + cityOwner:GetExtraBuildingHealthFromPolicies( buildingID )
local healthModifier = tonumber(building.HealthModifier) or 0
-- Effect of player perks
for _, perkID in ipairs(cityOwnerPerks) do
healthChange = healthChange + Game.GetPlayerPerkBuildingClassPercentHealthChange( perkID, buildingClassID )
healthModifier = healthModifier + Game.GetPlayerPerkBuildingClassPercentHealthChange( perkID, buildingClassID )
defenseChange = defenseChange + Game.GetPlayerPerkBuildingClassCityStrengthChange( perkID, buildingClassID )
hitPointChange = hitPointChange + Game.GetPlayerPerkBuildingClassCityHPChange( perkID, buildingClassID )
maintenanceCost = maintenanceCost + Game.GetPlayerPerkBuildingClassEnergyMaintenanceChange( perkID, buildingClassID )
end
if healthChange ~=0 then
insert( tips, healthChange .. "[ICON_HEALTH_1]" )
end
-- if healthModifier~=0 then insert( tips, L( "TXT_KEY_STAT_POSITIVE_YIELD_MOD", "[ICON_HEALTH_1]", healthModifier ) ) end
end
local buildingYieldRate, buildingYieldPerPop, buildingYieldModifier, cityYieldRate, cityYieldRateModifier, isProducing, yieldInfo
for yieldID = 0, YieldTypes.NUM_YIELD_TYPES-1 do
yieldInfo = GameInfo.Yields[yieldID]
if yieldInfo then
isProducing = isNotResistance
thisBuildingAndYieldTypes.YieldType = yieldInfo.Type or -1
-- Yield changes from the building
buildingYieldRate = Game.GetBuildingYieldChange( buildingID, yieldID )
+ (not IsCiv5vanilla and cityOwner:GetPlayerBuildingClassYieldChange( buildingClassID, yieldID )
+ city:GetReligionBuildingClassYieldChange( buildingClassID, yieldID ) or 0)
+ (IsCiv5BNW and city:GetLeagueBuildingClassYieldChange( buildingClassID, yieldID ) or 0)
-- Yield modifiers from the building
buildingYieldModifier = Game.GetBuildingYieldModifier( buildingID, yieldID )
+ cityOwner:GetPolicyBuildingClassYieldModifier( buildingClassID, yieldID )
-- Effect of player perks
if IsCivBE then
for _, perkID in ipairs(cityOwnerPerks) do
buildingYieldRate = buildingYieldRate + Game.GetPlayerPerkBuildingClassFlatYieldChange( perkID, buildingClassID, yieldID )
buildingYieldModifier = buildingYieldModifier + Game.GetPlayerPerkBuildingClassPercentYieldChange( perkID, buildingClassID, yieldID )
end
end
-- Specialists yield
if specialist then
buildingYieldRate = buildingYieldRate + numSpecialistsInBuilding * city:GetSpecialistYield( specialist.ID, yieldID )
end
cityYieldRateModifier = city:GetBaseYieldRateModifier( yieldID )
cityYieldRate = city:GetYieldPerPopTimes100( yieldID ) * population / 100 + city:GetBaseYieldRate( yieldID )
-- Special culture case
if yieldID == YieldTypes.YIELD_CULTURE then
buildingYieldRate = buildingYieldRate + buildingCultureRate
buildingYieldModifier = buildingYieldModifier + buildingCultureModifier
cityYieldRateModifier = cityYieldRateModifier + cityCultureRateModifier
cityYieldRate = cityYieldRate + cityCultureRate
buildingCultureRate = 0
buildingCultureModifier = 0
elseif yieldID == YieldTypes.YIELD_FOOD then
local foodPerPop = GameDefines.FOOD_CONSUMPTION_PER_POPULATION
local foodConsumed = city:FoodConsumption()
buildingYieldRate = buildingYieldRate + (foodConsumed < foodPerPop * population and foodPerPop * numSpecialistsInBuilding / 2 or 0)
buildingYieldModifier = buildingYieldModifier + (tonumber(building.FoodKept) or 0)
cityYieldRate = city:FoodDifferenceTimes100() / 100 -- cityYieldRate - foodConsumed
cityYieldRateModifier = cityYieldRateModifier + city:GetMaxFoodKeptPercent()
isProducing = true
end
-- Population yield
buildingYieldPerPop = 0
for row in GameInfo.Building_YieldChangesPerPop( thisBuildingAndYieldTypes ) do
buildingYieldPerPop = buildingYieldPerPop + (row.Yield or 0)
end
buildingYieldRate = buildingYieldRate + buildingYieldPerPop * population / 100
buildingYieldRate = buildingYieldRate * cityYieldRateModifier + ( cityYieldRate - buildingYieldRate ) * buildingYieldModifier
if isProducing and buildingYieldRate ~= 0 then
insert( tips, buildingYieldRate / 100 .. yieldInfo.IconString )
end
end
end
-- Culture leftovers
buildingCultureRate = buildingCultureRate * (100+cityCultureRateModifier) + ( cityCultureRate - buildingCultureRate ) * buildingCultureModifier
if isNotResistance and buildingCultureRate ~=0 then
insert( tips, buildingCultureRate / 100 .. "[ICON_CULTURE]" )
end
-- TODO TOURISM
if IsCiv5BNW then
local tourism = ( ( (building.FaithCost or 0) > 0
and building.UnlockedByBelief
and building.Cost == -1
and city and city:GetFaithBuildingTourism()
) or 0 )
-- local enhancedYieldTechID = GameInfoTypes[ building.EnhancedYieldTech ]
tourism = tourism + (tonumber(building.TechEnhancedTourism) or 0)
if tourism ~= 0 then
insert( tips, tourism.."[ICON_TOURISM]" )
end
end
if IsCiv5 and building.IsReligious then
buildingName = L( "TXT_KEY_RELIGIOUS_BUILDING", buildingName, Players[city:GetOwner()]:GetStateReligionKey() )
end
if city:GetNumFreeBuilding( buildingID ) > 0 then
buildingName = buildingName .. " (" .. L"TXT_KEY_FREE" .. ")"
elseif maintenanceCost ~=0 then
insert( tips, -maintenanceCost .. g_currencyIcon )
end
instance.Name:SetText( buildingName )
if defenseChange ~=0 then
insert( tips, defenseChange / 100 .. "[ICON_STRENGTH]" )
end
if hitPointChange ~= 0 then
insert( tips, L( "TXT_KEY_PEDIA_DEFENSE_HITPOINTS", hitPointChange ) )
end
instance.Label:ChangeParent( instance.Stack )
instance.Label:SetText( concat( tips, " ") )
slotStack:CalculateSize()
if slotStack:GetSizeX() + instance.Label:GetSizeX() < 254 then
instance.Label:ChangeParent( slotStack )
end
instance.Stack:CalculateSize()
-- slotStack:ReprocessAnchoring()
-- instance.Stack:ReprocessAnchoring()
buildingButton:SetSizeY( max(64, instance.Stack:GetSizeY() + 16) )
end
return buildingIM.Commit()
end
--==========================================================
-- Production Selection List Management
--==========================================================
local function SelectionPurchase( orderID, itemID, yieldID, soundKey )
local city = GetHeadSelectedCity()
if city then
local cityOwnerID = city:GetOwner()
if cityOwnerID == g_activePlayerID
and ( not city:IsPuppet() or ( IsCiv5BNW and g_activePlayer:MayNotAnnex() ) )
----------- Venice exception -----------
then
local cityID = city:GetID()
local isPurchase
if orderID == ORDER_TRAIN then
if cityIsCanPurchase( city, true, true, itemID, -1, -1, yieldID ) then
Game.CityPurchaseUnit( city, itemID, yieldID )
isPurchase = true
end
elseif orderID == ORDER_CONSTRUCT then
if cityIsCanPurchase( city, true, true, -1, itemID, -1, yieldID ) then
Game.CityPurchaseBuilding( city, itemID, yieldID )
Network.SendUpdateCityCitizens( cityID )
isPurchase = true
end
elseif orderID == ORDER_CREATE then
if cityIsCanPurchase( city, true, true, -1, -1, itemID, yieldID ) then
Game.CityPurchaseProject( city, itemID, yieldID )
isPurchase = true
end
end
if isPurchase then
Events.SpecificCityInfoDirty( cityOwnerID, cityID, CityUpdateTypes.CITY_UPDATE_TYPE_BANNER )
Events.SpecificCityInfoDirty( cityOwnerID, cityID, CityUpdateTypes.CITY_UPDATE_TYPE_PRODUCTION )
if soundKey then
Events.AudioPlay2DSound( soundKey )
end
end
end
end
end
local function AddSelectionItem( city, item,
selectionList,
orderID,
cityCanProduce,
unitID, buildingID, projectID,
cityGetProductionTurnsLeft,
cityGetGoldCost,
cityGetFaithCost )
local itemID = item.ID
local name = item._Name
local turnsLeft = not g_isViewingMode and cityCanProduce( city, itemID, 0, 1 ) -- 0 = /continue, 1 = testvisible, nil = /ignore cost
local canProduce = not g_isViewingMode and cityCanProduce( city, itemID ) -- nil = /continue, nil = /testvisible, nil = /ignore cost
local canBuyWithGold, goldCost, canBuyWithFaith, faithCost
if unitID then
if IsCivBE then
local bestUpgradeInfo = GameInfo.UnitUpgrades[ g_activePlayer:GetBestUnitUpgrade(unitID) ]
name = bestUpgradeInfo and bestUpgradeInfo._Name or name
end
if cityGetGoldCost then
canBuyWithGold = cityIsCanPurchase( city, true, true, unitID, buildingID, projectID, g_yieldCurrency )
goldCost = cityIsCanPurchase( city, false, false, unitID, buildingID, projectID, g_yieldCurrency )
and cityGetGoldCost( city, itemID )
end
if cityGetFaithCost then
canBuyWithFaith = cityIsCanPurchase( city, true, true, unitID, buildingID, projectID, YieldTypes.YIELD_FAITH )
faithCost = cityIsCanPurchase( city, false, false, unitID, buildingID, projectID, YieldTypes.YIELD_FAITH )
and cityGetFaithCost( city, itemID, true )
end
end
if turnsLeft or goldCost or faithCost then --or (g_isDebugMode and not city:IsHasBuilding(buildingID)) then
turnsLeft = turnsLeft and ( cityGetProductionTurnsLeft and cityGetProductionTurnsLeft( city, itemID ) or -1 )
return insert( selectionList, { item, orderID, name, turnsLeft, canProduce, goldCost, canBuyWithGold, faithCost, canBuyWithFaith } )
end
end
local function SortSelectionList(a,b)
return a[3]<b[3]
end
local g_SelectionListCallBacks = {
Button = {
[eLClick] = function( orderID, itemID )
local city = GetSelectedModifiableCity()
if city then
local cityOwnerID = city:GetOwner()
if cityOwnerID == g_activePlayerID and not city:IsPuppet() then
-- cityPushOrder( city, orderID, itemID, bAlt, bShift, bCtrl )
-- cityPushOrder( city, orderID, itemID, repeatBuild, replaceQueue, bottomOfQueue )
Game.CityPushOrder( city, orderID, itemID, UI.AltKeyDown(), UI.ShiftKeyDown(), not UI.CtrlKeyDown() )
Events.SpecificCityInfoDirty( cityOwnerID, city:GetID(), CityUpdateTypes.CITY_UPDATE_TYPE_BANNER )
Events.SpecificCityInfoDirty( cityOwnerID, city:GetID(), CityUpdateTypes.CITY_UPDATE_TYPE_PRODUCTION )
if g_isButtonPopupChooseProduction then
-- is there another city without production order ?
for cityX in g_activePlayer:Cities() do
if cityX ~= city and not cityX:IsPuppet() and cityX:GetOrderQueueLength() < 1 then
UI.SelectCity( cityX )
return UI.LookAtSelectionPlot()
end
end
-- all cities are producing...
return ExitCityScreen()
end
end
end
end,
[eRClick] = SelectionPedia,
},
GoldButton = {
[eLClick] = function( orderID, itemID )
return SelectionPurchase( orderID, itemID, g_yieldCurrency, "AS2D_INTERFACE_CITY_SCREEN_PURCHASE" )
end,
},
FaithButton = {
[eLClick] = function( orderID, itemID )
return SelectionPurchase( orderID, itemID, YieldTypes.YIELD_FAITH, "AS2D_INTERFACE_FAITH_PURCHASE" )
end,
},
}
local g_SelectionListTooltips = {
Button = function( control )
return CityOrderItemTooltip( GetHeadSelectedCity(), true, false, control:GetVoid1(), control:GetVoid2() )
end,
GoldButton = function( control )
return CityOrderItemTooltip( GetHeadSelectedCity(), control:IsDisabled(), g_yieldCurrency, control:GetVoid1(), control:GetVoid2() )
end,
FaithButton = function( control )
return CityOrderItemTooltip( GetHeadSelectedCity(), control:IsDisabled(), YieldTypes.YIELD_FAITH, control:GetVoid1(), control:GetVoid2() )
end,
}
local function SetupSelectionList( itemList, selectionIM, cityOwnerID, getUnitPortraitIcon )
sort( itemList, SortSelectionList )
selectionIM:ResetInstances()
local cash = g_activePlayer:GetGold()
local faith = not IsCiv5vanilla and g_activePlayer:GetFaith() or 0
for i = 1, #itemList do
local item, orderID, itemDescription, turnsLeft, canProduce, goldCost, canBuyWithGold, faithCost, canBuyWithFaith = unpack( itemList[i] )
local itemID = item.ID
local avisorRecommended = g_isAdvisor and g_avisorRecommended[ orderID ]
local instance, new = selectionIM:GetInstance()
if new then
SetupCallbacks( instance, g_SelectionListTooltips, "EUI_ItemTooltip", g_SelectionListCallBacks )
end
instance.DisabledProduction:SetHide( canProduce or not(canBuyWithGold or canBuyWithFaith) )
instance.Disabled:SetHide( canProduce or canBuyWithGold or canBuyWithFaith )
if getUnitPortraitIcon then
local iconIndex, iconAtlas = getUnitPortraitIcon( itemID, cityOwnerID )
IconHookup( iconIndex, 45, iconAtlas, instance.Portrait )
else
IconHookup( item.PortraitIndex, 45, item.IconAtlas, instance.Portrait )
end
instance.Name:SetText( itemDescription )
if not turnsLeft then
elseif turnsLeft > -1 and turnsLeft <= 999 then
instance.Turns:LocalizeAndSetText( "TXT_KEY_STR_TURNS", turnsLeft )
else
instance.Turns:LocalizeAndSetText( "TXT_KEY_PRODUCTION_HELP_INFINITE_TURNS" )
end
instance.Turns:SetHide( not turnsLeft )
instance.Button:SetVoids( orderID, itemID )
instance.GoldButton:SetHide( not goldCost )
if goldCost then
instance.GoldButton:SetDisabled( not canBuyWithGold )
instance.GoldButton:SetAlpha( canBuyWithGold and 1 or 0.5 )
instance.GoldButton:SetVoids( orderID, itemID )
instance.GoldButton:SetText( (cash>=goldCost and goldCost or "[COLOR_WARNING_TEXT]"..(goldCost-cash).."[ENDCOLOR]") .. g_currencyIcon )
end
instance.FaithButton:SetHide( not faithCost )
if faithCost then
instance.FaithButton:SetDisabled( not canBuyWithFaith )
instance.FaithButton:SetAlpha( canBuyWithFaith and 1 or 0.5 )
instance.FaithButton:SetVoids( orderID, itemID )
instance.FaithButton:SetText( (faith>=faithCost and faithCost or "[COLOR_WARNING_TEXT]"..(faithCost-faith).."[ENDCOLOR]") .. "[ICON_PEACE]" )
end
for advisorID, advisorName in pairs(g_advisors) do
local advisorControl = instance[ advisorName ]
if advisorControl then
advisorControl:SetHide( not (avisorRecommended and avisorRecommended( itemID, advisorID )) )
end
end
end
return selectionIM.Commit()
end
--==========================================================
-- Production Queue Managemeent
--==========================================================
local function RemoveQueueItem( queuedItemNumber )
local city = GetSelectedModifiableCity()
if city then
local queueLength = city:GetOrderQueueLength()
if city:GetOwner() == g_activePlayerID and queueLength > queuedItemNumber then
Game.SelectedCitiesGameNetMessage( GameMessageTypes.GAMEMESSAGE_POP_ORDER, queuedItemNumber )
if queueLength < 2 then
local strTooltip = L( "TXT_KEY_NOTIFICATION_NEW_CONSTRUCTION", city:GetNameKey() )
g_activePlayer:AddNotification( NotificationTypes.NOTIFICATION_PRODUCTION, strTooltip, strTooltip, city:GetX(), city:GetY(), -1, -1 )
end
end
end
end
local function SwapQueueItem( queuedItemNumber )
if g_queuedItemNumber and Controls.QueueSlider:IsTrackingLeftMouseButton() then
local a = g_queuedItemNumber
local b = queuedItemNumber
if a>b then a, b = b, a end
for i=a, b-1 do
Game.SelectedCitiesGameNetMessage( GameMessageTypes.GAMEMESSAGE_SWAP_ORDER, i )
end
for i=b-2, a, -1 do
Game.SelectedCitiesGameNetMessage( GameMessageTypes.GAMEMESSAGE_SWAP_ORDER, i )
end
end
g_queuedItemNumber = queuedItemNumber or g_queuedItemNumber
end
Controls.AutomateProduction:RegisterCheckHandler( function( isChecked )
Game.SelectedCitiesGameNetMessage( GameMessageTypes.GAMEMESSAGE_DO_TASK, TaskTypes.TASK_SET_AUTOMATED_PRODUCTION, -1, -1, isChecked, false )
-- Network.SendDoTask( city:GetID(), TaskTypes.TASK_SET_AUTOMATED_PRODUCTION, -1, -1, isChecked, false )
end)
--==========================================================
-- Update Production Queue
--==========================================================
local function UpdateCityProductionQueue( city, cityID, cityOwnerID, isVeniceException )
local queueLength = city:GetOrderQueueLength()
local currentProductionPerTurnTimes100 = city:GetCurrentProductionDifferenceTimes100( false, false ) -- bIgnoreFood, bOverflow
local isGeneratingProduction = ( currentProductionPerTurnTimes100 > 0 ) and not ( city.IsProductionProcess and city:IsProductionProcess() )
local isMaintain = false
local isQueueEmpty = queueLength < 1
Controls.ProductionFinished:SetHide( true )
-- Progress info for meter
ShowProgress( g_portraitSize, Controls.PQlossMeter, Controls.PQprogressMeter, Controls.PQline1, Controls.PQlabel1, Controls.PQline2, Controls.PQlabel2,
isGeneratingProduction and not isQueueEmpty and city:GetProductionTurnsLeft(),
city:GetProductionNeeded() * 100,
city:GetProductionTimes100() + city:GetCurrentProductionDifferenceTimes100( false, true ) - currentProductionPerTurnTimes100, -- bIgnoreFood, bOverflow
currentProductionPerTurnTimes100 )
Controls.ProdPerTurnLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_PERTURN_TEXT", currentProductionPerTurnTimes100 / 100 )
Controls.ProductionPortraitButton:SetHide( false )
g_ProdQueueIM:ResetInstances()
local queueItems = {}
for queuedItemNumber = 0, max( queueLength-1, 0 ) do
local orderID, itemID, _, isRepeat, isReallyRepeat
if isQueueEmpty then
local item = g_finishedItems[ cityID ]
if item then
orderID, itemID = unpack( item )
Controls.ProductionFinished:SetHide( false )
end
else
orderID, itemID, _, isRepeat = city:GetOrderFromQueue( queuedItemNumber )
queueItems[ orderID / 64 + itemID ] = true
end
local instance, portraitSize
if queuedItemNumber == 0 then
instance = Controls
portraitSize = g_portraitSize
else
portraitSize = 45
instance = g_ProdQueueIM:GetInstance()
instance.PQdisabled:SetHide( not isMaintain )
end
instance.PQbox:SetVoid1( queuedItemNumber )
instance.PQbox:RegisterCallback( eMouseEnter, SwapQueueItem )
instance.PQbox:RegisterCallback( eRClick, ProductionPedia )
instance.PQbox:SetToolTipCallback( ProductionToolTip )
instance.PQremove:SetHide( isQueueEmpty or g_isViewingMode )
instance.PQremove:SetVoid1( queuedItemNumber )
instance.PQremove:RegisterCallback( eLClick, RemoveQueueItem )
local itemInfo, turnsRemaining, portraitOffset, portraitAtlas
if orderID == ORDER_TRAIN then
itemInfo = GameInfo.Units
turnsRemaining = city:GetUnitProductionTurnsLeft( itemID, queuedItemNumber )
portraitOffset, portraitAtlas = GetUnitPortraitIcon( itemID, cityOwnerID )
isReallyRepeat = isRepeat
elseif orderID == ORDER_CONSTRUCT then
itemInfo = GameInfo.Buildings
turnsRemaining = city:GetBuildingProductionTurnsLeft( itemID, queuedItemNumber )
elseif orderID == ORDER_CREATE then
itemInfo = GameInfo.Projects
turnsRemaining = city:GetProjectProductionTurnsLeft( itemID, queuedItemNumber )
elseif orderID == ORDER_MAINTAIN then
itemInfo = GameInfo.Processes
isMaintain = true
isReallyRepeat = true
end
if itemInfo then
local item = itemInfo[itemID]
itemInfo = IconHookup( portraitOffset or item.PortraitIndex, portraitSize, portraitAtlas or item.IconAtlas, instance.PQportrait )
instance.PQname:SetText( item._Name )
if isMaintain or isQueueEmpty then
elseif isGeneratingProduction then
instance.PQturns:LocalizeAndSetText( "TXT_KEY_PRODUCTION_HELP_NUM_TURNS", turnsRemaining )
else
instance.PQturns:LocalizeAndSetText( "TXT_KEY_PRODUCTION_HELP_INFINITE_TURNS" )
end
else
instance.PQname:LocalizeAndSetText( "TXT_KEY_PRODUCTION_NO_PRODUCTION" )
end
instance.PQturns:SetHide( isMaintain or isQueueEmpty or not itemInfo )
instance.PQportrait:SetHide( not itemInfo )
if isReallyRepeat then
isMaintain = true
instance.PQrank:SetText( "[ICON_TURNS_REMAINING]" )
else
instance.PQrank:SetText( not isMaintain and queueLength > 1 and (queuedItemNumber+1).."." )
end
end
g_ProdQueueIM.Commit()
-------------------------------------------
-- Update Selection List
-------------------------------------------
local isSelectionList = not g_isViewingMode or isVeniceException or g_isDebugMode
Controls.SelectionScrollPanel:SetHide( not isSelectionList )
if isSelectionList then
local unitSelectList = {}
local buildingSelectList = {}
local wonderSelectList = {}
local processSelectList = {}
if g_isAdvisor then
Game.SetAdvisorRecommenderCity( city )
end
-- Buildings & Wonders
local orderID = ORDER_CONSTRUCT
local code = orderID / 64
for item in GameInfo.Buildings() do
local buildingClass = GameInfo.BuildingClasses[item.BuildingClass]
local isWonder = buildingClass and (buildingClass.MaxGlobalInstances > 0 or buildingClass.MaxPlayerInstances == 1 or buildingClass.MaxTeamInstances > 0)
if not queueItems[ code + item.ID ] then
AddSelectionItem( city, item,
isWonder and wonderSelectList or buildingSelectList,
orderID,
city.CanConstruct,
-1, item.ID, -1,
city.GetBuildingProductionTurnsLeft,
city.GetBuildingPurchaseCost,
city.GetBuildingFaithPurchaseCost )
end
end
-- Units
orderID = ORDER_TRAIN
for item in GameInfo.Units() do
AddSelectionItem( city, item,
unitSelectList,
orderID,
city.CanTrain,
item.ID, -1, -1,
city.GetUnitProductionTurnsLeft,
city.GetUnitPurchaseCost,
city.GetUnitFaithPurchaseCost )
end
-- Projects
orderID = ORDER_CREATE
code = orderID / 64
for item in GameInfo.Projects() do
if not queueItems[ code + item.ID ] then
AddSelectionItem( city, item,
wonderSelectList,
orderID,
city.CanCreate,
-1, -1, item.ID,
city.GetProjectProductionTurnsLeft,
city.GetProjectPurchaseCost,
city.GetProjectFaithPurchaseCost ) -- nil
end
end
-- Processes
orderID = ORDER_MAINTAIN
code = orderID / 64
for item in GameInfo.Processes() do
if not queueItems[ code + item.ID ] then
AddSelectionItem( city, item,
processSelectList,
orderID,
city.CanMaintain )
end
end
SetupSelectionList( unitSelectList, g_UnitSelectIM, cityOwnerID, GetUnitPortraitIcon )
SetupSelectionList( buildingSelectList, g_BuildingSelectIM )
SetupSelectionList( wonderSelectList, g_WonderSelectIM )
SetupSelectionList( processSelectList, g_ProcessSelectIM )
end
return ResizeProdQueue()
end
--==========================================================
-- City Hex Clicking & Mousing
--==========================================================
local function PlotButtonClicked( plotIndex )
local city = GetSelectedModifiableCity()
local plot = city and city:GetCityIndexPlot( plotIndex )
if plot then
local outside = city ~= plot:GetWorkingCity()
-- calling this with the city center (0 in the third param) causes it to reset all forced tiles
Network.SendDoTask( city:GetID(), TaskTypes.TASK_CHANGE_WORKING_PLOT, plotIndex, -1, false )
if outside then
return Network.SendUpdateCityCitizens( city:GetID() )
end
end
end
local function BuyPlotAnchorButtonClicked( plotIndex )
local city = GetSelectedModifiableCity()
if city then
local plot = city:GetCityIndexPlot( plotIndex )
local plotX = plot:GetX()
local plotY = plot:GetY()
Network.SendCityBuyPlot(city:GetID(), plotX, plotY)
Network.SendUpdateCityCitizens( city:GetID() )
UI.UpdateCityScreen()
Events.AudioPlay2DSound("AS2D_INTERFACE_BUY_TILE")
end
return true
end
--==========================================================
-- Update City Hexes
--==========================================================
local function UpdateCityWorkingHexes( city )
EventsClearHexHighlightStyle( "HexContour" )
EventsClearHexHighlightStyle( "WorkedFill" )
EventsClearHexHighlightStyle( "WorkedOutline" )
EventsClearHexHighlightStyle( "UnlockedFill" )
EventsClearHexHighlightStyle( "UnlockedOutline" )
EventsClearHexHighlightStyle( "OverlapFill" )
EventsClearHexHighlightStyle( "OverlapOutline" )
EventsClearHexHighlightStyle( "VacantFill" )
EventsClearHexHighlightStyle( "VacantOutline" )
EventsClearHexHighlightStyle( "EnemyFill" )
EventsClearHexHighlightStyle( "EnemyOutline" )
EventsClearHexHighlightStyle( "BuyFill" )
EventsClearHexHighlightStyle( "BuyOutline" )
g_PlotButtonIM:ResetInstances()
g_BuyPlotButtonIM:ResetInstances()
-- Show plots that will be acquired by culture
local purchasablePlots = {city:GetBuyablePlotList()}
for i = 1, #purchasablePlots do
local plot = purchasablePlots[i]
EventsSerialEventHexHighlight( ToHexFromGrid{ x=plot:GetX(), y=plot:GetY() }, true, ColorCulture, "HexContour" )
purchasablePlots[ plot ] = true
end
local cityArea = city:GetNumCityPlots() - 1
EventsRequestYieldDisplay( YieldDisplayTypesAREA, HexRadius( cityArea ), city:GetX(), city:GetY() )
-- display worked plots buttons
local cityOwnerID = city:GetOwner()
local notInStrategicView = not InStrategicView()
local showButtons = g_workerHeadingOpen and not g_isViewingMode
for cityPlotIndex = 0, cityArea do
local plot = city:GetCityIndexPlot( cityPlotIndex )
if plot and plot:GetOwner() == cityOwnerID then
local hexPos = ToHexFromGrid{ x=plot:GetX(), y=plot:GetY() }
local worldPos = HexToWorld( hexPos )
local iconID, tipKey
if city:IsWorkingPlot( plot ) then
-- The city itself
if cityPlotIndex == 0 then
iconID = 11
tipKey = "TXT_KEY_CITYVIEW_CITY_CENTER"
-- FORCED worked plot
elseif city:IsForcedWorkingPlot( plot ) then
iconID = 10
tipKey = "TXT_KEY_CITYVIEW_FORCED_WORK_TILE"
-- AI-picked worked plot
else
iconID = 0
tipKey = "TXT_KEY_CITYVIEW_GUVNA_WORK_TILE"
end
if notInStrategicView then
if plot:IsCity() or city:IsForcedWorkingPlot( plot ) then
EventsSerialEventHexHighlight( hexPos , true, nil, "WorkedFill" )
EventsSerialEventHexHighlight( hexPos , true, nil, "WorkedOutline" )
else
EventsSerialEventHexHighlight( hexPos , true, nil, "UnlockedFill")
EventsSerialEventHexHighlight( hexPos , true, nil, "UnlockedOutline")
end
end
else
local workingCity = plot:GetWorkingCity()
-- worked by another one of our Cities
if workingCity:IsWorkingPlot( plot ) then
iconID = 12
tipKey = "TXT_KEY_CITYVIEW_NUTHA_CITY_TILE"
-- Workable plot
elseif workingCity:CanWork( plot ) then
iconID = 9
tipKey = "TXT_KEY_CITYVIEW_UNWORKED_CITY_TILE"
-- Blockaded water plot
elseif plot:IsWater() and city:IsPlotBlockaded( plot ) then
iconID = 13
tipKey = "TXT_KEY_CITYVIEW_BLOCKADED_CITY_TILE"
cityPlotIndex = nil
-- Enemy Unit standing here
elseif plot:IsVisibleEnemyUnit( cityOwnerID ) then
iconID = 13
tipKey = "TXT_KEY_CITYVIEW_ENEMY_UNIT_CITY_TILE"
cityPlotIndex = nil
end
if notInStrategicView then
if workingCity ~= city then
EventsSerialEventHexHighlight( hexPos , true, nil, "OverlapFill" )
EventsSerialEventHexHighlight( hexPos , true, nil, "OverlapOutline" )
elseif cityPlotIndex then
EventsSerialEventHexHighlight( hexPos , true, nil, "VacantFill" )
EventsSerialEventHexHighlight( hexPos , true, nil, "VacantOutline" )
else
EventsSerialEventHexHighlight( hexPos , true, nil, "EnemyFill" )
EventsSerialEventHexHighlight( hexPos , true, nil, "EnemyOutline" )
end
end
end
if iconID and showButtons then
local instance = g_PlotButtonIM:GetInstance()
instance.PlotButtonAnchor:SetWorldPositionVal( worldPos.x + g_worldPositionOffset.x, worldPos.y + g_worldPositionOffset.y, worldPos.z + g_worldPositionOffset.z ) --todo: improve code
instance.PlotButtonImage:LocalizeAndSetToolTip( tipKey )
IconHookup( iconID, 45, "CITIZEN_ATLAS", instance.PlotButtonImage )
local button = instance.PlotButtonImage
if not cityPlotIndex or g_isViewingMode then
button:ClearCallback( eLClick )
else
button:SetVoid1( cityPlotIndex )
button:RegisterCallback( eLClick, PlotButtonClicked )
end
end
end
end --loop
-- display buy plot buttons
if g_BuyPlotMode and not g_isViewingMode then
local cash = g_activePlayer:GetGold()
for cityPlotIndex = 0, cityArea do
local plot = city:GetCityIndexPlot( cityPlotIndex )
if plot then
local x = plot:GetX()
local y = plot:GetY()
local hexPos = ToHexFromGrid{ x=x, y=y }
local worldPos = HexToWorld( hexPos )
if city:CanBuyPlotAt( x, y, true ) then
local instance = g_BuyPlotButtonIM:GetInstance()
local button = instance.BuyPlotAnchoredButton
instance.BuyPlotButtonAnchor:SetWorldPositionVal( worldPos.x + g_worldPositionOffset2.x, worldPos.y + g_worldPositionOffset2.y, worldPos.z + g_worldPositionOffset2.z ) --todo: improve code
local plotCost = city:GetBuyPlotCost( x, y )
local tip, txt, alpha
local canBuy = city:CanBuyPlotAt( x, y, false )
if canBuy then
tip = L( "TXT_KEY_CITYVIEW_CLAIM_NEW_LAND", plotCost )
txt = plotCost
alpha = 1
button:SetVoid1( cityPlotIndex )
button:RegisterCallback( eLClick, BuyPlotAnchorButtonClicked )
if notInStrategicView then
EventsSerialEventHexHighlight( hexPos , true, nil, "BuyFill" )
if not purchasablePlots[ plot ] then
EventsSerialEventHexHighlight( hexPos , true, nil, "BuyOutline" )
end
end
else
tip = L( "TXT_KEY_CITYVIEW_NEED_MONEY_BUY_TILE", plotCost )
txt = "[COLOR_WARNING_TEXT]"..(plotCost-cash).."[ENDCOLOR]"
alpha = 0.5
end
button:SetDisabled( not canBuy )
instance.BuyPlotButtonAnchor:SetAlpha( alpha )
--todo
button:SetToolTipString( tip )
instance.BuyPlotAnchoredButtonLabel:SetText( txt )
end
end
end --loop
end
end
local function UpdateWorkingHexes()
local city = GetHeadSelectedCity()
if city and UI.IsCityScreenUp() then
return UpdateCityWorkingHexes( city )
end
end
--==========================================================
-- Update City View
--==========================================================
local function UpdateCityView()
local city = GetHeadSelectedCity()
if city and UI.IsCityScreenUp() then
if g_citySpecialists.city ~= city then
g_citySpecialists = { city = city }
end
--[[
if g_previousCity ~= city then
g_previousCity = city
EventsClearHexHighlightStyle("CityLimits")
if not InStrategicView() then
for cityPlotIndex = 0, city:GetNumCityPlots() - 1 do
local plot = city:GetCityIndexPlot( cityPlotIndex )
if plot then
local hexPos = ToHexFromGrid{ x=plot:GetX(), y=plot:GetY() }
EventsSerialEventHexHighlight( hexPos , true, nil, "CityLimits" )
end
end
end
end
--]]
local cityID = city:GetID()
local cityOwnerID = city:GetOwner()
local cityOwner = Players[cityOwnerID]
local isActivePlayerCity = cityOwnerID == Game.GetActivePlayer()
local isCityCaptureViewingMode = UI.IsPopupTypeOpen(ButtonPopupTypes.BUTTONPOPUP_CITY_CAPTURED)
g_isDebugMode = Game.IsDebugMode()
g_isViewingMode = city:IsPuppet() or not isActivePlayerCity or isCityCaptureViewingMode
if IsCiv5 then
-- Auto Specialist checkbox
local isNoAutoAssignSpecialists = city:IsNoAutoAssignSpecialists()
Controls.NoAutoSpecialistCheckbox:SetCheck( isNoAutoAssignSpecialists )
Controls.NoAutoSpecialistCheckbox:SetDisabled( g_isViewingMode )
if IsCiv5BNW then
Controls.TourismPerTurnLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_PERTURN_TEXT", city:GetBaseTourism() )
Controls.NoAutoSpecialistCheckbox2:SetCheck( isNoAutoAssignSpecialists )
Controls.NoAutoSpecialistCheckbox2:SetDisabled( g_isViewingMode )
end
end
Controls.AutomateProduction:SetCheck( city:IsProductionAutomated() )
Controls.AutomateProduction:SetDisabled( g_isViewingMode )
-------------------------------------------
-- City Banner
-------------------------------------------
local isCapital = city:IsCapital()
Controls.CityCapitalIcon:SetHide( not isCapital )
Controls.CityIsConnected:SetHide( isCapital or city:IsBlockaded() or not cityOwner:IsCapitalConnectedToCity(city) or city:GetTeam() ~= Game.GetActiveTeam() )
Controls.CityIsBlockaded:SetHide( not city:IsBlockaded() )
if city:IsRazing() then
Controls.CityIsRazing:SetHide(false)
Controls.CityIsRazing:LocalizeAndSetToolTip("TXT_KEY_CITY_BURNING", city:GetRazingTurns())
else
Controls.CityIsRazing:SetHide(true)
end
Controls.CityIsPuppet:SetHide( not city:IsPuppet() )
if city:IsResistance() then
Controls.CityIsResistance:SetHide(false)
Controls.CityIsResistance:LocalizeAndSetToolTip("TXT_KEY_CITY_RESISTANCE", city:GetResistanceTurns())
else
Controls.CityIsResistance:SetHide(true)
end
--todo BE
Controls.CityIsOccupied:SetHide( not( IsCiv5 and city:IsOccupied() and not city:IsNoOccupiedUnhappiness() ) )
local cityName = Locale.ToUpper( city:GetName() )
if city:IsRazing() then
cityName = cityName .. " (" .. L"TXT_KEY_BURNING" .. ")"
end
local size = isCapital and Controls.CityCapitalIcon:GetSizeX() or 0
Controls.CityNameTitleBarLabel:SetOffsetX( size / 2 )
TruncateString( Controls.CityNameTitleBarLabel, abs(Controls.NextCityButton:GetOffsetX()) * 2 - Controls.NextCityButton:GetSizeX() - size, cityName )
Controls.Defense:SetText( floor( city:GetStrengthValue() / 100 ) )
CivIconHookup( cityOwnerID, 64, Controls.CivIcon, Controls.CivIconBG, Controls.CivIconShadow, false, true )
-------------------------------------------
-- City Damage
-------------------------------------------
local cityDamage = city:GetDamage()
if cityDamage > 0 then
local cityHealthPercent = 1 - cityDamage / ( not IsCiv5vanilla and city:GetMaxHitPoints() or GameDefines.MAX_CITY_HIT_POINTS )
Controls.HealthMeter:SetPercent( cityHealthPercent )
if cityHealthPercent > 0.66 then
Controls.HealthMeter:SetTexture("CityNamePanelHealthBarGreen.dds")
elseif cityHealthPercent > 0.33 then
Controls.HealthMeter:SetTexture("CityNamePanelHealthBarYellow.dds")
else
Controls.HealthMeter:SetTexture("CityNamePanelHealthBarRed.dds")
end
Controls.HealthFrame:SetHide( false )
else
Controls.HealthFrame:SetHide( true )
end
-------------------------------------------
-- Growth Meter
-------------------------------------------
local cityPopulation = floor( city:GetPopulation() )
Controls.CityPopulationLabel:SetText( cityPopulation )
Controls.PeopleMeter:SetPercent( city:GetFood() / city:GrowthThreshold() )
--Update suffix to use correct plurality.
Controls.CityPopulationLabelSuffix:LocalizeAndSetText( "TXT_KEY_CITYVIEW_CITIZENS_TEXT", cityPopulation )
-------------------------------------------
-- Citizen Focus & Slackers
-------------------------------------------
Controls.AvoidGrowthButton:SetCheck( city:IsForcedAvoidGrowth() )
local slackerCount = city:GetSpecialistCount( GameDefines.DEFAULT_SPECIALIST )
local focusButton = g_cityFocusButtons[ city:GetFocusType() ]
if focusButton then
focusButton:SetCheck( true )
end
local doHide = city:GetNumForcedWorkingPlots() < 1 and slackerCount < 1
Controls.ResetButton:SetHide( doHide )
Controls.ResetFooter:SetHide( doHide )
g_SlackerIM:ResetInstances()
for i = 1, slackerCount do
local instance = g_SlackerIM:GetInstance()
local slot = instance.Button
slot:SetVoids( -1, i )
slot:SetToolTipCallback( SpecialistTooltip )
slot:SetTexture( g_slackerTexture )
if g_isViewingMode then
slot:ClearCallback( eLClick )
else
slot:RegisterCallback( eLClick, OnSlackersSelected )
end
slot:RegisterCallback( eRClick, SpecialistPedia )
end
g_SlackerIM.Commit()
-------------------------------------------
-- Great Person Meters
-------------------------------------------
if IsCiv5 then
g_GreatPeopleIM:ResetInstances()
for specialist in GameInfo.Specialists() do
local gpuClass = specialist.GreatPeopleUnitClass -- nil / UNITCLASS_ARTIST / UNITCLASS_SCIENTIST / UNITCLASS_MERCHANT / UNITCLASS_ENGINEER ...
local unitClass = GameInfo.UnitClasses[ gpuClass or -1 ]
if unitClass then
local gpThreshold = city:GetSpecialistUpgradeThreshold(unitClass.ID)
local gpProgress = city:GetSpecialistGreatPersonProgressTimes100(specialist.ID) / 100
local gpChange = specialist.GreatPeopleRateChange * city:GetSpecialistCount( specialist.ID )
for building in GameInfo.Buildings{SpecialistType = specialist.Type} do
if city:IsHasBuilding(building.ID) then
gpChange = gpChange + building.GreatPeopleRateChange
end
end
local gpChangePlayerMod = cityOwner:GetGreatPeopleRateModifier()
local gpChangeCityMod = city:GetGreatPeopleRateModifier()
local gpChangePolicyMod = 0
local gpChangeWorldCongressMod = 0
local gpChangeGoldenAgeMod = 0
local isGoldenAge = cityOwner:GetGoldenAgeTurns() > 0
if IsCiv5BNW then
-- Generic GP mods
gpChangePolicyMod = cityOwner:GetPolicyGreatPeopleRateModifier()
local worldCongress = (Game.GetNumActiveLeagues() > 0) and Game.GetActiveLeague()
-- GP mods by type
if specialist.GreatPeopleUnitClass == "UNITCLASS_WRITER" then
gpChangePlayerMod = gpChangePlayerMod + cityOwner:GetGreatWriterRateModifier()
gpChangePolicyMod = gpChangePolicyMod + cityOwner:GetPolicyGreatWriterRateModifier()
if worldCongress then
gpChangeWorldCongressMod = gpChangeWorldCongressMod + worldCongress:GetArtsyGreatPersonRateModifier()
end
if isGoldenAge and cityOwner:GetGoldenAgeGreatWriterRateModifier() > 0 then
gpChangeGoldenAgeMod = gpChangeGoldenAgeMod + cityOwner:GetGoldenAgeGreatWriterRateModifier()
end
elseif specialist.GreatPeopleUnitClass == "UNITCLASS_ARTIST" then
gpChangePlayerMod = gpChangePlayerMod + cityOwner:GetGreatArtistRateModifier()
gpChangePolicyMod = gpChangePolicyMod + cityOwner:GetPolicyGreatArtistRateModifier()
if worldCongress then
gpChangeWorldCongressMod = gpChangeWorldCongressMod + worldCongress:GetArtsyGreatPersonRateModifier()
end
if isGoldenAge and cityOwner:GetGoldenAgeGreatArtistRateModifier() > 0 then
gpChangeGoldenAgeMod = gpChangeGoldenAgeMod + cityOwner:GetGoldenAgeGreatArtistRateModifier()
end
elseif specialist.GreatPeopleUnitClass == "UNITCLASS_MUSICIAN" then
gpChangePlayerMod = gpChangePlayerMod + cityOwner:GetGreatMusicianRateModifier()
gpChangePolicyMod = gpChangePolicyMod + cityOwner:GetPolicyGreatMusicianRateModifier()
if worldCongress then
gpChangeWorldCongressMod = gpChangeWorldCongressMod + worldCongress:GetArtsyGreatPersonRateModifier()
end
if isGoldenAge and cityOwner:GetGoldenAgeGreatMusicianRateModifier() > 0 then
gpChangeGoldenAgeMod = gpChangeGoldenAgeMod + cityOwner:GetGoldenAgeGreatMusicianRateModifier()
end
elseif specialist.GreatPeopleUnitClass == "UNITCLASS_SCIENTIST" then
gpChangePlayerMod = gpChangePlayerMod + cityOwner:GetGreatScientistRateModifier()
gpChangePolicyMod = gpChangePolicyMod + cityOwner:GetPolicyGreatScientistRateModifier()
if worldCongress then
gpChangeWorldCongressMod = gpChangeWorldCongressMod + worldCongress:GetScienceyGreatPersonRateModifier()
end
elseif specialist.GreatPeopleUnitClass == "UNITCLASS_MERCHANT" then
gpChangePlayerMod = gpChangePlayerMod + cityOwner:GetGreatMerchantRateModifier()
gpChangePolicyMod = gpChangePolicyMod + cityOwner:GetPolicyGreatMerchantRateModifier()
if worldCongress then
gpChangeWorldCongressMod = gpChangeWorldCongressMod + worldCongress:GetScienceyGreatPersonRateModifier()
end
elseif specialist.GreatPeopleUnitClass == "UNITCLASS_ENGINEER" then
gpChangePlayerMod = gpChangePlayerMod + cityOwner:GetGreatEngineerRateModifier()
gpChangePolicyMod = gpChangePolicyMod + cityOwner:GetPolicyGreatEngineerRateModifier()
if worldCongress then
gpChangeWorldCongressMod = gpChangeWorldCongressMod + worldCongress:GetScienceyGreatPersonRateModifier()
end
-- Compatibility with Gazebo's City-State Diplomacy Mod (CSD) for Brave New World
elseif cityOwner.GetGreatDiplomatRateModifier and specialist.GreatPeopleUnitClass == "UNITCLASS_GREAT_DIPLOMAT" then
gpChangePlayerMod = gpChangePlayerMod + cityOwner:GetGreatDiplomatRateModifier()
end
-- Player mod actually includes policy mod and World Congress mod, so separate them for tooltip
gpChangePlayerMod = gpChangePlayerMod - gpChangePolicyMod - gpChangeWorldCongressMod
elseif gpuClass == "UNITCLASS_SCIENTIST" then
gpChangePlayerMod = gpChangePlayerMod + cityOwner:GetTraitGreatScientistRateModifier()
end
local gpChangeMod = gpChangePlayerMod + gpChangePolicyMod + gpChangeWorldCongressMod + gpChangeCityMod + gpChangeGoldenAgeMod
gpChange = (gpChangeMod / 100 + 1) * gpChange
if gpProgress > 0 or gpChange > 0 then
local instance = g_GreatPeopleIM:GetInstance()
local percent = gpProgress / gpThreshold
instance.GPMeter:SetPercent( percent )
local labelText = unitClass._Name
local icon = GreatPeopleIcon(gpuClass)
local tips = { "[COLOR_YIELD_FOOD]" .. Locale.ToUpper( labelText ) .. "[ENDCOLOR]" .. " " .. gpProgress .. icon .." / " .. gpThreshold .. icon }
-- insert( tips, L( "TXT_KEY_PROGRESS_TOWARDS", "[COLOR_YIELD_FOOD]" .. Locale.ToUpper( labelText ) .. "[ENDCOLOR]" ) )
if gpChange > 0 then
local gpTurns = ceil( (gpThreshold - gpProgress) / gpChange )
insert( tips, "[COLOR_YIELD_FOOD]" .. Locale.ToUpper( L( "TXT_KEY_STR_TURNS", gpTurns ) ) .. "[ENDCOLOR] "
.. gpChange .. icon .. " " .. L"TXT_KEY_GOLD_PERTURN_HEADING4_TITLE" )
labelText = labelText .. ": " .. Locale.ToLower( L( "TXT_KEY_STR_TURNS", gpTurns ) )
end
instance.GreatPersonLabel:SetText( icon .. labelText )
if IsCiv5vanilla then
if gpChangeMod ~= 0 then
insert( tips, "[ICON_BULLET] "..gpChangeMod..icon )
end
else
if gpChangePlayerMod ~= 0 then
insert( tips, L( "TXT_KEY_PLAYER_GP_MOD", gpChangePlayerMod ) )
end
if gpChangePolicyMod ~= 0 then
insert( tips, L( "TXT_KEY_POLICY_GP_MOD", gpChangePolicyMod ) )
end
if gpChangeCityMod ~= 0 then
insert( tips, L( "TXT_KEY_CITY_GP_MOD", gpChangeCityMod ) )
end
if gpChangeGoldenAgeMod ~= 0 then
insert( tips, L( "TXT_KEY_GOLDENAGE_GP_MOD", gpChangeGoldenAgeMod ) )
end
if gpChangeWorldCongressMod < 0 then
insert( tips, L( "TXT_KEY_WORLD_CONGRESS_NEGATIVE_GP_MOD", gpChangeWorldCongressMod ) )
elseif gpChangeWorldCongressMod > 0 then
insert( tips, L( "TXT_KEY_WORLD_CONGRESS_POSITIVE_GP_MOD", gpChangeWorldCongressMod ) )
end
end
instance.GPBox:SetToolTipString( concat( tips, "[NEWLINE]") )
instance.GPBox:SetVoid1( unitClass.ID )
instance.GPBox:RegisterCallback( eRClick, UnitClassPedia )
local portraitOffset, portraitAtlas = GetUnitPortraitIcon( GameInfoTypes[ unitClass.DefaultUnit ], cityOwnerID )
instance.GPImage:SetHide(not IconHookup( portraitOffset, 64, portraitAtlas, instance.GPImage ) )
end
end
end
g_GreatPeopleIM.Commit()
end
-------------------------------------------
-- Buildings
-------------------------------------------
local greatWorkBuildings = {}
local specialistBuildings = {}
local wonders = {}
local otherBuildings = {}
local noWondersWithSpecialistInThisCity = true
for building in GameInfo.Buildings() do
local buildingID = building.ID
if city:IsHasBuilding(buildingID) then
local buildingClass = GameInfo.BuildingClasses[ building.BuildingClass ]
local buildings
local greatWorkCount = IsCiv5BNW and building.GreatWorkCount or 0
local areSpecialistsAllowedByBuilding = city:GetNumSpecialistsAllowedByBuilding(buildingID) > 0
if buildingClass
and ( buildingClass.MaxGlobalInstances > 0
or buildingClass.MaxTeamInstances > 0
or ( buildingClass.MaxPlayerInstances == 1 and not areSpecialistsAllowedByBuilding ) )
then
buildings = wonders
if areSpecialistsAllowedByBuilding then
noWondersWithSpecialistInThisCity = false
end
elseif areSpecialistsAllowedByBuilding then
buildings = specialistBuildings
elseif greatWorkCount > 0 then
buildings = greatWorkBuildings
elseif greatWorkCount == 0 then -- compatibility with Firaxis code exploit for invisibility
buildings = otherBuildings
end
if buildings then
insert( buildings, { building, building._Name, greatWorkCount, areSpecialistsAllowedByBuilding and GameInfoTypes[building.SpecialistType] or 999 } )
end
end
end
local strMaintenanceTT = L( "TXT_KEY_BUILDING_MAINTENANCE_TT", city:GetTotalBaseBuildingMaintenance() )
Controls.SpecialBuildingsHeader:SetToolTipString(strMaintenanceTT)
Controls.BuildingsHeader:SetToolTipString(strMaintenanceTT)
Controls.GreatWorkHeader:SetToolTipString(strMaintenanceTT)
Controls.SpecialistControlBox:SetHide( #specialistBuildings < 1 )
Controls.SpecialistControlBox2:SetHide( noWondersWithSpecialistInThisCity )
g_GreatWorksIM:ResetInstances()
g_SpecialistsIM:ResetInstances()
SetupBuildingList( city, specialistBuildings, g_SpecialBuildingsIM )
SetupBuildingList( city, wonders, g_WondersIM )
SetupBuildingList( city, greatWorkBuildings, g_GreatWorkIM )
SetupBuildingList( city, otherBuildings, g_BuildingsIM )
ResizeRightStack()
-------------------------------------------
-- Buying Plots
-------------------------------------------
-- szText = L"TXT_KEY_CITYVIEW_BUY_TILE"
-- Controls.BuyPlotButton:LocalizeAndSetToolTip( "TXT_KEY_CITYVIEW_BUY_TILE_TT" )
-- Controls.BuyPlotText:SetText(szText)
-- Controls.BuyPlotButton:SetDisabled( g_isViewingMode or (GameDefines.BUY_PLOTS_DISABLED ~= 0 and city:CanBuyAnyPlot()) )
-------------------------------------------
-- Resource Demanded
-------------------------------------------
if city:GetResourceDemanded(true) ~= -1 then
local resourceInfo = GameInfo.Resources[ city:GetResourceDemanded() ]
local weLoveTheKingDayCounter = city:GetWeLoveTheKingDayCounter()
if weLoveTheKingDayCounter > 0 then
Controls.ResourceDemandedString:LocalizeAndSetText( "TXT_KEY_CITYVIEW_WLTKD_COUNTER", weLoveTheKingDayCounter )
Controls.ResourceDemandedBox:LocalizeAndSetToolTip( "TXT_KEY_CITYVIEW_RESOURCE_FULFILLED_TT" )
else
Controls.ResourceDemandedString:LocalizeAndSetText( "TXT_KEY_CITYVIEW_RESOURCE_DEMANDED", (resourceInfo.IconString or"") .. " " .. resourceInfo._Name )
Controls.ResourceDemandedBox:LocalizeAndSetToolTip( "TXT_KEY_CITYVIEW_RESOURCE_DEMANDED_TT" )
end
Controls.ResourceDemandedBox:SetSizeX(Controls.ResourceDemandedString:GetSizeX() + 10)
Controls.ResourceDemandedBox:SetHide(false)
else
Controls.ResourceDemandedBox:SetHide(true)
end
Controls.IconsStack:CalculateSize()
Controls.IconsStack:ReprocessAnchoring()
Controls.NotificationStack:CalculateSize()
Controls.NotificationStack:ReprocessAnchoring()
-------------------------------------------
-- Raze / Unraze / Annex City Buttons
-------------------------------------------
local buttonToolTip, buttonLabel, taskID
if isActivePlayerCity then
if city:IsRazing() then
-- We can unraze this city
taskID = TaskTypes.TASK_UNRAZE
buttonLabel = L"TXT_KEY_CITYVIEW_UNRAZE_BUTTON_TEXT"
buttonToolTip = L"TXT_KEY_CITYVIEW_UNRAZE_BUTTON_TT"
elseif city:IsPuppet() and not(IsCiv5BNW and cityOwner:MayNotAnnex()) then
-- We can annex this city
taskID = TaskTypes.TASK_ANNEX_PUPPET
buttonLabel = L"TXT_KEY_POPUP_ANNEX_CITY"
-- todo
if IsCiv5 then
buttonToolTip = L( "TXT_KEY_POPUP_CITY_CAPTURE_INFO_ANNEX", cityOwner:GetUnhappinessForecast(city) - cityOwner:GetUnhappiness() )
end
elseif not g_isViewingMode and cityOwner:CanRaze( city, true ) then
buttonLabel = L"TXT_KEY_CITYVIEW_RAZE_BUTTON_TEXT"
if cityOwner:CanRaze( city, false ) then
-- We can actually raze this city
taskID = TaskTypes.TASK_RAZE
buttonToolTip = L"TXT_KEY_CITYVIEW_RAZE_BUTTON_TT"
else
-- We COULD raze this city if it weren't a capital
buttonToolTip = L"TXT_KEY_CITYVIEW_RAZE_BUTTON_DISABLED_BECAUSE_CAPITAL_TT"
end
end
end
local CityTaskButton = Controls.CityTaskButton
CityTaskButton:SetText( buttonLabel )
CityTaskButton:SetVoids( cityID, taskID or -1 )
CityTaskButton:SetToolTipString( buttonToolTip )
CityTaskButton:SetDisabled( not taskID )
CityTaskButton:SetHide( not buttonLabel )
--Controls.ReturnToMapButton:SetToolTipString( concat( {"g_isViewingMode:", tostring(g_isViewingMode), "Can raze:", tostring(cityOwner:CanRaze( city, true )), "Can actually raze:", tostring(cityOwner:CanRaze( city, false )), "taskID:", tostring(taskID) }, " " ) )
UpdateCityWorkingHexes( city )
UpdateCityProductionQueue( city, cityID, cityOwnerID, isActivePlayerCity and not isCityCaptureViewingMode and IsCiv5BNW and cityOwner:MayNotAnnex() and city:IsPuppet() )
-- display gold income
local iGoldPerTurn = city:GetYieldRateTimes100( g_yieldCurrency ) / 100
Controls.GoldPerTurnLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_PERTURN_TEXT", iGoldPerTurn )
-- display science income
if Game.IsOption(GameOptionTypes.GAMEOPTION_NO_SCIENCE) then
Controls.SciencePerTurnLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_OFF" )
else
local iSciencePerTurn = city:GetYieldRateTimes100(YieldTypes.YIELD_SCIENCE) / 100
Controls.SciencePerTurnLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_PERTURN_TEXT", iSciencePerTurn )
end
local culturePerTurn, cultureStored, cultureNext
-- thanks for Firaxis Cleverness !
if IsCiv5 then
culturePerTurn = city:GetJONSCulturePerTurn()
cultureStored = city:GetJONSCultureStored()
cultureNext = city:GetJONSCultureThreshold()
else
culturePerTurn = city:GetCulturePerTurn()
cultureStored = city:GetCultureStored()
cultureNext = city:GetCultureThreshold()
end
Controls.CulturePerTurnLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_PERTURN_TEXT", culturePerTurn )
local cultureDiff = cultureNext - cultureStored
if culturePerTurn > 0 then
local cultureTurns = max( ceil(cultureDiff / culturePerTurn), 1 )
Controls.CultureTimeTillGrowthLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_TURNS_TILL_TILE_TEXT", cultureTurns )
Controls.CultureTimeTillGrowthLabel:SetHide( false )
else
Controls.CultureTimeTillGrowthLabel:SetHide( true )
end
local percentComplete = cultureStored / cultureNext
Controls.CultureMeter:SetPercent( percentComplete )
if not IsCiv5vanilla then
if Game.IsOption(GameOptionTypes.GAMEOPTION_NO_RELIGION) then
Controls.FaithPerTurnLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_OFF" )
else
Controls.FaithPerTurnLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_PERTURN_TEXT", city:GetFaithPerTurn() )
end
Controls.FaithFocusButton:SetDisabled( g_isViewingMode )
end
local cityGrowth = city:GetFoodTurnsLeft()
local foodPerTurnTimes100 = city:FoodDifferenceTimes100()
if city:IsFoodProduction() or foodPerTurnTimes100 == 0 then
Controls.CityGrowthLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_STAGNATION_TEXT" )
elseif foodPerTurnTimes100 < 0 then
Controls.CityGrowthLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_STARVATION_TEXT" )
else
Controls.CityGrowthLabel:LocalizeAndSetText( "TXT_KEY_CITYVIEW_TURNS_TILL_CITIZEN_TEXT", cityGrowth )
end
Controls.FoodPerTurnLabel:LocalizeAndSetText( foodPerTurnTimes100 >= 0 and "TXT_KEY_CITYVIEW_PERTURN_TEXT" or "TXT_KEY_CITYVIEW_PERTURN_TEXT_NEGATIVE", foodPerTurnTimes100 / 100 )
-------------------------------------------
-- Disable Buttons as Appropriate
-------------------------------------------
local bIsLock = g_isViewingMode or (cityOwner:GetNumCities() <= 1)
Controls.PrevCityButton:SetDisabled( bIsLock )
Controls.NextCityButton:SetDisabled( bIsLock )
for _, control in pairs( g_cityFocusButtons ) do
control:SetDisabled( g_isViewingMode )
end
end
end
local function UpdateOptionsAndCityView()
g_isAdvisor = UserInterfaceSettings.CityAdvisor ~= 0
g_isScreenAutoClose = UserInterfaceSettings.ScreenAutoClose ~= 0
g_isResetCityPlotPurchase = UserInterfaceSettings.ResetCityPlotPurchase ~= 0
g_FocusSelectIM.Collapse( not OptionsManager.IsNoCitizenWarning() )
return UpdateCityView()
end
g_SpecialBuildingsIM = StackInstanceManager( "BuildingInstance", "Button", Controls.SpecialBuildingsStack, Controls.SpecialBuildingsHeader, ResizeRightStack )
g_GreatWorkIM = StackInstanceManager( "BuildingInstance", "Button", Controls.GreatWorkStack, Controls.GreatWorkHeader, ResizeRightStack )
g_WondersIM = StackInstanceManager( "BuildingInstance", "Button", Controls.WondersStack, Controls.WondersHeader, ResizeRightStack )
g_BuildingsIM = StackInstanceManager( "BuildingInstance", "Button", Controls.BuildingsStack, Controls.BuildingsHeader, ResizeRightStack )
g_GreatPeopleIM = StackInstanceManager( "GPInstance", "GPBox", Controls.GPStack, Controls.GPHeader, ResizeRightStack )
g_SlackerIM = StackInstanceManager( "Slot", "Button", Controls.SlackerStack, Controls.SlackerHeader, ResizeRightStack )
g_ProdQueueIM = StackInstanceManager( "ProductionInstance", "PQbox", Controls.QueueStack, Controls.ProdBox, ResizeProdQueue, true )
g_UnitSelectIM = StackInstanceManager( "SelectionInstance", "Button", Controls.UnitButtonStack, Controls.UnitButton, ResizeProdQueue )
g_BuildingSelectIM = StackInstanceManager( "SelectionInstance", "Button", Controls.BuildingButtonStack, Controls.BuildingsButton, ResizeProdQueue )
g_WonderSelectIM = StackInstanceManager( "SelectionInstance", "Button", Controls.WonderButtonStack, Controls.WondersButton, ResizeProdQueue )
g_ProcessSelectIM = StackInstanceManager( "SelectionInstance", "Button", Controls.OtherButtonStack, Controls.OtherButton, ResizeProdQueue )
g_FocusSelectIM = StackInstanceManager( "", "", Controls.WorkerManagementBox, Controls.WorkerHeader, function(collapsed) g_workerHeadingOpen = not collapsed ResizeRightStack() UpdateWorkingHexes() end, true, not g_workerHeadingOpen )
--------------
-- Rename City
local function RenameCity()
local city = GetHeadSelectedCity()
if city then
return Events.SerialEventGameMessagePopup{
Type = ButtonPopupTypes.BUTTONPOPUP_RENAME_CITY,
Data1 = city:GetID(),
Data2 = -1,
Data3 = -1,
Option1 = false,
Option2 = false
}
end
end
local NoAutoSpecialistCheckbox = { [eLClick] = function()
return Game.SelectedCitiesGameNetMessage(GameMessageTypes.GAMEMESSAGE_DO_TASK, TaskTypes.TASK_NO_AUTO_ASSIGN_SPECIALISTS, -1, -1, not GetHeadSelectedCity():IsNoAutoAssignSpecialists() )
end }
--==========================================================
-- Register Events
--==========================================================
SetupCallbacks( Controls,
{
ProdBox = LuaEvents.CityViewToolTips.Call,
FoodBox = LuaEvents.CityViewToolTips.Call,
GoldBox = LuaEvents.CityViewToolTips.Call,
ScienceBox = LuaEvents.CityViewToolTips.Call,
CultureBox = LuaEvents.CityViewToolTips.Call,
FaithBox = LuaEvents.CityViewToolTips.Call,
TourismBox = LuaEvents.CityViewToolTips.Call,
ProductionPortraitButton = LuaEvents.CityViewToolTips.Call,
PopulationBox = LuaEvents.CityViewToolTips.Call,
},
"EUI_ItemTooltip",
{
AvoidGrowthButton = {
[eLClick] = function()
local city = GetSelectedModifiableCity()
if city then
Network.SendSetCityAvoidGrowth( city:GetID(), not city:IsForcedAvoidGrowth() )
return Network.SendUpdateCityCitizens( city:GetID() )
end
end,
},
CityTaskButton = {
[eLClick] = function( cityID, taskID, button )
local city = GetSelectedCity()
if city and city:GetID() == cityID then
return Events.SerialEventGameMessagePopup{
Type = ButtonPopupTypes.BUTTONPOPUP_CONFIRM_CITY_TASK,
Data1 = cityID,
Data2 = taskID,
Text = button:GetToolTipString()
}
end
end,
},
YesButton = {
[eLClick] = function( cityID, buildingID )
Controls.SellBuildingConfirm:SetHide( true )
if cityID and buildingID and buildingID > 0 and GetSelectedModifiableCity() then
Network.SendSellBuilding( cityID, buildingID )
Network.SendUpdateCityCitizens( cityID )
end
return Controls.YesButton:SetVoids( -1, -1 )
end,
},
NoButton = { [eLClick] = CancelBuildingSale },
NextCityButton = { [eLClick] = GotoNextCity },
PrevCityButton = { [eLClick] = GotoPrevCity },
ReturnToMapButton = { [eLClick] = ExitCityScreen },
ProductionPortraitButton = { [eRClick] = ProductionPedia },
BoxOSlackers = { [eLClick] = OnSlackersSelected },
ResetButton = { [eLClick] = PlotButtonClicked },
NoAutoSpecialistCheckbox = NoAutoSpecialistCheckbox,
NoAutoSpecialistCheckbox2 = NoAutoSpecialistCheckbox,
EditButton = { [eLClick] = RenameCity },
TitlePanel = { [eRClick] = RenameCity },
})
--Controls.ResetButton:SetVoid1( 0 ) -- calling with 0 = city center causes reset of all forced tiles
--Controls.BoxOSlackers:SetVoids(-1,-1)
--Controls.ProductionPortraitButton:SetVoid1( 0 )
Controls.FaithBox:SetHide( IsCivBE or IsCiv5vanilla )
Controls.TourismBox:SetHide( not IsCiv5BNW )
Controls.BuyPlotCheckBox:RegisterCheckHandler( function( isChecked ) -- Void1, Void2, control )
g_BuyPlotMode = isChecked
return UpdateCityView()
end)
Events.GameOptionsChanged.Add( UpdateOptionsAndCityView )
UpdateOptionsAndCityView()
--------------------------
-- Enter City Screen Event
Events.SerialEventEnterCityScreen.Add( function()
--print("enter city screen", GetHeadSelectedCity())
LuaEvents.TryQueueTutorial("CITY_SCREEN", true)
Events.SerialEventCityScreenDirty.Add( UpdateCityView )
Events.SerialEventCityInfoDirty.Add( UpdateCityView )
Events.SerialEventCityHexHighlightDirty.Add( UpdateWorkingHexes )
g_queuedItemNumber = nil
g_previousCity = nil
if g_isResetCityPlotPurchase then
g_BuyPlotMode = false
Controls.BuyPlotCheckBox:SetCheck( false )
end
Controls.RightScrollPanel:SetScrollValue(0)
--TODO other scroll panels
return UpdateCityView()
end)
-------------------------
-- Exit City Screen Event
Events.SerialEventExitCityScreen.Add( function()
--print("exit city screen")
if UI.IsCityScreenUp() then
Events.SerialEventCityScreenDirty.RemoveAll()
Events.SerialEventCityInfoDirty.RemoveAll()
Events.SerialEventCityHexHighlightDirty.RemoveAll()
local city = UI.GetHeadSelectedCity()
local plot = city and city:Plot()
CleanupCityScreen()
Events.ClearHexHighlights()
-- We may get here after a player change, clear the UI if this is not the active player's city
if not city or city:GetOwner() ~= g_activePlayerID then
ClearCityUIInfo()
end
-- required for game engine to display proper hex shading
UI.ClearSelectedCities()
LuaEvents.TryDismissTutorial("CITY_SCREEN")
-- Try and re-select the last unit selected
if not UI.GetHeadSelectedUnit() and UI.GetLastSelectedUnit() then
UI.SelectUnit( UI.GetLastSelectedUnit() )
end
if plot then
UI.LookAt( plot, 2 ) -- 1 = CAMERALOOKAT_CITY_ZOOM_IN, 2 = CAMERALOOKAT_NORMAL (player zoom)
else
UI.LookAtSelectionPlot()
end
g_isViewingMode = true
end
end)
--==========================================================
-- Strategic View State Change Event
--==========================================================
if IsCiv5 then
local NormalWorldPositionOffset = g_worldPositionOffset
local NormalWorldPositionOffset2 = g_worldPositionOffset2
local StrategicViewWorldPositionOffset = { x = 0, y = 20, z = 0 }
Events.StrategicViewStateChanged.Add( function( bStrategicView )
if bStrategicView then
g_worldPositionOffset = StrategicViewWorldPositionOffset
g_worldPositionOffset2 = StrategicViewWorldPositionOffset
else
g_worldPositionOffset = NormalWorldPositionOffset
g_worldPositionOffset2 = NormalWorldPositionOffset2
end
g_previousCity = false
return UpdateCityView()
end)
end
--==========================================================
-- 'Active' (local human) player has changed
--==========================================================
Events.GameplaySetActivePlayer.Add( function( activePlayerID )--, previousActivePlayerID )
g_activePlayerID = activePlayerID
g_activePlayer = Players[ g_activePlayerID ]
g_finishedItems = {}
ClearCityUIInfo()
if UI.IsCityScreenUp() then
return ExitCityScreen()
end
end)
Events.ActivePlayerTurnEnd.Add( function()
g_finishedItems = {}
end)
AddSerialEventGameMessagePopup( function( popupInfo )
if popupInfo.Type == ButtonPopupTypes.BUTTONPOPUP_CHOOSEPRODUCTION then
Events.SerialEventGameMessagePopupProcessed.CallImmediate(ButtonPopupTypes.BUTTONPOPUP_CHOOSEPRODUCTION, 0)
Events.SerialEventGameMessagePopupShown( popupInfo )
local cityID = popupInfo.Data1 -- city id
local orderID = popupInfo.Data2 -- finished order id
local itemID = popupInfo.Data3 -- finished item id
local city = cityID and g_activePlayer:GetCityByID( cityID )
if city and not UI.IsCityScreenUp() then
if orderID >= 0 and itemID >= 0 then
g_finishedItems[ cityID ] = { orderID, itemID }
end
g_isButtonPopupChooseProduction = g_isScreenAutoClose
return UI.DoSelectCityAtPlot( city:Plot() ) -- open city screen
end
end
end, ButtonPopupTypes.BUTTONPOPUP_CHOOSEPRODUCTION )
Events.NotificationAdded.Add( function( notificationID, notificationType, toolTip, strSummary, data1, data2, playerID )
if notificationType == NotificationTypes.NOTIFICATION_PRODUCTION and playerID == g_activePlayerID then
-- Hack to find city
for city in g_activePlayer:Cities() do
if strSummary == L( "TXT_KEY_NOTIFICATION_NEW_CONSTRUCTION", city:GetNameKey() ) then
if data1 >= 0 and data2 >=0 then
g_finishedItems[ city:GetID() ] = { data1, data2 }
end
if city:GetGameTurnFounded() == Game.GetGameTurn() and not UI.IsCityScreenUp() then
return UI.DoSelectCityAtPlot( city:Plot() ) -- open city screen
end
return
end
end
end
end)
end)
--==========================================================
-- Support for Modded Add-in UI's
--==========================================================
do
g_uiAddins = {}
local Modding = Modding
local uiAddins = g_uiAddins
for addin in Modding.GetActivatedModEntryPoints("CityViewUIAddin") do
local addinFile = Modding.GetEvaluatedFilePath(addin.ModID, addin.Version, addin.File)
if addinFile then
print( "Loading MOD CityViewUIAddin\n", Modding.GetModProperty(addin.ModID, addin.Version, "Name"), addin.File )
table.insert( uiAddins, ContextPtr:LoadNewContext( addinFile.EvaluatedPath:match("(.*)%..*") ) )
end
end
end
Add UI_bc1 folder to MP_MODSPACK
Replace:
IGE-Mod: IGE_Window.lua --> EUI compatible
EUI: UnitPanel.lua --> mod compatible
EUI: CityBannerManager.lua, CityView.lua & Highlights.xml --> Unlocked recolored
Add "ContextPtr:LoadNewContext"-Parts from old UI files to UI_bc1 in:
CityView.lua
InGame.lua
LeaderHeadRoot.lua
UnitPanel.lua (EvilSpiritsMission, THTanukiMission)
Delete:
Old UI folder
BNW Mass Effect (v 7)\Dummy Building Folder\CivilopediaScreen.lua
BNW Mass Effect (v 7)\Dummy Building Folder\CityView.lua
Touhou - Evil Spirits (v 2)\Lua\UnitPanel.lua
Touhou - Probability Space Hypervessel (v 1)\Lua\TechTree.lua
Touhou - Probability Space Hypervessel (v 1)\Lua\TechButtonInclude.lua
\ No newline at end of file
#!/usr/bin/env python
#Imports
import os
from os.path import join as j
from glob import glob as g
import subprocess
import shutil
import re
#Change to base DLC directory
os.chdir("../..")
##Global Values
print("Configuring variables...")
#Names
modpack_folder_name = "MP_MODSPACK"
modded_eui_zip_name = "EUI_CUC.7z"
eui_cu_file_names = ["CityBannerManager.lua",
"CityView.lua",
"Highlights.xml"]
load_tag = "ContextPtr:LoadNewContext"
unit_panel_file_name = "UnitPanel.lua"
ige_compat_file_name = "IGE_Window.lua"
delete_file_names = ["CivilopediaScreen.lua",
"CityView.lua",
"TechTree.lua",
"TechButtonInclude.lua",
unit_panel_file_name]
unit_panel_modcompat_file_names = ["EvilSpiritsMission.lua",
"THTanukiMission.lua"]
#Paths
base_path = os.getcwd()
modsave_path = j(base_path, "zzz_Modsaves")
modpack_path = j(base_path, modpack_folder_name)
vanilla_packs_path = j(base_path, "zz_Vanilla_Versions")
ui_path = j(modpack_path, "UI")
eui_path = j(base_path, "UI_bc1")
szip = r"C:\Program Files\7-Zip\7z.exe"
#Files
mod_files = j(modpack_path, "Mods", "**", "*.lua")
ui_files = j(ui_path, "*.lua")
eui_files = j(eui_path, "*", "*.lua")
base_eui_zip = j(vanilla_packs_path, "0EUI.7z")
modded_eui_zip_path = j(base_path, modded_eui_zip_name)
#Global Variables
load_tags = {}
unit_panel_modcompat_needed = False
null = open(os.devnull, 'w')
#Get modpack zip
while True:
modpack_name = input("\nWhich pack should be converted?\n")
modpack_zips = g(j(vanilla_packs_path, modpack_name + ".*"))
if len(modpack_zips) > 0:
modpack_zip = modpack_zips[0]
break
print("This file doesn't exist, try again.")
#Remove previous modpack
print("Removing previous modpack leftovers...")
if os.path.isdir(modpack_path):
shutil.rmtree(modpack_path)
if os.path.isdir(eui_path):
shutil.rmtree(eui_path)
#Compile EUI with colored unlocked citizens
if not os.path.isfile(modded_eui_zip_path):
print("Creating colored unlocked Citizens EUI...")
subprocess.run([szip, 'x', base_eui_zip], stdout=null, stderr=null)
#shutil.move(j(vanilla_packs_path, eui_file_name), eui_path)
for eui_cu_file_name in eui_cu_file_names:
eui_cu_file = g(j(modsave_path, eui_cu_file_name + "*"))[0]
orig_eui_file = g(j(eui_path, "*", eui_cu_file_name))[0]
shutil.move(orig_eui_file, orig_eui_file + ".orig")
shutil.copyfile(eui_cu_file, orig_eui_file)
subprocess.run([szip, 'a', modded_eui_zip_name, eui_path], stdout=null, stderr=null)
else:
#Unzip EUI
print("Unzipping EUI...")
subprocess.run([szip, 'x', modded_eui_zip_path], stdout=null, stderr=null)
#Unzip modpack zip
print("Unzipping Modpack...")
subprocess.run([szip, 'x', j(vanilla_packs_path, modpack_zip)], stdout=null, stderr=null)
#Manage mod files
for mod_file in g(mod_files, recursive = True):
mod_file_path = mod_file.split(os.sep)
mod_file_name = mod_file_path[len(mod_file_path) - 1]
#IGE UI compat file
if mod_file_name == ige_compat_file_name:
print("Providing IGE-EUI-compat...")
shutil.move(mod_file, mod_file + ".orig")
shutil.copyfile(g(j(modsave_path, ige_compat_file_name + "*"))[0], mod_file)
#Delete UI overwrite duplicates
if mod_file_name in delete_file_names:
print("Removing overwriting file " + mod_file_name + "...")
os.remove(mod_file)
#Find out if modcompat unit panel needed
if mod_file_name in unit_panel_modcompat_file_names:
print("UnitPanel modcompat need detected...")
unit_panel_modcompat_needed = True
#Delete useless desktop.ini (Thanks True...)
ini_files = re.sub(r"\.\w+$", ".ini", mod_files)
for ini_file in g(ini_files, recursive = True):
ini_file_path = ini_file.split(os.sep)
ini_file_name = ini_file_path[len(ini_file_path) - 1]
if ini_file_name == "desktop.ini":
print("Removing useless desktop.ini (Thanks True)...")
os.remove(mod_file)
#Get stuff from UI files
for ui_file in g(ui_files):
with open(ui_file, 'r') as file:
lines = file.readlines()
ui_file_path = ui_file.split(os.sep)
ui_file_name = ui_file_path[len(ui_file_path) - 1]
print("Getting tags from " + ui_file_name + "...")
load_tags[ui_file_name] = []
for line in lines:
if line.startswith(load_tag):
load_tags[ui_file_name].append(line)
#Insert stuff into EUI files
for eui_file in g(eui_files):
eui_file_path = eui_file.split(os.sep)
eui_file_name = eui_file_path[len(eui_file_path) - 1]
#Base UI files
if eui_file_name in load_tags.keys():
print("Writing tags to " + eui_file_name + "...")
with open(eui_file, 'a') as file:
file.write('\n')
for load_tag in load_tags[eui_file_name]:
file.write(load_tag)
#Modcompat unit panel
elif eui_file_name == unit_panel_file_name and unit_panel_modcompat_needed:
print("Providing EUI-UnitPanel-Modcompat...")
shutil.move(eui_file, eui_file + ".orig")
shutil.copyfile(g(j(modsave_path, unit_panel_file_name + "*"))[0], eui_file)
#Move EUI folder
print("Moving EUI folder...")
shutil.move(eui_path, modpack_path)
print("Removing UI folder...")
shutil.rmtree(ui_path)
#Zip modpack folder
print("Zipping Modpack...")
subprocess.run([szip, 'a', modpack_name + "_EUI.7z", modpack_path], stdout=null, stderr=null)
##Move modpack folder
#print("Moving Modspack folder")
#shutil.move(modpack_path, j(base_path, modpack_folder_name))
null.close()
print("Done.\n")
\ No newline at end of file
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>ea28d07f-cd43-45d1-b01d-1eeeb360d215</ProjectGuid>
<ProjectHome>.</ProjectHome>
<StartupFile>EUI_Converter.py</StartupFile>
<SearchPath>
</SearchPath>
<WorkingDirectory>.</WorkingDirectory>
<OutputPath>.</OutputPath>
<Name>EUI_Converter</Name>
<RootNamespace>EUI_Converter</RootNamespace>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>true</DebugSymbols>
<EnableUnmanagedDebugging>false</EnableUnmanagedDebugging>
</PropertyGroup>
<ItemGroup>
<Compile Include="EUI_Converter.py" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Python Tools\Microsoft.PythonTools.targets" />
<!-- Uncomment the CoreCompile target to enable the Build command in
Visual Studio and specify your pre- and post-build commands in
the BeforeBuild and AfterBuild targets below. -->
<!--<Target Name="CoreCompile" />-->
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
</Project>
\ No newline at end of file

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31019.35
MinimumVisualStudioVersion = 10.0.40219.1
Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "EUI_Converter", "EUI_Converter.pyproj", "{EA28D07F-CD43-45D1-B01D-1EEEB360D215}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{081253F6-C547-4C81-B928-0D7472199986}"
ProjectSection(SolutionItems) = preProject
..\.gitattributes = ..\.gitattributes
..\.gitignore = ..\.gitignore
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{EA28D07F-CD43-45D1-B01D-1EEEB360D215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA28D07F-CD43-45D1-B01D-1EEEB360D215}.Release|Any CPU.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D4E8032E-FBFB-40D5-8FEC-B7EF67F27664}
EndGlobalSection
EndGlobal
<?xml version="1.0" encoding="utf-8"?>
<Highlights>
<style name="" type="HexContour" width=".2" texture="hex_contour2.dds"/>
<style name="SampleFilledHex" type="FilledHex" width="1" color="0,0,0,128"/>
<style name="SampleStaticTexture" type="StaticTexture" texture="static_texture_highlight.dds"/>
<style name="SampleHexModel" type="HexModel" model="SelectedAniOneTurn.fxsxml"/>
<style name="EditorHexStyle1" type="HexContour" width=".15" texture="Solid_Contour.dds"/>
<style name="EditorHexStyle2" type="HexContour" width=".08" texture="Solid_Contour.dds"/>
<style name="EditorHexStyle3" type="HexContour" width=".03" texture="Solid_Contour.dds"/>
<style name="TempBorder" type="HexContour" width=".2" texture="hex_contour2.dds"/>
<style name="GroupBorder" type="SplineBorder" width ="6" texture="spline_border_contour2.dds" color="255,128,0,200"/>
<style name="ValidFireTargetBorder" type="StaticTexture" texture="static_texture_highlight.dds"/>
<style name="FireRangeBorder" type="SplineBorder" width="6" texture="spline_border_contour2.dds" color="255,0,0,200"/>
<style name="MovementRangeBorder" type="SplineBorder" width="4" texture="spline_border_contour2.dds" color="100,185,245,240"/>
<style name="AMRBorder" type="StaticTexture" texture="static_texture_highlight.dds"/>
<style name="TradeRoute" type="HexContour" width=".2" texture="hex_contour2.dds"/>
<style name="GUHB" type="HexContour" width=".2" texture="hex_contour2.dds"/>
<!-- EUI styles -->
<style name="HexContour" type="HexContour" width=".2" texture="hex_contour2.dds" />
<style name="CityOverlap" type="FilledHex" width ="1" color="255,140,0,64" />
<style name="OverlapFill" type="FilledHex" width ="1" color="0,0,255,50" />
<style name="OverlapOutline" type="SplineBorder" width ="7" texture="hex_contour1.dds" color="0,0,255,164" />
<style name="WorkedFill" type="FilledHex" width ="1" color="0,255,0,50" />
<style name="WorkedOutline" type="SplineBorder" width ="7" texture="hex_contour1.dds" color="0,255,0,164" />
<style name="UnlockedFill" type="FilledHex" width ="1" color="7,107,0,50" />
<style name="UnlockedOutline" type="SplineBorder" width ="7" texture="hex_contour1.dds" color="7,107,0,164" />
<style name="OwnedFill" type="FilledHex" width ="1" color="0,140,255,50" />
<style name="OwnedOutline" type="SplineBorder" width ="7" texture="hex_contour1.dds" color="0,140,255,164" />
<style name="BuyFill" type="FilledHex" width ="1" color="255,215,0,50" />
<style name="BuyOutline" type="SplineBorder" width ="7" texture="hex_contour1.dds" color="255,215,0,192" />
<style name="VacantFill" type="FilledHex" width ="1" color="0,140,255,50" />
<style name="VacantOutline" type="SplineBorder" width ="7" texture="hex_contour1.dds" color="0,140,255,164" />
<style name="EnemyFill" type="FilledHex" width ="1" color="255,0,0,64" />
<style name="EnemyOutline" type="SplineBorder" width ="7" texture="hex_contour1.dds" color="255,0,0,200" />
<style name="CityLimits" type="SplineBorder" width ="7" texture="hex_contour1.dds" color="0,0,0,164" />
</Highlights>
-- Released under GPL v3
--------------------------------------------------------------
include("IGE_API_All");
print("IGE_Window");
IGE = nil;
local initialized = false;
local currentPlot = nil;
local oldCurrentPlot = nil;
local mouseHandlers = {};
local mouseMode = 0;
--local busy = false;
--===============================================================================================
-- INIT-SHOW-HIDE
--===============================================================================================
local function OnSharingGlobalAndOptions(_IGE)
IGE = _IGE;
OnUpdatedOptions(_IGE);
end
LuaEvents.IGE_SharingGlobalAndOptions.Add(OnSharingGlobalAndOptions);
-------------------------------------------------------------------------------------------------
function OnInitialize()
Resize(Controls.MainGrid);
local sizeX, sizeY = UIManager:GetScreenSizeVal();
local offset = (sizeX - 320) - Controls.MainGrid:GetSizeX();
Controls.MainGrid:SetOffsetX(offset > 0 and offset * 0.5 or -10);
if sizeY < 1000 then
Controls.PanelsContainer:SetOffsetY(47);
LowerSizeY(Controls.MainGrid, 21);
end
if not UI.CompareFileTime then
print("Pirate version, autosave disabled.");
Controls.ReloadButton:SetHide(true);
Controls.SaveButton:SetHide(true);
Controls.AutoSave:SetHide(true);
end
end
LuaEvents.IGE_Initialize.Add(OnInitialize);
-------------------------------------------------------------------------------------------------
local function IsVisible()
return not Controls.Container:IsHidden();
end
-------------------------------------------------------------------------------------------------
local function SetBusy(flag, loading)
busy = flag;
UI.SetBusy(flag);--[[
Controls.MainButton:SetDisabled(busy);
UIManager:SetUICursor(busy and 1 or 0);]]
end
-------------------------------------------------------------------------------------------------
local function ClosePopups()
LookUpControl("InGame/WorldView/InfoCorner/TechPanel"):SetHide(true);
LookUpControl("InGame/TechAwardPopup"):SetHide(true);
LookUpControl("InGame/ProductionPopup"):SetHide(true);
Controls.ChooseReligionPopup:SetHide(true);
Controls.ChoosePantheonPopup:SetHide(true);
Controls.ProductionPopup:SetHide(true);
Controls.OptionsPanel:SetHide(true);
Controls.WonderPopup:SetHide(true);
end
-------------------------------------------------------------------------------------------------
local function OpenCore()
if not initialized then
LuaEvents.IGE_Initialize();
initialized = true;
print("Initialization completed");
end
IGE.revealMap = false;
OnUpdateUI()
LuaEvents.IGE_Showing();
UpdateMouse();
ClosePopups();
UI.SetInterfaceMode(InterfaceModeTypes.INTERFACEMODE_SELECTION);
print("OpenCore - step1");
Events.SystemUpdateUI.CallImmediate(SystemUpdateUIType.BulkHideUI);
Events.SerialEventMouseOverHex.Add(OnMouseMoveOverHex);
print("OpenCore - step2");
Events.CameraViewChanged.Add(UpdateMouse);
Controls.Container:SetHide(false);
print("OpenCore - done");
end
-------------------------------------------------------------------------------------------------
local reportedError = false;
local function OnInitializationError(err)
if reportedError then return end
reportedError = true;
print("Failed to open IGE:");
err = FormatError(err, 1);
-- Show popup to user
local str = L("TXT_KEY_IGE_LOADING_ERROR").."[NEWLINE][ICON_PIRATE] "..err;
Events.SerialEventGameMessagePopup( { Type = ButtonPopupTypes.BUTTONPOPUP_TEXT, Data1 = 800, Option1 = true, Text = str } );
-- Restore things up
Events.SystemUpdateUI.CallImmediate(SystemUpdateUIType.BulkShowUI);
Events.ClearHexHighlights();
LuaEvents.IGE_Show_Fail();
return false
end
-------------------------------------------------------------------------------------------------
local function Open()
if not IsVisible() and not busy then
SetBusy(true);
-- More than one version installed?
local pingData = { count = 0 };
LuaEvents.IGE_PingAllVersions(pingData);
if (pingData.count > 1) then
local str = L("TXT_KEY_IGE_MORE_THAN_ONE_VERSION_ERROR");
Events.SerialEventGameMessagePopup( { Type = ButtonPopupTypes.BUTTONPOPUP_TEXT, Data1 = 800, Option1 = true, Text = str } );
SetBusy(false);
return;
end
-- Try to init data
reportedError = false;
local status, err = xpcall(OpenCore, OnInitializationError);
if not status then
SetBusy(false);
return;
end
-- Autosave
print("SaveFile - begin");
if IGE.autoSave then
SaveFile(IGE.cleanUpFiles);
end
print("SaveFile - done");
-- Restore current plot
if oldCurrentPlot then
SetCurrentPlot(oldCurrentPlot);
end
SetBusy(false);
print("SetBusy - done");
LuaEvents.IGE_Update();
end
end
-------------------------------------------------------------------------------------------------
local function Close(keepBulkUIHidden, takingSeat)
if IsVisible() and not busy then
SetBusy(true);
if not takingSeat then
if Game.GetActivePlayer() ~= IGE.initialPlayerID then
Game.SetActivePlayer(IGE.initialPlayerID);
end
end
leftButtonDown = false;
rightButtonDown = false;
oldCurrentPlot = currentPlot;
SetCurrentPlot(nil);
LuaEvents.IGE_Closing(takingSeat);
if not keepBulkUIHidden then
Events.SystemUpdateUI.CallImmediate(SystemUpdateUIType.BulkShowUI);
end
ClosePopups();
Events.SerialEventMouseOverHex.Remove(OnMouseMoveOverHex);
Events.CameraViewChanged.Remove(UpdateMouse);
Controls.Container:SetHide(true);
UI.SetInterfaceMode(InterfaceModeTypes.INTERFACEMODE_SELECTION);
SetMouseMode(IGE_MODE_NONE);
Map.RecalculateAreas();
SetBusy(false);
end
end
Controls.CloseButton:RegisterCallback(Mouse.eLClick, function() Close(false, false) end);
-------------------------------------------------------------------------------------------------
local function OnForceQuit(takingSeat)
Close(false, takingSeat);
end
LuaEvents.IGE_ForceQuit.Add(OnForceQuit);
-------------------------------------------------------------------------------------------------
local function CloseAndKeepUIHidden()
Close(true, false);
end
Events.SearchForPediaEntry.Add(CloseAndKeepUIHidden);
Events.GoToPediaHomePage.Add(CloseAndKeepUIHidden);
--===============================================================================================
-- MOUSE HOVER
--===============================================================================================
local selectedNewPlot = false;
local highlightedPlots = {};
function SetCurrentPlot(plot)
selectedNewPlot = (plot ~= currentPlot);
currentPlot = plot;
LuaEvents.IGE_SelectedPlot(plot);
LuaEvents.IGE_Update();
end
-------------------------------------------------------------------------------------------------
local function HighlightPlot(plot, color)
if plot then
Events.SerialEventHexHighlight(ToHexFromGrid(Vector2(plot:GetX(), plot:GetY())), true, color);
end
end
-------------------------------------------------------------------------------------------------
function UpdateMouse(mouseOver, gridX, gridY)
if gridX == nil then
gridX, gridY = UI.GetMouseOverHex();
end
if mouseOver == nil then
mouseOver = Controls.Background:HasMouseOver();
end
local shift = UIManager:GetShift();
local plot = mouseOver and Map.GetPlot(gridX, gridY) or nil;
Events.ClearHexHighlights();
if mouseMode == IGE_MODE_PAINT then
if plot then
local color = rightButtonDown and Vector4(1.0, 0.0, 0.0, 1) or Vector4(0, 1.0, 0, 1);
HighlightPlot(plot, color);
if shift then
for neighbor in Neighbors(plot) do
HighlightPlot(neighbor, color);
end
end
if rightButtonDown then
LuaEvents.IGE_PaintPlot(2, plot, shift);
end
end
elseif mouseMode == IGE_MODE_PLOP then
if plot then
local color = rightButtonDown and Vector4(1, 0, 0, 1) or Vector4(0, 1, 0, 1);
HighlightPlot(plot, color);
end
elseif mouseMode == IGE_MODE_EDIT_AND_PLOP then
if currentPlot then
local rightClickCurrentPlot = (rightButtonDown and plot == currentPlot);
local color = rightClickCurrentPlot and Vector4(0, 1, 0, 1) or Vector4(1, 0, 0, 1);
HighlightPlot(currentPlot, color);
end
elseif mouseMode == IGE_MODE_EDIT then
if currentPlot then
HighlightPlot(currentPlot, Vector4(1, 0, 0, 1));
end
end
-- Plots that have been undone
for i, v in ipairs(highlightedPlots) do
HighlightPlot(v, Vector4(0, 0, 1, 1));
end
LuaEvents.IGE_BroadcastingMouseState(mouseOver, gridX, gridY, plot, shift);
end
-------------------------------------------------------------------------------------------------
function OnMouseMoveOverHex(hexX, hexY)
UpdateMouse(nil, hexX, hexY);
end
-------------------------------------------------------------------------------------------------
function OnBackgroundMouseEnter()
if IsVisible() then
leftButtonDown = false;
rightButtonDown = false;
UpdateCursor(true);
UpdateMouse(true);
end
end
Controls.Background:RegisterCallback(Mouse.eMouseEnter, OnBackgroundMouseEnter);
-------------------------------------------------------------------------------------------------
function OnBackgroundMouseExit()
if IsVisible() then
leftButtonDown = false;
rightButtonDown = false;
UpdateCursor(false);
UpdateMouse(false);
end
end
Controls.Background:RegisterCallback(Mouse.eMouseExit, OnBackgroundMouseExit);
-------------------------------------------------------------------------------------------------
function UpdateCursor(hasMouseOver)
local cursor = 0;
if hasMouseOver then
if mouseMode > IGE_MODE_EDIT_AND_PLOP then
cursor = 8;
elseif mouseMode > 0 then
cursor = 3;
end
end
UIManager:SetUICursor(cursor);
end
-------------------------------------------------------------------------------------------------
function SetMouseMode(mode)
if mode == mouseMode then return end
leftButtonDown = false;
rightButtonDown = false;
mouseMode = mode;
UpdateCursor();
UpdateMouse();
end
LuaEvents.IGE_SetMouseMode.Add(SetMouseMode);
-------------------------------------------------------------------------------------------------
function OnFlashPlot(plot)
table.insert(highlightedPlots, plot);
UpdateMouse();
LuaEvents.IGE_Schedule(nil, 1.0, function()
table.remove(highlightedPlots, 1);
UpdateMouse();
end);
end
LuaEvents.IGE_FlashPlot.Add(OnFlashPlot);
--===============================================================================================
-- INPUTS
--===============================================================================================
mouseHandlers[IGE_MODE_NONE] = function(uiMsg)
end
-------------------------------------------------------------------------------------------------
mouseHandlers[IGE_MODE_EDIT] = function(uiMsg)
if uiMsg == MouseEvents.RButtonDown then
SetCurrentPlot(nil);
UpdateMouse();
elseif uiMsg == MouseEvents.LButtonDown then
SetCurrentPlot(Map.GetPlot(UI.GetMouseOverHex()));
UpdateMouse();
end
end
-------------------------------------------------------------------------------------------------
mouseHandlers[IGE_MODE_EDIT_AND_PLOP] = function(uiMsg)
if uiMsg == MouseEvents.RButtonDown then
SetCurrentPlot(nil);
UpdateMouse();
elseif uiMsg == MouseEvents.LButtonDown then
SetCurrentPlot(Map.GetPlot(UI.GetMouseOverHex()));
UpdateMouse();
if UIManager:GetShift() then
LuaEvents.IGE_Plop(1, Map.GetPlot(UI.GetMouseOverHex()), true);
end
end
end
-------------------------------------------------------------------------------------------------
mouseHandlers[IGE_MODE_PAINT] = function(uiMsg)
if uiMsg == MouseEvents.RButtonUp then
UpdateMouse();
elseif uiMsg == MouseEvents.RButtonDown then
LuaEvents.IGE_BeginPaint();
UpdateMouse();
end
end
-------------------------------------------------------------------------------------------------
mouseHandlers[IGE_MODE_PLOP] = function(uiMsg)
if uiMsg == MouseEvents.RButtonUp then
UpdateMouse();
elseif uiMsg == MouseEvents.RButtonDown then
UpdateMouse();
LuaEvents.IGE_Plop(2, Map.GetPlot(UI.GetMouseOverHex()), UIManager:GetShift());
end
end
-------------------------------------------------------------------------------------------------
function InputHandler(uiMsg, wParam, lParam)
if IsVisible() then
if uiMsg == MouseEvents.LButtonDown then
selectedNewPlot = false;
leftButtonDown = true;
elseif uiMsg == MouseEvents.LButtonUp then
leftButtonDown = false;
elseif uiMsg == MouseEvents.RButtonDown then
rightButtonDown = true;
elseif uiMsg == MouseEvents.RButtonUp then
rightButtonDown = false;
end
if Controls.Background:HasMouseOver() then
local func = mouseHandlers[mouseMode];
func(uiMsg);
end
if uiMsg == MouseEvents.LButtonDown then
return false;
elseif uiMsg == MouseEvents.LButtonUp then
return selectedNewPlot;
elseif uiMsg == MouseEvents.RButtonDown then
return true;
elseif uiMsg == MouseEvents.RButtonUp then
return true;
elseif uiMsg == KeyEvents.KeyUp then
UpdateMouse();
if wParam == Keys.Z and UIManager:GetControl() then
return true;
end
-- Shortcuts
elseif uiMsg == KeyEvents.KeyDown then
if ProcessShortcuts(wParam) then
UpdateMouse();
return true;
else
UpdateMouse();
end
end
end
-- Open IGE
if uiMsg == KeyEvents.KeyDown and wParam == Keys.I and UIManager:GetControl() then
Toggle();
return true;
end
return false;
end
ContextPtr:SetInputHandler(InputHandler);
-------------------------------------------------------------------------------------------------
function ProcessShortcuts(key)
-- Escape = quit
if key == Keys.VK_ESCAPE then
Close(false, false);
return true;
end
-- Ctrl + Z = undo
if key == Keys.Z and UIManager:GetControl() then
rightButtonDown = false;
leftButtonDown = false;
LuaEvents.IGE_Undo();
return true;
end
-- Ctrl + Y = redo
if key == Keys.Y and UIManager:GetControl() then
rightButtonDown = false;
leftButtonDown = false;
LuaEvents.IGE_Redo();
return true;
end
-- F5 = quicksave
-- Ctrl + F5 = save and reload
if key == Keys.VK_F5 then
if UIManager:GetControl() then
OnReloadButtonClick();
else
OnSaveButtonClick();
end
return true;
end
-- F1-F4 and F6-F8 : panels
if key == Keys.VK_F1 then
LuaEvents.IGE_SetTab("TERRAIN_EDITION");
return true;
end
if key == Keys.VK_F2 then
LuaEvents.IGE_SetTab("CITIES_AND_UNITS");
return true;
end
if key == Keys.VK_F3 then
LuaEvents.IGE_SetTab("TERRAIN_PAINTING");
return true;
end
if key == Keys.VK_F4 then
LuaEvents.IGE_SetTab("UNITS");
return true;
end
if key == Keys.VK_F6 then
LuaEvents.IGE_SetTab("PLAYERS");
return true;
end
if key == Keys.VK_F7 then
LuaEvents.IGE_SetTab("TECHS");
return true;
end
if key == Keys.VK_F8 then
LuaEvents.IGE_SetTab("POLICIES");
return true;
end
end
--===============================================================================================
-- OPTIONS AND CONTROLS
--===============================================================================================
function OnUpdatedOptions(IGE)
Controls.AutoSave:SetCheck(IGE.autoSave);
Controls.ShowResources:SetCheck(IGE.showResources);
Controls.ShowUnknownResources:SetCheck(IGE.showUnknownResources);
Controls.DisableStrategicView:SetCheck(IGE.disableStrategicView);
Controls.CleanUpFiles:SetCheck(IGE.cleanUpFiles);
Controls.ShowYields:SetCheck(IGE.showYields);
Controls.SafeMode:SetCheck(IGE.safeMode);
end
LuaEvents.IGE_UpdatedOptions.Add(OnUpdatedOptions);
-------------------------------------------------------------------------------------------------
function OnOptionControlChanged()
local options = {};
options.autoSave = Controls.AutoSave:IsChecked();
options.cleanUpFiles = Controls.CleanUpFiles:IsChecked();
options.disableStrategicView = Controls.DisableStrategicView:IsChecked();
options.showUnknownResources = Controls.ShowUnknownResources:IsChecked();
options.showResources = Controls.ShowResources:IsChecked();
options.showYields = Controls.ShowYields:IsChecked();
options.safeMode = Controls.SafeMode:IsChecked();
LuaEvents.IGE_UpdateOptions(options);
end
Controls.CleanUpFiles:RegisterCheckHandler(OnOptionControlChanged);
Controls.DisableStrategicView:RegisterCheckHandler(OnOptionControlChanged);
Controls.ShowUnknownResources:RegisterCheckHandler(OnOptionControlChanged);
Controls.ShowResources:RegisterCheckHandler(OnOptionControlChanged);
Controls.ShowYields:RegisterCheckHandler(OnOptionControlChanged);
Controls.SafeMode:RegisterCheckHandler(OnOptionControlChanged);
Controls.AutoSave:RegisterCheckHandler(OnOptionControlChanged);
-------------------------------------------------------------------------------------------------
function OnSaveButtonClick()
SaveFile(IGE.cleanUpFiles);
end
Controls.SaveButton:RegisterCallback(Mouse.eLClick, OnSaveButtonClick);
-------------------------------------------------------------------------------------------------
function OnReloadButtonClick()
LuaEvents.IGE_ConfirmPopup(L("TXT_KEY_IGE_CONFIRM_SAVE_AND_RELOAD"), function()
local fileName = "IGE - reload";
if IGE.cleanUpFiles then
DeleteFiles(fileName);
end
UI.SaveGame(fileName, true);
LoadFile(fileName);
end);
end
Controls.ReloadButton:RegisterCallback(Mouse.eLClick, OnReloadButtonClick);
-------------------------------------------------------------------------------------------------
local function OnRevealMapButtonClick()
IGE.revealMap = true;
LuaEvents.IGE_ToggleRevealMap(IGE.revealMap);
end
Controls.RevealMapButton:RegisterCallback(Mouse.eLClick, OnRevealMapButtonClick);
-------------------------------------------------------------------------------------------------
local function OnCoverMapButtonClick()
IGE.revealMap = false;
LuaEvents.IGE_ToggleRevealMap(IGE.revealMap);
end
Controls.CoverMapButton:RegisterCallback(Mouse.eLClick, OnCoverMapButtonClick);
-------------------------------------------------------------------------------------------------
function OnUpdateUI()
local notHuman = not Players[Game.GetActivePlayer()]:IsHuman()
Controls.CoverMapButton:SetHide(notHuman or not IGE.revealMap);
Controls.RevealMapButton:SetHide(notHuman or IGE.revealMap);
Controls.IGECameraButton:SetHide(notHuman)
end
LuaEvents.IGE_Update.Add(OnUpdateUI)
LuaEvents.IGE_ToggleRevealMap.Add(OnUpdateUI);
-------------------------------------------------------------------------------------------------
local function OnIGECameraHome()
local plot = IGE.currentPlayer:GetStartingPlot()
if plot then
print("Go home")
UI.LookAt(plot)
end
end
Controls.IGECameraButton:RegisterCallback(Mouse.eLClick, OnIGECameraHome);
-------------------------------------------------------------------------------------------------
local function ToggleOptions()
local hidden = Controls.OptionsPanel:IsHidden();
Controls.OptionsPanel:SetHide(not hidden);
end
Controls.MainButton:RegisterCallback(Mouse.eRClick, ToggleOptions);
-------------------------------------------------------------------------------------------------
function Toggle()
if IsVisible() then
Close();
else
Open();
end
end
Controls.MainButton:RegisterCallback(Mouse.eLClick, Toggle);
-------------------------------------------------------------------------------------------------
local TOP = 0;
local BOTTOM = 1;
local LEFT = 2;
local RIGHT = 3;
local function ScrollMouseEnter(which)
if which == TOP then
Events.SerialEventCameraStartMovingForward();
elseif which == BOTTOM then
Events.SerialEventCameraStartMovingBack();
elseif which == LEFT then
Events.SerialEventCameraStartMovingLeft();
else
Events.SerialEventCameraStartMovingRight();
end
end
local function ScrollMouseExit(which)
if which == TOP then
Events.SerialEventCameraStopMovingForward();
elseif which == BOTTOM then
Events.SerialEventCameraStopMovingBack();
elseif which == LEFT then
Events.SerialEventCameraStopMovingLeft();
else
Events.SerialEventCameraStopMovingRight();
end
end
Controls.ScrollTop:RegisterCallback( Mouse.eMouseEnter, ScrollMouseEnter);
Controls.ScrollTop:RegisterCallback( Mouse.eMouseExit, ScrollMouseExit);
Controls.ScrollTop:SetVoid1(TOP);
Controls.ScrollBottom:RegisterCallback( Mouse.eMouseEnter, ScrollMouseEnter);
Controls.ScrollBottom:RegisterCallback( Mouse.eMouseExit, ScrollMouseExit);
Controls.ScrollBottom:SetVoid1(BOTTOM);
Controls.ScrollLeft:RegisterCallback( Mouse.eMouseEnter, ScrollMouseEnter);
Controls.ScrollLeft:RegisterCallback( Mouse.eMouseExit, ScrollMouseExit);
Controls.ScrollLeft:SetVoid1(LEFT);
Controls.ScrollRight:RegisterCallback( Mouse.eMouseEnter, ScrollMouseEnter);
Controls.ScrollRight:RegisterCallback( Mouse.eMouseExit, ScrollMouseExit);
Controls.ScrollRight:SetVoid1(RIGHT);
LuaEvents.IGE_ShareGlobalAndOptions();
print("IGE loaded");
-----------------------------------------------------------------------------------------
-- Changes by bc1 to hook up IGE's Main Button to the rigth of the Top Panel's left stack
-----------------------------------------------------------------------------------------
ContextPtr:SetUpdate( function()
ContextPtr:ClearUpdate();
local topPanelInfoStack = LookUpControl( "/InGame/TopPanel/TopPanelInfoStack" );
if topPanelInfoStack then
Controls.MainButton:ChangeParent( topPanelInfoStack );
Controls.MainButton:SetOffsetVal( 0, 0 );
topPanelInfoStack:ReprocessAnchoring();
print( "IGE main button moved successfully." );
else
print( "IGE main button move attempt failed." );
end
end);
\ No newline at end of file
--==========================================================
-- Unit Panel
-- Re-written by bc1 using Notepad++
-- code is common using gk_mode and bnw_mode switches
--==========================================================
Events.SequenceGameInitComplete.Add(function()
include "UserInterfaceSettings"
local UserInterfaceSettings = UserInterfaceSettings
include "GameInfoCache" -- warning! booleans are true, not 1, and use iterator ONLY with table field conditions, NOT string SQL query
local GameInfo = GameInfoCache
include "IconHookup"
local IconHookup = IconHookup
local Color = Color
local PrimaryColors = PrimaryColors
local BackgroundColors = BackgroundColors
include "GetUnitBuildProgressData"
local GetUnitBuildProgressData = GetUnitBuildProgressData
--==========================================================
-- Minor lua optimizations
--==========================================================
local gk_mode = Game.GetReligionName ~= nil
local bnw_mode = Game.GetActiveLeague ~= nil
--local debug_print = print
local ceil = math.ceil
local floor = math.floor
local max = math.max
local pairs = pairs
--local print = print
local format = string.format
local concat = table.concat
local insert = table.insert
local remove = table.remove
local tostring = tostring
local ActionSubTypes = ActionSubTypes
local ActivityTypes = ActivityTypes
local ContextPtr = ContextPtr
local Controls = Controls
local DomainTypes = DomainTypes
local Events = Events
local Game = Game
local GameDefines = GameDefines
local GameInfoActions = GameInfoActions
local GameInfo_Automates = GameInfo.Automates
local GameInfo_Builds = GameInfo.Builds
local GameInfo_Missions = GameInfo.Missions
local GameInfo_Units = GameInfo.Units
local L = Locale.ConvertTextKey
local ToUpper = Locale.ToUpper
--local PlotDistance = Map.PlotDistance
local Mouse = Mouse
local OrderTypes = OrderTypes
local Players = Players
local Teams = Teams
local ToHexFromGrid = ToHexFromGrid
local DoSelectCityAtPlot = UI.DoSelectCityAtPlot
local GetHeadSelectedCity = UI.GetHeadSelectedCity
local GetHeadSelectedUnit = UI.GetHeadSelectedUnit
--local GetSelectedUnitID = UI.GetSelectedUnitID
local GetUnitFlagIcon = UI.GetUnitFlagIcon
local GetUnitPortraitIcon = UI.GetUnitPortraitIcon
local LookAt = UI.LookAt
local SelectUnit = UI.SelectUnit
include "InstanceManager"
local actionIM = InstanceManager:new("UnitAction", "UnitActionButton", Controls.ActionStack)
--==========================================================
-- Globals
--==========================================================
local g_activePlayerID, g_activePlayer, g_activeTeamID, g_activeTeam, g_activeTechs
local g_AllPlayerOptions = { UnitTypes = {}, UnitsInRibbon = {} }
local g_ActivePlayerUnitTypes
local g_ActivePlayerUnitsInRibbon = {}
local g_isHideCityList, g_isHideUnitList, g_isHideUnitTypes
--[[
_ _ _ _ ___ ____ _ _ _ ____ _ _ _
| | | |_ __ (_) |_ ___ ( _ ) / ___(_) |_(_) ___ ___ | _ \(_) |__ | |__ ___ _ __
| | | | '_ \| | __/ __| / _ \/\ | | | | __| |/ _ \/ __| | |_) | | '_ \| '_ \ / _ \| '_ \
| |_| | | | | | |_\__ \ | (_> < | |___| | |_| | __/\__ \ | _ <| | |_) | |_) | (_) | | | |
\___/|_| |_|_|\__|___/ \___/\/ \____|_|\__|_|\___||___/ |_| \_\_|_.__/|_.__/ \___/|_| |_|
]]
-- NO_ACTIVITY, ACTIVITY_AWAKE, ACTIVITY_HOLD, ACTIVITY_SLEEP, ACTIVITY_HEAL, ACTIVITY_SENTRY, ACTIVITY_INTERCEPT, ACTIVITY_MISSION
local g_activityMissions = {
--[ActivityTypes.ACTIVITY_AWAKE or -1] = nil,
[ActivityTypes.ACTIVITY_HOLD or -1] = false, --GameInfo_Missions.MISSION_SKIP, -- only when moves left > 0
--[ActivityTypes.ACTIVITY_SLEEP or -1] = GameInfo_Missions.MISSION_SLEEP, -- can be sleep or fortify
[ActivityTypes.ACTIVITY_HEAL or -1] = GameInfo_Missions.MISSION_HEAL,
[ActivityTypes.ACTIVITY_SENTRY or -1] = GameInfo_Missions.MISSION_ALERT,
[ActivityTypes.ACTIVITY_INTERCEPT or -1] = GameInfo_Missions.MISSION_AIRPATROL,
--[ActivityTypes.ACTIVITY_MISSION or -1] = GameInfo_Missions.MISSION_MOVE_TO,
[-1] = nil }
local MAX_HIT_POINTS = GameDefines.MAX_HIT_POINTS or 100
local AIR_UNIT_REBASE_RANGE_MULTIPLIER = GameDefines.AIR_UNIT_REBASE_RANGE_MULTIPLIER
local RELIGION_MISSIONARY_PRESSURE_MULTIPLIER = GameDefines.RELIGION_MISSIONARY_PRESSURE_MULTIPLIER or 1
local MOVE_DENOMINATOR = GameDefines.MOVE_DENOMINATOR
local g_unitsIM, g_citiesIM, g_unitTypesIM, g_units, g_cities, g_unitTypes
local g_cityFocusIcons = {
--[CityAIFocusTypes.NO_CITY_AI_FOCUS_TYPE or -1] = "",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_FOOD or -1] = "[ICON_FOOD]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_PRODUCTION or -1] = "[ICON_PRODUCTION]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_GOLD or -1] = "[ICON_GOLD]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_SCIENCE or -1] = "[ICON_RESEARCH]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_CULTURE or -1] = "[ICON_CULTURE]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_GREAT_PEOPLE or -1] = "[ICON_GREAT_PEOPLE]",
[CityAIFocusTypes.CITY_AI_FOCUS_TYPE_FAITH or -1] = "[ICON_PEACE]",
[-1] = nil }
local g_UnitTypeOrder = {}
do
local i = 1
for unit in GameInfo.Units() do
g_UnitTypeOrder[ unit.ID ] = i
i = i + 1
end
end
local function SortByVoid2( a, b )
return a and b and a:GetVoid2() > b:GetVoid2()
end
--==========================================================
-- Mod Panels
--==========================================================
local addinActions = {}
local addinBuilds = {}
function OnUnitPanelActionAddin(action)
print(string.format("Adding UnitPanel action %s (%s)", Locale.ConvertTextKey(action.Title), action.Name))
table.insert(addinActions, action)
end
LuaEvents.UnitPanelActionAddin.Add(OnUnitPanelActionAddin)
-- function OnUnitPanelBuildAddin(build)
-- print(string.format("Adding UnitPanel build %s (%s)", Locale.ConvertTextKey(build.Title), build.Name))
-- table.insert(addinBuilds, build)
-- end
-- LuaEvents.UnitPanelBuildAddin.Add(OnUnitPanelBuildAddin)
do
g_uiAddins = {}
local Modding = Modding
local insert = table.insert
local uiAddins = g_uiAddins
for addin in Modding.GetActivatedModEntryPoints("UnitPanelAddin") do
local addinFile = Modding.GetEvaluatedFilePath(addin.ModID, addin.Version, addin.File)
if addinFile then
print("Loading MOD UnitPanelUIAddin\n", Modding.GetModProperty(addin.ModID, addin.Version, "Name"), addin.File )
insert(uiAddins, ContextPtr:LoadNewContext( addinFile.EvaluatedPath:match("(.*)%..*")))
end
end
end
ContextPtr:LoadNewContext("EvilSpiritsMission")
ContextPtr:LoadNewContext("THTanukiMission")
--==========================================================
-- Tooltip Utilities
--==========================================================
local function lookAtPlot( plot )
local hex = ToHexFromGrid{ x=plot:GetX(), y=plot:GetY() }
Events.GameplayFX( hex.x, hex.y, -1 )
return LookAt( plot )
end
local function lookAtUnit( unit )
if unit then
return lookAtPlot( unit:GetPlot() )
end
end
--==========================================================
-- Ribbon Manager
--==========================================================
local function g_RibbonManager( name, stack, scrap, createAllItems, initItem, callbacks, tooltips, closure, toolTipCallback )
local index = {}
local spares = {}
local function Create( item, itemID, itemOrder )
if item then
local instance = remove( spares )
local button
if instance then
--debug_print("Recycle from scrap", name, instance, "item", itemID, item and item:GetName() )
button = instance.Button
button:ChangeParent( stack )
else
instance = { m_PromotionIcons={} }
--debug_print("Create new ", name, instance, "item", itemID, item and item:GetName() )
ContextPtr:BuildInstanceForControl( name, instance, stack )
-- Setup Tootip Callbacks
for controlID, toolTipType in pairs( tooltips ) do
instance[ controlID ]:SetToolTipCallback( function( control )
control:SetToolTipCallback( function( control ) return toolTipCallback( control, closure( button ) ) end )
control:SetToolTipType( toolTipType )
end)
end
-- Setup action Callbacks
button = instance.Button
for event, callback in pairs( callbacks ) do
button:RegisterCallback( event, callback )
end
end
index[ itemID ] = instance
button:SetVoids( itemID, itemOrder )
return initItem( item, instance )
--else print( "Failed attempt to add an item to the list", itemID )
end
end
return{
Create = Create,
Destroy = function( itemID )
local instance = index[ itemID ]
--debug_print( "Remove item from list", name, "item", itemID, instance )
if instance then
index[ itemID ] = nil
insert( spares, instance )
instance.Button:ChangeParent( scrap )
end
end,
Initialize = function( isHidden )
--debug_print("Initializing ", name, " stack", "hidden ?", isHidden )
for itemID, instance in pairs( index ) do
insert( spares, instance )
instance.Button:ChangeParent( scrap )
index[ itemID ] = nil
end
if not isHidden then
--debug_print("Initializing ", name, " stack contents" )
createAllItems( Create )
end
end,
}, index
end
--==========================================================
-- Item Functions
--==========================================================
local function UpdateCity( city, instance )
if city and instance then
local itemInfo, portraitOffset, portraitAtlas, buildPercent
local turnsRemaining = city:GetProductionTurnsLeft()
local productionNeeded = city:GetProductionNeeded()
local storedProduction = city:GetProduction() + city:GetOverflowProduction() + city:GetFeatureProduction()
local orderID, itemID = city:GetOrderFromQueue()
if orderID == OrderTypes.ORDER_TRAIN then
itemInfo = GameInfo.Units
portraitOffset, portraitAtlas = GetUnitPortraitIcon( itemID, g_activePlayerID )
elseif orderID == OrderTypes.ORDER_CONSTRUCT then
itemInfo = GameInfo.Buildings
elseif orderID == OrderTypes.ORDER_CREATE then
itemInfo = GameInfo.Projects
elseif orderID == OrderTypes.ORDER_MAINTAIN then
itemInfo = GameInfo.Processes
turnsRemaining = nil
productionNeeded = 0
end
if itemInfo then
itemInfo = itemInfo[ itemID ]or{}
itemInfo = IconHookup( portraitOffset or itemInfo.PortraitIndex, 64, portraitAtlas or itemInfo.IconAtlas, instance.CityProduction )
if productionNeeded > 0 then
buildPercent = 1 - max( 0, storedProduction/productionNeeded )
else
buildPercent = 0
end
instance.BuildMeter:SetPercents( 0, buildPercent )
else
turnsRemaining = nil
end
instance.CityProduction:SetHide( not itemInfo )
instance.BuildGrowth:SetString( turnsRemaining )
instance.CityPopulation:SetString( city:GetPopulation() )
local foodPerTurnTimes100 = city:FoodDifferenceTimes100()
if foodPerTurnTimes100 < 0 then
instance.CityGrowth:SetString( " [COLOR_RED]" .. (floor( city:GetFoodTimes100() / -foodPerTurnTimes100 ) + 1) .. "[ENDCOLOR] " )
elseif city:IsForcedAvoidGrowth() then
instance.CityGrowth:SetString( "[ICON_LOCKED]" )
elseif city:IsFoodProduction() or foodPerTurnTimes100 == 0 then
instance.CityGrowth:SetString()
else
instance.CityGrowth:SetString( " "..city:GetFoodTurnsLeft().." " )
end
local isNotPuppet = not city:IsPuppet()
local isNotRazing = not city:IsRazing()
local isNotResistance = not city:IsResistance()
local isCapital = city:IsCapital()
instance.CityIsCapital:SetHide( not isCapital )
instance.CityIsPuppet:SetHide( isNotPuppet )
instance.CityFocus:SetText( isNotRazing and isNotPuppet and g_cityFocusIcons[city:GetFocusType()] )
instance.CityQuests:SetText( city:GetWeLoveTheKingDayCounter() > 0 and "[ICON_HAPPINESS_1]" or (GameInfo.Resources[city:GetResourceDemanded()] or {}).IconString )
instance.CityIsRazing:SetHide( isNotRazing )
instance.CityIsResistance:SetHide( isNotResistance )
instance.CityIsConnected:SetHide( isCapital or not g_activePlayer:IsCapitalConnectedToCity( city ) )
instance.CityIsBlockaded:SetHide( not city:IsBlockaded() )
instance.CityIsOccupied:SetHide( not city:IsOccupied() or city:IsNoOccupiedUnhappiness() )
instance.Name:SetString( city:GetName() )
local culturePerTurn = city:GetJONSCulturePerTurn()
instance.BorderGrowth:SetString( culturePerTurn > 0 and ceil( (city:GetJONSCultureThreshold() - city:GetJONSCultureStored()) / culturePerTurn ) )
local percent = 1 - city:GetDamage() / ( gk_mode and city:GetMaxHitPoints() or GameDefines.MAX_CITY_HIT_POINTS )
instance.Button:SetColor( Color( 1, percent, percent, 1 ) )
end
end
local function UpdateUnit( unit, instance, nextInstance )
if unit and instance then
local unitMovesLeft = unit:MovesLeft()
local pip
if unitMovesLeft >= unit:MaxMoves() then
pip = 0 -- cyan (green)
elseif unitMovesLeft > 0 then
if unit:IsCombatUnit() and unit:IsOutOfAttacks() then
pip = 96 -- orange (gray)
else
pip = 32 -- green (yellow)
end
else
pip = 64 -- red
end
local damage = unit:GetDamage()
local percent
if damage <= 0 then
percent = 1
elseif instance == Controls then
percent = 1 - damage / MAX_HIT_POINTS / 3
else
percent = 1 - damage / MAX_HIT_POINTS
end
local info
local text
local buildID = unit:GetBuildType()
if buildID ~= -1 then -- unit is actively building something
info = GameInfo_Builds[buildID]
text = GetUnitBuildProgressData( unit:GetPlot(), buildID, unit )
if text > 99 then text = nil end
elseif unit:IsEmbarked() then
info = GameInfo_Missions.MISSION_EMBARK
elseif unit:IsReadyToMove() then
elseif unit:IsAutomated() then
if unit:IsWork() then
info = GameInfo_Automates.AUTOMATE_BUILD
elseif bnw_mode and unit:IsTrade() then
info = GameInfo_Missions.MISSION_ESTABLISH_TRADE_ROUTE
else
info = GameInfo_Automates.AUTOMATE_EXPLORE
end
elseif unit:LastMissionPlot() ~= unit:GetPlot() then
info = GameInfo_Missions.MISSION_MOVE_TO
elseif unit:IsWaiting() then
local activityType = unit:GetActivityType()
info = g_activityMissions[ activityType ]
if not info and unitMovesLeft > 0 then
--print( "ACTIVITY_MISSION", unit:GetName(), unit:GetX(), unit:GetY(), unit:GetPlot() ~= unit:LastMissionPlot() )
if info == false then
info = GameInfo_Missions.MISSION_SKIP
elseif unit:IsGarrisoned() then
info = GameInfo_Missions.MISSION_GARRISON
elseif unit:IsEverFortifyable() then
info = GameInfo_Missions.MISSION_FORTIFY
else
info = GameInfo_Missions.MISSION_SLEEP
end
end
elseif unitMovesLeft > 0 then
info = GameInfo_Missions.MISSION_MOVE_TO
end
repeat
instance.Button:SetColor( Color( 1, percent, percent, 1 ) )
instance.MovementPip:SetTextureOffsetVal( 0, pip )
instance.Mission:SetHide( not( info and IconHookup( info.IconIndex, 45, info.IconAtlas, instance.Mission ) ) )
instance.MissionText:SetText( text )
if nextInstance then
instance, nextInstance = nextInstance
instance.MovementPip:Play()
else
break
end
until false
end
end
local function FilterUnit( unit )
return unit and g_ActivePlayerUnitsInRibbon[ unit:GetUnitType() ]
end
--==========================================================
-- Unit Ribbon "Object"
--==========================================================
local CallFlagManagerUpdateUnitPromotions = LuaEvents.CallFlagManagerUpdateUnitPromotions.Call
g_unitsIM, g_units = g_RibbonManager( "UnitInstance", Controls.UnitStack, Controls.Scrap,
function( Create ) -- createAllItems( Create )
local unitID
for unit in g_activePlayer:Units() do
if FilterUnit( unit ) then
unitID = unit:GetID()
Create( unit, unitID, g_UnitTypeOrder[unit:GetUnitType()] * 65536 + unitID % 65536 )
end
end
Controls.UnitStack:SortChildren( SortByVoid2 )
end,
function( unit, instance ) -- initItem( item, instance )
local portraitOffset, portraitAtlas = GetUnitPortraitIcon( unit )
IconHookup( portraitOffset, 64, portraitAtlas, instance.Portrait )
if unit == GetHeadSelectedUnit() then
instance.MovementPip:Play()
else
instance.MovementPip:SetToBeginning()
end
UpdateUnit( unit, instance )
return CallFlagManagerUpdateUnitPromotions( unit )
end,
{-- the callback function table names need to match associated instance control ID defined in xml
[Mouse.eLClick] = function( unitID )
local unit = g_activePlayer:GetUnitByID( unitID )
SelectUnit( unit )
lookAtUnit( unit )
end,
[Mouse.eRClick] = function( unitID )
lookAtUnit( g_activePlayer:GetUnitByID( unitID ) )
end,
},--/unit callbacks
{
Button = "EUI_UnitTooltip",
MovementPip = "EUI_ItemTooltip",
Mission = "EUI_ItemTooltip",
},
function( button )
return g_activePlayer:GetUnitByID( button:GetVoid1() )
end,
LuaEvents.UnitToolTips.Call
)--/unit ribbon object
--==========================================================
LuaEvents.EUI_UnitRibbonTable( g_units )
--==========================================================
-- City Ribbon "Object"
--==========================================================
g_citiesIM, g_cities = g_RibbonManager( "CityInstance", Controls.CityStack, Controls.Scrap,
function( Create ) -- createAllItems( Create )
for city in g_activePlayer:Cities() do
Create( city, city:GetID() )
end
end,
UpdateCity, -- initItem( item, instance )
{-- the callback function table names need to match associated instance control ID defined in xml
[Mouse.eLClick] = function( cityID )
local city = g_activePlayer:GetCityByID( cityID )
if city then
DoSelectCityAtPlot( city:Plot() )
end
end,
[Mouse.eRClick] = function( cityID )
local city = g_activePlayer:GetCityByID( cityID )
if city then
lookAtPlot( city:Plot() )
end
end,
},--/city callbacks
{
Button = "EUI_CityProductionTooltip",
CityPopulation = "EUI_CityGrowthTooltip",
-- CityProduction = "EUI_CityProductionTooltip",
-- BuildMeter = "EUI_ItemTooltip",
-- GrowthMeter = "EUI_ItemTooltip",
CityIsCapital = "EUI_ItemTooltip",
CityIsPuppet = "EUI_ItemTooltip",
CityIsOccupied = "EUI_ItemTooltip",
CityIsResistance = "EUI_ItemTooltip",
CityIsRazing = "EUI_ItemTooltip",
CityIsConnected = "EUI_ItemTooltip",
CityIsBlockaded = "EUI_ItemTooltip",
CityFocus = "EUI_ItemTooltip",
CityGrowth = "EUI_ItemTooltip",
CityQuests = "EUI_ItemTooltip",
BuildGrowth = "EUI_ItemTooltip",
BorderGrowth = "EUI_ItemTooltip",
},
function( button )
return g_activePlayer:GetCityByID( button:GetVoid1() )
end,
LuaEvents.CityToolTips.Call
)--/city ribbon object
--==========================================================
--[[
_ _ _ _ ____ _
| | | |_ __ (_) |_ | _ \ __ _ _ __ ___| |
| | | | '_ \| | __| | |_) / _` | '_ \ / _ \ |
| |_| | | | | | |_ | __/ (_| | | | | __/ |
\___/|_| |_|_|\__| |_| \__,_|_| |_|\___|_|
]]
local g_screenWidth , g_screenHeight = UIManager:GetScreenSizeVal()
local g_topOffset0 = Controls.CityPanel:GetOffsetY()
local g_topOffset = g_topOffset0
local g_bottomOffset0 = Controls.UnitPanel:GetOffsetY()
local g_bottomOffset = g_bottomOffset0
local g_Actions = {}
local g_Promotions = {}
local g_UnusedControls = Controls.Scrap
local g_lastUnit -- Used to determine if a different unit has been selected.
local g_isWorkerActionPanelOpen = false
local g_unitPortraitSize = Controls.UnitPortrait:GetSizeX()
local g_actionButtonSpacing = OptionsManager.GetSmallUIAssets() and 42 or 58
--[[
local g_actionIconSize = OptionsManager.GetSmallUIAssets() and 36 or 50
local g_recommendedActionButton = {}
ContextPtr:BuildInstanceForControlAtIndex( "UnitAction", g_recommendedActionButton, Controls.WorkerActionStack, 1 )
--Controls.RecommendedActionLabel:ChangeParent( g_recommendedActionButton.UnitActionButton )
local g_existingBuild = {}
ContextPtr:BuildInstanceForControl( "UnitAction", g_existingBuild, Controls.WorkerActionStack )
g_existingBuild.WorkerProgressBar:SetPercent( 1 )
g_existingBuild.UnitActionButton:SetDisabled( true )
g_existingBuild.UnitActionButton:SetAlpha( 0.8 )
--]]
--==========================================================
-- Event Handlers
--==========================================================
local function OnUnitActionClicked( actionID )
local action = GameInfoActions[actionID]
if action and g_activePlayer:IsTurnActive() then
Game.HandleAction( actionID )
if action.SubType == ActionSubTypes.ACTIONSUBTYPE_PROMOTION then
Events.AudioPlay2DSound("AS2D_INTERFACE_UNIT_PROMOTION")
end
end
end
Controls.CycleLeft:RegisterCallback( Mouse.eLClick,
function()
-- Cycle to next selection.
Game.CycleUnits(true, true, false)
end)
Controls.CycleRight:RegisterCallback( Mouse.eLClick,
function()
-- Cycle to previous selection.
Game.CycleUnits(true, false, false)
end)
local function OnUnitNameClicked()
-- go to this unit
lookAtUnit( GetHeadSelectedUnit() )
end
Controls.UnitNameButton:RegisterCallback( Mouse.eLClick, OnUnitNameClicked )
do
local UnitToolTipCall = LuaEvents.UnitToolTip.Call
Controls.UnitPortraitButton:SetToolTipCallback( function( control )
control:SetToolTipCallback( function() return UnitToolTipCall( GetHeadSelectedUnit(), L"TXT_KEY_CURRENTLY_SELECTED_UNIT", "----------------" ) end )
control:SetToolTipType( "EUI_UnitTooltip" )
end)
end
Controls.UnitPortraitButton:RegisterCallback( Mouse.eLClick, OnUnitNameClicked )
Controls.UnitPortraitButton:RegisterCallback( Mouse.eRClick,
function()
local unit = GetHeadSelectedUnit()
Events.SearchForPediaEntry( unit and unit:GetNameKey() )
end)
local function OnEditNameClick()
if GetHeadSelectedUnit() then
Events.SerialEventGameMessagePopup{
Type = ButtonPopupTypes.BUTTONPOPUP_RENAME_UNIT,
Data1 = GetHeadSelectedUnit():GetID(),
Data2 = -1,
Data3 = -1,
Option1 = false,
Option2 = false
}
end
end
Controls.EditButton:RegisterCallback( Mouse.eLClick, OnEditNameClick )
Controls.UnitNameButton:RegisterCallback( Mouse.eRClick, OnEditNameClick )
--==========================================================
-- Utilities
--==========================================================
local function ResizeCityUnitRibbons()
--debug_print("ResizeCityUnitRibbons" )
local maxTotalStackHeight = g_screenHeight - g_topOffset - g_bottomOffset
local halfTotalStackHeight = floor(maxTotalStackHeight / 2)
Controls.CityStack:CalculateSize()
local cityStackHeight = Controls.CityStack:GetSizeY()
Controls.UnitStack:CalculateSize()
local unitStackHeight = Controls.UnitStack:GetSizeY()
if unitStackHeight + cityStackHeight <= maxTotalStackHeight then
unitStackHeight = false
halfTotalStackHeight = false
elseif cityStackHeight <= halfTotalStackHeight then
unitStackHeight = maxTotalStackHeight - cityStackHeight
halfTotalStackHeight = false
elseif unitStackHeight <= halfTotalStackHeight then
cityStackHeight = maxTotalStackHeight - unitStackHeight
unitStackHeight = false
else
cityStackHeight = halfTotalStackHeight
unitStackHeight = halfTotalStackHeight
end
Controls.CityScrollPanel:SetHide( not halfTotalStackHeight )
if halfTotalStackHeight then
Controls.CityStack:ChangeParent( Controls.CityScrollPanel )
Controls.CityScrollPanel:SetSizeY( cityStackHeight )
Controls.CityScrollPanel:CalculateInternalSize()
else
Controls.CityStack:ChangeParent( Controls.CityPanel )
end
Controls.CityPanel:ReprocessAnchoring()
-- Controls.CityPanel:SetSizeY( cityStackHeight )
Controls.UnitScrollPanel:SetHide( not unitStackHeight )
if unitStackHeight then
Controls.UnitStack:ChangeParent( Controls.UnitScrollPanel )
Controls.UnitScrollPanel:SetSizeY( unitStackHeight )
Controls.UnitScrollPanel:CalculateInternalSize()
else
Controls.UnitStack:ChangeParent( Controls.UnitPanel )
end
Controls.UnitPanel:ReprocessAnchoring()
end
local function UpdateUnits()
local activePlayer = g_activePlayer
for unitID, instance in pairs( g_units ) do
UpdateUnit( activePlayer:GetUnitByID( unitID ), instance )
end
end
local function UpdateCities()
local activePlayer = g_activePlayer
for cityID, instance in pairs( g_cities ) do
UpdateCity( activePlayer:GetCityByID( cityID ), instance )
end
end
local function UpdateSpecificCity( playerID, cityID )
if playerID == g_activePlayerID then
UpdateCity( g_activePlayer:GetCityByID( cityID ), g_cities[cityID] )
end
end
local function SelectUnitType( isChecked, unitTypeID ) -- Void2, control )
g_ActivePlayerUnitsInRibbon[ unitTypeID ] = isChecked
g_unitsIM.Initialize( g_isHideUnitList )
ResizeCityUnitRibbons()
-- only save player 0 preferences, not other hotseat player's
if g_activePlayerID == 0 then
UserInterfaceSettings[ "RIBBON_"..GameInfo_Units[ unitTypeID ].Type] = isChecked and 1 or 0
end
end
local function ResizeUnitTypesPanel()
-- if not g_isHideUnitTypes then
local n = Controls.UnitTypesStack:GetNumChildren()
Controls.UnitTypesStack:SetWrapWidth( ceil( n / ceil( n / 5 ) ) * 64 )
Controls.UnitTypesStack:CalculateSize()
local x, y = Controls.UnitTypesStack:GetSizeVal()
if y<64 then y=64 elseif y>320 then y=320 end
Controls.UnitTypesPanel:SetSizeVal( x+40, y+85 )
Controls.UnitTypesScrollPanel:SetSizeVal( x, y )
Controls.UnitTypesScrollPanel:CalculateInternalSize()
Controls.UnitTypesScrollPanel:ReprocessAnchoring()
end
local function AddUnitType( unit, unitID )
local unitTypeID = unit:GetUnitType()
g_ActivePlayerUnitTypes[ unitID or unit:GetID() ] = unitTypeID
local instance = g_unitTypes[ unitTypeID ]
if instance then
--debug_print( "Add unit:", unit:GetID(), unit:GetName(), "type:", instance, unitTypeID, "count:", n )
return instance.Count:SetText( instance.Count:GetText()+1 )
else
--debug_print( "Add unit:", unit:GetID(), unit:GetName(), "new type:", unitTypeID )
g_unitTypesIM.Create( unit, unitTypeID, -g_UnitTypeOrder[unitTypeID] )
if unitID then
Controls.UnitTypesStack:SortChildren( SortByVoid2 )
return ResizeUnitTypesPanel()
end
end
end
--==========================================================
-- Unit Options "Object"
--==========================================================
g_unitTypesIM, g_unitTypes = g_RibbonManager( "UnitTypeInstance", Controls.UnitTypesStack, Controls.Scrap,
function() -- createAllItems
g_ActivePlayerUnitTypes = {}
for unit in g_activePlayer:Units() do
AddUnitType( unit )
end
Controls.UnitTypesStack:SortChildren( SortByVoid2 )
return ResizeUnitTypesPanel()
end,
function( unit, instance ) -- initItem( item, instance )
local portrait = instance.Portrait
local portraitOffset, portraitAtlas = GetUnitPortraitIcon( unit )
portrait:SetHide(not ( portraitOffset and portraitAtlas and IconHookup( portraitOffset, portrait:GetSizeX(), portraitAtlas, portrait ) ) )
instance.CheckBox:RegisterCheckHandler( SelectUnitType )
local unitTypeID = unit:GetUnitType()
instance.CheckBox:SetCheck( g_ActivePlayerUnitsInRibbon[ unitTypeID ] )
instance.CheckBox:SetVoid1( unitTypeID )
instance.Count:SetText("1")
end,
{-- the callback function table names need to match associated instance control ID defined in xml
[Mouse.eRClick] = function( unitTypeID )
local unit = GameInfo.Units[ unitTypeID ]
if unit then
Events.SearchForPediaEntry( unit.Description )
end
end,
},--/unit options callbacks
{-- the tooltip function names need to match associated instance control ID defined in xml
Button = "EUI_ItemTooltip",
},--/units options tooltips
function( button )
return button:GetVoid1()
end,
LuaEvents.UnitPanelItemTooltip.Call
)--/unit options object
local function CreateUnit( playerID, unitID ) --hexVec, unitType, cultureType, civID, primaryColor, secondaryColor, unitFlagIndex, fogState, selected, military, notInvisible )
if playerID == g_activePlayerID then
local unit = g_activePlayer:GetUnitByID( unitID )
--debug_print("Create unit", unitID, unit and unit:GetName() )
if unit then
AddUnitType( unit, unitID )
if FilterUnit( unit ) then
g_unitsIM.Create( unit, unitID, g_UnitTypeOrder[unit:GetUnitType()] + unitID / 65536 )
Controls.UnitStack:SortChildren( SortByVoid2 )
return ResizeCityUnitRibbons()
end
end
end
end
local function CreateCity( hexPos, playerID, cityID ) --, cultureType, eraType, continent, populationSize, size, fowState )
if playerID == g_activePlayerID then
g_citiesIM.Create( g_activePlayer:GetCityByID( cityID ), cityID )
return ResizeCityUnitRibbons()
end
end
local function DestroyUnit( playerID, unitID )
if playerID == g_activePlayerID then
g_unitsIM.Destroy( unitID )
local unitTypeID = g_ActivePlayerUnitTypes[ unitID ]
local instance = g_unitTypes[ unitTypeID ]
--debug_print( "Destroy unit", unitID, "type:", g_ActivePlayerUnitTypes[ unitID ], instance, "previous count:", instance.Count )
g_ActivePlayerUnitTypes[ unitID ] = nil
if instance then
local n = instance.Count:GetText() - 1
if n <= 0 then
g_unitTypesIM.Destroy( unitTypeID )
ResizeUnitTypesPanel()
else
instance.Count:SetText( n )
end
end
return ResizeCityUnitRibbons()
end
end
local function DestroyCity( hexPos, playerID, cityID )
if playerID == g_activePlayerID then
g_citiesIM.Destroy( cityID )
return ResizeCityUnitRibbons()
end
end
local function SetHide( ... )
for _, control in pairs{...} do
control:SetHide( true )
end
end
local function SetShow( ... )
for _, control in pairs{...} do
control:SetHide( false )
end
end
local function SetTextAndFontSize( control, text, x )
control:SetText( text )
for i = 24, 14, -2 do
control:SetFontByName( "TwCenMT"..i )
if control:GetSizeVal() <= x then
break
end
end
end
local function DeselectLastUnit( unit )
if g_lastUnit then
local lastUnitID = g_lastUnit:GetID()
Events.UnitSelectionChanged( g_lastUnit:GetOwner(), lastUnitID, 0, 0, 0, false, false )
local instance = g_units[ lastUnitID ]
if instance then
instance.MovementPip:SetToBeginning()
UpdateUnit( g_lastUnit, instance )
end
end
g_lastUnit = unit
end
local g_infoSource = {
[ ActionSubTypes.ACTIONSUBTYPE_PROMOTION or -1 ] = GameInfo.UnitPromotions,
[ ActionSubTypes.ACTIONSUBTYPE_INTERFACEMODE or -1 ] = GameInfo.InterfaceModes,
[ ActionSubTypes.ACTIONSUBTYPE_MISSION or -1 ] = GameInfo.Missions,
[ ActionSubTypes.ACTIONSUBTYPE_COMMAND or -1 ] = GameInfo.Commands,
[ ActionSubTypes.ACTIONSUBTYPE_AUTOMATE or -1 ] = GameInfo.Automates,
[ ActionSubTypes.ACTIONSUBTYPE_BUILD or -1 ] = GameInfo.Builds,
[ ActionSubTypes.ACTIONSUBTYPE_CONTROL or -1 ] = GameInfo.Controls,
[-1] = nil
}
local UnitActionToolTipCall = LuaEvents.UnitActionToolTip.Call
local function UnitActionToolTip( button )
button:SetToolTipCallback( UnitActionToolTipCall )
button:SetToolTipType( "EUI_UnitAction" )
end
local function UpdateUnitPanel()
actionIM:ResetInstances()
-- Retrieve the currently selected unit.
local unit = GetHeadSelectedUnit()
-- Events.GameplayAlertMessage( "SerialEventUnitInfoDirty, GetHeadSelectedUnit=".. tostring(unit and unit:GetName())..", last unit="..tostring(g_lastUnit and g_lastUnit:GetName()) )
--debug_print( "UpdateUnitPanel", "GetHeadSelectedCity", GetHeadSelectedCity() and GetHeadSelectedCity():GetName(), "GetHeadSelectedUnit", GetHeadSelectedUnit()and GetHeadSelectedUnit():GetName(), "Last unit", g_lastUnit and g_lastUnit:GetName() )
if unit then
local unitID = unit:GetID()
-- Selected Unit
if unit ~= g_lastUnit then
DeselectLastUnit( unit )
local hexPosition = ToHexFromGrid{ x = unit:GetX(), y = unit:GetY() }
Events.UnitSelectionChanged( unit:GetOwner(), unitID, hexPosition.x, hexPosition.y, 0, true, false )
end
local unitMovesLeft = unit:MovesLeft() / MOVE_DENOMINATOR
local unitPlot = unit:GetPlot()
-- Unit Name
SetTextAndFontSize( Controls.UnitName, ToUpper( L( unit:IsGreatPerson() and unit:HasName() and unit:GetNameNoDesc() or unit:GetName() ) ), Controls.UnitNameButton:GetSizeVal()-50 )
-- Unit Actions
local canPromote = unit:IsPromotionReady()
local GameCanHandleAction = Game.CanHandleAction
local numBuildActions = 0
local action, instance, button, buildTurnsLeft, buildProgress, buildTime, canBuild, isBuildRecommended
--==========================================================
--Mod Actions
--==========================================================
local function SetToolTip(sTitle, sToolTip)
print(string.format("Setting Tooltip: Title: %s - Tooltip: %s", sTitle, sToolTip))
local ttTable = {}
TTManager:GetTypeControlTable( "EUI_UnitAction", ttTable )
ttTable.UnitActionHelp:SetText(string.format("[NEWLINE]%s", sToolTip))
ttTable.UnitActionText:SetText(string.format("[COLOR_POSITIVE_TEXT]%s[ENDCOLOR]", Locale.ConvertTextKey(sTitle)))
ttTable.UnitActionHotKey:SetText("")
ttTable.UnitActionMouseover:DoAutoSize()
local mouseoverSize = ttTable.UnitActionMouseover:GetSize();
if (mouseoverSize.x < 350) then
ttTable.UnitActionMouseover:SetSizeX(350)
end
end
for _, action in pairs(addinActions) do
print(string.format("Processing UnitPanel action %s (%s)", Locale.ConvertTextKey(action.Title), action.Name))
if (action.Condition == nil or
(type(action.Condition) == "function" and action.Condition(action, unit)) or
(type(action.Condition) ~= "function" and action.Condition)) then
local instance = actionIM:GetInstance()
if ((type(action.Disabled) == "function" and action.Disabled(action, unit)) or
(type(action.Disabled) ~= "function" and action.Disabled)) then
instance.UnitActionButton:SetAlpha(0.4)
instance.UnitActionButton:SetDisabled(true)
else
instance.UnitActionButton:SetAlpha(1.0)
instance.UnitActionButton:SetDisabled(false)
end
IconHookup(action.PortraitIndex, actionIconSize, action.IconAtlas, instance.UnitActionIcon)
local sTitle
if (type(action.Title) == "function") then
sTitle = action.Title(action, unit)
else
sTitle = action.Title
end
local sToolTip
if (type(action.ToolTip) == "function") then
sToolTip = action.ToolTip(action, unit)
else
sToolTip = action.ToolTip
end
instance.UnitActionButton:SetToolTipCallback(function() SetToolTip(sTitle, sToolTip) end)
if (type(action.Action) == "function") then
instance.UnitActionButton:RegisterCallback(Mouse.eLClick, function() action.Action(action, unit, Mouse.eLClick) end)
instance.UnitActionButton:RegisterCallback(Mouse.eRClick, function() action.Action(action, unit, Mouse.eRClick) end)
else
instance.UnitActionButton:RegisterCallback(Mouse.eLClick, function() end)
instance.UnitActionButton:RegisterCallback(Mouse.eRClick, function() end)
end
end
end
-- for _, build in pairs(addinBuilds) do
-- if (build.Condition == nil or
-- (type(build.Condition) == "function" and build.Condition(build, unit)) or
-- (type(build.Condition) ~= "function" and build.Condition)) then
-- local instance = g_BuildIM:GetInstance()
-- instance.UnitActionButton:SetAnchor( "L,B" )
-- instance.UnitActionButton:SetOffsetVal((numBuildActions % numberOfButtonsPerRow) * buttonSize + buttonPadding + buttonOffsetX, math.floor(numBuildActions / numberOfButtonsPerRow) * buttonSize + buttonPadding + buttonOffsetY)
-- numBuildActions = numBuildActions + 1
-- if ((type(build.Disabled) == "function" and build.Disabled(build, unit)) or
-- (type(build.Disabled) ~= "function" and build.Disabled)) then
-- instance.UnitActionButton:SetAlpha(0.4)
-- instance.UnitActionButton:SetDisabled(true)
-- else
-- instance.UnitActionButton:SetAlpha(1.0)
-- instance.UnitActionButton:SetDisabled(false)
-- end
-- IconHookup(build.PortraitIndex, actionIconSize, build.IconAtlas, instance.UnitActionIcon)
-- local sToolTip
-- if (type(build.ToolTip) == "function") then
-- sToolTip = build.ToolTip(build, unit)
-- else
-- sToolTip = build.ToolTip
-- end
-- instance.UnitActionButton:SetToolTipCallback(function() SetToolTip(build.Title, sToolTip) end)
-- if (type(build.Build) == "function") then
-- instance.UnitActionButton:RegisterCallback(Mouse.eLClick, function() build.Build(build, unit, Mouse.eLClick) end)
-- instance.UnitActionButton:RegisterCallback(Mouse.eRClick, function() build.Build(build, unit, Mouse.eRClick) end)
-- else
-- instance.UnitActionButton:RegisterCallback(Mouse.eLClick, function() end)
-- instance.UnitActionButton:RegisterCallback(Mouse.eRClick, function() end)
-- end
-- if (recommendedBuild == nil and
-- ((type(build.Recommended) == "function" and build.Recommended(build, unit)) or
-- (type(build.Recommended) ~= "function" and build.Recommended))) then
-- recommendedBuild = build;
-- IconHookup(build.PortraitIndex, actionIconSize, build.IconAtlas, Controls.RecommendedActionImage)
-- if (type(build.Build) == "function") then
-- Controls.RecommendedActionButton:RegisterCallback(Mouse.eLClick, function() build.Build(build, unit, Mouse.eLClick) end)
-- Controls.RecommendedActionButton:RegisterCallback(Mouse.eRClick, function() build.Build(build, unit, Mouse.eRClick) end)
-- else
-- Controls.RecommendedActionButton:RegisterCallback(Mouse.eLClick, function() end)
-- Controls.RecommendedActionButton:RegisterCallback(Mouse.eRClick, function() end)
-- end
-- Controls.RecommendedActionButton:SetToolTipCallback(function() SetToolTip(build.Title, sToolTip) end)
-- Controls.RecommendedActionLabel:SetText(Locale.ConvertTextKey(build.Title))
-- end
-- end
-- end
--==========================================================
for actionID = 0, #GameInfoActions do
action = GameInfoActions[ actionID ]
if action and action.Visible ~= false then
instance = g_Actions[ actionID ]
if GameCanHandleAction( actionID, unitPlot, true ) then
if instance then
button = instance.UnitActionButton
else
instance = {}
instance.isBuild = action.SubType == ActionSubTypes.ACTIONSUBTYPE_BUILD
instance.isBuildType = instance.isBuild or action.Type == "INTERFACEMODE_ROUTE_TO" or action.Type == "AUTOMATE_BUILD"
instance.isPromotion = action.SubType == ActionSubTypes.ACTIONSUBTYPE_PROMOTION
instance.isException = instance.isPromotion or action.Type == "COMMAND_CANCEL" or action.Type == "COMMAND_STOP_AUTOMATION"
instance.recommendation = (bnw_mode and (L"TXT_KEY_UPANEL_RECOMMENDED" .. "[NEWLINE]") or "") .. L( tostring( action.TextKey or action.Type ) )
if action.Type == "MISSION_FOUND" then
instance.UnitActionButton = Controls.BuildCityButton
else
ContextPtr:BuildInstanceForControl( "UnitAction", instance, g_UnusedControls )
instance.WorkerProgressBar:SetHide( not instance.isBuild )
local info = ( g_infoSource[ action.SubType ] or {} )[ action.Type ]
if info then
instance.IconIndex = info.IconIndex or info.PortraitIndex
instance.IconAtlas = info.IconAtlas
IconHookup( instance.IconIndex, instance.UnitActionIcon:GetSizeX(), instance.IconAtlas, instance.UnitActionIcon )
end
end
button = instance.UnitActionButton
button:RegisterCallback( Mouse.eLClick, OnUnitActionClicked )
button:SetVoid1( actionID )
button:SetToolTipCallback( UnitActionToolTip )
instance.ID = actionID
g_Actions[ actionID ] = instance
end
if unitMovesLeft > 0 or instance.isException then
if instance.isPromotion then
numBuildActions = numBuildActions + 1
button:ChangeParent( Controls.WorkerActionStack )
elseif instance.isBuildType and not canPromote then
numBuildActions = numBuildActions + 1
if unitMovesLeft > 0 and not isBuildRecommended and unit:IsActionRecommended( actionID ) then
isBuildRecommended = true
button:ChangeParent( Controls.RecommendedActionIcon )
Controls.RecommendedActionLabel:SetText( instance.recommendation )
else
button:ChangeParent( Controls.WorkerActionStack )
end
if instance.isBuild then
canBuild = true
buildTurnsLeft, buildProgress, buildTime = GetUnitBuildProgressData( unitPlot, action.MissionData, unit )
instance.WorkerProgressBar:SetPercent( buildProgress / buildTime )
instance.UnitActionText:SetText( buildTurnsLeft > 0 and buildTurnsLeft or nil )
end
else
button:ChangeParent( Controls.ActionStack )
end
-- test w/o visible flag (ie can train right now)
if GameCanHandleAction( actionID, unitPlot, false ) then
button:SetAlpha( 1.0 )
button:SetDisabled( false )
else
button:SetAlpha( 0.6 )
button:SetDisabled( true )
end
instance.isVisible = true
elseif instance.isVisible then
button:ChangeParent( g_UnusedControls )
instance.isVisible = false
end
elseif instance and instance.isVisible then
instance.UnitActionButton:ChangeParent( g_UnusedControls )
instance.isVisible = false
end
end -- action.Visible
end -- GameInfoActions loop
if numBuildActions > 0 or canPromote then
Controls.WorkerActionPanel:SetHide( false )
g_isWorkerActionPanelOpen = true
Controls.RecommendedAction:SetHide( not isBuildRecommended )
--[[
local improvement = canBuild and not canPromote and GameInfo.Improvements[ unitPlot:GetImprovementType() ]
local build = improvement and GameInfo_Builds{ ImprovementType = improvement.Type }()
if build then
numBuildActions = numBuildActions + 1
IconHookup( build.IconIndex, g_actionIconSize, build.IconAtlas, g_existingBuild.UnitActionIcon )
end
g_existingBuild.UnitActionButton:SetHide( not build )
--]]
Controls.WorkerText:SetHide( canPromote )
Controls.PromotionText:SetHide( not canPromote )
Controls.PromotionAnimation:SetHide( not canPromote )
Controls.EditButton:SetHide( not canPromote )
Controls.WorkerActionStack:SetWrapWidth( isBuildRecommended and 232 or ceil( numBuildActions / ceil( numBuildActions / 5 ) ) * g_actionButtonSpacing )
Controls.WorkerActionStack:CalculateSize()
local x, y = Controls.WorkerActionStack:GetSizeVal()
Controls.WorkerActionPanel:SetSizeVal( max( x, 200 ) + 50, y + 96 )
Controls.WorkerActionStack:ReprocessAnchoring()
else
Controls.WorkerActionPanel:SetHide( true )
g_isWorkerActionPanelOpen = false
end
-- Unit XP
if unit:IsCombatUnit() or unit:GetDomainType() == DomainTypes.DOMAIN_AIR then
local iLevel = unit:GetLevel()
local iExperience = unit:GetExperience()
local iExperienceNeeded = unit:ExperienceNeeded()
Controls.XPMeter:LocalizeAndSetToolTip( "TXT_KEY_UNIT_EXPERIENCE_INFO", iLevel, iExperience, iExperienceNeeded )
Controls.XPMeter:SetPercent( iExperience / iExperienceNeeded )
Controls.XPFrame:SetHide( false )
else
Controls.XPFrame:SetHide( true )
end
-- Unit Flag
local flagOffset, flagAtlas = GetUnitFlagIcon( unit )
IconHookup( flagOffset, 32, flagAtlas, Controls.UnitIcon )
IconHookup( flagOffset, 32, flagAtlas, Controls.UnitIconShadow )
-- Unit Portrait
local portraitOffset, portraitAtlas = GetUnitPortraitIcon( unit )
IconHookup( portraitOffset, g_unitPortraitSize, portraitAtlas, Controls.UnitPortrait )
-- Unit Promotions
for promotion in GameInfo.UnitPromotions() do
if promotion.ShowInUnitPanel ~= false then
instance = g_Promotions[ promotion.ID ]
if unit:IsHasPromotion( promotion.ID ) then
if instance then
instance.EarnedPromotion:ChangeParent( Controls.EarnedPromotionStack )
else
instance = {}
ContextPtr:BuildInstanceForControl( "EarnedPromotionInstance", instance, Controls.EarnedPromotionStack )
IconHookup( promotion.PortraitIndex, 32, promotion.IconAtlas, instance.UnitPromotionImage )
instance.EarnedPromotion:SetToolTipString( ( promotion._Name or "???" ) .. "[NEWLINE][NEWLINE]" .. L(promotion.Help or "???") )
g_Promotions[ promotion.ID ] = instance
end
instance.isVisible = true
elseif instance and instance.isVisible then
instance.EarnedPromotion:ChangeParent( g_UnusedControls )
instance.isVisible = false
end
end
end
-- Unit Movement
if unit:GetDomainType() == DomainTypes.DOMAIN_AIR then
local unitRange = unit:Range()
Controls.UnitStatMovement:SetText( unitRange .. "[ICON_MOVES]" )
Controls.UnitStatMovement:LocalizeAndSetToolTip( "TXT_KEY_UPANEL_UNIT_MAY_STRIKE_REBASE", unitRange, unitRange * AIR_UNIT_REBASE_RANGE_MULTIPLIER / 100 )
else
local text = format(" %.3g/%g[ICON_MOVES]", unitMovesLeft, unit:MaxMoves() / MOVE_DENOMINATOR )
Controls.UnitStatMovement:SetText( text )
Controls.UnitStatMovement:LocalizeAndSetToolTip( "TXT_KEY_UPANEL_UNIT_MAY_MOVE", text )
end
-- Unit Strength
local strength = ( unit:GetDomainType() == DomainTypes.DOMAIN_AIR and unit:GetBaseRangedCombatStrength() )
or ( not unit:IsEmbarked() and unit:GetBaseCombatStrength() ) or 0
if strength > 0 then
Controls.UnitStatStrength:SetText( strength .. "[ICON_STRENGTH]" )
Controls.UnitStatStrength:LocalizeAndSetToolTip( "TXT_KEY_UPANEL_STRENGTH_TT" )
elseif gk_mode and unit:GetSpreadsLeft() > 0 then
-- Religious units
Controls.UnitStatStrength:SetText( floor(unit:GetConversionStrength()/RELIGION_MISSIONARY_PRESSURE_MULTIPLIER) .. "[ICON_PEACE]" )
Controls.UnitStatStrength:LocalizeAndSetToolTip( "TXT_KEY_UPANEL_RELIGIOUS_STRENGTH_TT" )
elseif bnw_mode and unit:GetTourismBlastStrength() > 0 then
Controls.UnitStatStrength:SetText( unit:GetTourismBlastStrength() .. "[ICON_TOURISM]" )
Controls.UnitStatStrength:LocalizeAndSetToolTip( "TXT_KEY_UPANEL_TOURISM_STRENGTH_TT" )
else
Controls.UnitStatStrength:SetText()
end
-- Ranged Strength
local rangedStrength = unit:GetDomainType() ~= DomainTypes.DOMAIN_AIR and unit:GetBaseRangedCombatStrength() or 0
if rangedStrength > 0 then
Controls.UnitStatRangedAttack:SetText( rangedStrength .. "[ICON_RANGE_STRENGTH]" .. unit:Range() )
Controls.UnitStatRangedAttack:LocalizeAndSetToolTip( "TXT_KEY_UPANEL_RANGED_ATTACK_TT" )
elseif gk_mode and unit:GetSpreadsLeft() > 0 then
-- Religious units
local unitReligion = unit:GetReligion()
local icon = (GameInfo.Religions[unitReligion] or {}).IconString
Controls.UnitStatRangedAttack:SetText( icon and (unit:GetSpreadsLeft()..icon) )
Controls.UnitStatRangedAttack:SetToolTipString( L(Game.GetReligionName(unitReligion))..": "..L"TXT_KEY_UPANEL_SPREAD_RELIGION_USES_TT" )
-- elseif gk_mode and GameInfo_Units[unit:GetUnitType()].RemoveHeresy then
-- Controls.UnitStatRangedAttack:LocalizeAndSetText( "TXT_KEY_UPANEL_REMOVE_HERESY_USES" )
-- Controls.UnitStatRangedAttack:LocalizeAndSetToolTip( "TXT_KEY_UPANEL_REMOVE_HERESY_USES_TT" )
elseif bnw_mode and unit:CargoSpace() > 0 then
Controls.UnitStatRangedAttack:SetText( L"TXT_KEY_UPANEL_CARGO_CAPACITY" .. " " .. unit:CargoSpace() )
Controls.UnitStatRangedAttack:LocalizeAndSetToolTip( "TXT_KEY_UPANEL_CARGO_CAPACITY_TT", unit:GetName() )
else
Controls.UnitStatRangedAttack:SetText()
end
Controls.UnitStats:CalculateSize()
Controls.UnitStats:ReprocessAnchoring()
-- Unit Health Bar
local damage = unit:GetDamage()
if damage ~= 0 then
local healthPercent = 1.0 - (damage / MAX_HIT_POINTS)
local barSize = 123 * healthPercent
if healthPercent <= .33 then
Controls.RedBar:SetSizeY(barSize)
Controls.RedAnim:SetSizeY(barSize)
Controls.GreenBar:SetHide(true)
Controls.YellowBar:SetHide(true)
Controls.RedBar:SetHide(false)
elseif healthPercent <= .66 then
Controls.YellowBar:SetSizeY(barSize)
Controls.GreenBar:SetHide(true)
Controls.YellowBar:SetHide(false)
Controls.RedBar:SetHide(true)
else
Controls.GreenBar:SetSizeY(barSize)
Controls.GreenBar:SetHide(false)
Controls.YellowBar:SetHide(true)
Controls.RedBar:SetHide(true)
end
Controls.HealthBar:LocalizeAndSetToolTip( "TXT_KEY_UPANEL_SET_HITPOINTS_TT", MAX_HIT_POINTS-damage, MAX_HIT_POINTS )
Controls.HealthBar:SetHide(false)
else
Controls.HealthBar:SetHide(true)
end
-- Unit Stats
UpdateUnit( unit, Controls, g_units[ unitID ] )
Controls.UnitStatBox:SetHide( bnw_mode and unit:IsTrade() )
-- These controls need to be shown since potentially hidden depending on previous selection
SetShow( Controls.EarnedPromotionStack, Controls.UnitTypeFrame, Controls.CycleLeft, Controls.CycleRight, Controls.ActionStack )
Controls.ActionStack:CalculateSize()
Controls.ActionStack:ReprocessAnchoring()
else
-- Deselect last unit, if any
DeselectLastUnit()
-- Attempt to show currently selected city
unit = GetHeadSelectedCity()
if unit then
-- City Name
SetTextAndFontSize( Controls.UnitName, ToUpper( L(unit:GetName()) ), Controls.UnitNameButton:GetSizeVal()-50 )
-- City Portrait
IconHookup( 0, g_unitPortraitSize, "CITY_ATLAS", Controls.UnitPortrait )
-- Hide various aspects of Unit Panel since they don't apply to the city.
SetHide( Controls.EarnedPromotionStack, Controls.UnitTypeFrame, Controls.CycleLeft, Controls.CycleRight, Controls.XPFrame, Controls.UnitStatBox, Controls.WorkerActionPanel, Controls.ActionStack )
g_isWorkerActionPanelOpen = false
end
end
if (not unit) ~= Controls.Panel:IsHidden() then
if unit then
g_bottomOffset = g_bottomOffset0
Controls.UnitTypesPanel:SetOffsetVal( g_unitPortraitSize * 0.625, 120 )
else
g_bottomOffset = 35
Controls.UnitTypesPanel:SetOffsetVal( 80, -40 )
end
Controls.Panel:SetHide( not unit )
Controls.Actions:SetHide( not unit )
Controls.UnitPanel:SetOffsetY( g_bottomOffset )
ResizeCityUnitRibbons()
end
end
local function UpdateOptions()
local option = UserInterfaceSettings.UnitTypes == 0
if g_isHideUnitTypes ~= option then
g_unitTypesIM.Initialize( option )
ResizeUnitTypesPanel()
g_isHideUnitTypes = option
Controls.UnitTypesOpen:SetHide( option )
Controls.UnitTypesClose:SetHide( not option )
end
option = UserInterfaceSettings.UnitRibbon == 0
if g_isHideUnitList ~= option then
g_isHideUnitList = option
local AddOrRemove = option and "Remove" or "Add"
Events.SerialEventUnitCreated[ AddOrRemove ]( CreateUnit )
Events.SerialEventUnitDestroyed[ AddOrRemove ]( DestroyUnit )
Events.ActivePlayerTurnStart[ AddOrRemove ]( UpdateUnits )
end
g_unitsIM.Initialize( option )
Controls.UnitPanel:SetHide( option )
Controls.UnitTypesPanel:SetHide( option or g_isHideUnitTypes )
option = UserInterfaceSettings.CityRibbon == 0
if g_isHideCityList ~= option then
g_isHideCityList = option
local AddOrRemove = option and "Remove" or "Add"
Events.SerialEventCityCreated[ AddOrRemove ]( CreateCity )
Events.SerialEventCityDestroyed[ AddOrRemove ]( DestroyCity )
Events.SerialEventCityCaptured[ AddOrRemove ]( DestroyCity )
Events.SerialEventCityInfoDirty[ AddOrRemove ]( UpdateCities )
Events.SerialEventCitySetDamage[ AddOrRemove ]( UpdateSpecificCity )
Events.SpecificCityInfoDirty[ AddOrRemove ]( UpdateSpecificCity )
end
g_citiesIM.Initialize( option )
Controls.CityPanel:SetHide( option )
UpdateUnitPanel()
ResizeCityUnitRibbons()
end
Controls.UnitTypesButton:RegisterCallback( Mouse.eLClick,
function()
UserInterfaceSettings.UnitTypes = g_isHideUnitTypes and 1 or 0
return UpdateOptions()
end)
local function SetActivePlayer()-- activePlayerID, prevActivePlayerID )
-- initialize globals
if g_activePlayerID then
g_AllPlayerOptions.UnitTypes[ g_activePlayerID ] = g_ActivePlayerUnitTypes
g_AllPlayerOptions.UnitsInRibbon[ g_activePlayerID ] = g_ActivePlayerUnitsInRibbon
end
g_activePlayerID = Game.GetActivePlayer()
g_activePlayer = Players[ g_activePlayerID ]
g_activeTeamID = g_activePlayer:GetTeam()
g_activeTeam = Teams[ g_activeTeamID ]
g_activeTechs = g_activeTeam:GetTeamTechs()
g_ActivePlayerUnitTypes = g_AllPlayerOptions.UnitTypes[ g_activePlayerID ] or {}
g_ActivePlayerUnitsInRibbon = g_AllPlayerOptions.UnitsInRibbon[ g_activePlayerID ]
if not g_ActivePlayerUnitsInRibbon then
g_ActivePlayerUnitsInRibbon = {}
for row in GameInfo.Units() do
g_ActivePlayerUnitsInRibbon[ row.ID ] = UserInterfaceSettings[ "RIBBON_"..row.Type ] ~= 0
end
end
-- set civilization icon and color
local civInfo = GameInfo.Civilizations[ g_activePlayer:GetCivilizationType() ] or {}
IconHookup( civInfo.PortraitIndex, 128, civInfo.IconAtlas, Controls.BackgroundCivSymbol )
Controls.UnitIcon:SetColor( PrimaryColors[ g_activePlayerID ] )
Controls.UnitIconBackground:SetColor( BackgroundColors[ g_activePlayerID ] )
return UpdateOptions()
end
SetActivePlayer()
Events.GameplaySetActivePlayer.Add( SetActivePlayer )
Events.GameOptionsChanged.Add( UpdateOptions )
Events.SerialEventUnitInfoDirty.Add( UpdateUnitPanel )
--[[
Events.UnitActionChanged.Add(
function( playerID, unitID )
if playerID == g_activePlayerID then
local instance = g_units[ unitID ]
if instance then
return UpdateUnit( g_activePlayer:GetUnitByID( unitID ), instance )
end
end
end)
--]]
Events.SerialEventEnterCityScreen.Add(
function()
DeselectLastUnit()
end)
local g_infoCornerYmax = {
[InfoCornerID.None or -1] = g_topOffset0,
[InfoCornerID.Tech or -1] = OptionsManager.GetSmallUIAssets() and 150 or 225,
[-1] = nil }
Events.OpenInfoCorner.Add( function( infoCornerID )
g_topOffset = g_infoCornerYmax[infoCornerID] or 380
Controls.CityPanel:SetOffsetY( g_topOffset )
return UpdateOptions()
end)
--[[
Events.EndCombatSim.Add( function(
attackerPlayerID,
attackerUnitID,
attackerUnitDamage,
attackerFinalUnitDamage,
attackerMaxHitPoints,
defenderPlayerID,
defenderUnitID,
defenderUnitDamage,
defenderFinalUnitDamage,
defenderMaxHitPoints )
if attackerPlayerID == g_activePlayerID then
local instance = g_units[ attackerUnitID ]
if instance then
local toolTip = instance.Button:GetToolTipString()
if toolTip then
toolTip = toolTip .. "[NEWLINE]"
else
toolTip = ""
end
toolTip = toolTip
.."Attack: "
.. " / " .. tostring( attackerPlayerID )
.. " / " .. tostring( attackerUnitID )
.. " / " .. tostring( attackerUnitDamage )
.. " / " .. tostring( attackerFinalUnitDamage )
.. " / " .. tostring( attackerMaxHitPoints )
.. " / " .. tostring( defenderPlayerID )
.. " / " .. tostring( defenderUnitID )
.. " / " .. tostring( defenderUnitDamage )
.. " / " .. tostring( defenderFinalUnitDamage )
.. " / " .. tostring( defenderMaxHitPoints )
instance.Button:SetToolTipString( toolTip )
end
elseif defenderPlayerID == g_activePlayerID then
local instance = g_units[ defenderUnitID ]
if instance then
local toolTip = instance.Button:GetToolTipString()
if toolTip then
toolTip = toolTip .. "[NEWLINE]"
else
toolTip = ""
end
toolTip = toolTip
.."Defense: "
.. " / " .. tostring( attackerPlayerID )
.. " / " .. tostring( attackerUnitID )
.. " / " .. tostring( attackerUnitDamage )
.. " / " .. tostring( attackerFinalUnitDamage )
.. " / " .. tostring( attackerMaxHitPoints )
.. " / " .. tostring( defenderPlayerID )
.. " / " .. tostring( defenderUnitID )
.. " / " .. tostring( defenderUnitDamage )
.. " / " .. tostring( defenderFinalUnitDamage )
.. " / " .. tostring( defenderMaxHitPoints )
instance.Button:SetToolTipString( toolTip )
end
end
end)
--]]
-- Process request to hide enemy panel
LuaEvents.EnemyPanelHide.Add(
function( isEnemyPanelHide )
if g_isWorkerActionPanelOpen then
Controls.WorkerActionPanel:SetHide( not isEnemyPanelHide )
end
if not g_isHideUnitTypes and not g_isHideUnitList then
Controls.UnitTypesPanel:SetHide( not isEnemyPanelHide )
end
end)
local EnemyUnitPanel = LookUpControl( "/InGame/WorldView/EnemyUnitPanel" )
local isHidden = ContextPtr:IsHidden()
ContextPtr:SetShowHideHandler(
function( isHide, isInit )
if not isInit and isHidden ~= isHide then
isHidden = isHide
if isHide and EnemyUnitPanel then
EnemyUnitPanel:SetHide( true )
end
end
end)
ContextPtr:SetHide( false )
end)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment