diff --git a/Additions/CityPanelCulture.xml b/Additions/CityPanelCulture.xml index 9578145..a900f0b 100644 --- a/Additions/CityPanelCulture.xml +++ b/Additions/CityPanelCulture.xml @@ -50,7 +50,7 @@ - diff --git a/Additions/CityPanelPower.lua b/Additions/CityPanelPower.lua new file mode 100644 index 0000000..e1a6f44 --- /dev/null +++ b/Additions/CityPanelPower.lua @@ -0,0 +1,160 @@ +include("InstanceManager"); +include("SupportFunctions"); +include("EspionageViewManager"); + +local m_kPowerBreakdownIM:table = InstanceManager:new( "PowerLineInstance", "Top"); + +local m_kEspionageViewManager = EspionageViewManager:CreateManager(); + +-- =========================================================================== +function OnRefresh() + if ContextPtr:IsHidden() then + return; + end + + local playerID = Game.GetLocalPlayer(); + local pPlayer = Players[playerID]; + if (pPlayer == nil) then + return; + end + + local pCity = UI.GetHeadSelectedCity(); + if (pCity == nil) then + pCity = m_kEspionageViewManager:GetEspionageViewCity(); + if pCity == nil then + return; + end + else + m_kEspionageViewManager:ClearEspionageViewCity(); + end + + if pPlayer == nil or pCity == nil then + return; + end + + local pCityPower = pCity:GetPower(); + if pCityPower == nil then + return; + end + + -- Status + local freePower:number = pCityPower:GetFreePower(); + local temporaryPower:number = pCityPower:GetTemporaryPower(); + local currentPower:number = freePower + temporaryPower; + local requiredPower:number = pCityPower:GetRequiredPower(); + local powerStatusName:string = "LOC_POWER_STATUS_POWERED_NAME"; + local powerStatusDescription:string = "LOC_POWER_STATUS_POWERED_DESCRIPTION"; + if (requiredPower == 0) then + powerStatusName = "LOC_POWER_STATUS_NO_POWER_NEEDED_NAME"; + powerStatusDescription = "LOC_POWER_STATUS_NO_POWER_NEEDED_DESCRIPTION"; + elseif (not pCityPower:IsFullyPowered()) then + powerStatusName = "LOC_POWER_STATUS_UNPOWERED_NAME"; + powerStatusDescription = "LOC_POWER_STATUS_UNPOWERED_DESCRIPTION"; + elseif (pCityPower:IsFullyPoweredByActiveProject()) then + currentPower = requiredPower; + end + Controls.ConsumingPowerLabel:SetText(Locale.Lookup("LOC_POWER_PANEL_CONSUMED", Round(currentPower, 1))); + Controls.RequiredPowerLabel:SetText(Locale.Lookup("LOC_POWER_PANEL_REQUIRED", Round(requiredPower, 1))); + Controls.PowerStatusNameLabel:SetText(Locale.Lookup(powerStatusName)); + + -- Status Effects + Controls.PowerStatusDescriptionLabel:SetText(Locale.Lookup(powerStatusDescription)); + Controls.PowerStatusDescriptionBox:SetSizeY(Controls.PowerStatusDescriptionLabel:GetSizeY() + 15); + + -- Breakdown + m_kPowerBreakdownIM:ResetInstances(); + -----Consumed + local temporaryPowerBreakdown:table = pCityPower:GetTemporaryPowerSources(); + local freePowerBreakdown:table = pCityPower:GetFreePowerSources(); + local somethingToShow:boolean = false; + for _,innerTable in ipairs(temporaryPowerBreakdown) do + somethingToShow = true; + local scoreSource, scoreValue = next(innerTable); + local lineInstance = m_kPowerBreakdownIM:GetInstance(Controls.ConsumedPowerBreakdownStack); + lineInstance.LineTitle:SetText(scoreSource); + lineInstance.LineValue:SetText("[ICON_Power]" .. Round(scoreValue, 1)); + end + for _,innerTable in ipairs(freePowerBreakdown) do + somethingToShow = true; + local scoreSource, scoreValue = next(innerTable); + local lineInstance = m_kPowerBreakdownIM:GetInstance(Controls.ConsumedPowerBreakdownStack); + lineInstance.LineTitle:SetText(scoreSource); + lineInstance.LineValue:SetText("[ICON_Power]" .. Round(scoreValue, 1)); + end + Controls.ConsumedPowerBreakdownStack:CalculateSize(); + Controls.ConsumedBreakdownBox:SetSizeY(Controls.ConsumedPowerBreakdownStack:GetSizeY() + 15); + Controls.ConsumedBreakdownBox:SetHide(not somethingToShow); + Controls.ConsumedTitle:SetHide(not somethingToShow); + -----Required + local requiredPowerBreakdown:table = pCityPower:GetRequiredPowerSources(); + local somethingToShow:boolean = false; + for _,innerTable in ipairs(requiredPowerBreakdown) do + somethingToShow = true; + local scoreSource, scoreValue = next(innerTable); + local lineInstance = m_kPowerBreakdownIM:GetInstance(Controls.RequiredPowerBreakdownStack); + lineInstance.LineTitle:SetText(scoreSource); + lineInstance.LineValue:SetText("[ICON_Power]" .. Round(scoreValue, 1)); + end + Controls.RequiredPowerBreakdownStack:CalculateSize(); + Controls.RequiredBreakdownBox:SetSizeY(Controls.RequiredPowerBreakdownStack:GetSizeY() + 15); + Controls.RequiredBreakdownBox:SetHide(not somethingToShow); + Controls.RequiredTitle:SetHide(not somethingToShow); + -----Generated + local generatedPowerBreakdown:table = pCityPower:GetGeneratedPowerSources(); + local somethingToShow:boolean = false; + for _,innerTable in ipairs(generatedPowerBreakdown) do + somethingToShow = true; + local scoreSource, scoreValue = next(innerTable); + local lineInstance = m_kPowerBreakdownIM:GetInstance(Controls.GeneratedPowerBreakdownStack); + lineInstance.LineTitle:SetText(scoreSource); + lineInstance.LineValue:SetText("[ICON_Power]" .. Round(scoreValue, 1)); + lineInstance.LineValue:SetColorByName("White"); + end + Controls.GeneratedPowerBreakdownStack:CalculateSize(); + Controls.GeneratedBreakdownBox:SetSizeY(Controls.GeneratedPowerBreakdownStack:GetSizeY() + 15); + Controls.GeneratedBreakdownBox:SetHide(not somethingToShow); + Controls.GeneratedTitle:SetHide(not somethingToShow); + + -- Advisor + if m_kEspionageViewManager:IsEspionageView() then + Controls.PowerAdvisor:SetHide(true); + else + Controls.PowerAdvice:SetText(pCity:GetPowerAdvice()); + Controls.PowerAdvisor:SetHide(false); + end + + Controls.TabStack:CalculateSize(); +end + +-- =========================================================================== +function OnShowEnemyCityOverview( ownerID:number, cityID:number) + m_kEspionageViewManager:SetEspionageViewCity( ownerID, cityID ); + OnRefresh(); +end + +-- =========================================================================== +function OnTabStackSizeChanged() + -- Manually resize the context to fit the child stack + ContextPtr:SetSizeX(Controls.TabStack:GetSizeX()); + ContextPtr:SetSizeY(Controls.TabStack:GetSizeY()); +end + +-- =========================================================================== +function OnTogglePowerPanel(pCity:table) + if (pCity ~= nil) then + UI.LookAtPlot(pCity:GetX(), pCity:GetY()); + UI.SelectCity(pCity); + LuaEvents.CityPanel_ToggleOverviewPower(); + end +end + +-- =========================================================================== +function Initialize() + LuaEvents.CityPanelTabRefresh.Add(OnRefresh); + Events.CitySelectionChanged.Add( OnRefresh ); + + LuaEvents.CityBannerManager_ShowEnemyCityOverview.Add( OnShowEnemyCityOverview ); + + Controls.TabStack:RegisterSizeChanged( OnTabStackSizeChanged ); +end +Initialize(); \ No newline at end of file diff --git a/Additions/CityPanelPower.xml b/Additions/CityPanelPower.xml new file mode 100644 index 0000000..9302010 --- /dev/null +++ b/Additions/CityPanelPower.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Additions/ClimateScreen.lua b/Additions/ClimateScreen.lua new file mode 100644 index 0000000..4de69c1 --- /dev/null +++ b/Additions/ClimateScreen.lua @@ -0,0 +1,1156 @@ +-- Copyright 2018, Firaxis Games + +-- =========================================================================== +include("InstanceManager"); +include("SupportFunctions"); --Round +include("TabSupport"); +include("PopupDialog"); +include("ModalScreen_PlayerYieldsHelper"); -- Resizing and top panel vis. +include("GameRandomEvents"); +include("CivilizationIcon"); + +-- =========================================================================== +-- DEBUG +-- =========================================================================== +debug_amt = 0; + +-- =========================================================================== +-- CONSTANTS +-- =========================================================================== +local RELOAD_CACHE_ID :string = "ClimateScreen"; -- Unique name for hotreload +local MAX_PHASES :number = 7; -- Maximum climate phases +local PLAYER_NO_ONE :number = -1; -- Signify no player (autoplay) + +local NUCLEAR_ACCIDENT_EVENT_TYPE :string = "NUCLEAR_ACCIDENT"; +local CLIMATE_CHANGE_EVENT_TYPE :string = "SEA_LEVEL"; + +local SEA_LEVEL_WAVE_OFFSET :number = 15; + +-- =========================================================================== +-- MEMBERS +-- =========================================================================== +local m_kCO2CivsIM :table = InstanceManager:new( "ResourceCO2Instance", "Top", Controls.GlobalCityStack ); +local m_kCivCO2IM :table = InstanceManager:new( "CivCO2Instance", "Top", Controls.GlobalCityStack ); +local m_kYourCO2IM :table = InstanceManager:new( "ResourceCO2Instance", "Top", Controls.YourCO2Stack ); +local m_kSliceIM :table = InstanceManager:new( "PieChartSliceInstance", "Slice" ); +local m_kAffectedCitiesIM :table = InstanceManager:new( "CityInstance", "Top", Controls.CitiesStack ); +local m_kEventRowInstance :table = InstanceManager:new( "EventRowInstance", "Top", Controls.EventStack ); +local m_kClimateChangeInstance :table = InstanceManager:new( "ClimateChangeInstance", "Top", Controls.EventStack ); + +local m_tabs :table; -- Main tabs +local m_CO2tabs :table; -- CO2 contribtion tabs +local m_kGlobalPieSlices :table = {}; -- holds pie slice instances created for the global pie charts +local m_playerID :number = -1; +local m_worldAgeName :string; +local m_RealismName :string; +local m_currentTabName :string; +local m_currentCO2TabName :string; +local m_kBarSegments :table = {}; +local m_TopPanelHeight :number = 0; -- Used to push vignette below top panel +local m_firstSeaLevelEvent :number = -1; +local m_currentSeaLevelEvent :number = -1; +local m_currentSeaLevelPhase :number = 0; + + +-- =========================================================================== +-- FUNCTIONS +-- =========================================================================== + +-- =========================================================================== +function Open( selectedTabName:string ) + + m_playerID = Game.GetLocalPlayer(); -- Get ID and leave if during autoplay + if m_playerID == -1 then return end; + + m_kSliceIM:ResetInstances(); -- Instance manager that generates pie chart slices. + + m_CO2tabs.SelectTab( Controls.CO2ButtonByCivilization ); + + UpdateClimateChangeEventsData(); + + if selectedTabName=="Overview" or selectedTabName==nil then m_tabs.SelectTab( Controls.ButtonOverview ); end + if selectedTabName=="CO2Levels" then m_tabs.SelectTab( Controls.ButtonCO2Levels ); end + if selectedTabName=="EventHistory" then m_tabs.SelectTab( Controls.ButtonEventHistory ); end + + UI.PlaySound("UI_Screen_Open"); + + -- From ModalScreen_PlayerYieldsHelper + if not RefreshYields() then + Controls.Vignette:SetSizeY(m_TopPanelHeight); + end + + -- From Civ6_styles: FullScreenVignetteConsumer + Controls.ScreenAnimIn:SetToBeginning(); + Controls.ScreenAnimIn:Play(); + + LuaEvents.ClimateScreen_Opened(); -- Tell other UI's (e.g., LaunchBar) this is opened + + local kParameters = {}; + kParameters.RenderAtCurrentParent = true; + kParameters.InputAtCurrentParent = true; + kParameters.AlwaysVisibleInQueue = true; + UIManager:QueuePopup(ContextPtr, PopupPriority.Low, kParameters); +end + +-- =========================================================================== +-- Actual close function, asserts if already closed +-- =========================================================================== +function Close() + if not ContextPtr:IsHidden() then + UI.PlaySound("UI_Screen_Close"); + LuaEvents.ClimateScreen_Closed(); -- Tell other UI's (e.g., LaunchBar) this is closed + end + + UIManager:DequeuePopup(ContextPtr); +end + +-- =========================================================================== +-- LUA Event, Callback +-- Close this screen +-- =========================================================================== +function OnClose() + if not ContextPtr:IsHidden() then + Close(); + end +end + +-- =========================================================================== +-- LUA Event +-- Explicit close (from partial screen hooks), part of closing everything, +-- =========================================================================== +function OnCloseAllExcept( contextToStayOpen:string ) + if contextToStayOpen == ContextPtr:GetID() then return; end + Close(); +end + +-- =========================================================================== +function GetWorstCO2PlayerID() + local CO2Total :number = GameClimate.GetTotalCO2Footprint(); + local CO2TopPlayer :number = PLAYER_NO_ONE; + local worstCO2 :number = 0; + + if CO2Total > 0 then + for _,pPlayer in ipairs(PlayerManager.GetAliveMajors()) do + local CO2:number = GameClimate.GetPlayerCO2Footprint( pPlayer:GetID() ); + if CO2 > worstCO2 then + CO2TopPlayer = pPlayer:GetID(); + worstCO2 = CO2; + end + end + end + return CO2TopPlayer; +end + +-- =========================================================================== +-- Assumes all tabs are made of two buttons, one for actual button state and +-- one for holding onto a selected state (e.g., the current tab.) +-- Each tab has: "ButtonFoo" and in it a "SelectFoo" +-- =========================================================================== +function RealizeTabs( selectedTabName:string ) + + m_currentTabName = selectedTabName; + + local kTabNames:table = {"Overview","CO2Levels","EventHistory" } + + Controls.SelectedOverview:SetHide( selectedTabName ~= "Overview" ); + Controls.ButtonOverview:SetSelected( selectedTabName == "Overview" ); + Controls.OverviewPane:SetHide( selectedTabName ~= "Overview" ); + Controls.OverviewBG:SetHide( selectedTabName ~= "Overview" ); + + Controls.SelectedCO2Levels:SetHide( selectedTabName ~= "CO2Levels" ); + Controls.ButtonCO2Levels:SetSelected( selectedTabName == "CO2Levels" ); + Controls.CO2LevelsPane:SetHide( selectedTabName ~= "CO2Levels" ); + + Controls.SelectedEventHistory:SetHide( selectedTabName ~= "EventHistory" ); + Controls.ButtonEventHistory:SetSelected( selectedTabName == "EventHistory" ); + Controls.EventHistoryPane:SetHide( selectedTabName ~= "EventHistory" ); +end + +-- =========================================================================== +-- Same as above but for CO2 sub-tabs +-- =========================================================================== +function RealizeCO2Tabs( selectedTabName:string ) + + m_currentCO2TabName = selectedTabName; + + local kTabNames:table = {"ByCivilization","ByResource","Deforestation" } + + Controls.CO2SelectedByCivilization:SetHide( selectedTabName ~= "ByCivilization" ); + Controls.CO2ButtonByCivilization:SetSelected( selectedTabName == "ByCivilization" ); + + Controls.CO2SelectedByResource:SetHide( selectedTabName ~= "ByResource" ); + Controls.CO2ButtonByResource:SetSelected( selectedTabName == "ByResource" ); + + -- TODO: pending gamecore implementation + --Controls.CO2SelectedDeforestation:SetHide( selectedTabName ~= "Deforestation" ); + --Controls.CO2ButtonDeforestation:SetSelected( selectedTabName == "Deforestation" ); +end + +-- =========================================================================== +function GetDirectionText( eDirection:number ) + if eDirection == DirectionTypes.NO_DIRECTION then + return ""; + elseif eDirection == DirectionTypes.DIRECTION_NORTHEAST then + return "LOC_CLIMATE_SCREEN_NORTHEAST"; + elseif eDirection == DirectionTypes.DIRECTION_EAST then + return "LOC_CLIMATE_SCREEN_EAST"; + elseif eDirection == DirectionTypes.DIRECTION_SOUTHEAST then + return "LOC_CLIMATE_SCREEN_SOUTHEAST"; + elseif eDirection == DirectionTypes.DIRECTION_SOUTHWEST then + return "LOC_CLIMATE_SCREEN_SOUTHWEST"; + elseif eDirection == DirectionTypes.DIRECTION_WEST then + return "LOC_CLIMATE_SCREEN_WEST"; + elseif eDirection == DirectionTypes.DIRECTION_NORTHWEST then + return "LOC_CLIMATE_SCREEN_NORTHWEST"; + end +end + +-- =========================================================================== +function RefreshCurrentEvent() + local kCurrentEvent:table = GameRandomEvents.GetCurrentTurnEvent(); + if kCurrentEvent ~= nil then + local kCurrentEventDef:table = GameInfo.RandomEvents[kCurrentEvent.RandomEvent]; + if kCurrentEventDef ~= nil then + + if kCurrentEventDef.EffectOperatorType == CLIMATE_CHANGE_EVENT_TYPE then + -- If we're a Climate Change event (have SeaLevel) then bail + Controls.CurrentEventStack:SetHide(true); + Controls.SeaLevelAlertIndicator:SetHide(false); + Controls.PolarIceAlertIndicator:SetHide(false); + return; + elseif kCurrentEventDef.EffectOperatorType == NUCLEAR_ACCIDENT_EVENT_TYPE then + -- Don't show nuclear accidents + Controls.CurrentEventStack:SetHide(true); + return; + end + + local pCurrentPlot:table = Map.GetPlotByIndex(kCurrentEvent.CurrentLocation); + + -- Determine if the current location of this event is visible so we can hide some data + local bIsEventVisible:boolean = false; + if pCurrentPlot ~= nil then + local pLocalPlayerVis:table = PlayersVisibility[Game.GetLocalPlayer()]; + if pLocalPlayerVis ~= nil then + if pLocalPlayerVis:IsRevealed(pCurrentPlot:GetX(), pCurrentPlot:GetY()) then + bIsEventVisible = true; + end + end + end + + -- Weather type name + Controls.WeatherStatusText:SetText(Locale.ToUpper(kCurrentEventDef.Name)); + + -- Event specific name + if kCurrentEvent.Name and bIsEventVisible then + Controls.WeatherName:SetText(Locale.Lookup(kCurrentEvent.Name)); + Controls.WeatherName:SetHide(false); + else + Controls.WeatherName:SetHide(true); + end + + -- Icon + if kCurrentEventDef.IconLarge and kCurrentEventDef.IconLarge ~= "" then + Controls.WeatherStatusImage:SetTexture(kCurrentEventDef.IconLarge); + else + UI.DataError("Unable to find IconLarge for RandomEvents type: " .. kCurrentEventDef.PrimaryKey); + end + + -- Current Location and Direction + local location:string = ""; + if pCurrentPlot ~= nil then + local eContinentType:number = pCurrentPlot:GetContinentType(); + if eContinentType and eContinentType ~= -1 then + local kContinentDef:table = GameInfo.Continents[eContinentType]; + location = Locale.ToUpper(kContinentDef.Description); + else + location = Locale.Lookup("LOC_CLIMATE_SCREEN_WATER"); + end + end + + local direction:string = Locale.Lookup(GetDirectionText(kCurrentEvent.CurrentDirection)); + + if not bIsEventVisible then + Controls.WeatherLocation:SetText(Locale.Lookup("LOC_CLIMATE_SCREEN_LOCATION", Locale.Lookup("LOC_CIVICS_TREE_UNREVEALED_CIVIC"))); + elseif location ~= "" and direction ~= "" then + Controls.WeatherLocation:SetText(Locale.Lookup("LOC_CLIMATE_SCREEN_LOCATION_DIRECTION", location, direction)); + elseif location ~= "" then + Controls.WeatherLocation:SetText(Locale.Lookup("LOC_CLIMATE_SCREEN_LOCATION", location)); + else + Controls.WeatherLocation:SetText(""); + end + + -- Affected Cities + m_kAffectedCitiesIM:ResetInstances(); + local doesAffectACity:boolean = false; + local kCurrentAffectedCities:table = GameRandomEvents.GetCurrentAffectedCities(); + for _, affectedCity in ipairs(kCurrentAffectedCities) do + local pOwner:table = Players[affectedCity.CityOwner]; + local pLocalPlayerDiplo:table = Players[Game.GetLocalPlayer()]:GetDiplomacy(); + if pOwner ~= nil and pLocalPlayerDiplo:HasMet(affectedCity.CityOwner) then + local pCity:table = pOwner:GetCities():FindID(affectedCity.CityID); + if pCity then + local pOwnerConfig:table = PlayerConfigurations[affectedCity.CityOwner]; + local iconString:string = "ICON_" .. pOwnerConfig:GetCivilizationTypeName(); + local textureOffsetX, textureOffsetY, textureSheet = IconManager:FindIconAtlas(iconString, 30); + local secondaryColor, primaryColor = UI.GetPlayerColors( affectedCity.CityOwner ); + + local cityInstance:table = m_kAffectedCitiesIM:GetInstance(); + cityInstance.Icon:SetTexture(textureOffsetX, textureOffsetY, textureSheet); + cityInstance.Icon:LocalizeAndSetToolTip( pOwnerConfig:GetCivilizationDescription() ); + cityInstance.Icon:SetColor( primaryColor ); + cityInstance.IconBacking:SetColor( secondaryColor ); + cityInstance.Name:SetText(Locale.Lookup(pCity:GetName())); + doesAffectACity = true; + end + end + end + Controls.CitiesStack:SetHide(not bIsEventVisible); + Controls.CitiesStackDivider:SetHide(not doesAffectACity or not bIsEventVisible); + + if kCurrentEventDef.EffectString ~= nil then + Controls.WeatherEffect:SetText(Locale.Lookup(kCurrentEventDef.EffectString)); + else + Controls.WeatherEffect:SetText(""); + end + + -- Buff/Debuff + local bAnyBuff:boolean = false; + + if kCurrentEvent.FertilityAdded ~= nil and kCurrentEvent.FertilityAdded > 0 then + Controls.PlotFertileLabel:SetText(kCurrentEvent.FertilityAdded); + Controls.PlotFertileContainer:SetHide(false); + bAnyBuff = true; + else + Controls.PlotFertileContainer:SetHide(true); + end + + if kCurrentEvent.TilesDamaged ~= nil and kCurrentEvent.TilesDamaged > 0 then + Controls.PlotDamagedLabel:SetText(kCurrentEvent.TilesDamaged); + Controls.PlotDamagedContainer:SetHide(false); + bAnyBuff = true; + else + Controls.PlotDamagedContainer:SetHide(true); + end + + if kCurrentEvent.UnitsLost ~= nil and kCurrentEvent.UnitsLost > 0 then + Controls.UnitsLostLabel:SetText(kCurrentEvent.UnitsLost); + Controls.UnitsLostContainer:SetHide(false); + bAnyBuff = true; + else + Controls.UnitsLostContainer:SetHide(true); + end + + if kCurrentEvent.PopLost ~= nil and kCurrentEvent.PopLost > 0 then + Controls.PopLostLabel:SetText(kCurrentEvent.PopLost); + Controls.PopLostContainer:SetHide(false); + bAnyBuff = true; + else + Controls.PopLostContainer:SetHide(true); + end + + local showBuffStack:boolean = bIsEventVisible and bAnyBuff; + Controls.BuffStack:SetHide(not showBuffStack); + end + + Controls.CurrentEventStack:SetHide(false); + else + Controls.CurrentEventStack:SetHide(true); + end +end + +-- =========================================================================== +function TabSelectOverview() + RealizeTabs("Overview"); + + -- Alert indicators are shown by RefreshCurrentEvent if required + Controls.SeaLevelAlertIndicator:SetHide(true); + Controls.PolarIceAlertIndicator:SetHide(true); + + RefreshCurrentEvent(); + + local ClimateLevel :number = m_currentSeaLevelPhase; + + local ClimateName :string; + if (m_currentSeaLevelEvent < 0) then + ClimateName = Locale.ToUpper("LOC_CLIMATE_CLIMATE_CHANGE_PHASE_0"); + else + ClimateName = Locale.ToUpper(GameInfo.RandomEvents[m_currentSeaLevelEvent].Name); + end + + local CO2Total :number = GameClimate.GetTotalCO2Footprint(); + local CO2Player :number = GameClimate.GetPlayerCO2Footprint( m_playerID ); + local CO2TopPlayer :number = GetWorstCO2PlayerID(); + local CO2Modifier :number = GameClimate.GetCO2FootprintModifier(); + + -- Determine worst CO2 contributor + local TopContributorName :string = Locale.Lookup("LOC_CLIMATE_NO_ONE"); + if CO2TopPlayer ~= PLAYER_NO_ONE then + local pPlayerConfiguration :table = PlayerConfigurations[CO2TopPlayer]; + TopContributorName = pPlayerConfiguration:GetPlayerName(); + end + + local TempIncrease :number = GameClimate.GetTemperatureChange(); -- Change in temperature from the starting baseline, in Celsius + local TempIncreaseText :string = tostring(Locale.ToNumber(TempIncrease, "#.#")); + local deforestationType :number = GameClimate.GetDeforestationType(); + local co2Modifier :number = GameClimate.GetCO2FootprintModifier(); + local deforestationName :string = ""; + local deforestationDescription :string = ""; + local TempTooltip :string = ""; + if (deforestationType >= 0) then + local kDeforestationLevel:table = GameInfo.DeforestationLevels[deforestationType]; + deforestationName = kDeforestationLevel.Name; + deforestationDescription = kDeforestationLevel.Description; + TempTooltip = Locale.Lookup("LOC_CLIMATE_TEMPERATURE_TOOLTIP", deforestationName, deforestationDescription, co2Modifier ); + end + local co2Modifier :number = GameClimate.GetCO2FootprintModifier(); + + local stormChance :number = GameClimate.GetStormPercentChance(); + local stormIncrease :number = GameClimate.GetStormClimateIncreasedChance(); + + local riverFloodChance :number = GameClimate.GetFloodPercentChance(); + local riverFloodIncrease :number = GameClimate.GetFloodClimateIncreasedChance(); + local riverNum :number = RiverManager.GetNumRivers(); + local riverFloodableNum :number = RiverManager.GetNumFloodableRivers(); + + local volcanoTotalNum :number = MapFeatureManager.GetNumNormalVolcanoes(); + local volcanoActiveNum :number = MapFeatureManager.GetNumActiveVolcanoes(); + local volcanoEruptionsNum :number = MapFeatureManager.GetNumEruptions(); + local volcanoNaturalWonder :number = MapFeatureManager.GetNumNaturalWonderVolcanoes(); + --local volcanoPercent :number = MapFeatureManager.GetPercentVolcanoesActive(); + local volcanoEruptChance :number = GameClimate.GetEruptionPercentChance(); + + local droughtChance :number = GameClimate.GetDroughtPercentChance(); + local droughtIncrease :number = GameClimate.GetDroughtClimateIncreasedChance(); + + local nextIceLostTurns :number = GameClimate.GetNextIceLossTurns(); + + local tilesFlooded :number = GameClimate.GetTilesFlooded(); + local tilesSubmerged :number = GameClimate.GetTilesSubmerged(); + local nextSeaRiseTurns :number = GameClimate.GetNextSeaLevelRiseTurns(); + + Controls.ClimateChangePhaseText:SetText(ClimateName); + UpdatePhaseBar(ClimateLevel,-1,-1); + + -- Left + Controls.ContributeTotal:SetText(Locale.Lookup("LOC_CLIMATE_TOTAL_NUM", CO2Total)); + Controls.ContributeTop:SetText(Locale.Lookup("LOC_CLIMATE_TOP_CONTRIBUTOR_NUM", TopContributorName)); + Controls.ContributeMe:SetText(Locale.Lookup("LOC_CLIMATE_MY_CONTRIBUTION_NUM", CO2Player)); + Controls.OverviewCO2Grid:SetToolTipString(Locale.Lookup("LOC_CLIMATE_CO2_TOTAL_TOOLTIP", CO2Modifier)); + + Controls.ClimateTemperature:SetText(Locale.Lookup("LOC_CLIMATE_TEMPERATURE_SUBTEXT")); + Controls.TemperatureValue:SetText(Locale.Lookup("LOC_CLIMATE_TEMPERATURE", TempIncreaseText)); + Controls.GlobalTempGrid:SetToolTipString(TempTooltip); + + Controls.WorldAgeText:SetHide(m_worldAgeName==nil); + if m_worldAgeName then + Controls.WorldAgeText:SetText( Locale.Lookup("LOC_CLIMATE_WORLD_AGE",m_worldAgeName) ); + end + + Controls.RealismText:SetHide(m_RealismName==nil); + if m_RealismName then + Controls.RealismText:SetText( Locale.Lookup("LOC_CLIMATE_REALISM", m_RealismName) ); + end + + + -- Right + Controls.StormChanceNum:SetText(Locale.Lookup("LOC_CLIMATE_PERCENT_CHANCE", stormChance)); + Controls.StormChanceFromClimateChange:SetText( Locale.Lookup("LOC_CLIMATE_AMOUNT_FROM_CLIMATE_CHANGE", stormIncrease) ); + + Controls.RiverFloodChanceNum:SetText(Locale.Lookup("LOC_CLIMATE_PERCENT_CHANCE", riverFloodChance)); + Controls.RiverFloodChanceFromClimateChange:SetText( Locale.Lookup("LOC_CLIMATE_AMOUNT_FROM_CLIMATE_CHANGE", riverFloodIncrease) ); + + Controls.DroughtActivityChanceNum:SetText(Locale.Lookup("LOC_CLIMATE_PERCENT_CHANCE", droughtChance)); + Controls.DroughtChanceFromClimateChange:SetText( Locale.Lookup("LOC_CLIMATE_AMOUNT_FROM_CLIMATE_CHANGE", droughtIncrease) ); + + Controls.VolcanicActivityChanceNum:SetText(Locale.Lookup("LOC_CLIMATE_PERCENT_CHANCE", volcanoEruptChance)); + Controls.VolatileNum:SetText( Locale.Lookup("LOC_CLIMATE_VOLCANO_VOLATILE_NUM", volcanoNaturalWonder) ); + Controls.InactiveNum:SetText( Locale.Lookup("LOC_CLIMATE_VOLCANO_INACTIVE_NUM", volcanoTotalNum - volcanoActiveNum) ); + Controls.ActiveNum:SetText( Locale.Lookup("LOC_CLIMATE_VOLCANO_ACTIVE_NUM", volcanoActiveNum) ); + Controls.EruptedNum:SetText( Locale.Lookup("LOC_CLIMATE_VOLCANO_ERUPTED_NUM", volcanoEruptionsNum) ); + + -- Bottom + local iIceLoss :number = 0; + local fSeaLevel :number = 0.0; + if (m_currentSeaLevelEvent > -1) then + iIceLoss = GameInfo.RandomEvents[m_currentSeaLevelEvent].IceLoss; + szSeaLevel = GameInfo.RandomEvents[m_currentSeaLevelEvent].Description; + end + + if szSeaLevel == nil then + szSeaLevel = "0"; + end + + Controls.PolarIceLostNum:SetText( Locale.Lookup("LOC_CLIMATE_LOST", iIceLoss)); + if nextIceLostTurns > 0 and ClimateLevel < MAX_PHASES then + Controls.NextPolarIceLost:SetHide(false); + Controls.NextPolarIceLost:SetText( Locale.Lookup("LOC_CLIMATE_POLAR_ICE_MELT_X_TURNS", nextIceLostTurns)); + else + Controls.NextPolarIceLost:SetHide(true); + end + + Controls.SeaLevel:SetText(Locale.Lookup("LOC_CLIMATE_SEA_LEVEL_RISE", Locale.Lookup(szSeaLevel))); + Controls.SeaLevelArea:SetToolTipString( Locale.Lookup("LOC_CLIMATE_SEA_LEVEL_RISE_DESCRIPTION_TOOLTIP", szSeaLevel) ); + Controls.TilesFlooded:SetText( Locale.Lookup("LOC_CLIMATE_COASTAL_TILES_FLOODED_NUM", tilesFlooded )); + Controls.TilesSubmerged:SetText( Locale.Lookup("LOC_CLIMATE_COASTAL_TILES_SUBMERGED_NUM", tilesSubmerged )); + if nextSeaRiseTurns > 0 and ClimateLevel < MAX_PHASES then + Controls.NextSeaLevelRise:SetHide(false); + Controls.NextSeaLevelRise:SetText( Locale.Lookup("LOC_CLIMATE_SEA_LEVEL_RISE_X_TURNS", nextSeaRiseTurns)); + else + Controls.NextSeaLevelRise:SetHide(true); + end + + Controls.SeaLevelWave:SetOffsetY((ClimateLevel * SEA_LEVEL_WAVE_OFFSET) - SEA_LEVEL_WAVE_OFFSET); +end + + +-- =========================================================================== +-- Creates a pie chart by abusing the meter control +-- Pie slices are in percents (e.g., .1 is 10%) and summed are 1.0 or less. +-- +-- uiHolder UI control that will host the meter control "slices" +-- sliceIM An instance manager which generates the "Slice" graphics. +-- kSliceAmounts Ordered array of numbers 0 to 1.0 for each slice. +-- kColors (optional) Ordered array of numbers (AABBGGRR) for pie slices. +-- +-- RETURNS: A table of the slice instances. +-- =========================================================================== +function BuildPieChart( uiHolder:table, sliceIM:table, kSliceAmounts:table, kColors:table ) + + -- Protect the flock, bad arguements raise errors and return empty tables: + if uiHolder == nil then UI.DataError("Cannot build pie chart due to nil uiHolder passed in."); return {}; end; + if sliceIM == nil then UI.DataError("Cannot build pie chart due to a nil instance manager for generating slices passed in."); return {}; end; + if kSliceAmounts == nil then UI.DataError("Cannot build pie chart due to a nil table of slice amounts passed in."); return {}; end; + + -- Determine total amount from slices and check bounds (create non-1 multiplier if necessary.) + local total :number = 0; + local multiplier :number = 1; + for i,v in ipairs(kSliceAmounts) do + total = total + v; + end + if total > 1.0 then + multiplier = 1.0 / total; + UI.DataError("Total of pie chart slices "..tostring(total).." exceeds 1.0 (100%). Applying multiplier "..tostring(multiplier)); + elseif total < 0 then + UI.DataError("Total of slices "..tostring(total).." is less than 0! Something is fishy with your data."); + total = 0; + end + + -- If colors were not passed in, generate a table. + if kColors == nil or table.count(kColors)==0 then + kColors = { 0xff000099, 0xff008888, 0xff009900, 0xff888800, 0xff990000, 0xff880088 }; + end + local maxColors:number = #kColors; + + + -- Loop through generating pie slices. + local kUISlices :table = {}; + local remaining :number = total; + + for i,v in ipairs(kSliceAmounts) do + local uiInstance:table = sliceIM:GetInstance( uiHolder ); + table.insert(kUISlices, uiInstance); + + uiInstance["Slice"]:SetColor( kColors[ ((i-1) % maxColors)+1 ] ); -- MOD + uiInstance["Slice"]:SetPercent( remaining ); + + remaining = remaining - v; + end + + return kUISlices; +end + +-- =========================================================================== +-- Create a table of colors to use for pie charting. +-- =========================================================================== +function GetPieChartColorTable() + local kColors = {}; + table.insert(kColors, UI.GetColorValue("COLOR_STANDARD_RED_MD") ); + table.insert(kColors, UI.GetColorValue("COLOR_STANDARD_ORANGE_MD") ); + table.insert(kColors, UI.GetColorValue("COLOR_STANDARD_YELLOW_MD") ); + table.insert(kColors, UI.GetColorValue("COLOR_STANDARD_GREEN_MD") ); + table.insert(kColors, UI.GetColorValue("COLOR_STANDARD_AQUA_MD") ); + table.insert(kColors, UI.GetColorValue("COLOR_STANDARD_BLUE_MD") ); + table.insert(kColors, UI.GetColorValue("COLOR_STANDARD_PURPLE_MD") ); + return kColors; +end + +-- =========================================================================== +function TabSelectCO2Levels() + + RealizeTabs("CO2Levels"); + RealizePlayerCO2(); + + local CO2Total :number = GameClimate.GetTotalCO2Footprint(); + local CO2Player :number = GameClimate.GetPlayerCO2Footprint(m_playerID); + local CO2Modifier :number = GameClimate.GetCO2FootprintModifier(); + + local sGlobalTotal:string = ""; + if CO2Modifier ~= 0 then + sGlobalTotal = Locale.Lookup("LOC_CLIMATE_TOTAL_NUM_W_MOD", CO2Total, CO2Modifier); + else + sGlobalTotal = Locale.Lookup("LOC_CLIMATE_TOTAL_NUM", CO2Total); + end + Controls.GlobalContributionsTotalNum:SetText( sGlobalTotal ) ; + Controls.YourContributionsNum:SetText( Locale.Lookup("LOC_CLIMATE_TOTAL_NUM", CO2Player) ); + Controls.GlobalContributionsTotalNum:SetToolTipString(Locale.Lookup("LOC_CLIMATE_CO2_TOTAL_TOOLTIP", CO2Modifier)); +end + +-- =========================================================================== +function TabSelectEventHistory() + + RealizeTabs("EventHistory"); + + m_kEventRowInstance:ResetInstances(); + m_kClimateChangeInstance:ResetInstances(); + + local iCurrentTurn = Game.GetCurrentGameTurn(); + for i=iCurrentTurn, 0, -1 do + local kEvent:table = GameRandomEvents.GetEventForTurn(i); + if kEvent ~= nil then + local kEventDef:table = GameInfo.RandomEvents[kEvent.RandomEvent]; + if kEventDef ~= nil then + if kEventDef.ClimateChangePoints > 0 then + CreateClimateChangeInstance(kEvent, kEventDef, i); + elseif kEventDef.EffectOperatorType ~= NUCLEAR_ACCIDENT_EVENT_TYPE then + local pEventPlot:table = Map.GetPlotByIndex(kEvent.CurrentLocation); + if pEventPlot ~= nil then + local pLocalPlayerVis:table = PlayersVisibility[Game.GetLocalPlayer()]; + if pLocalPlayerVis ~= nil and pLocalPlayerVis:IsRevealed(pEventPlot:GetX(), pEventPlot:GetY()) then + CreateEventInstance(kEvent, kEventDef, i); + end + end + end + end + end + end +end + +-- =========================================================================== +function CreateClimateChangeInstance( kEvent:table, kEventDef:table, iTurn:number ) + local kInstance:table = m_kClimateChangeInstance:GetInstance(); + + kInstance.EventTypeName:SetText(Locale.ToUpper(kEventDef.Name)); + + local strDate = Calendar.MakeYearStr(iTurn); + kInstance.DateString:SetText("[Icon_Turn]" .. Locale.Lookup("LOC_CLIMATE_ENTRY_DATE", iTurn, strDate)); +end + +-- =========================================================================== +function CreateEventInstance( kEvent:table, kEventDef:table, iTurn:number ) + local kInstance:table = m_kEventRowInstance:GetInstance(); + + -- Icon + if kEventDef.IconSmall and kEventDef.IconSmall ~= "" then + kInstance.Icon:SetTexture(kEventDef.IconSmall); + end + + -- Name + kInstance.EventTypeName:SetText(Locale.ToUpper(kEventDef.Name)); + kInstance.EventName:SetText(Locale.ToUpper(kEvent.Name)); + + -- Create descriptive tooltip + local tooltip:string = ""; + if kEventDef.EffectString then + tooltip = tooltip .. Locale.Lookup(kEventDef.EffectString); + kInstance.NameContainer:SetToolTipString(tooltip); + end + + -- Location + local pPlot:table = Map.GetPlotByIndex(kEvent.StartLocation); + if pPlot ~= nil then + local eContinentType:number = pPlot:GetContinentType(); + if eContinentType and eContinentType ~= -1 then + local kContinentDef:table = GameInfo.Continents[eContinentType]; + kInstance.LocationString:SetText(Locale.Lookup(kContinentDef.Description)); + else + kInstance.LocationString:SetText(Locale.Lookup("LOC_CLIMATE_SCREEN_WATER")); + end + end + + -- Effects + if kEvent.FertilityAdded > 0 then + kInstance.FertilizedTilesIcon:SetHide(false); + kInstance.FertilizedTiles:SetText(kEvent.FertilityAdded); + else + kInstance.FertilizedTilesIcon:SetHide(true); + kInstance.FertilizedTiles:SetText(""); + end + + if kEvent.TilesDamaged > 0 then + kInstance.DamagedTilesIcon:SetHide(false); + kInstance.DamagedTiles:SetText(kEvent.TilesDamaged); + else + kInstance.DamagedTilesIcon:SetHide(true); + kInstance.DamagedTiles:SetText(""); + end + + if kEvent.UnitsLost > 0 then + kInstance.UnitsLostIcon:SetHide(false); + kInstance.UnitsLost:SetText(kEvent.UnitsLost); + else + kInstance.UnitsLostIcon:SetHide(true); + kInstance.UnitsLost:SetText(""); + end + + if kEvent.PopLost > 0 then + kInstance.PopLostIcon:SetHide(false); + kInstance.PopLost:SetText(kEvent.PopLost); + else + kInstance.PopLostIcon:SetHide(true); + kInstance.PopLost:SetText(""); + end + + -- Date + local strDate = Calendar.MakeYearStr(iTurn); + kInstance.DateString:SetText("[Icon_Turn]" .. Locale.Lookup("LOC_CLIMATE_ENTRY_DATE", iTurn, strDate)); +end + +-- =========================================================================== +-- Create the pie-chart on the right side of the screen that is composed of +-- overlayed meters. +-- =========================================================================== +function RealizePlayerCO2() + + local pLocalPlayer :table = Players[m_playerID]; + local pResources :table = pLocalPlayer:GetResources(); + local kResourceUseAmounts :table = {}; -- hold raw CO2 usage amounts by each resource + local kSliceAmounts :table = {}; -- hold the % each resource is contributing to CO2 + local total :number = 0; + local kColors :table = GetPieChartColorTable(); + local maxColors :number = #kColors; + local colorIndex :number = 1; -- Used to tint correponding colors + + m_kYourCO2IM:ResetInstances(); + + for kResourceInfo in GameInfo.Resources() do + local resourceIndex :number = kResourceInfo.Index; + if pResources:HasResource(resourceIndex) or pResources:HasExportedResource(resourceIndex) then + + -- Player has the resource, but does the resource contribute to CO2? + local kConsumption:table = GameInfo.Resource_Consumption[kResourceInfo.ResourceType]; + if kConsumption ~= nil and kConsumption.CO2perkWh ~= nil and kConsumption.CO2perkWh > 0 then + + -- Is the player using the resource? + local amount :number = GameClimate.GetPlayerResourceCO2Footprint( m_playerID, kResourceInfo.Index ); + if amount > 0 then + + local uiResource :table = m_kYourCO2IM:GetInstance(); + local resourceName :string = Locale.Lookup( kResourceInfo.Name ); + local co2Amount :number = amount; + local color :number = kColors[colorIndex]; + + uiResource.Amount:SetText( co2Amount ); + uiResource.Icon:SetIcon("ICON_" .. kResourceInfo.ResourceType); + uiResource.Palette:SetColor( color ); + uiResource.Icon:SetToolTipString( resourceName ); + + table.insert( kResourceUseAmounts, amount); + total = total + co2Amount; + + colorIndex = (colorIndex + 1) % maxColors; + end + end + end + end + + -- Now total is known, create an array based on percentages (0.0 - 1.0) each resources makes and chart it. + for i,amount in ipairs( kResourceUseAmounts ) do + table.insert(kSliceAmounts, amount/total ); + end + + -- TODO remove, ??TRON debug data + -- kSliceAmounts = { 0.02, 0.03, 0.2, 0.05, 0.1, 0.07, 0.13, 0.21, 0.04, 0.15 }; + -- kSliceAmounts ={ 0.02, 0.03, 0.2, 0.05, 0.1 }; + + BuildPieChart( Controls.TotalContributionsPie, m_kSliceIM, kSliceAmounts, kColors ); +end + + +-- =========================================================================== +function TabCO2ByCiviliation() + + RealizeCO2Tabs("ByCivilization"); + + m_kCO2CivsIM:ResetInstances(); + m_kCivCO2IM:ResetInstances(); + + -- Realease instances of pie slices previously used in the global section. + for _,uiSliceInstance in ipairs(m_kGlobalPieSlices) do + m_kSliceIM:ReleaseInstance( uiSliceInstance ); + end + + local pLocalPlayer :table = Players[m_playerID]; + local pPlayerDiplomacy :table = pLocalPlayer:GetDiplomacy(); + local pPlayers :table = PlayerManager.GetAliveMajors(); + local total :number = 0; + local kFootprints :table = {}; -- hold raw CO2 usage amounts by each resource + local kColors :table = {}; + + for _, pPlayer in ipairs(pPlayers) do + + local playerID :number = pPlayer:GetID(); + local CO2FootprintNum :number = GameClimate.GetPlayerCO2Footprint( playerID ); + + total = total + CO2FootprintNum; + + -- Only chart a slice if player has been met. + if pPlayerDiplomacy:HasMet(playerID) or m_playerID == playerID then + + local pPlayerConfig :table = PlayerConfigurations[playerID]; + local civType :string = pPlayerConfig:GetCivilizationTypeName(); + local civName :string = Locale.Lookup( pPlayerConfig:GetCivilizationDescription() ); + local backColor, frontColor = UI.GetPlayerColors(playerID); + + if (m_playerID == playerID) then + civName = Locale.Lookup( "LOC_CLIMATE_YOU", civName ); -- Add "(You)" for your civ. + end + + uiCiv = m_kCivCO2IM:GetInstance(); + + local civIconController = CivilizationIcon:AttachInstance( uiCiv.CivIcon ); + civIconController:UpdateIconFromPlayerID( playerID ); + civIconController:SetLeaderTooltip( playerID ); + + uiCiv.Amount:SetText( CO2FootprintNum ); + + if CO2FootprintNum > 0 then + table.insert( kFootprints, CO2FootprintNum); -- Add value + table.insert( kColors, backColor ); -- Add color based on player's color + end + end + end + + -- Now total is known, create an array based on percentages (0.0 - 1.0) for each player and chart it. + local kSliceAmounts :table = {}; -- hold the % each resource is contributing to CO2 + for i,amount in ipairs( kFootprints ) do + table.insert(kSliceAmounts, amount/total ); + end + + m_kGlobalPieSlices = BuildPieChart( Controls.GlobalContributionsPie, m_kSliceIM, kSliceAmounts, kColors ); +end + + +-- =========================================================================== +function TabCO2ByResource() + + RealizeCO2Tabs("ByResource"); + + m_kCO2CivsIM:ResetInstances(); + m_kCivCO2IM:ResetInstances(); + + -- Realease instances of pie slices previously used in the global section. + for _,uiSliceInstance in ipairs(m_kGlobalPieSlices) do + m_kSliceIM:ReleaseInstance( uiSliceInstance ); + end + + local kResourceUseAmounts :table = {}; -- hold raw CO2 usage amounts by each resource + local kSliceAmounts :table = {}; -- hold the % each resource is contributing to CO2 + local kColors :table = GetPieChartColorTable(); + local maxColors :number = #kColors; + local colorIndex :number = 1; -- Used to tint correponding colors + local total :number = 0; -- Total CO2 from all resources + + -- For all the resources in the game + for kResourceInfo in GameInfo.Resources() do + local resourceIndex :number = kResourceInfo.Index; + + -- Does the resource contribute to CO2? + local kConsumption:table = GameInfo.Resource_Consumption[kResourceInfo.ResourceType]; + if kConsumption ~= nil and kConsumption.CO2perkWh ~= nil and kConsumption.CO2perkWh > 0 then + + -- Loop through all players and sum up the CO2 + local amount :number = 0; + for _,pPlayer in ipairs(PlayerManager.GetAliveMajors()) do + amount = amount + GameClimate.GetPlayerResourceCO2Footprint( pPlayer:GetID(), kResourceInfo.Index ); + end + + -- If more than 0, add a UI element. + if amount > 0 then + local uiResource :table = m_kCO2CivsIM:GetInstance(); + local resourceName :string = Locale.Lookup( kResourceInfo.Name ); + local co2Amount :number = amount; + local color :number = kColors[colorIndex]; + + uiResource.Amount:SetText( co2Amount ); + uiResource.Icon:SetIcon("ICON_" .. kResourceInfo.ResourceType); + uiResource.Palette:SetColor( color ); + uiResource.Icon:SetToolTipString( resourceName ); + + table.insert( kResourceUseAmounts, amount ); + total = total + co2Amount; + + colorIndex = (colorIndex + 1) % maxColors; + end + end + end + + -- Now total is known, create an array based on percentages (0.0 - 1.0) each resources makes and chart it. + for i,amount in ipairs( kResourceUseAmounts ) do + table.insert(kSliceAmounts, amount/total ); + end + + m_kGlobalPieSlices = BuildPieChart( Controls.GlobalContributionsPie, m_kSliceIM, kSliceAmounts, kColors ); +end + + +-- =========================================================================== +function TabCO2Deforestation() + + RealizeCO2Tabs("Deforestation"); + + m_kCO2CivsIM:ResetInstances(); + + -- Realease instances of pie slices previously used in the global section. + for _,uiSliceInstance in ipairs(m_kGlobalPieSlices) do + m_kSliceIM:ReleaseInstance( uiSliceInstance ); + end + +end + + +-- =========================================================================== +-- Get indices of important climate change random events +-- =========================================================================== +function UpdateClimateChangeEventsData() + local iCurrentClimateChangePoints = GameClimate.GetClimateChangeForLastSeaLevelEvent(); + for row in GameInfo.RandomEvents() do + if (row.EffectOperatorType == "SEA_LEVEL") then + if (m_firstSeaLevelEvent == -1) then + m_firstSeaLevelEvent = row.Index; + end + if (row.ClimateChangePoints == iCurrentClimateChangePoints) then + m_currentSeaLevelEvent = row.Index; + m_currentSeaLevelPhase = m_currentSeaLevelEvent - m_firstSeaLevelEvent + 1; + end + end + end +end + +-- =========================================================================== +-- Set the phase bar to current values. +-- phase Current phase number +-- realismAmount Amount bar is affect by realism (TODO: value range? ??TRON) +-- globalTemperature Amount bar is affect by temperature (TODO: value range? ??TRON) +-- =========================================================================== +function UpdatePhaseBar( phase:number, realismAmount:number, globalTemp:number ) + + if phase < 0 then + UI.DataError("SetPhaseBar() needs to cap phase of "..tostring(phase).." to 1"); + phase = 1; + end + if phase > MAX_PHASES then + UI.DataError("SetPhaseBar() needs to cap phase of "..tostring(phase).." to max phase of "..tostring(MAX_PHASE).."."); + phase = MAX_PHASES; + end + + -- Fill in all existing bars. + if (phase > 0) then + for i=1,phase,1 do + local uiSegment:table = m_kBarSegments[i]; + uiSegment.Progress:SetColor(0xFFFFFFFF); + uiSegment.Pip:SetTexture("Climate_PhaseMeterPip_On"); + end + end + + -- Update tooltips for all phases + for i=1,MAX_PHASES,1 do + UpdatePhaseTooltips(i); + end +end + +-- =========================================================================== +-- Set default values to phase segment and store in local variable for +-- later access. +-- segmentNum Number of the phase segement to initialize. +-- =========================================================================== +function InitPhaseSegment( segmentNum:number ) + + local uiSegment:table= Controls["Phase"..tostring(segmentNum)]; + uiSegment.Name:SetText(Locale.ToRomanNumeral(segmentNum)); + m_kBarSegments[segmentNum] = uiSegment; + uiSegment.Progress:SetTexture("Climate_PhaseMeter_" .. segmentNum); + uiSegment.Progress:SetColor(0x00FFFFFF); + uiSegment.Pip:SetTexture("Climate_PhaseMeterPip_Off"); + + UpdatePhaseTooltips(segmentNum); +end + +-- =========================================================================== +function UpdatePhaseTooltips( segmentNum:number ) + local kEventDef = GameInfo.RandomEvents[m_firstSeaLevelEvent + segmentNum - 1]; + if kEventDef == nil then + return; + end + + local szPhaseName = kEventDef.Name; + local szSeaLevelRise = kEventDef.Description; + local szPhaseType = kEventDef.RandomEventType; + local iPoints = kEventDef.ClimateChangePoints; + local szAtOrAboveString = ""; + + for row in GameInfo.CoastalLowlands() do + if (row.FloodedEvent == szPhaseType) then + szAtOrAboveString = Locale.Lookup("LOC_CLIMATE_TILES_AT_OR_BELOW_FLOOD_TOOLTIP", row.Name); + break; + elseif (row.SubmergedEvent == szPhaseType) then + szAtOrAboveString = Locale.Lookup("LOC_CLIMATE_TILES_AT_OR_BELOW_SUBMERGE_TOOLTIP", row.Name); + break; + end + end + + local tooltip:string = + Locale.ToUpper(szPhaseName) + .."[NEWLINE]" + .."[NEWLINE]"..Locale.Lookup("LOC_CLIMATE_CLIMATE_CHANGE_POINTS_TOOLTIP", GameClimate.GetClimateChangeLevel(), iPoints) + .."[NEWLINE]"..Locale.Lookup("LOC_CLIMATE_FROM_WORLD_REALISM_NUM_TOOLTIP", GameClimate.GetClimateChangeFromRealism()) + .."[NEWLINE]"..Locale.Lookup("LOC_CLIMATE_FROM_GLOBAL_TEMPERATURE_NUM_TOOLTIP", GameClimate.GetClimateChangeFromTemperature()) + .."[NEWLINE]" + .."[NEWLINE]"..Locale.ToUpper("LOC_CLIMATE_EFFECTS_ADDED_THIS_PHASE_TOOLTIP") + .."[NEWLINE]" + .."[NEWLINE]"..Locale.Lookup("LOC_CLIMATE_SEA_LEVEL_RISES_NUM_TOOLTIP", szSeaLevelRise) + ..szAtOrAboveString + .."[NEWLINE]" + .."[NEWLINE]"..Locale.Lookup("LOC_CLIMATE_POLAR_ICE_MELT_TOOLTIP", kEventDef.IceLoss); + + m_kBarSegments[segmentNum].Progress:SetToolTipString( tooltip ); +end + +-- =========================================================================== +-- LUA Event +-- =========================================================================== +function OnToggleClimateScreen() + if ContextPtr:IsHidden() then + Open("Overview"); + else + Close(); + end +end + + +-- =========================================================================== +function OnInputHandler( pInputStruct:table ) + local uiMsg :number = pInputStruct:GetMessageType(); + if uiMsg == KeyEvents.KeyUp and pInputStruct:GetKey() == Keys.VK_ESCAPE then + Close(); + return true; + end + return false; +end + +-- =========================================================================== +function LateInitialize() + + -- Tab setup and setting of default tab. + m_tabs = CreateTabs( Controls.TabContainer, 42, 34, 0xFF331D05 ); + m_tabs.AddTab( Controls.ButtonOverview, TabSelectOverview ); + m_tabs.AddTab( Controls.ButtonCO2Levels, TabSelectCO2Levels ); + m_tabs.AddTab( Controls.ButtonEventHistory, TabSelectEventHistory ); + m_tabs.CenterAlignTabs(-10); + + m_CO2tabs = CreateTabs( Controls.CO2TabContainer ); + m_CO2tabs.AddTab( Controls.CO2ButtonByCivilization, TabCO2ByCiviliation ); + m_CO2tabs.AddTab( Controls.CO2ButtonByResource, TabCO2ByResource ); + --m_CO2tabs.AddTab( Controls.CO2ButtonDeforestation, TabCO2Deforestation ); -- TODO: Gamecore + m_CO2tabs.CenterAlignTabs(-2); + + -- Lua Events + LuaEvents.GameDebug_Return.Add(OnGameDebugReturn); + LuaEvents.Launchbar_ToggleClimateScreen.Add( OnToggleClimateScreen ) + LuaEvents.Launchbar_Expansion2_ClimateScreen_Close.Add( OnClose ); +end + +-- =========================================================================== +-- Hot Reload Related Events +-- =========================================================================== +function OnInit(isReload:boolean) + LateInitialize(); + if isReload then + LuaEvents.GameDebug_GetValues(RELOAD_CACHE_ID); + end +end + +-- =========================================================================== +function OnShutdown() + LuaEvents.GameDebug_AddValue(RELOAD_CACHE_ID, "isHidden", ContextPtr:IsHidden()); + LuaEvents.GameDebug_AddValue(RELOAD_CACHE_ID, "m_currentTabName", m_currentTabName); +end + +-- =========================================================================== +function OnGameDebugReturn(context:string, contextTable:table) + if context ~= RELOAD_CACHE_ID then return; end + m_currentTabName = contextTable["m_currentTabName"]; + if contextTable["isHidden"] ~= nil and not contextTable["isHidden"] then + Open(m_currentTabName); + end +end + +-- =========================================================================== +function OnPlayerTurnActivated( ePlayer:number, isFirstTime:boolean ) + if ContextPtr:IsHidden() == false and ePlayer == Game.GetLocalPlayer() then + Open(m_currentTabName); + end +end + +-- =========================================================================== +function OnLocalPlayerTurnEnd() + if GameConfiguration.IsHotseat() and ContextPtr:IsVisible() then + Close(); + end +end + +-- =========================================================================== +function Initialize() + + -- Re-used local variables: + local worldAgeNum :number; + local query :string; + local pResults :table; + local kResult :table; + + worldAgeNum = MapConfiguration.GetValue("world_age"); + if worldAgeNum then + query = "SELECT * FROM DomainValues where Domain = 'WorldAge' and Value = ? LIMIT 1"; + pResults = DB.ConfigurationQuery(query, worldAgeNum); + kResult = pResults[1]; + if kResult ~= nil then + m_worldAgeName = Locale.Lookup( kResult.Name ); + end + end + + local realismLevel:number = GameConfiguration.GetValue("GAME_REALISM"); + if realismLevel then + query = "SELECT * FROM RealismSettings ORDER BY rowid"; + pResults = DB.Query(query); + kResult = pResults[realismLevel + 1]; + if kResult ~= nil then + m_RealismName = Locale.Lookup( kResult.Name ); + end + end + + UpdateClimateChangeEventsData(); -- Required for phase segment initialization. + + for phase=1,MAX_PHASES,1 do + InitPhaseSegment(phase); + end + + -- UI Events + ContextPtr:SetInitHandler( OnInit ); + ContextPtr:SetShutdown( OnShutdown ); + ContextPtr:SetInputHandler( OnInputHandler, true ); + + -- UI Controls + Controls.ModalScreenTitle:SetText(Locale.ToUpper("LOC_CLIMATE_TITLE")); + Controls.ModalScreenClose:RegisterCallback(Mouse.eLClick, OnClose); + + -- Game Events + Events.PlayerTurnActivated.Add( OnPlayerTurnActivated ); + Events.LocalPlayerTurnEnd.Add( OnLocalPlayerTurnEnd ); + + m_TopPanelHeight = Controls.Vignette:GetSizeY() - TOP_PANEL_OFFSET; + +end + +--No capability means never initialize this so it can never be used. +if GameCapabilities.HasCapability("CAPABILITY_WORLD_CLIMATE_VIEW") then + Initialize(); +end diff --git a/Additions/ClimateScreen.xml b/Additions/ClimateScreen.xml new file mode 100644 index 0000000..784caeb --- /dev/null +++ b/Additions/ClimateScreen.xml @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Additions/DiplomacyActionView_AllianceRow.lua b/Additions/DiplomacyActionView_AllianceRow.lua index 1fcc2ec..711acf3 100644 --- a/Additions/DiplomacyActionView_AllianceRow.lua +++ b/Additions/DiplomacyActionView_AllianceRow.lua @@ -42,7 +42,17 @@ function Refresh(selectedPlayerID:number) local selectedPlayerDiplomaticAI = selectedPlayer:GetDiplomaticAI(); -- What do they think of us? local iState :number = selectedPlayerDiplomaticAI:GetDiplomaticStateIndex(localPlayerID); - local relationshipString:string = Locale.Lookup(GameInfo.DiplomaticStates[iState].Name); +-- local relationshipString:string = Locale.Lookup(GameInfo.DiplomaticStates[iState].Name); + local iGrievancesOnThem = localPlayer:GetDiplomacy():GetGrievancesAgainst(selectedPlayerID); + local relationshipString:string; + if iGrievancesOnThem > 0 then + relationshipString = Locale.Lookup("LOC_DIPLOMACY_GRIEVANCES_WITH_THEM", GameInfo.DiplomaticStates[iState].Name, iGrievancesOnThem); + elseif iGrievancesOnThem < 0 then + relationshipString = Locale.Lookup("LOC_DIPLOMACY_GRIEVANCES_WITH_US", GameInfo.DiplomaticStates[iState].Name, -iGrievancesOnThem); + else + relationshipString = Locale.Lookup("LOC_DIPLOMACY_GRIEVANCES_NONE", GameInfo.DiplomaticStates[iState].Name); + end + -- Add team name to relationship text for our own teams if localPlayer:GetTeam() == selectedPlayer:GetTeam() then relationshipString = "(" .. Locale.Lookup("LOC_WORLD_RANKINGS_TEAM", localPlayer:GetTeam()) .. ") " .. relationshipString; @@ -106,7 +116,7 @@ function Refresh(selectedPlayerID:number) if allianceType ~= -1 then Controls.RelationshipText:SetToolTipString(Locale.Lookup("LOC_DIPLOACTION_EXPIRES_IN_X_TURNS", localPlayerDiplomacy:GetAllianceTurnsUntilExpiration(selectedPlayerID))); - -- Alliance Type + -- Alliance Type local iAllianceType = GameInfo.Alliances[allianceType]; Controls.AllianceTypeText:SetText(Locale.Lookup(iAllianceType.Name)); diff --git a/Additions/DiplomacyActionView_AllianceRow.xml b/Additions/DiplomacyActionView_AllianceRow.xml index 868afa9..9a37e17 100644 --- a/Additions/DiplomacyActionView_AllianceRow.xml +++ b/Additions/DiplomacyActionView_AllianceRow.xml @@ -4,19 +4,19 @@ + + + + + + + + + + + + diff --git a/Replacements/DiplomacyActionView_Expansion1.lua b/Replacements/DiplomacyActionView_Expansion1.lua index f747647..e00178d 100644 --- a/Replacements/DiplomacyActionView_Expansion1.lua +++ b/Replacements/DiplomacyActionView_Expansion1.lua @@ -397,6 +397,7 @@ function AddIntelEmergency(tabContainer:table) m_EmergencyTabContext:SetHide(false); + -- Create tab button local tabButtonInstance:table = CreateTabButton(); tabButtonInstance.Button:RegisterCallback( Mouse.eLClick, function() ShowPanel(tabAnchor.Anchor); end ); diff --git a/Replacements/DiplomacyActionView_Expansion2.lua b/Replacements/DiplomacyActionView_Expansion2.lua new file mode 100644 index 0000000..df388d3 --- /dev/null +++ b/Replacements/DiplomacyActionView_Expansion2.lua @@ -0,0 +1,302 @@ +-- Copyright 2018, Firaxis Games + +-- =========================================================================== +-- INCLUDE XP1 Functionality +-- =========================================================================== +include("DiplomacyActionView_Expansion1.lua"); + + +-- =========================================================================== +-- CACHE FUNCTIONS +-- Do not make cache functions local so overriden functions can check these names. +-- =========================================================================== +BASE_Close = Close; +BASE_LateInitialize = LateInitialize; +BASE_OnShow = OnShow; +XP1_PopulateIntelPanels = PopulateIntelPanels; + + +-- =========================================================================== +-- MEMBERS +-- =========================================================================== +local m_uiWorldCongressInfoContext :table = nil; + + +-- =========================================================================== +-- OVERRIDE BASE FUNCTIONS +-- =========================================================================== +function AddOverviewAgendas(overviewInstance:table) + GetIntelOverviewAgendas():ResetInstances(); + local overviewAgendasInst:table = GetIntelOverviewAgendas():GetInstance(overviewInstance.IntelOverviewStack); + + GetIntelOverviewAgendaEntries():ResetInstances(); + + if (PlayerConfigurations[ms_SelectedPlayerID]:IsHuman()) then + -- Humans don't have agendas, at least ones we can show + overviewAgendasInst.Top:SetHide(true); + else + overviewAgendasInst.Top:SetHide(false); + -- What Historical Agenda does the selected player have? + local leader:string = PlayerConfigurations[ms_SelectedPlayerID]:GetLeaderTypeName(); + + local localPlayerDiplomacy = ms_LocalPlayer:GetDiplomacy(); + local iAccessLevel = localPlayerDiplomacy:GetVisibilityOn(ms_SelectedPlayerID); + + -- What randomly assigned agendas does the selected player have? + -- Determine whether our Diplomatic Visibility allows us to see random agendas + local bRevealRandom = false; + for row in GameInfo.Visibilities() do + if (row.Index <= iAccessLevel and row.RevealAgendas == true) then + bRevealRandom = true; + end + end + local kAgendaTypes = {}; + kAgendaTypes = ms_SelectedPlayer:GetAgendasAndVisibilities(); + --GetAgendaTypes() returns ALL of my agendas, including the historical agenda. + --To retrieve only the randomly assigned agendas, delete the first entry from the table. + local numRandomAgendas = table.count(kAgendaTypes); + local numHiddenAgendas = 0; + local numRandomAgendas = 0; + for i, entry in ipairs(kAgendaTypes) do + if (entry.Visibility <= iAccessLevel) then + local randomAgenda = GetIntelOverviewAgendaEntries():GetInstance(overviewAgendasInst.OverviewAgendasStack); + randomAgenda.Text:LocalizeAndSetText( GameInfo.Agendas[entry.Agenda].Name ); + randomAgenda.Text:LocalizeAndSetToolTip( GameInfo.Agendas[entry.Agenda].Description ); + numRandomAgendas = numRandomAgendas + 1; + else + numHiddenAgendas = numHiddenAgendas + 1; + end + end + if ( numHiddenAgendas > 0 ) then + local hiddenAgenda = GetIntelOverviewAgendaEntries():GetInstance(overviewAgendasInst.OverviewAgendasStack); + hiddenAgenda.Text:LocalizeAndSetText("LOC_DIPLOMACY_HIDDEN_AGENDAS", numHiddenAgendas, numHiddenAgendas>1 ); + if ( numHiddenAgendas > 1 ) then + hiddenAgenda.Text:LocalizeAndSetToolTip("LOC_DIPLOMACY_HIDDEN_AGENDAS_TT"); + else + hiddenAgenda.Text:LocalizeAndSetToolTip("LOC_DIPLOMACY_HIDDEN_AGENDAS_TT_LATE"); + end + elseif (numHiddenAgendas == 0) then + if (numRandomAgendas == 0) then + local noRandomAgendas = GetIntelOverviewAgendaEntries():GetInstance(overviewAgendasInst.OverviewAgendasStack); + noRandomAgendas.Text:LocalizeAndSetText("LOC_DIPLOMACY_RANDOM_AGENDA_NONE"); + noRandomAgendas.Text:SetToolTipString(nil); -- disable tooltip for this one + end + end + end + + return not overviewAgendasInst.Top:IsHidden(); +end + +-- =========================================================================== +function PopulateStatementList( options: table, rootControl: table, isSubList: boolean ) + local buttonIM:table; + local stackControl:table; + local selectionText :string = "[SIZE_16]"; -- Resetting the string size for the new button instance + if (isSubList) then + buttonIM = g_ActionListIM; + stackControl = rootControl.SubOptionStack; + else + buttonIM = g_SubActionListIM; + stackControl = rootControl.OptionStack; + end + buttonIM:ResetInstances(); + + for _, selection in ipairs(options) do + local instance :table = buttonIM:GetInstance(stackControl); + local selectionText :string = selectionText.. Locale.Lookup(selection.Text); + local callback :ifunction; + local tooltipString :string = nil; + if( selection.Key ~= nil) then + callback = function() OnSelectInitialDiplomacyStatement( selection.Key ) end; + + local pActionDef = GameInfo.DiplomaticActions[selection.DiplomaticActionType]; + instance.Button:SetToolTipString(GetStatementButtonTooltip(pActionDef)); + + -- If costs gold add text + local iCost = GetGoldCost(selection.Key); + if iCost > 0 then + local szGoldString = Locale.Lookup("LOC_DIPLO_CHOICE_GOLD_INFO", iCost); + selectionText = selectionText .. szGoldString; + end + + local pDiploActionData:table = GameInfo.DiplomaticActions_XP2[selection.DiplomaticActionType]; + if pDiploActionData ~= nil then + local favorCost = pDiploActionData.FavorCost; + if favorCost ~= nil then + selectionText = selectionText .. Locale.Lookup("LOC_DIPLO_CHOICE_FAVOR_INFO", favorCost); + end + end + + -- If war statement add warmongering info + if (IsWarChoice(selection.Key))then + local eWarType = GetWarType(selection.Key); + local iWarmongerPoints = ms_LocalPlayer:GetDiplomacy():ComputeDOWWarmongerPoints(ms_SelectedPlayerID, eWarType); + local szWarmongerString = Locale.Lookup("LOC_DIPLO_CHOICE_GENERATES_GRIEVANCES_INFO", iWarmongerPoints); + selectionText = selectionText .. szWarmongerString; + + -- Change callback to prompt first. + callback = function() + LuaEvents.DiplomacyActionView_ConfirmWarDialog(ms_LocalPlayerID, ms_SelectedPlayerID, eWarType); + end; + end + + --If denounce statement change callback to prompt first. + if (selection.Key == "CHOICE_DENOUNCE")then + local szWarmongerString = Locale.Lookup("LOC_DIPLO_CHOICE_GENERATES_GRIEVANCES_INFO", GlobalParameters.GRIEVANCES_FOR_DENOUNCEMENT); + selectionText = selectionText .. szWarmongerString; + local denounceFn = function() OnSelectInitialDiplomacyStatement( selection.Key ); end; + callback = function() + local playerConfig = PlayerConfigurations[ms_SelectedPlayer:GetID()]; + if (playerConfig ~= nil) then + + selectedCivName = playerConfig:GetCivilizationShortDescription(); + m_PopupDialog:Reset(); + m_PopupDialog:AddText(Locale.Lookup("LOC_DENOUNCE_POPUP_BODY", selectedCivName)); + m_PopupDialog:AddButton(Locale.Lookup("LOC_CANCEL"), nil); + m_PopupDialog:AddButton(Locale.Lookup("LOC_DIPLO_CHOICE_DENOUNCE_NO_GRIEVANCE"), denounceFn, nil, nil, "PopupButtonInstanceRed"); + m_PopupDialog:Open(); + + end + end; + end + + instance.ButtonText:SetText( selectionText ); + if (selection.IsDisabled == nil or selection.IsDisabled == false) then + instance.Button:RegisterCallback(Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end); + instance.Button:RegisterCallback( Mouse.eLClick, callback ); + instance.ButtonText:SetColor( COLOR_BUTTONTEXT_NORMAL ); + instance.Button:SetDisabled( false ); + else + instance.ButtonText:SetColor( COLOR_BUTTONTEXT_DISABLED ); + instance.Button:SetDisabled( true ); + if (selection.FailureReasons ~= nil) then + instance.Button:SetToolTipString(Locale.Lookup(selection.FailureReasons[1])); + end + end + instance.Button:SetDisabled(not g_bIsLocalPlayerTurn or selection.IsDisabled == true); + else + callback = selection.Callback; + instance.ButtonText:SetColor( COLOR_BUTTONTEXT_NORMAL ); + instance.Button:SetDisabled(not g_bIsLocalPlayerTurn); + if ( selection.ToolTip ~= nil) then + tooltipString = Locale.Lookup(selection.ToolTip); + instance.Button:SetToolTipString(tooltipString); + else + instance.Button:SetToolTipString(nil); -- Clear any existing + end + end + + local wasTruncated :boolean = TruncateString(instance.ButtonText, MAX_BEFORE_TRUNC_BUTTON_INST, selectionText); + if wasTruncated then + local finalTooltipString :string = selectionText; + if tooltipString ~= nil then + finalTooltipString = finalTooltipString .. "[NEWLINE]" .. tooltipString; + end + instance.Button:SetToolTipString( finalTooltipString ); + end + + -- Append tooltip string to the end of the tooltip if it exists in this selection + if selection.Tooltip then + local currentTooltipString = instance.Button:GetToolTipString(); + instance.Button:SetToolTipString(currentTooltipString .. Locale.Lookup(selection.Tooltip)); + end + + instance.Button:RegisterCallback(Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end); + instance.Button:RegisterCallback( Mouse.eLClick, callback ); + end + if (isSubList) then + local instance :table = buttonIM:GetInstance(stackControl); + selectionText = selectionText.. Locale.Lookup("LOC_CANCEL_BUTTON"); + instance.ButtonText:SetText( selectionText ); + instance.Button:SetToolTipString(nil); + instance.Button:SetDisabled(false); + instance.ButtonText:SetColor( COLOR_BUTTONTEXT_NORMAL ); + instance.Button:RegisterCallback(Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end); + instance.Button:RegisterCallback( Mouse.eLClick, function() ShowOptionStack(false); end ); + end + stackControl:CalculateSize(); +end + +-- =========================================================================== +function PopulateIntelPanels( kTabContainer:table) + XP1_PopulateIntelPanels( kTabContainer ); + + AddWorldCongressInfoTab( kTabContainer ); + + -- Refresh contexts (if this isn't being called from an override.) + if XP2_PopulateIntelPanels == nil then + LuaEvents.DiploScene_RefreshTabs(GetSelectedPlayerID()); + end +end + +-- =========================================================================== +function AddWorldCongressInfoTab( kTabContainer:table ) + + -- Create tab + local kTabAnchor :table = GetTabAnchor( kTabContainer ); + if m_uiWorldCongressInfoContext == nil then + m_uiWorldCongressInfoContext = ContextPtr:LoadNewContext("DiplomacyActionView_WorldCongressTab", kTabAnchor.Anchor); + else + m_uiWorldCongressInfoContext:ChangeParent( kTabAnchor.Anchor ); + end + + -- Create tab button + local uiTabButton:table = CreateTabButton(); + uiTabButton.Button:RegisterCallback( Mouse.eLClick, function() ShowPanel(kTabAnchor.Anchor); end ); + uiTabButton.Button:SetToolTipString(Locale.Lookup("LOC_DIPLOACTION_WORLD_CONGRESS_TAB_TOOLTIP")); + uiTabButton.ButtonIcon:SetIcon("ICON_STAT_GRIEVANCE"); + + -- Cache references to the button instance and header text on the panel instance + kTabAnchor.Anchor.m_ButtonInstance = uiTabButton; + kTabAnchor.Anchor.m_HeaderText = Locale.ToUpper("LOC_DIPLOACTION_INTEL_REPORT_GRIEVANCES"); +end + +-- =========================================================================== +function Close() + BASE_Close(); + local pWorldCongress:table = Game.GetWorldCongress(); + LuaEvents.DiplomacyActionView_HideCongress(); +end + +-- =========================================================================== +function OnShow() + BASE_OnShow(); + if Game.GetEras():GetCurrentEra() >= GlobalParameters.WORLD_CONGRESS_INITIAL_ERA then + Controls.TabBar:SetHide(false); + else + Controls.TabBar:SetHide(true); + end +end + +-- =========================================================================== +function OnTalkToLeader( playerID : number ) + local pWorldCongress:table = Game.GetWorldCongress(); + m_LiteMode = pWorldCongress:IsInSession(); + OnOpenDiplomacyActionView( playerID ); +end + +-- =========================================================================== +function LateInitialize() + BASE_LateInitialize(); + LuaEvents.WorldCongress_OpenDiplomacyActionViewLite.Add(OnOpenDiplomacyActionViewLite); + LuaEvents.WorldCongress_OpenDiplomacyActionView.Add(OnOpenDiplomacyActionView); + + local isCongressInSession:boolean = false; + + Events.WorldCongressStage1.Add(function() isCongressInSession = true; end); + Events.WorldCongressStage2.Add(function() isCongressInSession = true; end); + Events.WorldCongressFinished.Add(function() isCongressInSession = false; end); + + Controls.WCButton:RegisterCallback(Mouse.eLClick, function() + OnClose(); + if not isCongressInSession then + LuaEvents.DiplomacyActionView_ShowCongressResults(); + else + LuaEvents.DiplomacyActionView_ResumeCongress(); + end + end); + Controls.LaunchBacking:SetSizeX(Controls.TabBar:GetSizeX() + 144); + Controls.LaunchBackingTile:SetSizeX(Controls.TabBar:GetSizeX() + 10); + Controls.LaunchBarDropShadow:SetSizeX(Controls.TabBar:GetSizeX()); + ContextPtr:SetShowHandler( OnShow ); +end \ No newline at end of file diff --git a/Replacements/DiplomacyDealView.lua b/Replacements/DiplomacyDealView.lua new file mode 100644 index 0000000..65441d5 --- /dev/null +++ b/Replacements/DiplomacyDealView.lua @@ -0,0 +1,2769 @@ +-- =========================================================================== +-- Diplomacy Trade View Manager +-- =========================================================================== +include( "InstanceManager" ); +include( "Colors" ); +include( "Civ6Common" ); -- AutoSizeGridButton +include( "SupportFunctions" ); +include( "PopupDialog" ); +include( "ToolTipHelper_PlayerYields" ); +include( "CivilizationIcon" ); +include( "GreatWorksSupport" ); + + +-- =========================================================================== +-- Globals +-- =========================================================================== +g_LocalPlayer = nil; +g_OtherPlayer = nil; +g_AvailableGroups = {}; +g_IconOnlyIM = InstanceManager:new( "IconOnly", "SelectButton", Controls.IconOnlyContainer ); +g_IconAndTextIM = InstanceManager:new( "IconAndText", "SelectButton", Controls.IconAndTextContainer ); +g_ValueEditDealItemID = -1; -- The ID of the deal item that is being value edited. +g_ValueEditDealItemControlTable = nil; -- The control table of the deal item that is being edited. + +-- These are initialized in CreateGroupTypes +DealItemGroupTypes = nil; +AvailableDealItemGroupTypes = nil; + +-- =========================================================================== +-- VARIABLES +-- =========================================================================== +local ms_PlayerPanelIM :table = InstanceManager:new( "PlayerAvailablePanel", "Root" ); +local ms_LeftRightListIM :table = InstanceManager:new( "LeftRightList", "List", Controls.LeftRightListContainer ); +local ms_TopDownListIM :table = InstanceManager:new( "TopDownList", "List", Controls.TopDownListContainer ); +local ms_AgreementOptionIM :table = InstanceManager:new( "AgreementOptionInstance", "AgreementOptionButton", Controls.ValueEditStack ); + +local OTHER_PLAYER = 0; +local LOCAL_PLAYER = 1; + +ms_OtherPlayerID = -1; +local ms_OtherPlayerIsHuman = false; + +ms_InitiatedByPlayerID = -1; + +local ms_bIsGift = false; +ms_bIsDemand = false; +local ms_bExiting = false; + +local ms_LastIncomingDealProposalAction = DealProposalAction.PENDING; + +local m_kPopupDialog :table; -- Will use custom "popup" since in leader mode the Popup stack is disabled. + +local ms_DealGroups = {}; + +local ms_DealAgreementsGroup = {}; + +local ms_DefaultOneTimeGoldAmount = 100; + +local ms_DefaultMultiTurnGoldAmount = 10; +local ms_DefaultMultiTurnGoldDuration = 30; + +local ms_bForceUpdateOnCommit = false; + +local ms_bDontUpdateOnBack = false; + +local MAX_DEAL_ITEM_EDIT_HEIGHT = 300; + +-- =========================================================================== +function SetIconToSize(iconControl, iconName, iconSize) + if iconSize == nil then + iconSize = 50; + end + local x, y, szIconName, iconSize = IconManager:FindIconAtlasNearestSize(iconName, iconSize, true); + iconControl:SetTexture(x, y, szIconName); + iconControl:SetSizeVal(iconSize, iconSize); +end + +-- =========================================================================== +function InitializeDealGroups() + + for i = 1, table.count(AvailableDealItemGroupTypes), 1 do + g_AvailableGroups[i] = {}; + end + + for i = 1, table.count(DealItemGroupTypes), 1 do + ms_DealGroups[i] = {}; + end + +end + +-- =========================================================================== +function GetPlayerType(player : table) + if (player:GetID() == g_LocalPlayer:GetID()) then + return LOCAL_PLAYER; + end + + return OTHER_PLAYER; +end + +-- =========================================================================== +function GetPlayerOfType(playerType : number) + if (playerType == LOCAL_PLAYER) then + return g_LocalPlayer; + end + + return g_OtherPlayer; +end + +-- =========================================================================== +function GetOtherPlayer(player : table) + if (player ~= nil and player:GetID() == g_OtherPlayer:GetID()) then + return g_LocalPlayer; + end + + return g_OtherPlayer; +end + +-- =========================================================================== +function SetDefaultLeaderDialogText() + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + SetLeaderDialog("LOC_DIPLO_DEMAND_INTRO", ""); + else + SetLeaderDialog("LOC_DIPLO_DEAL_INTRO", ""); + end +end + +-- =========================================================================== +function ProposeWorkingDeal(bIsAutoPropose : boolean) + if (bIsAutoPropose == nil) then + bIsAutoPropose = false; + end + + if (not DealManager.HasPendingDeal(g_LocalPlayer:GetID(), g_OtherPlayer:GetID())) then + if (ms_bIsDemand) then + DealManager.SendWorkingDeal(DealProposalAction.DEMANDED, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + else + if (bIsAutoPropose) then + DealManager.SendWorkingDeal(DealProposalAction.INSPECT, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + else + DealManager.SendWorkingDeal(DealProposalAction.PROPOSED, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + end + end + end +end + +-- =========================================================================== +function RequestEqualizeWorkingDeal() + if (not DealManager.HasPendingDeal(g_LocalPlayer:GetID(), g_OtherPlayer:GetID())) then + DealManager.SendWorkingDeal(DealProposalAction.EQUALIZE, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + end +end + +-- =========================================================================== +function DealIsEmpty() + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal == nil or pDeal:GetItemCount() == 0) then + return true; + end + + return false; +end + +-- =========================================================================== +-- Update the proposed working deal. This is called as items are changed in the deal. +-- It is primarily used to 'auto-propose' the deal when working with an AI. +function UpdateProposedWorkingDeal() + if (ms_LastIncomingDealProposalAction ~= DealProposalAction.PENDING or IsAutoPropose()) then + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal == nil or pDeal:GetItemCount() == 0 or ms_bIsDemand) then + -- Is a demand or no items, restart + ms_LastIncomingDealProposalAction = DealProposalAction.PENDING; + UpdateDealStatus(); + else + if (IsAutoPropose()) then + ProposeWorkingDeal(true); + end + end + end +end + +-- =========================================================================== +function UpdateOtherPlayerText(otherPlayerSays) + local bHide = true; + if (g_OtherPlayer ~= nil and otherPlayerSays ~= nil) then + local playerConfig = PlayerConfigurations[g_OtherPlayer:GetID()]; + if (playerConfig ~= nil) then + -- leader icon + local otherPlayerController = CivilizationIcon:AttachInstance(Controls.OtherPlayerBubbleIcon); + otherPlayerController:UpdateIconFromPlayerID(g_OtherPlayer:GetID()); + + -- Set the leader name + local leaderDesc = playerConfig:GetLeaderName(); + Controls.OtherPlayerBubbleName:SetText(Locale.ToUpper(Locale.Lookup("LOC_DIPLOMACY_DEAL_OTHER_PLAYER_SAYS", leaderDesc))); + end + end + -- When we get dialog for what the leaders say during a trade, we can add it here! +end + +-- =========================================================================== +function OnToggleCollapseGroup(iconList : table) + if (iconList.ListStack:IsHidden()) then + iconList.ListStack:SetHide(false); + else + iconList.ListStack:SetHide(true); + end + + iconList.List:CalculateSize(); + iconList.List:ReprocessAnchoring(); +end +-- =========================================================================== +function CreateHorizontalGroup(rootStack : table, title : string) + local iconList = ms_LeftRightListIM:GetInstance(rootStack); + if (title == nil or title == "") then + iconList.Title:SetHide(true); -- No title + else + iconList.TitleText:LocalizeAndSetText(title); + end + iconList.List:CalculateSize(); + iconList.List:ReprocessAnchoring(); + + return iconList; +end + +-- =========================================================================== +function CreateVerticalGroup(rootStack : table, title : string) + local iconList = ms_TopDownListIM:GetInstance(rootStack); + if (title == nil or title == "") then + iconList.Title:SetHide(true); -- No title + else + iconList.TitleText:LocalizeAndSetText(title); + end + iconList.List:CalculateSize(); + iconList.List:ReprocessAnchoring(); + + return iconList; +end + + +-- =========================================================================== +function CreatePlayerAvailablePanel(playerType : number, rootControl : table) + + --local playerPanel = ms_PlayerPanelIM:GetInstance(rootControl); + + g_AvailableGroups[AvailableDealItemGroupTypes.GOLD][playerType] = g_AvailableGroups[AvailableDealItemGroupTypes.FAVOR][playerType]; + g_AvailableGroups[AvailableDealItemGroupTypes.LUXURY_RESOURCES][playerType] = CreateHorizontalGroup(rootControl, "LOC_DIPLOMACY_DEAL_LUXURY_RESOURCES"); + g_AvailableGroups[AvailableDealItemGroupTypes.STRATEGIC_RESOURCES][playerType] = CreateHorizontalGroup(rootControl, "LOC_DIPLOMACY_DEAL_STRATEGIC_RESOURCES"); + g_AvailableGroups[AvailableDealItemGroupTypes.AGREEMENTS][playerType] = CreateVerticalGroup(rootControl, "LOC_DIPLOMACY_DEAL_AGREEMENTS"); + g_AvailableGroups[AvailableDealItemGroupTypes.CITIES][playerType] = CreateVerticalGroup(rootControl, "LOC_DIPLOMACY_DEAL_CITIES"); + g_AvailableGroups[AvailableDealItemGroupTypes.OTHER_PLAYERS][playerType] = CreateVerticalGroup(rootControl, "LOC_DIPLOMACY_DEAL_OTHER_PLAYERS"); + g_AvailableGroups[AvailableDealItemGroupTypes.GREAT_WORKS][playerType] = CreateVerticalGroup(rootControl, "LOC_DIPLOMACY_DEAL_GREAT_WORKS"); + g_AvailableGroups[AvailableDealItemGroupTypes.CAPTIVES][playerType] = CreateVerticalGroup(rootControl, "LOC_DIPLOMACY_DEAL_CAPTIVES"); + + rootControl:CalculateSize(); + rootControl:ReprocessAnchoring(); + + return playerPanel; +end + +-- =========================================================================== +function CreatePlayerDealPanel(playerType : number, rootControl : table) +--This creates the containers for the offer area... + --ms_DealGroups[DealItemGroupTypes.RESOURCES][playerType] = CreateHorizontalGroup(rootControl); + --ms_DealGroups[DealItemGroupTypes.AGREEMENTS][playerType] = CreateVerticalGroup(rootControl); + --********************************************************************** + -- Currently putting them all in the same control. + ms_DealGroups[DealItemGroupTypes.RESOURCES][playerType] = rootControl; + ms_DealGroups[DealItemGroupTypes.AGREEMENTS][playerType] = rootControl; + ms_DealGroups[DealItemGroupTypes.CITIES][playerType] = rootControl; + ms_DealGroups[DealItemGroupTypes.GREAT_WORKS][playerType] = rootControl; + ms_DealGroups[DealItemGroupTypes.CAPTIVES][playerType] = rootControl; + +end + +-- =========================================================================== +function OnValuePulldownCommit(forType) + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + local pDealItem = pDeal:FindItemByID(g_ValueEditDealItemID); + if (pDealItem ~= nil) then + pDealItem:SetValueType( forType ); + + local valueName = pDealItem:GetValueTypeNameID(); + if (g_ValueEditDealItemControlTable ~= nil) then + -- Keep the text on the icon, that is currently hidden, up to date too. + g_ValueEditDealItemControlTable.ValueText:LocalizeAndSetText(pDealItem:GetValueTypeNameID(valueName)); + end + + UpdateDealStatus(); + UpdateProposedWorkingDeal(); + end + end + + Controls.ValueEditPopupBackground:SetHide(true); + +end + +-- =========================================================================== +function SetValueText(icon, pDealItem) + + if (icon.ValueText ~= nil) then + local valueName = pDealItem:GetValueTypeNameID(); + if (valueName == nil) then + if (pDealItem:HasPossibleValues()) then + valueName = "LOC_DIPLOMACY_DEAL_CLICK_TO_CHANGE_DEAL_PARAMETER"; + end + end + if (valueName ~= nil) then + icon.ValueText:LocalizeAndSetText(valueName); + icon.ValueText:SetHide(false); + else + icon.ValueText:SetHide(true); + end + end +end + +-- =========================================================================== +function CreatePanels() + + -- Create the Other Player Panels + CreatePlayerAvailablePanel(OTHER_PLAYER, Controls.TheirInventoryStack); + + -- Create the Local Player Panels + CreatePlayerAvailablePanel(LOCAL_PLAYER, Controls.MyInventoryStack); + + CreatePlayerDealPanel(OTHER_PLAYER, Controls.TheirOfferStack); + CreatePlayerDealPanel(LOCAL_PLAYER, Controls.MyOfferStack); + + Controls.EqualizeDeal:RegisterCallback( Mouse.eLClick, OnEqualizeDeal ); + Controls.EqualizeDeal:RegisterCallback( Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end); + Controls.AcceptDeal:RegisterCallback( Mouse.eLClick, OnProposeOrAcceptDeal ); + Controls.AcceptDeal:RegisterCallback( Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end); + Controls.DemandDeal:RegisterCallback( Mouse.eLClick, OnProposeOrAcceptDeal ); + Controls.DemandDeal:RegisterCallback( Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end); + Controls.RefuseDeal:RegisterCallback(Mouse.eLClick, OnRefuseDeal); + Controls.RefuseDeal:RegisterCallback( Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end); + Controls.ResumeGame:RegisterCallback(Mouse.eLClick, OnResumeGame); + Controls.ResumeGame:RegisterCallback( Mouse.eMouseEnter, function() UI.PlaySound("Main_Menu_Mouse_Over"); end); + +end + +function CreateGroupTypes() + AvailableDealItemGroupTypes = { + GOLD = 1, + LUXURY_RESOURCES = 2, + STRATEGIC_RESOURCES = 3, + AGREEMENTS = 4, + CITIES = 5, + OTHER_PLAYERS = 6, + GREAT_WORKS = 7, + CAPTIVES = 8, + }; + + DealItemGroupTypes = { + GOLD = 1, + RESOURCES = 2, + AGREEMENTS = 3, + CITIES = 4, + GREAT_WORKS = 5, + CAPTIVES = 6 + }; +end + +-- =========================================================================== +-- Find the 'instance' table from the control +function FindIconInstanceFromControl(rootControl : table) + + if (rootControl ~= nil) then + local controlTable = g_IconOnlyIM:FindInstanceByControl(rootControl); + if (controlTable == nil) then + controlTable = g_IconAndTextIM:FindInstanceByControl(rootControl); + end + + return controlTable; + end + + return nil; +end + +-- =========================================================================== +-- Show or hide the "amount text" or the "Value Text" sub-control of the supplied control instance +function SetHideValueText(controlTable : table, bHide : boolean) + + if (controlTable ~= nil) then + if (controlTable.AmountText ~= nil) then + controlTable.AmountText:SetHide(bHide); + end + if (controlTable.ValueText ~= nil) then + controlTable.ValueText:SetHide(bHide); + end + end +end + +-- =========================================================================== +-- Detach the value edit overlay from anything it is attached to. +function ClearValueEdit() + + SetHideValueText(g_ValueEditDealItemControlTable, false); + + g_ValueEditDealItemControlTable = nil + g_ValueEditDealItemID = -1; + +end + +-- =========================================================================== +function UpdateDealStatus() + local bDealValid = false; + ClearValueEdit(); + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + if (pDeal:GetItemCount() > 0) then + bDealValid = true; + end + end + + if (bDealValid) then + if pDeal:Validate() ~= DealValidationResult.VALID then + bDealValid = false; + end + end + + Controls.EqualizeDeal:SetHide(ms_bIsDemand); + + -- Have we sent out a deal? + local bHasPendingDeal = DealManager.HasPendingDeal(g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + + if (not bHasPendingDeal and ms_LastIncomingDealProposalAction == DealProposalAction.PENDING) then + -- We have yet to send out a deal. + Controls.AcceptDeal:SetHide(true); + local showDemand = bDealValid and ms_bIsDemand; + Controls.DemandDeal:SetHide(not showDemand); + else + local cantAccept = (ms_LastIncomingDealProposalAction ~= DealProposalAction.ACCEPTED and ms_LastIncomingDealProposalAction ~= DealProposalAction.PROPOSED and ms_LastIncomingDealProposalAction ~= DealProposalAction.ADJUSTED) or not bDealValid or bHasPendingDeal; + Controls.AcceptDeal:SetHide(cantAccept); + if (ms_bIsDemand) then + if (g_LocalPlayer:GetID() == ms_InitiatedByPlayerID) then + -- Local human is making a demand + if (ms_LastIncomingDealProposalAction == DealProposalAction.ACCEPTED) then + Controls.DemandDeal:SetHide(cantAccept); + -- The other player has accepted the demand, but we must enact it. + -- We won't have the human need to press the accept button, just do it and exit. + OnProposeOrAcceptDeal(); + return; + else + Controls.AcceptDeal:SetHide(true); + Controls.DemandDeal:SetHide(false); + end + else + Controls.DemandDeal:SetHide(true); + end + else + Controls.DemandDeal:SetHide(true); + end + end + + UpdateProposalButtons(bDealValid); + + ResizeDealAndButtons(); +end + +-- =========================================================================== +function ResizeDealAndButtons() + + -- Find the widest deal button text and size others to match + local refuseX, refuseY = AutoSizeGridButton(Controls.RefuseDeal,200,32,10,"1"); + local equalizeX, equalizeY = AutoSizeGridButton(Controls.EqualizeDeal,200,32,10,"1"); + local acceptX, acceptY = AutoSizeGridButton(Controls.AcceptDeal,200,41,10,"1"); + + local minX = refuseX; + if not Controls.EqualizeDeal:IsHidden() and minX < equalizeX then + minX = equalizeX; + end + if not Controls.AcceptDeal:IsHidden() and minX < acceptX then + minX = acceptX; + end + + if Controls.RefuseDeal:GetSizeX() < minX then + Controls.RefuseDeal:SetSizeX(minX); + end + if Controls.EqualizeDeal:GetSizeX() < minX then + Controls.EqualizeDeal:SetSizeX(minX); + end + if Controls.AcceptDeal:GetSizeX() < minX then + Controls.AcceptDeal:SetSizeX(minX); + end + + Controls.DealOptionsStack:CalculateSize(); + Controls.DealOptionsStack:ReprocessAnchoring(); + + Controls.TheirOfferStack:CalculateSize(); + Controls.TheirOfferBracket:DoAutoSize(); + Controls.TheirOfferScroll:CalculateSize(); + + Controls.MyOfferStack:CalculateSize(); + Controls.MyOfferBracket:DoAutoSize(); + Controls.MyOfferScroll:CalculateSize(); +end + +-- =========================================================================== +-- The Human has ask to have the deal equalized. Well, what the AI is +-- willing to take. +function OnEqualizeDeal() + ClearValueEdit(); + RequestEqualizeWorkingDeal(); +end + +-- =========================================================================== +-- Propose the deal, if this is the first time, or accept it, if the other player has +-- accepted it. +function OnProposeOrAcceptDeal() + + ClearValueEdit(); + + if (ms_LastIncomingDealProposalAction == DealProposalAction.PENDING or + ms_LastIncomingDealProposalAction == DealProposalAction.REJECTED or + ms_LastIncomingDealProposalAction == DealProposalAction.EQUALIZE_FAILED) then + ProposeWorkingDeal(); + UpdateDealStatus(); + UI.PlaySound("Confirm_Bed_Positive"); + else + if (ms_LastIncomingDealProposalAction == DealProposalAction.ACCEPTED or ms_LastIncomingDealProposalAction == DealProposalAction.PROPOSED or ms_LastIncomingDealProposalAction == DealProposalAction.ADJUSTED) then + -- Any adjustments? + if (DealManager.AreWorkingDealsEqual(g_LocalPlayer:GetID(), g_OtherPlayer:GetID())) then + -- Yes, we can accept + -- if deal will trigger war, prompt user before confirming deal + local sendDealAndContinue = function() + -- Send the deal. This will also send out a POSITIVE response statement + DealManager.SendWorkingDeal(DealProposalAction.ACCEPTED, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + OnContinue(); + UI.PlaySound("Confirm_Bed_Positive"); + end; + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local pJointWarItem = pDeal:FindItemByType(DealItemTypes.AGREEMENTS, DealAgreementTypes.JOINT_WAR); + if DealAgreementTypes.JOINT_WAR and pJointWarItem then + local iWarType = pJointWarItem:GetParameterValue("WarType"); + + if (iWarType == nil) then iWarType = WarTypes.FORMAL_WAR; end + + local targetPlayerID = pJointWarItem:GetValueType(); + if (targetPlayerID >= 0) then + LuaEvents.DiplomacyActionView_ConfirmWarDialog(g_LocalPlayer:GetID(), targetPlayerID, iWarType, sendDealAndContinue); + else + UI.DataError("Invalid Player ID to declare Joint War to: " .. targetPlayerID); + end + else + local pThirdPartyWarItem = pDeal:FindItemByType(DealItemTypes.AGREEMENTS, DealAgreementTypes.THIRD_PARTY_WAR); + if (DealAgreementTypes.THIRD_PARTY_WAR and pThirdPartyWarItem) then + local iWarType = pThirdPartyWarItem:GetParameterValue("WarType"); + + if (iWarType == nil) then iWarType = WarTypes.FORMAL_WAR; end + + local targetPlayerID = pThirdPartyWarItem:GetValueType(); + if (targetPlayerID >= 0) then + LuaEvents.DiplomacyActionView_ConfirmWarDialog(g_LocalPlayer:GetID(), targetPlayerID, iWarType, sendDealAndContinue); + else + UI.DataError("Invalid Player ID to declare Third Party War to: " .. targetPlayerID); + end + else + sendDealAndContinue(); + end + end + else + -- No, send an adjustment and stay in the deal view. + DealManager.SendWorkingDeal(DealProposalAction.ADJUSTED, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + UpdateDealStatus(); + end + end + end +end + +-- =========================================================================== +function OnRefuseDeal(bForceClose) + + if (bForceClose == nil) then + bForceClose = false; + end + + local bHasPendingDeal = DealManager.HasPendingDeal(g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + + local sessionID = DiplomacyManager.FindOpenSessionID(Game.GetLocalPlayer(), g_OtherPlayer:GetID()); + if (sessionID ~= nil) then + if (not ms_OtherPlayerIsHuman and not bHasPendingDeal) then + -- Refusing an AI's deal + ClearValueEdit(); + + if (ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- AI started this, so tell them that we don't want the deal + if (bForceClose == true) then + -- Forcing the close, usually because the turn timer expired + DealManager.SendWorkingDeal(DealProposalAction.REJECTED, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + DiplomacyManager.CloseSession(sessionID); + StartExitAnimation(); + else + DiplomacyManager.AddResponse(sessionID, Game.GetLocalPlayer(), "NEGATIVE"); + end + else + -- Else close the session + DiplomacyManager.CloseSession(sessionID); + StartExitAnimation(); + end + else + if (ms_OtherPlayerIsHuman) then + if (bHasPendingDeal) then + -- Canceling the deal with the other player. + DealManager.SendWorkingDeal(DealProposalAction.CLOSED, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + else + if (ms_InitiatedByPlayerID ~= Game.GetLocalPlayer()) then + -- Refusing the deal with the other player. + DealManager.SendWorkingDeal(DealProposalAction.REJECTED, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + end + end + + DiplomacyManager.CloseSession(sessionID); + StartExitAnimation(); + end + end + else + -- We have lost our session! + if (not ContextPtr:IsHidden()) then + if (not ms_bExiting) then + OnResumeGame(); + end + end + end + +end + +-- =========================================================================== +function OnResumeGame() + + -- Exiting back to wait for a response + ClearValueEdit(); + + local sessionID = DiplomacyManager.FindOpenSessionID(Game.GetLocalPlayer(), g_OtherPlayer:GetID()); + if (sessionID ~= nil) then + DiplomacyManager.CloseSession(sessionID); + end + + -- Start the exit animation, it will call OnContinue when complete + StartExitAnimation(); +end + +-- =========================================================================== +function OnExitFadeComplete() + if(Controls.TradePanelFade:IsReversing()) then + Controls.TradePanelFade:SetSpeed(2); + Controls.TradePanelSlide:SetSpeed(2); + + OnContinue(); + end +end +Controls.TradePanelFade:RegisterEndCallback(OnExitFadeComplete); +-- =========================================================================== +-- Change the value number edit by a delta +function OnValueAmountEditDelta(dealItemID:number, delta:number) + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + local pDealItem = pDeal:FindItemByID(dealItemID); + if (pDealItem ~= nil) then + local iNewAmount = tonumber(Controls.ValueAmountEditBox:GetText() or 0) + delta; + iNewAmount = clip(iNewAmount, 1, pDealItem:GetMaxAmount()); + Controls.ValueAmountEditBox:SetText(tostring(iNewAmount)); + end + end +end + +-- =========================================================================== +-- Detach the value edit if it is attached to the control +function DetachValueEdit(itemID: number) + + if (itemID == g_ValueEditDealItemID) then + ClearValueEdit(); + end + +end + +-- =========================================================================== +function IsItemValueEditable(itemType: number) + return itemType == DealItemTypes.GOLD or itemType == DealItemTypes.RESOURCES; +end + +-- =========================================================================== +function GetItemTypeIcon(pDealItem: table) + local itemType = pDealItem:GetType(); + if (itemType == DealItemTypes.GOLD) then + return "ICON_YIELD_GOLD_5"; + elseif (itemType == DealItemTypes.RESOURCES) then + local resourceType = pDealItem:GetValueType(); + local resourceDesc = GameInfo.Resources[resourceType]; + return "ICON_" .. resourceDesc.ResourceType; + end + return nil; +end + +-- =========================================================================== +-- Reattach the value edit overlay to the control set it is editing. +function ReAttachValueEdit() + + if (g_ValueEditDealItemControlTable ~= nil) then + + SetHideValueText(g_ValueEditDealItemControlTable, true); + + -- Display the number in the value edit field + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + local pDealItem = pDeal:FindItemByID(g_ValueEditDealItemID); + if (pDealItem ~= nil) then + + local itemID = pDealItem:GetID(); + local itemType = pDealItem:GetType(); + if (IsItemValueEditable(itemType)) then + -- Hide/show everything for GOLD and RESOURCE options + ms_AgreementOptionIM:ResetInstances(); + Controls.ValueEditIconGrid:SetHide(false); + Controls.ValueAmountEditBoxContainer:SetHide(false); + + local iDuration = pDealItem:GetDuration(); + + Controls.ValueEditHeaderLabel:SetText(Locale.Lookup("LOC_DIPLOMACY_DEAL_HOW_MANY")); + + if (iDuration == 0) then + ---- One time + Controls.ValueEditValueText:SetHide(true); + else + ---- Multi-turn + Controls.ValueEditValueText:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_FOR_TURNS", iDuration); + Controls.ValueEditValueText:SetHide(false); + end + + SetIconToSize(Controls.ValueEditIcon, GetItemTypeIcon(pDealItem)); + + Controls.ValueEditAmountText:SetText(tostring(pDealItem:GetAmount())); + Controls.ValueEditAmountText:SetHide(false); + + Controls.ValueAmountEditBox:SetText(tostring(pDealItem:GetAmount())); + Controls.ValueEditButton:RegisterCallback( Mouse.eLClick, function() OnValueEditButton(itemID); end ); + Controls.ValueAmountEditLeftButton:RegisterCallback( Mouse.eLClick, function() OnValueAmountEditDelta(itemID, -1); end ); + Controls.ValueAmountEditRightButton:RegisterCallback( Mouse.eLClick, function() OnValueAmountEditDelta(itemID, 1); end ); + elseif (itemType == DealItemTypes.AGREEMENTS) then + local subType = pDealItem:GetSubType(); + local iDuration = pDealItem:GetDuration(); + + ShowAgreementOptionPopup(subType, iDuration, pDealItem:GetFromPlayerID()); + else + -- The value of the item cannot be adjusted so don't show a popup + return; + end + end + end + + Controls.ValueEditIconGrid:DoAutoSize(); + + ResizeValueEditScrollPanel(); + + Controls.ValueEditPopup:DoAutoSize(); + Controls.ValueEditPopupBackground:SetHide(false); + end + +end + +-- =========================================================================== +-- Attach the value edit overlay to a control set. +function AttachValueEdit(rootControl : table, dealItemID : number) + + ClearValueEdit(); + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + local pDealItem = pDeal:FindItemByID(dealItemID); + if (pDealItem ~= nil) then + -- Do we have something to edit? + if (pDealItem:HasPossibleValues() or pDealItem:HasPossibleAmounts()) then + -- Yes + g_ValueEditDealItemControlTable = FindIconInstanceFromControl(rootControl); + g_ValueEditDealItemID = dealItemID; + + ReAttachValueEdit(); + end + end + end + +end + +-- =========================================================================== +-- Update the deal panel for a player +function UpdateDealPanel(player) + + -- If we modify the deal without sending it to the AI then reset the status to PENDING + ms_LastIncomingDealProposalAction = DealProposalAction.PENDING; + + UpdateDealStatus(); + + PopulatePlayerDealPanel(Controls.TheirOfferStack, g_OtherPlayer); + PopulatePlayerDealPanel(Controls.MyOfferStack, g_LocalPlayer); + + ResizeDealAndButtons(); + +end + +-- =========================================================================== +function OnClickAvailableOneTimeGold(player, iAddAmount : number) + + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Can't modifiy demand that is not ours + return; + end + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + local pPlayerTreasury = player:GetTreasury(); + local bFound = false; + + -- Already there? + local dealItems = pDeal:FindItemsByType(DealItemTypes.GOLD, DealItemSubTypes.NONE, player:GetID()); + local pDealItem; + if (dealItems ~= nil) then + for i, pDealItem in ipairs(dealItems) do + if (pDealItem:GetDuration() == 0) then + -- Already have a one time gold. Up the amount + iAddAmount = pDealItem:GetAmount() + iAddAmount; + iAddAmount = clip(iAddAmount, nil, pDealItem:GetMaxAmount()); + if (iAddAmount ~= pDealItem:GetAmount()) then + pDealItem:SetAmount(iAddAmount); + bFound = true; + break; + else + return; -- No change, just exit + end + end + end + end + + -- Doesn't exist yet, add it. + if (not bFound) then + + -- Going to add anything? + pDealItem = pDeal:AddItemOfType(DealItemTypes.GOLD, player:GetID()); + if (pDealItem ~= nil) then + + -- Set the duration, so the max amount calculation knows what we are doing + pDealItem:SetDuration(0); + + -- Adjust the gold to our max + iAddAmount = clip(iAddAmount, nil, pDealItem:GetMaxAmount()); + if (iAddAmount > 0) then + pDealItem:SetAmount(iAddAmount); + bFound = true; + else + -- It is empty, remove it. + local itemID = pDealItem:GetID(); + pDeal:RemoveItemByID(itemID); + end + end + end + + + if (bFound) then + UpdateProposedWorkingDeal(); + UpdateDealPanel(player); + end + end +end + +-- =========================================================================== +function OnClickAvailableMultiTurnGold(player, iAddAmount : number, iDuration : number) + + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Can't modifiy demand that is not ours + return; + end + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + local pPlayerTreasury = player:GetTreasury(); + + local bFound = false; + UI.PlaySound("UI_GreatWorks_Put_Down"); + + -- Already there? + local dealItems = pDeal:FindItemsByType(DealItemTypes.GOLD, DealItemSubTypes.NONE, player:GetID()); + local pDealItem; + if (dealItems ~= nil) then + for i, pDealItem in ipairs(dealItems) do + if (pDealItem:GetDuration() ~= 0) then + -- Already have a multi-turn gold. Up the amount + iAddAmount = pDealItem:GetAmount() + iAddAmount; + iAddAmount = clip(iAddAmount, nil, pDealItem:GetMaxAmount()); + if (iAddAmount ~= pDealItem:GetAmount()) then + pDealItem:SetAmount(iAddAmount); + bFound = true; + break; + else + return; -- No change, just exit + end + end + end + end + + -- Doesn't exist yet, add it. + if (not bFound) then + -- Going to add anything? + pDealItem = pDeal:AddItemOfType(DealItemTypes.GOLD, player:GetID()); + if (pDealItem ~= nil) then + + -- Set the duration, so the max amount calculation knows what we are doing + pDealItem:SetDuration(iDuration); + + -- Adjust the gold to our max + iAddAmount = clip(iAddAmount, nil, pDealItem:GetMaxAmount()); + + if (iAddAmount > 0) then + pDealItem:SetAmount(iAddAmount); + bFound = true; + else + -- It is empty, remove it. + local itemID = pDealItem:GetID(); + pDeal:RemoveItemByID(itemID); + end + end + end + + if (bFound) then + UpdateProposedWorkingDeal(); + UpdateDealPanel(player); + end + end +end + +-- =========================================================================== +-- Clip val to be within the range of min and max +function clip(val: number, min: number, max: number) + if min and val < min then + val = min; + elseif max and val > max then + val = max; + end + return val; +end + +-- =========================================================================== +-- Check to see if the deal should be auto-proposed. +function IsAutoPropose() + if (not ms_OtherPlayerIsHuman) then + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + pDeal:Validate(); + if (pDeal ~= nil and not ms_bIsDemand and pDeal:IsValid() and not DealManager.HasPendingDeal(g_LocalPlayer:GetID(), g_OtherPlayer:GetID())) then + local iItemsFromLocal = pDeal:GetItemCount(g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local iItemsFromOther = pDeal:GetItemCount(g_OtherPlayer:GetID(), g_LocalPlayer:GetID()); + + if (iItemsFromLocal > 0 or iItemsFromOther > 0) then + return true; + end + end + end + return false; +end + +-- =========================================================================== +-- Check the state of the deal and show/hide the special proposal buttons for a possible gift (not actually possible until XP2) +function UpdateProposalButtonsForGift(iItemsFromLocal : number, iItemsFromOther : number) + if (iItemsFromLocal == 0 and iItemsFromOther > 0) then + return true; + end + + return false; +end + +-- =========================================================================== +-- Check the state of the deal and show/hide the special proposal buttons +function UpdateProposalButtons(bDealValid) + + local bDealIsPending = DealManager.HasPendingDeal(g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + + if (bDealValid and (not bDealIsPending or not ms_OtherPlayerIsHuman)) then + Controls.ResumeGame:SetHide(true); + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + Controls.EqualizeDeal:SetHide(ms_bIsDemand); + if (pDeal ~= nil) then + + local iItemsFromLocal = pDeal:GetItemCount(g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local iItemsFromOther = pDeal:GetItemCount(g_OtherPlayer:GetID(), g_LocalPlayer:GetID()); + ms_bIsGift = pDeal:IsGift() and iItemsFromOther > 0; + + -- Hide/show directions if either side has no items + Controls.MyDirections:SetHide( iItemsFromLocal > 0); + Controls.TheirDirections:SetHide( iItemsFromOther > 0); + + if (not ms_bIsDemand) then + if (not ms_OtherPlayerIsHuman) then + -- Dealing with an AI + if (pDeal:HasUnacceptableItems()) then + Controls.EqualizeDeal:SetHide(true); + Controls.AcceptDeal:SetHide(true); + SetLeaderDialog("LOC_DIPLO_DEAL_UNACCEPTABLE_DEAL", ""); + elseif (iItemsFromLocal > 0 and iItemsFromOther == 0) then + -- One way gift? + + if ms_LastIncomingDealProposalAction == DealProposalAction.EQUALIZE_FAILED then + -- Equalize failed, hide the button, and we can't accept now! + -- Except... not. + -- The AI will yield EQUALIZE_FAILED if it would have accepted the gift without modifications. + -- The AI does not distinguish between 'this gift is fine as is' and 'i would not give you anything for that'. + Controls.AcceptDeal:SetShow(false); + Controls.EqualizeDeal:SetShow(false); + SetLeaderDialog("LOC_DIPLO_DEAL_LEADER_GIFT_EQUALIZE_FAILED", ""); + elseif ms_LastIncomingDealProposalAction == DealProposalAction.REJECTED then + -- Most likely autoproposed, there's a chance for an equalize. No accept, again. + Controls.AcceptDeal:SetShow(false); + Controls.EqualizeDeal:SetShow(true); + Controls.EqualizeDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_WHAT_WOULD_IT_TAKE"); + Controls.EqualizeDeal:LocalizeAndSetToolTip("LOC_DIPLOMACY_DEAL_WHAT_IT_WILL_TAKE_TOOLTIP"); + SetLeaderDialog("LOC_DIPLO_MAKE_DEAL_AI_REFUSE_DEAL_ANY_ANY", ""); + else + -- No immediate complaints, I guess we can show both equalize and accept. + Controls.AcceptDeal:SetShow(true); + Controls.AcceptDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_GIFT_DEAL"); + Controls.EqualizeDeal:SetShow(true); + Controls.EqualizeDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_WHAT_WOULD_YOU_GIVE_ME"); + Controls.EqualizeDeal:LocalizeAndSetToolTip("LOC_DIPLO_DEAL_WHAT_WOULD_YOU_GIVE_ME_TOOLTIP"); + SetLeaderDialog("LOC_DIPLO_DEAL_LEADER_GIFT", "LOC_DIPLO_DEAL_LEADER_GIFT_EFFECT"); + end + elseif ms_bIsGift then -- Incoming gift + Controls.EqualizeDeal:SetShow(false); + else + if (UpdateProposalButtonsForGift(iItemsFromLocal, iItemsFromOther)) then + -- AI was unable to equalize for the requested items so hide the equalize button + if ms_LastIncomingDealProposalAction == DealProposalAction.EQUALIZE_FAILED then + Controls.EqualizeDeal:SetHide(true); + SetLeaderDialog("LOC_DIPLO_DEAL_LEADER_EQUALIZE_FAILED", ""); + else + Controls.EqualizeDeal:SetHide(false); + SetLeaderDialog("LOC_DIPLO_DEAL_UNFAIR", ""); + end + + Controls.EqualizeDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_WHAT_WOULD_IT_TAKE"); + Controls.EqualizeDeal:LocalizeAndSetToolTip("LOC_DIPLOMACY_DEAL_WHAT_IT_WILL_TAKE_TOOLTIP"); + Controls.AcceptDeal:SetHide(true); --If either of the above buttons are showing, disable the main accept button + + else --Something is being offered on both sides + -- Show equalize button if the accept button is hidden and the AI already hasn't attempted to equalize the deal + if Controls.AcceptDeal:IsHidden() and ms_LastIncomingDealProposalAction ~= DealProposalAction.EQUALIZE_FAILED then + Controls.EqualizeDeal:SetHide(false); + Controls.EqualizeDeal:LocalizeAndSetText("LOC_DIPLOMACY_MAKE_DEAL_EQUITABLE"); + Controls.EqualizeDeal:LocalizeAndSetToolTip("LOC_DIPLOMACY_MAKE_DEAL_EQUITABLE_TOOLTIP"); + else + Controls.EqualizeDeal:SetHide(true); + if ms_LastIncomingDealProposalAction == DealProposalAction.PROPOSED then + SetLeaderDialog("LOC_DIPLO_DEAL_INTRO_AI", ""); + elseif ms_LastIncomingDealProposalAction == DealProposalAction.ACCEPTED then + SetLeaderDialog("LOC_DIPLO_MAKE_DEAL_AI_ACCEPT_DEAL_ANY_ANY", ""); + elseif ms_LastIncomingDealProposalAction == DealProposalAction.ADJUSTED then + SetLeaderDialog("LOC_DIPLO_DEAL_LEADER_EQUALIZE_SUCCEEDED", ""); + else + SetLeaderDialog("LOC_DIPLO_DEAL_LEADER_EQUALIZE_FAILED", ""); + end + end + + Controls.AcceptDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_ACCEPT_DEAL"); + end + end + else + -- Dealing with another human + + Controls.EqualizeDeal:SetHide(true); + Controls.AcceptDeal:SetHide(false); + + if (ms_LastIncomingDealProposalAction == DealProposalAction.PENDING) then + -- Just starting the deal + if (iItemsFromLocal > 0 and iItemsFromOther == 0) then + -- Is this one way to them? + Controls.MyDirections:SetHide(true); + Controls.TheirDirections:SetHide(false); + Controls.AcceptDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_GIFT_DEAL"); + else + -- Everything else is a proposal to another human + Controls.MyDirections:SetHide(true); + Controls.TheirDirections:SetHide(true); + Controls.AcceptDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_PROPOSE_DEAL"); + end + -- Make sure the leader text is set to something appropriate. + SetDefaultLeaderDialogText(); + else + Controls.MyDirections:SetHide(true); + Controls.TheirDirections:SetHide(true); + -- Are the incoming and outgoing deals the same? + if (DealManager.AreWorkingDealsEqual(g_LocalPlayer:GetID(), g_OtherPlayer:GetID())) then + Controls.AcceptDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_ACCEPT_DEAL"); + else + Controls.AcceptDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_PROPOSE_DEAL"); + end + end + end + else + -- Is a Demand + if (ms_InitiatedByPlayerID == ms_OtherPlayerID) then + Controls.MyDirections:SetHide(true); + Controls.TheirDirections:SetHide(true); + SetDefaultLeaderDialogText(); + else + if (iItemsFromOther == 0) then + Controls.TheirDirections:SetHide(false); + else + Controls.TheirDirections:SetHide(true); + end + -- Demand against another player + SetLeaderDialog("LOC_DIPLO_DEAL_LEADER_DEMAND", "LOC_DIPLO_DEAL_LEADER_DEMAND_EFFECT"); + end + end + else + -- Make sure the leader text is set to something appropriate. + SetDefaultLeaderDialogText(); + end + else + --There isn't a valid deal, or we are just viewing a pending deal. + local bIsViewing = (bDealIsPending and ms_OtherPlayerIsHuman); + + local iItemsFromLocal = 0; + local iItemsFromOther = 0; + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + iItemsFromLocal = pDeal:GetItemCount(g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + iItemsFromOther = pDeal:GetItemCount(g_OtherPlayer:GetID(), g_LocalPlayer:GetID()); + end + + Controls.MyDirections:SetHide( bIsViewing or iItemsFromLocal > 0); + Controls.TheirDirections:SetHide( bIsViewing or iItemsFromOther > 0); + Controls.EqualizeDeal:SetHide(true); + Controls.AcceptDeal:SetHide(true); + Controls.DemandDeal:SetHide(true); + + if (not DealIsEmpty() and not bDealValid) then + -- Set have the other leader tell them that the deal has invalid items. + SetLeaderDialog("LOC_DIPLOMACY_DEAL_INVALID", ""); + else + SetDefaultLeaderDialogText(); + end + + Controls.ResumeGame:SetHide(not bIsViewing); + end + + if (bDealIsPending and ms_OtherPlayerIsHuman) then + if (ms_bIsDemand) then + Controls.RefuseDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_CANCEL_DEMAND"); + elseif ms_bIsGift then -- Incoming gift + Controls.RefuseDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_REFUSE_GIFT"); + else + Controls.RefuseDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_CANCEL_DEAL"); + end + else + -- Did the other player start this or the local player? + if (ms_InitiatedByPlayerID == ms_OtherPlayerID) then + if (not bDealValid) then + -- Our changes have made the deal invalid, say cancel instead + Controls.RefuseDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_CANCEL_DEAL"); + else + if (ms_bIsDemand) then + Controls.AcceptDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_ACCEPT_DEMAND"); + Controls.RefuseDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_REFUSE_DEMAND"); + elseif ms_bIsGift then -- Incoming gift + Controls.AcceptDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_ACCEPT_GIFT"); + Controls.RefuseDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_REFUSE_GIFT"); + else + Controls.RefuseDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_REFUSE_DEAL"); + end + end + else + Controls.RefuseDeal:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_EXIT_DEAL"); + end + end + Controls.DealOptionsStack:CalculateSize(); + Controls.DealOptionsStack:ReprocessAnchoring(); + + if (ms_bIsDemand) then + if (ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Demand from the other player and we are responding + Controls.MyOfferBracket:SetHide(false); + Controls.MyOfferLabel:SetHide(false); + Controls.TheirOfferLabel:SetHide(true); + Controls.TheirOfferBracket:SetHide(true); + else + -- Demand from us, to the other player + Controls.MyOfferBracket:SetHide(true); + Controls.MyOfferLabel:SetHide(true); + Controls.TheirOfferLabel:SetHide(false); + Controls.TheirOfferBracket:SetHide(false); + end + else + Controls.MyOfferLabel:SetHide(false); + Controls.MyOfferBracket:SetHide(false); + Controls.TheirOfferLabel:SetHide(false); + Controls.TheirOfferBracket:SetHide(false); + end +end + +-- =========================================================================== +function PopulateAvailableGold(player : table, iconList : table) + + local iAvailableItemCount = 0; + + local eFromPlayerID = player:GetID(); + local eToPlayerID = GetOtherPlayer(player):GetID(); + + local pForDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local possibleResources = DealManager.GetPossibleDealItems(eFromPlayerID, eToPlayerID, DealItemTypes.GOLD, pForDeal); + if (possibleResources ~= nil) then + for i, entry in ipairs(possibleResources) do + if (entry.Duration == 0) then + -- One time gold + local playerTreasury:table = player:GetTreasury(); + local goldBalance :number = math.floor(playerTreasury:GetGoldBalance()); + + if (not ms_bIsDemand) then + -- One time gold + local icon = g_IconOnlyIM:GetInstance(iconList.ListStack); + icon.AmountText:SetText(goldBalance); + icon.SelectButton:SetToolTipString(nil); -- We recycle the entries, so make sure this is clear. + SetIconToSize(icon.Icon, "ICON_YIELD_GOLD_5"); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function() OnClickAvailableOneTimeGold(player, ms_DefaultOneTimeGoldAmount); end ); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function() OnClickAvailableOneTimeGold(player, ms_DefaultOneTimeGoldAmount); end ); + icon.Icon:SetColor(1, 1, 1); + iAvailableItemCount = iAvailableItemCount + 1; + end + else + -- Multi-turn gold + icon = g_IconAndTextIM:GetInstance(iconList.ListStack); + SetIconToSize(icon.Icon, "ICON_YIELD_GOLD_5"); + icon.IconText:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_GOLD_PER_TURN"); + icon.SelectButton:SetToolTipString(nil); -- We recycle the entries, so make sure this is clear. + icon.SelectButton:RegisterCallback( Mouse.eLClick, function() OnClickAvailableMultiTurnGold(player, ms_DefaultMultiTurnGoldAmount, ms_DefaultMultiTurnGoldDuration); end ); + icon.ValueText:SetHide(true); + icon.Icon:SetColor(1, 1, 1); + + iconList.ListStack:CalculateSize(); + iconList.List:ReprocessAnchoring(); + + iAvailableItemCount = iAvailableItemCount + 1; + end + end + end + + return iAvailableItemCount; +end + +-- =========================================================================== +function OnClickAvailableBasic(itemType, player, valueType) + + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Can't modifiy demand that is not ours + return; + end + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + -- Already there? + local pDealItem = pDeal:FindItemByValueType(itemType, DealItemSubTypes.NONE, valueType, player:GetID()); + if (pDealItem == nil) then + -- No + pDealItem = pDeal:AddItemOfType(itemType, player:GetID()); + if (pDealItem ~= nil) then + pDealItem:SetValueType(valueType); + UpdateDealPanel(player); + UpdateProposedWorkingDeal(); + end + end + end +end + +-- =========================================================================== +function OnClickAvailableResource(player, resourceType) + + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Can't modifiy demand that is not ours + return; + end + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + -- Already there? + local dealItems = pDeal:FindItemsByType(DealItemTypes.RESOURCES, DealItemSubTypes.NONE, player:GetID()); + local pDealItem; + if (dealItems ~= nil) then + for i, pDealItem in ipairs(dealItems) do + if pDealItem:GetValueType() == resourceType then + -- Check for non-zero duration. There may already be a one-time transfer of the resource if a city is in the deal. + if (pDealItem:GetDuration() ~= 0) then + return; -- Already in there. + end + end + end + end + + local pPlayerResources = player:GetResources(); + -- Get the total amount of the resource we have. This does not take into account anything already in the deal. + local iAmount = pPlayerResources:GetResourceAmount( resourceType ); + if (iAmount > 0) then + + pDealItem = pDeal:AddItemOfType(DealItemTypes.RESOURCES, player:GetID()); + if (pDealItem ~= nil) then + -- Add one + pDealItem:SetValueType(resourceType); + pDealItem:SetAmount(1); + pDealItem:SetDuration(30); -- Default to this many turns + + -- After we add the item, test to see if the item is valid, it is possible that we have exceeded the amount of resources we can trade. + if not pDealItem:IsValid() then + pDeal:RemoveItemByID(pDealItem:GetID()); + pDealItem = nil; + else + UI.PlaySound("UI_GreatWorks_Put_Down"); + end + + UpdateDealPanel(player); + UpdateProposedWorkingDeal(); + end + end + end +end + +-- =========================================================================== +function OnClickAvailableAgreement(player, agreementType, agreementTurns) + + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Can't modifiy demand that is not ours + return; + end + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + -- Already there? + local pDealItem = pDeal:FindItemByType(DealItemTypes.AGREEMENTS, agreementType, player:GetID()); + if (pDealItem == nil) then + if (agreementType == DealAgreementTypes.JOINT_WAR or + agreementType == DealAgreementTypes.THIRD_PARTY_WAR or + agreementType == DealAgreementTypes.RESEARCH_AGREEMENT ) then + ShowAgreementOptionPopup(agreementType, agreementTurns, player:GetID()); + else + -- No + pDealItem = pDeal:AddItemOfType(DealItemTypes.AGREEMENTS, player:GetID()); + if (pDealItem ~= nil) then + pDealItem:SetSubType(agreementType); + pDealItem:SetDuration(agreementTurns); + + UpdateDealPanel(player); + UpdateProposedWorkingDeal(); + UI.PlaySound("UI_GreatWorks_Put_Down"); + end + end + end + end +end + +-- =========================================================================== +function OnSelectAgreementOption(agreementType, agreementTurns, agreementValue, agreementParameters, fromPlayerId) + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + -- Already there? + local pDealItem = pDeal:FindItemByType(DealItemTypes.AGREEMENTS, agreementType, fromPlayerId); + if (pDealItem ~= nil) then + -- deal manager doesn't update properly unless we delete the deal item + -- and add a new one. + if (not pDealItem:IsLocked()) then + local itemID = pDealItem:GetID(); + DetachValueEdit(itemID); + pDeal:RemoveItemByID(itemID); + pDealItem = pDeal:AddItemOfType(DealItemTypes.AGREEMENTS, fromPlayerId); + end + else + pDealItem = pDeal:AddItemOfType(DealItemTypes.AGREEMENTS, fromPlayerId); + end + + if (pDealItem ~= nil) then + pDealItem:SetSubType(agreementType); + pDealItem:SetDuration(agreementTurns); + pDealItem:SetValueType(agreementValue); + + if (agreementType == DealAgreementTypes.JOINT_WAR or + agreementType == DealAgreementTypes.THIRD_PARTY_WAR) then + pDealItem:SetParameterValue("WarType", agreementParameters.WarType); + end + + UpdateDealPanel(g_LocalPlayer); + UpdateProposedWorkingDeal(); + UI.PlaySound("UI_GreatWorks_Put_Down"); + end + + Controls.ValueEditPopupBackground:SetHide(true); + end +end + +-- =========================================================================== +function ShowAgreementOptionPopup(agreementType, agreementTurns, fromPlayerId) + + -- Hide/show everything for AGREEMENTS options + ms_AgreementOptionIM:ResetInstances(); + Controls.ValueEditIconGrid:SetHide(true); + Controls.ValueAmountEditBoxContainer:SetHide(true); + + -- don't update when backing out of this on a war + if ((agreementType == DealAgreementTypes.JOINT_WAR) or + (agreementType == DealAgreementTypes.THIRD_PARTY_WAR)) then + ms_bDontUpdateOnBack = true; + end + + if agreementType == DealAgreementTypes.RESEARCH_AGREEMENT then + Controls.ValueEditHeaderLabel:SetText(Locale.Lookup("LOC_DIPLOMACY_DEAL_SELECT_TECH")); + elseif agreementType == DealAgreementTypes.ALLIANCE then + Controls.ValueEditHeaderLabel:SetText(Locale.Lookup("LOC_DIPLOMACY_DEAL_SELECT_ALLIANCE")); + else + Controls.ValueEditHeaderLabel:SetText(Locale.Lookup("LOC_DIPLOMACY_DEAL_SELECT_TARGET")); + end + + local toPlayerId = g_LocalPlayer:GetID(); + if (toPlayerId == fromPlayerId ) then + toPlayerId = g_OtherPlayer:GetID(); + end + local pForDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local possibleValues = DealManager.GetPossibleDealItems(fromPlayerId, toPlayerId, DealItemTypes.AGREEMENTS, agreementType, pForDeal); + if (possibleValues ~= nil) then + for i, entry in ipairs(possibleValues) do + local instance:table = ms_AgreementOptionIM:GetInstance(); + + local szDisplayName = ""; + local szItemName = Locale.Lookup(entry.ForTypeDisplayName); + if (entry.SubType == DealAgreementTypes.RESEARCH_AGREEMENT) then + local eTech = GameInfo.Technologies[entry.ForType].Index; + local iTurns = g_LocalPlayer:GetDiplomacy():ComputeResearchAgreementTurns(g_OtherPlayer, eTech); + szDisplayName = Locale.Lookup("LOC_DIPLOMACY_DEAL_PARAMETER_WITH_TURNS", szItemName, iTurns); + instance.AgreementOptionIcon:SetIcon("ICON_" .. entry.ForTypeName); + instance.AgreementOptionIcon:SetHide(false); + else + if (entry.SubType == DealAgreementTypes.JOINT_WAR or + entry.SubType == DealAgreementTypes.THIRD_PARTY_WAR) then + szDisplayName = szItemName; + + -- Have a type of war that describes the joint war? + if entry.Parameters ~= nil then + if entry.Parameters.WarType ~= nil then + local warDef = GameInfo.Wars[entry.Parameters.WarType]; + if warDef ~= nil then + szDisplayName = szDisplayName .. "[newline]" .. Locale.Lookup(warDef.Name); + end + end + end + + instance.AgreementOptionIcon:SetHide(true); + else + szDisplayName = szItemName; + instance.AgreementOptionIcon:SetHide(true); + end + end + + instance.AgreementOptionLabel:SetText(szDisplayName); + + if agreementType == DealAgreementTypes.ALLIANCE then + local allianceLevel:number = g_LocalPlayer:GetDiplomacy():GetAllianceLevel(g_OtherPlayer); + local allianceData:table = GameInfo.Alliances[entry.ForTypeName]; + local tooltip = Game.GetGameDiplomacy():GetAllianceBenefitsString(allianceData.Index, allianceLevel, true); + instance.AgreementOptionButton:SetToolTipString(tooltip); + else + instance.AgreementOptionButton:SetToolTipString(""); + end + + local agreementValueType = entry.ForType; + local agreementParameters = entry.Parameters; + instance.AgreementOptionButton:RegisterCallback(Mouse.eLClick, function() + OnSelectAgreementOption(agreementType, agreementTurns, agreementValueType, agreementParameters, fromPlayerId); + end); + + Controls.ValueEditButton:RegisterCallback( Mouse.eLClick, OnAgreementBackButton ); + end + end + + Controls.ValueEditIconGrid:DoAutoSize(); + + ResizeValueEditScrollPanel(); + + Controls.ValueEditPopup:DoAutoSize(); + Controls.ValueEditPopupBackground:SetHide(false); +end + +-- =========================================================================== +function ResizeValueEditScrollPanel() + -- Resize scroll panel to a maximum height of five agreement options + Controls.ValueEditStack:CalculateSize(); + if Controls.ValueEditStack:GetSizeY() > MAX_DEAL_ITEM_EDIT_HEIGHT then + Controls.ValueEditScrollPanel:SetSizeY(MAX_DEAL_ITEM_EDIT_HEIGHT); + else + Controls.ValueEditScrollPanel:SetSizeY(Controls.ValueEditStack:GetSizeY()); + end + Controls.ValueEditScrollPanel:CalculateSize(); +end + +-- =========================================================================== +function OnAgreementBackButton() + if not ms_bDontUpdateOnBack then + UpdateDealPanel(g_LocalPlayer); + UpdateProposedWorkingDeal(); + end + ms_bDontUpdateOnBack = false; + Controls.ValueEditPopupBackground:SetHide(true); +end + +-- =========================================================================== +function OnClickAvailableGreatWork(player, type) + + OnClickAvailableBasic(DealItemTypes.GREATWORK, player, type); + UI.PlaySound("UI_GreatWorks_Put_Down"); + +end + +-- =========================================================================== +function OnClickAvailableCaptive(player, type) + + OnClickAvailableBasic(DealItemTypes.CAPTIVE, player, type); + UI.PlaySound("UI_GreatWorks_Put_Down"); + +end + +-- =========================================================================== +function OnClickAvailableCity(player, valueType, subType) + + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Can't modifiy demand that is not ours + return; + end + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + -- Already there? + local pDealItem = pDeal:FindItemByValueType(DealItemTypes.CITIES, subType, valueType, player:GetID()); + if (pDealItem == nil) then + -- No + pDealItem = pDeal:AddItemOfType(DealItemTypes.CITIES, player:GetID()); + if (pDealItem ~= nil) then + pDealItem:SetSubType(subType); + pDealItem:SetValueType(valueType); + if (not pDealItem:IsValid(pDeal)) then + pDeal:RemoveItemByID(pDealItem:GetID()); + end + UpdateDealPanel(player); + UpdateProposedWorkingDeal(); + end + end + end + + UI.PlaySound("UI_GreatWorks_Put_Down"); + +end + +-- =========================================================================== +function OnRemoveDealItem(player, itemID) + + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Can't remove it + return; + end + + DetachValueEdit(itemID); + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + local pDealItem = pDeal:FindItemByID(itemID); + if (pDealItem ~= nil) then + if (not pDealItem:IsLocked()) then + if (pDeal:RemoveItemByID(itemID)) then + UpdateDealPanel(player); + UpdateProposedWorkingDeal(); + UI.PlaySound("UI_GreatWorks_Pick_Up"); + end + end + end + end +end + +-- =========================================================================== +function OnSelectValueDealItem(player, itemID, controlInstance) + + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Can't edit it + return; + end + + if (controlInstance ~= nil) then + AttachValueEdit(controlInstance, itemID); + end +end + +-- =========================================================================== +function OnValueEditButton(itemID) + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if pDeal then + local pDealItem = pDeal:FindItemByID(itemID); + if pDealItem then + local newAmount:number = tonumber(Controls.ValueAmountEditBox:GetText()); + newAmount = clip(newAmount, 1, pDealItem:GetMaxAmount()); + + if (newAmount ~= pDealItem:GetAmount()) then + local subtype = pDealItem:GetSubType(); + local duration = pDealItem:GetDuration(); + local valueType = pDealItem:GetValueType(); + local fromPlayerId = pDealItem:GetFromPlayerID(); + local type = pDealItem:GetType(); + if (not pDealItem:IsLocked()) then + DetachValueEdit(itemID); + pDeal:RemoveItemByID(itemID); + pDealItem = pDeal:AddItemOfType(type, fromPlayerId); + pDealItem:SetSubType(subtype); + pDealItem:SetDuration(duration); + pDealItem:SetValueType(valueType); + end + + pDealItem:SetAmount(newAmount); + ms_bForceUpdateOnCommit = true; + UpdateProposedWorkingDeal(); + end + + if g_ValueEditDealItemControlTable then + g_ValueEditDealItemControlTable.AmountText:SetText(newAmount); + g_ValueEditDealItemControlTable.AmountText:SetHide(false); + end + UpdateDealStatus(); + end + end + + Controls.ValueEditPopupBackground:SetHide(true); +end + +-- =========================================================================== +function PopulateAvailableResources(player : table, iconList : table, className : string) + + local iAvailableItemCount = 0; + local pForDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local possibleResources = DealManager.GetPossibleDealItems(player:GetID(), GetOtherPlayer(player):GetID(), DealItemTypes.RESOURCES, pForDeal); + if (possibleResources ~= nil) then + for i, entry in ipairs(possibleResources) do + + local resourceDesc = GameInfo.Resources[entry.ForType]; + if (resourceDesc ~= nil) then + -- Do we have some and is it a luxury item? + if (entry.MaxAmount > 0 and resourceDesc.ResourceClassType == className ) then + local icon = g_IconOnlyIM:GetInstance(iconList.ListStack); + SetIconToSize(icon.Icon, "ICON_" .. resourceDesc.ResourceType); + icon.AmountText:SetText(tostring(entry.MaxAmount)); + icon.AmountText:SetHide(false); + + local resourceType = entry.ForType; + -- What to do when double clicked/tapped. + icon.SelectButton:RegisterCallback( Mouse.eLClick, function() OnClickAvailableResource(player, resourceType); end ); + -- Set a tool tip + if entry.IsValid then + icon.SelectButton:LocalizeAndSetToolTip(resourceDesc.Name); + icon.SelectButton:SetDisabled(false); + icon.Icon:SetColor(1, 1, 1); + else + local tempstr = Locale.Lookup(resourceDesc.Name).."[NEWLINE][COLOR_RED]"; + if player ~= g_LocalPlayer then + tempstr = tempstr .. Locale.Lookup("LOC_DEAL_PLAYER_HAS_NO_CAP_ROOM"); + icon.SelectButton:SetToolTipString(tempstr); + else + tempstr = tempstr .. Locale.Lookup("LOC_DEAL_AI_HAS_NO_CAP_ROOM"); + icon.SelectButton:SetToolTipString(tempstr); + end + icon.SelectButton:SetDisabled(true); + icon.Icon:SetColor(0.5, 0.5, 0.5); + end + icon.SelectButton:ReprocessAnchoring(); + + iAvailableItemCount = iAvailableItemCount + 1; + end + end + end + + iconList.ListStack:CalculateSize(); + iconList.List:ReprocessAnchoring(); + end + + -- Hide if empty + iconList.GetTopControl():SetHide( iconList.ListStack:GetSizeX()==0 ); + + return iAvailableItemCount; +end + +-- =========================================================================== +function PopulateAvailableLuxuryResources(player : table, iconList : table) + + local iAvailableItemCount = 0; + iAvailableItemCount = iAvailableItemCount + PopulateAvailableResources(player, iconList, "RESOURCECLASS_LUXURY"); + return iAvailableItemCount; +end + +-- =========================================================================== +function PopulateAvailableStrategicResources(player : table, iconList : table) + + local iAvailableItemCount = 0; + iAvailableItemCount = iAvailableItemCount + PopulateAvailableResources(player, iconList, "RESOURCECLASS_STRATEGIC"); + return iAvailableItemCount; +end + +-- =========================================================================== +function PopulateAvailableAgreements(player : table, iconList : table) + + local iAvailableItemCount = 0; + local pForDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local possibleAgreements = DealManager.GetPossibleDealItems(player:GetID(), GetOtherPlayer(player):GetID(), DealItemTypes.AGREEMENTS, pForDeal); + if (possibleAgreements ~= nil) then + for i, entry in ipairs(possibleAgreements) do + local agreementType = entry.SubType; + + local agreementDuration = entry.Duration; + local icon = g_IconAndTextIM:GetInstance(iconList.ListStack); + + local info: table = GameInfo.DiplomaticActions[ agreementType ]; + if (info ~= nil) then + SetIconToSize(icon.Icon, "ICON_".. info.DiplomaticActionType, 38); + end + icon.AmountText:SetHide(true); + icon.IconText:LocalizeAndSetText(entry.SubTypeName); + icon.SelectButton:SetDisabled( not entry.IsValid and entry.ValidationResult ~= DealValidationResult.MISSING_DEPENDENCY ); -- Hide if invalid, unless it is just missing a dependency, the user will update that when it is added to the deal. + icon.ValueText:SetHide(true); + icon.Icon:SetColor(1, 1, 1); + + -- What to do when double clicked/tapped. + icon.SelectButton:RegisterCallback( Mouse.eLClick, function() OnClickAvailableAgreement(player, agreementType, agreementDuration); end ); + -- Set a tool tip if their is a duration + if (entry.Duration > 0) then + local szTooltip = Locale.Lookup("LOC_DIPLOMACY_DEAL_PARAMETER_WITH_TURNS", entry.SubTypeName, entry.Duration); + icon.SelectButton:SetToolTipString(szTooltip); + else + icon.SelectButton:SetToolTipString(nil); + end + + -- icon.SelectButton:LocalizeAndSetToolTip( ); + icon.SelectButton:ReprocessAnchoring(); + + iAvailableItemCount = iAvailableItemCount + 1; + end + + iconList.ListStack:CalculateSize(); + iconList.List:ReprocessAnchoring(); + end + + -- Hide if empty + iconList.GetTopControl():SetHide( iconList.ListStack:GetSizeX()==0 ); + + return iAvailableItemCount; +end + +-- =========================================================================== +function MakeCityToolTip(player : table, cityID : number) + local pCity = player:GetCities():FindID( cityID ); + if (pCity ~= nil) then + local szToolTip = Locale.Lookup("LOC_DEAL_CITY_POPULATION_TOOLTIP", pCity:GetPopulation()); + local districtNames = {}; + local pCityDistricts = pCity:GetDistricts(); + if (pCityDistricts ~= nil) then + + for i, pDistrict in pCityDistricts:Members() do + local pDistrictDef = GameInfo.Districts[ pDistrict:GetType() ]; + if (pDistrictDef ~= nil) then + local districtType:string = pDistrictDef.DistrictType; + -- Skip the city center and any wonder districts + if (districtType ~= "DISTRICT_CITY_CENTER" and districtType ~= "DISTRICT_WONDER") then + table.insert(districtNames, pDistrictDef.Name); + end + end + end + end + + if (#districtNames > 0) then + szToolTip = szToolTip .. "[NEWLINE]" .. Locale.Lookup("LOC_DEAL_CITY_DISTRICTS_TOOLTIP"); + for i, name in ipairs(districtNames) do + szToolTip = szToolTip .. "[NEWLINE]" .. Locale.Lookup(name); + end + end + + -- Add Resources + local extractedResources = player:GetResources():GetResourcesExtractedByCity( cityID, ResultFormat.SUMMARY ); + if extractedResources ~= nil and #extractedResources > 0 then + szToolTip = szToolTip .. "[NEWLINE]" .. Locale.Lookup("LOC_DEAL_CITY_RESOURCES_TOOLTIP"); + for i, entry in ipairs(extractedResources) do + local resourceDesc = GameInfo.Resources[entry.ResourceType]; + if resourceDesc ~= nil then + szToolTip = szToolTip .. "[NEWLINE]" .. Locale.Lookup(resourceDesc.Name) .. " : " .. tostring(entry.Amount); + end + end + end + + -- Add Great Works + local cityGreatWorks = player:GetCulture():GetGreatWorksInCity( cityID ); + if cityGreatWorks ~= nil and #cityGreatWorks > 0 then + szToolTip = szToolTip .. "[NEWLINE]" .. Locale.Lookup("LOC_DEAL_CITY_GREAT_WORKS_TOOLTIP"); + for i, entry in ipairs(cityGreatWorks) do + local greatWorksDesc = GameInfo.GreatWorks[entry.GreatWorksType]; + if greatWorksDesc ~= nil then + szToolTip = szToolTip .. "[NEWLINE]" .. Locale.Lookup(greatWorksDesc.Name); + end + end + end + + return szToolTip; + end + + return ""; +end + +-- =========================================================================== +function PopulateAvailableCities(player : table, iconList : table) + + local iAvailableItemCount = 0; + local pForDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local possibleItems = DealManager.GetPossibleDealItems(player:GetID(), GetOtherPlayer(player):GetID(), DealItemTypes.CITIES, pForDeal); + if (possibleItems ~= nil) then + for i, entry in ipairs(possibleItems) do + + local type = entry.ForType; + local subType = entry.SubType; + local icon = g_IconAndTextIM:GetInstance(iconList.ListStack); + SetIconToSize(icon.Icon, "ICON_BUILDINGS", 45); + icon.AmountText:SetHide(true); + icon.IconText:LocalizeAndSetText(entry.ForTypeName); + icon.SelectButton:SetDisabled( not entry.IsValid and entry.ValidationResult ~= DealValidationResult.MISSING_DEPENDENCY ); -- Hide if invalid, unless it is just missing a dependency, the user will update that when it is added to the deal. + icon.ValueText:SetHide(true); + icon.Icon:SetColor(1, 1, 1); + + -- What to do when double clicked/tapped. + icon.SelectButton:RegisterCallback( Mouse.eLClick, function() OnClickAvailableCity(player, type, subType); end ); + + -- Since we're ceding this city make sure to look for this city in the current owners city list + if entry.SubType == 1 then -- CitySubTypes:CEDE_OCCUPIED + icon.SelectButton:SetToolTipString( MakeCityToolTip(GetOtherPlayer(player), type) ); + else + icon.SelectButton:SetToolTipString( MakeCityToolTip(player, type) ); + end + + iAvailableItemCount = iAvailableItemCount + 1; + end + + iconList.ListStack:CalculateSize(); + end + + -- Hide if empty + iconList.GetTopControl():SetHide( iconList.ListStack:GetSizeX()==0 ); + + return iAvailableItemCount; +end + +-- =========================================================================== +function PopulateAvailableOtherPlayers(player : table, iconList : table) + + local iAvailableItemCount = 0; + -- Hide if empty + iconList.GetTopControl():SetHide( iconList.ListStack:GetSizeX()==0 ); + + return iAvailableItemCount; +end + +-- =========================================================================== +function PopulateAvailableGreatWorks(player : table, iconList : table) + + local iAvailableItemCount = 0; + local pForDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local possibleItems = DealManager.GetPossibleDealItems(player:GetID(), GetOtherPlayer(player):GetID(), DealItemTypes.GREATWORK, pForDeal); + if (possibleItems ~= nil) then + for i, entry in ipairs(possibleItems) do + local greatWorkDesc = GameInfo.GreatWorks[entry.ForTypeDescriptionID]; + if (greatWorkDesc ~= nil) then + local type = entry.ForType; + local icon = g_IconAndTextIM:GetInstance(iconList.ListStack); + SetIconToSize(icon.Icon, "ICON_" .. greatWorkDesc.GreatWorkType, 45); + icon.AmountText:SetHide(true); + icon.IconText:LocalizeAndSetText(entry.ForTypeName); + icon.SelectButton:SetDisabled( not entry.IsValid and entry.ValidationResult ~= DealValidationResult.MISSING_DEPENDENCY ); -- Hide if invalid, unless it is just missing a dependency, the user will update that when it is added to the deal. + icon.ValueText:SetHide(true); + icon.Icon:SetColor(1, 1, 1); + + -- What to do when double clicked/tapped. + icon.SelectButton:RegisterCallback( Mouse.eLClick, function() OnClickAvailableGreatWork(player, type); end ); + -- Set a tool tip + + local strGreatWorkTooltip = GreatWorksSupport_GetBasicTooltip(entry.ForType, false); + icon.SelectButton:SetToolTipString(strGreatWorkTooltip); + icon.SelectButton:ReprocessAnchoring(); + + iAvailableItemCount = iAvailableItemCount + 1; + end + end + + iconList.ListStack:CalculateSize(); + iconList.List:ReprocessAnchoring(); + end + + -- Hide if empty + iconList.GetTopControl():SetHide( iconList.ListStack:GetSizeX()==0 ); + + return iAvailableItemCount; + +end + +-- =========================================================================== +function PopulateAvailableCaptives(player : table, iconList : table) + + local iAvailableItemCount = 0; + + local pForDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local possibleItems = DealManager.GetPossibleDealItems(player:GetID(), GetOtherPlayer(player):GetID(), DealItemTypes.CAPTIVE, pForDeal); + if (possibleItems ~= nil) then + for i, entry in ipairs(possibleItems) do + + local type = entry.ForType; + local icon = g_IconAndTextIM:GetInstance(iconList.ListStack); + SetIconToSize(icon.Icon, "ICON_UNIT_SPY"); + icon.AmountText:SetHide(true); + if (entry.ForTypeName ~= nil ) then + icon.IconText:LocalizeAndSetText(entry.ForTypeName); + end + icon.SelectButton:SetDisabled( not entry.IsValid and entry.ValidationResult ~= DealValidationResult.MISSING_DEPENDENCY ); -- Hide if invalid, unless it is just missing a dependency, the user will update that when it is added to the deal. + icon.ValueText:SetHide(true); + icon.Icon:SetColor(1, 1, 1); + + -- What to do when double clicked/tapped. + icon.SelectButton:RegisterCallback( Mouse.eLClick, function() OnClickAvailableCaptive(player, type); end ); + icon.SelectButton:SetToolTipString(nil); -- We recycle the entries, so make sure this is clear. + icon.SelectButton:ReprocessAnchoring(); + + iAvailableItemCount = iAvailableItemCount + 1; + end + + iconList.ListStack:CalculateSize(); + iconList.List:ReprocessAnchoring(); + end + + -- Hide if empty + iconList.GetTopControl():SetHide( iconList.ListStack:GetSizeX()==0 ); + + return iAvailableItemCount; +end + +-- =========================================================================== +function PopulatePlayerAvailablePanel(rootControl : table, player : table) + + local iAvailableItemCount = 0; + + if (player ~= nil) then + + local playerType = GetPlayerType(player); + if (ms_bIsDemand and player:GetID() == ms_InitiatedByPlayerID) then + -- This is a demand, so hide all the demanding player's items + for i = 1, table.count(AvailableDealItemGroupTypes), 1 do + g_AvailableGroups[i][playerType].GetTopControl():SetHide(true); + end + else + g_AvailableGroups[AvailableDealItemGroupTypes.GOLD][playerType].GetTopControl():SetHide(false); + + iAvailableItemCount = iAvailableItemCount + PopulateAvailableGold(player, g_AvailableGroups[AvailableDealItemGroupTypes.GOLD][playerType]); + iAvailableItemCount = iAvailableItemCount + PopulateAvailableLuxuryResources(player, g_AvailableGroups[AvailableDealItemGroupTypes.LUXURY_RESOURCES][playerType]); + iAvailableItemCount = iAvailableItemCount + PopulateAvailableStrategicResources(player, g_AvailableGroups[AvailableDealItemGroupTypes.STRATEGIC_RESOURCES][playerType]); + + if (not ms_bIsDemand) then + iAvailableItemCount = iAvailableItemCount + PopulateAvailableAgreements(player, g_AvailableGroups[AvailableDealItemGroupTypes.AGREEMENTS][playerType]); + else + g_AvailableGroups[AvailableDealItemGroupTypes.AGREEMENTS][playerType].GetTopControl():SetHide(true); + end + + iAvailableItemCount = iAvailableItemCount + PopulateAvailableCities(player, g_AvailableGroups[AvailableDealItemGroupTypes.CITIES][playerType]); + + if (not ms_bIsDemand) then + iAvailableItemCount = iAvailableItemCount + PopulateAvailableOtherPlayers(player, g_AvailableGroups[AvailableDealItemGroupTypes.OTHER_PLAYERS][playerType]); + else + g_AvailableGroups[AvailableDealItemGroupTypes.OTHER_PLAYERS][playerType].GetTopControl():SetHide(false); + end + + iAvailableItemCount = iAvailableItemCount + PopulateAvailableGreatWorks(player, g_AvailableGroups[AvailableDealItemGroupTypes.GREAT_WORKS][playerType]); + iAvailableItemCount = iAvailableItemCount + PopulateAvailableCaptives(player, g_AvailableGroups[AvailableDealItemGroupTypes.CAPTIVES][playerType]); + + end + + rootControl:CalculateSize(); + rootControl:ReprocessAnchoring(); + + end + + return iAvailableItemCount; +end + +-- =========================================================================== +function PopulateDealBasic(player : table, iconList : table, populateType : number, iconName : string) + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local playerType = GetPlayerType(player); + if (pDeal ~= nil) then + + local pDealItem; + for pDealItem in pDeal:Items() do + local type = pDealItem:GetType(); + if (pDealItem:GetFromPlayerID() == player:GetID()) then + local iDuration = pDealItem:GetDuration(); + local dealItemID = pDealItem:GetID(); + + if (type == populateType) then + local icon = g_IconAndTextIM:GetInstance(iconList); + SetIconToSize(icon.Icon, iconName); + icon.AmountText:SetHide(true); + local typeName = pDealItem:GetValueTypeNameID(); + if (typeName ~= nil) then + icon.IconText:LocalizeAndSetText(typeName); + end + + -- Show/hide unacceptable item notification + icon.UnacceptableIcon:SetHide(not pDealItem:IsUnacceptable()); + + icon.SelectButton:RegisterCallback(Mouse.eRClick, function(void1, void2, self) OnRemoveDealItem(player, dealItemID, self); end); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function(void1, void2, self) OnSelectValueDealItem(player, dealItemID, self); end ); + + icon.SelectButton:SetToolTipString(nil); -- We recycle the entries, so make sure this is clear. + icon.SelectButton:SetDisabled(false); + icon.Icon:SetColor(1, 1, 1); + end + end + end + + iconList:CalculateSize(); + iconList:ReprocessAnchoring(); + + end + +end + +-- =========================================================================== +function GetParentItemTransferToolTip(parentDealItem) + local szToolTip = ""; + + -- If it is from a city, put the city name in the tool tip. + if (parentDealItem:GetType() == DealItemTypes.CITIES) then + + local cityTypeName = parentDealItem:GetValueTypeNameID(); + if (cityTypeName ~= nil) then + local cityName = Locale.Lookup(cityTypeName); + local szTransfer = Locale.Lookup("LOC_DEAL_ITEM_TRANSFERRED_WITH_CITY_TOOLTIP", cityName); + + szToolTip = "[NEWLINE]" .. szTransfer; + end + end + + return szToolTip; +end +-- =========================================================================== +function PopulateDealResources(player : table, iconList : table) + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local playerType = GetPlayerType(player); + if (pDeal ~= nil) then + g_IconOnlyIM:ReleaseInstanceByParent(iconList); + g_IconAndTextIM:ReleaseInstanceByParent(iconList); + + local pDealItem; + for pDealItem in pDeal:Items() do + + local type = pDealItem:GetType(); + if (pDealItem:GetFromPlayerID() == player:GetID()) then + local iDuration = pDealItem:GetDuration(); + local dealItemID = pDealItem:GetID(); + -- Gold? + if (type == DealItemTypes.GOLD) then + local icon; + if (iDuration == 0) then + -- One time + icon = g_IconOnlyIM:GetInstance(iconList); + else + -- Multi-turn + icon = g_IconAndTextIM:GetInstance(iconList); + icon.IconText:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_FOR_TURNS", iDuration); + icon.ValueText:SetHide(true); + end + SetIconToSize(icon.Icon, "ICON_YIELD_GOLD_5"); + icon.AmountText:SetText(tostring(pDealItem:GetAmount())); + icon.AmountText:SetHide(false); + + -- Show/hide unacceptable item notification + icon.UnacceptableIcon:SetHide(not pDealItem:IsUnacceptable()); + + icon.SelectButton:RegisterCallback(Mouse.eRClick, function(void1, void2, self) OnRemoveDealItem(player, dealItemID, self); end); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function(void1, void2, self) OnSelectValueDealItem(player, dealItemID, self); end ); + icon.SelectButton:SetToolTipString(nil); -- We recycle the entries, so make sure this is clear. + icon.SelectButton:SetDisabled(false); + icon.Icon:SetColor(1, 1, 1); + if (dealItemID == g_ValueEditDealItemID) then + g_ValueEditDealItemControlTable = icon; + end + else + if (type == DealItemTypes.RESOURCES) then + + local resourceType = pDealItem:GetValueType(); + local icon; + if (iDuration == 0) then + -- One time + icon = g_IconOnlyIM:GetInstance(iconList); + else + -- Multi-turn + icon = g_IconAndTextIM:GetInstance(iconList); + icon.IconText:LocalizeAndSetText("LOC_DIPLOMACY_DEAL_FOR_TURNS", iDuration); + icon.ValueText:SetHide(true); + end + local resourceDesc = GameInfo.Resources[resourceType]; + SetIconToSize(icon.Icon, "ICON_" .. resourceDesc.ResourceType); + icon.AmountText:SetText(tostring(pDealItem:GetAmount())); + icon.AmountText:SetHide(false); + + -- Show/hide unacceptable item notification + icon.UnacceptableIcon:SetHide(not pDealItem:IsUnacceptable()); + + local szToolTip = Locale.Lookup(resourceDesc.Name); + + local parentDealItem = pDeal:GetItemParent(pDealItem); + + if parentDealItem == nil then + -- No parent, the user can click on the item to change it. + icon.SelectButton:RegisterCallback(Mouse.eRClick, function(void1, void2, self) OnRemoveDealItem(player, dealItemID, self); end); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function(void1, void2, self) OnSelectValueDealItem(player, dealItemID, self); end ); + icon.SelectButton:SetDisabled(false); + icon.Icon:SetColor(1, 1, 1); + else + icon.SelectButton:ClearCallback( Mouse.eRClick ); -- Clear, we are re-using control instances + icon.SelectButton:ClearCallback( Mouse.eLClick ); + + szToolTip = szToolTip .. GetParentItemTransferToolTip(parentDealItem); + end + + -- Set a tool tip + icon.SelectButton:SetToolTipString(szToolTip); + + -- KWG: Make a way for the icon manager to have categories, so the API is like this + -- icon.Icon:SetTexture(IconManager:FindIconAtlasForType(IconTypes.RESOURCE, resourceType)); + + if (dealItemID == g_ValueEditDealItemID) then + g_ValueEditDealItemControlTable = icon; + end + end --end else if the item isn't gold + end -- end for each item in dael + end -- end if deal + end + + iconList:CalculateSize(); + iconList:ReprocessAnchoring(); + + end + +end + +-- =========================================================================== +function PopulateDealAgreements(player : table, iconList : table) + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local playerType = GetPlayerType(player); + if (pDeal ~= nil) then + + local pDealItem; + for pDealItem in pDeal:Items() do + + local type = pDealItem:GetType(); + if (pDealItem:GetFromPlayerID() == player:GetID()) then + local dealItemID = pDealItem:GetID(); + -- Agreement? + if (type == DealItemTypes.AGREEMENTS) then + local icon = g_IconAndTextIM:GetInstance(iconList); + local info: table = GameInfo.DiplomaticActions[ pDealItem:GetSubType() ]; + if (info ~= nil) then + SetIconToSize(icon.Icon, "ICON_".. info.DiplomaticActionType, 38); + end + + icon.AmountText:SetHide(true); + local subTypeDisplayName = pDealItem:GetSubTypeNameID(); + if (subTypeDisplayName ~= nil) then + icon.IconText:LocalizeAndSetText(subTypeDisplayName); + end + icon.SelectButton:SetToolTipString(nil); -- We recycle the entries, so make sure this is clear. + + -- Show/hide unacceptable item notification + icon.UnacceptableIcon:SetHide(not pDealItem:IsUnacceptable()); + + -- Populate the value pulldown + SetValueText(icon, pDealItem); + + icon.SelectButton:RegisterCallback(Mouse.eRClick, function(void1, void2, self) OnRemoveDealItem(player, dealItemID, self); end); + + if(info.DiplomaticActionType == "DIPLOACTION_JOINT_WAR" and pDealItem:GetFromPlayerID() == g_OtherPlayer:GetID()) then + icon.SelectButton:SetDisabled(true); + icon.SelectButton:SetToolTipString(Locale.Lookup("LOC_JOINT_WAR_CANNOT_EDIT_THEIRS_TOOLTIP")); + else + icon.SelectButton:SetDisabled(false); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function(void1, void2, self) OnSelectValueDealItem(player, dealItemID, self); end ); + icon.Icon:SetColor(1, 1, 1); + end + end + end + end + + iconList:CalculateSize(); + iconList:ReprocessAnchoring(); + + end + +end + +-- =========================================================================== +function PopulateDealGreatWorks(player : table, iconList : table) + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local playerType = GetPlayerType(player); + if (pDeal ~= nil) then + + local pDealItem; + for pDealItem in pDeal:Items() do + + local type = pDealItem:GetType(); + if (pDealItem:GetFromPlayerID() == player:GetID()) then + local iDuration = pDealItem:GetDuration(); + local dealItemID = pDealItem:GetID(); + + if (type == DealItemTypes.GREATWORK) then + local icon = g_IconAndTextIM:GetInstance(iconList); + + local typeID = pDealItem:GetValueTypeID(); + SetIconToSize(icon.Icon, "ICON_" .. typeID, 45); + icon.AmountText:SetHide(true); + + local typeName = pDealItem:GetValueTypeNameID(); + + local strTooltip :string = ""; + + if (typeName ~= nil) then + icon.IconText:LocalizeAndSetText(typeName); + strTooltip = Locale.Lookup( GreatWorksSupport_GetBasicTooltip(pDealItem:GetValueType(), false) ); + else + icon.IconText:SetText(nil); + end + + icon.ValueText:SetHide(true); + + -- Show/hide unacceptable item notification + icon.UnacceptableIcon:SetHide(not pDealItem:IsUnacceptable()); + + local parentDealItem = pDeal:GetItemParent(pDealItem); + + if parentDealItem == nil then + -- No parent, we can remove independently + icon.SelectButton:RegisterCallback(Mouse.eRClick, function(void1, void2, self) OnRemoveDealItem(player, dealItemID, self); end); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function(void1, void2, self) OnSelectValueDealItem(player, dealItemID, self); end ); + icon.SelectButton:SetDisabled(false); + icon.Icon:SetColor(1, 1, 1); + else + icon.SelectButton:ClearCallback( Mouse.eRClick ); + icon.SelectButton:ClearCallback( Mouse.eLClick ); + -- Add on to the tool tip to show why it is there. + strTooltip = strTooltip .. GetParentItemTransferToolTip(parentDealItem); + end + + icon.SelectButton:SetToolTipString(strTooltip); + end + end + end + + iconList:CalculateSize(); + iconList:ReprocessAnchoring(); + + end + +end + +-- =========================================================================== +function PopulateDealCaptives(player : table, iconList : table) + + PopulateDealBasic(player, iconList, DealItemTypes.CAPTIVE, "ICON_UNIT_SPY"); + +end + +-- =========================================================================== +function PopulateDealCities(player : table, iconList : table) + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local playerType = GetPlayerType(player); + if (pDeal ~= nil) then + + local pDealItem; + for pDealItem in pDeal:Items() do + + local type = pDealItem:GetType(); + if (pDealItem:GetFromPlayerID() == player:GetID()) then + local dealItemID = pDealItem:GetID(); + + if (type == DealItemTypes.CITIES) then + local icon = g_IconAndTextIM:GetInstance(iconList); + SetIconToSize(icon.Icon, "ICON_BUILDINGS"); + icon.AmountText:SetHide(true); + local typeName = pDealItem:GetValueTypeNameID(); + if (typeName ~= nil) then + icon.IconText:LocalizeAndSetText(typeName); + end + + -- Show/hide unacceptable item notification + icon.UnacceptableIcon:SetHide(not pDealItem:IsUnacceptable()); + + icon.SelectButton:RegisterCallback(Mouse.eRClick, function(void1, void2, self) OnRemoveDealItem(player, dealItemID, self); end); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function(void1, void2, self) OnSelectValueDealItem(player, dealItemID, self); end ); + icon.SelectButton:SetDisabled(false); + icon.Icon:SetColor(1, 1, 1); + + icon.SelectButton:SetToolTipString( MakeCityToolTip(player, pDealItem:GetValueType() ) ); + end + end + end + + iconList:CalculateSize(); + iconList:ReprocessAnchoring(); + + end + + +end + +-- =========================================================================== +function PopulatePlayerDealPanel(rootControl : table, player : table) + + if (player ~= nil) then + + local playerType = GetPlayerType(player); + PopulateDealResources(player, ms_DealGroups[DealItemGroupTypes.RESOURCES][playerType]); + PopulateDealAgreements(player, ms_DealGroups[DealItemGroupTypes.AGREEMENTS][playerType]); + PopulateDealCaptives(player, ms_DealGroups[DealItemGroupTypes.CAPTIVES][playerType]); + PopulateDealGreatWorks(player, ms_DealGroups[DealItemGroupTypes.GREAT_WORKS][playerType]); + PopulateDealCities(player, ms_DealGroups[DealItemGroupTypes.CITIES][playerType]); + + rootControl:CalculateSize(); + rootControl:ReprocessAnchoring(); + end +end + +-- =========================================================================== +function HandleESC() + -- Were we just viewing the deal? + if ( m_kPopupDialog:IsOpen()) then + m_kPopupDialog:Close(); + elseif (not Controls.ResumeGame:IsHidden()) then + OnResumeGame(); + else + OnRefuseDeal(); + end +end + +-- =========================================================================== +-- INPUT Handlings +-- If this context is visible, it will get a crack at the input. +-- =========================================================================== +function KeyHandler( key:number ) + if (key == Keys.VK_ESCAPE) then + HandleESC(); + return true; + end + + return false; +end + +-- =========================================================================== +function InputHandler( pInputStruct:table ) + local uiMsg = pInputStruct:GetMessageType(); + if uiMsg == KeyEvents.KeyUp then + return KeyHandler( pInputStruct:GetKey() ); + end + if (uiMsg == MouseEvents.LButtonUp or + uiMsg == MouseEvents.RButtonUp or + uiMsg == MouseEvents.MButtonUp or + uiMsg == MouseEvents.PointerUp) then + ClearValueEdit(); + end + + return false; +end + +-- =========================================================================== +-- Handle a request to be shown, this should only be called by +-- the diplomacy statement handler. +-- =========================================================================== + +function OnShowMakeDeal(otherPlayerID) + ms_OtherPlayerID = otherPlayerID; + ms_bIsDemand = false; + ContextPtr:SetHide( false ); +end +LuaEvents.DiploPopup_ShowMakeDeal.Add(OnShowMakeDeal); + +-- =========================================================================== +-- Handle a request to be shown, this should only be called by +-- the diplomacy statement handler. +-- =========================================================================== + +function OnShowMakeDemand(otherPlayerID) + ms_OtherPlayerID = otherPlayerID; + ms_bIsDemand = true; + ContextPtr:SetHide( false ); +end +LuaEvents.DiploPopup_ShowMakeDemand.Add(OnShowMakeDemand); + +-- =========================================================================== +-- Handle a request to be hidden, this should only be called by +-- the diplomacy statement handler. +-- =========================================================================== + +function OnHideDeal(otherPlayerID) + OnContinue(); +end +LuaEvents.DiploPopup_HideDeal.Add(OnHideDeal); + +-- =========================================================================== +-- The other player has updated the deal +function OnDiplomacyIncomingDeal(eFromPlayer, eToPlayer, eAction) + if (eFromPlayer == ms_OtherPlayerID) then + local pDeal = DealManager.GetWorkingDeal(DealDirection.INCOMING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + ms_bIsGift = pDeal:IsGift(); + + -- Copy the deal to our OUTGOING deal back to the other player, in case we want to make modifications + DealManager.CopyIncomingToOutgoingWorkingDeal(g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + ms_LastIncomingDealProposalAction = eAction; + + PopulatePlayerDealPanel(Controls.TheirOfferStack, g_OtherPlayer); + PopulatePlayerDealPanel(Controls.MyOfferStack, g_LocalPlayer); + UpdateDealStatus(); + end + end +end +Events.DiplomacyIncomingDeal.Add(OnDiplomacyIncomingDeal); + +-- =========================================================================== +-- Handle a deal changing, usually from an incoming statement. +-- =========================================================================== + +function OnDealUpdated(otherPlayerID, eAction, szText) + if (not ContextPtr:IsHidden()) then + -- Display some updated text. + if (szText ~= nil and szText ~= "") then + SetLeaderDialog(szText, ""); + end + -- Update deal and possible override text from szText + OnDiplomacyIncomingDeal( otherPlayerID, Game.GetLocalPlayer(), eAction); + end +end +LuaEvents.DiploPopup_DealUpdated.Add(OnDealUpdated); + +-- =========================================================================== +function SetLeaderDialog(leaderDialog:string, leaderEffect:string) + -- Update dialog + Controls.LeaderDialog:LocalizeAndSetText(leaderDialog); + + -- Add parentheses to the effect text unless the text is "" + if leaderEffect ~= "" then + leaderEffect = "(" .. Locale.Lookup(leaderEffect) .. ")"; + end + Controls.LeaderEffect:SetText(leaderEffect); + + -- Recenter text + Controls.LeaderDialogStack:CalculateSize(); + Controls.LeaderDialogStack:ReprocessAnchoring(); +end + +-- =========================================================================== +function StartExitAnimation() + -- Start the exit animation, it will call OnContinue when complete + ms_bExiting = true; + Controls.YieldSlide:Reverse(); + Controls.YieldAlpha:Reverse(); + Controls.TradePanelFade:Reverse(); + Controls.TradePanelSlide:Reverse(); + Controls.TradePanelFade:SetSpeed(5); + Controls.TradePanelSlide:SetSpeed(5); + UI.PlaySound("UI_Diplomacy_Menu_Change"); +end + +-- =========================================================================== +function OnContinue() + ContextPtr:SetHide( true ); +end + +-- =========================================================================== +-- Functions for setting the data in the yield area +-- =========================================================================== + +function FormatValuePerTurn( value:number ) + return Locale.ToNumber(value, "+#,###.#;-#,###.#"); +end + +function RefreshYields() + + local ePlayer :number = Game.GetLocalPlayer(); + local localPlayer :table= nil; + if ePlayer ~= -1 then + localPlayer = Players[ePlayer]; + if localPlayer == nil then + return; + end + else + return; + end + + ---- SCIENCE ---- + local playerTechnology :table = localPlayer:GetTechs(); + local currentScienceYield :number = playerTechnology:GetScienceYield(); + Controls.SciencePerTurn:SetText( FormatValuePerTurn(currentScienceYield) ); + Controls.ScienceBacking:SetToolTipString( GetScienceTooltip() ); + Controls.ScienceStack:CalculateSize(); + + ---- CULTURE---- + local playerCulture :table = localPlayer:GetCulture(); + local currentCultureYield :number = playerCulture:GetCultureYield(); + Controls.CulturePerTurn:SetText( FormatValuePerTurn(currentCultureYield) ); + Controls.CultureBacking:SetToolTipString( GetCultureTooltip() ); + Controls.CultureStack:CalculateSize(); + + ---- GOLD ---- + local playerTreasury:table = localPlayer:GetTreasury(); + local goldYield :number = playerTreasury:GetGoldYield() - playerTreasury:GetTotalMaintenance(); + local goldBalance :number = math.floor(playerTreasury:GetGoldBalance()); + Controls.GoldBalance:SetText( Locale.ToNumber(goldBalance, "#,###.#")); + Controls.GoldPerTurn:SetText( FormatValuePerTurn(goldYield) ); + Controls.GoldBacking:SetToolTipString(GetGoldTooltip()); + Controls.GoldStack:CalculateSize(); + + ---- FAITH ---- + local playerReligion :table = localPlayer:GetReligion(); + local faithYield :number = playerReligion:GetFaithYield(); + local faithBalance :number = playerReligion:GetFaithBalance(); + Controls.FaithBalance:SetText( Locale.ToNumber(faithBalance, "#,###.#")); + Controls.FaithPerTurn:SetText( FormatValuePerTurn(faithYield) ); + Controls.FaithBacking:SetToolTipString( GetFaithTooltip() ); + Controls.FaithStack:CalculateSize(); + if (faithYield == 0) then + Controls.FaithBacking:SetHide(true); + else + Controls.FaithBacking:SetHide(false); + end + + Controls.YieldStack:CalculateSize(); + Controls.YieldStack:ReprocessAnchoring(); +end +-- =========================================================================== + +-- =========================================================================== +function OnShow() + RefreshYields(); + Controls.YieldAlpha:SetToBeginning(); + Controls.YieldAlpha:Play(); + Controls.YieldSlide:SetToBeginning(); + Controls.YieldSlide:Play(); + Controls.TradePanelFade:SetToBeginning(); + Controls.TradePanelFade:Play(); + Controls.TradePanelSlide:SetToBeginning(); + Controls.TradePanelSlide:Play(); + Controls.LeaderDialogFade:SetToBeginning(); + Controls.LeaderDialogFade:Play(); + Controls.LeaderDialogSlide:SetToBeginning(); + Controls.LeaderDialogSlide:Play(); + Controls.ValueEditPopupBackground:SetHide(true); + + g_IconOnlyIM:ResetInstances(); + g_IconAndTextIM:ResetInstances(); + + ms_bExiting = false; + + if (Game.GetLocalPlayer() == -1) then + return; + end + + -- For hotload testing, force the other player to be valid + if (ms_OtherPlayerID == -1) then + local playerID = 0 + for playerID = 0, GameDefines.MAX_PLAYERS-1, 1 do + if (playerID ~= Game.GetLocalPlayer() and Players[playerID]:IsAlive()) then + ms_OtherPlayerID = playerID; + break; + end + end + end + + -- Set up some globals for easy access + g_LocalPlayer = Players[Game.GetLocalPlayer()]; + g_OtherPlayer = Players[ms_OtherPlayerID]; + ms_OtherPlayerIsHuman = g_OtherPlayer:IsHuman(); + + local sessionID = DiplomacyManager.FindOpenSessionID(Game.GetLocalPlayer(), g_OtherPlayer:GetID()); + if (sessionID ~= nil) then + local sessionInfo = DiplomacyManager.GetSessionInfo(sessionID); + ms_InitiatedByPlayerID = sessionInfo.FromPlayer; + end + + -- Did the AI start this or the human? + if (ms_InitiatedByPlayerID == ms_OtherPlayerID) then + ms_LastIncomingDealProposalAction = DealProposalAction.PROPOSED; + + local pDeal = DealManager.GetWorkingDeal(DealDirection.INCOMING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + ms_bIsGift = pDeal:IsGift(); + + DealManager.CopyIncomingToOutgoingWorkingDeal(g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + + local pDeal = DealManager.GetWorkingDeal(DealDirection.INCOMING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + ms_bIsGift = pDeal:IsGift(); + else + ms_LastIncomingDealProposalAction = DealProposalAction.PENDING; + -- We are NOT clearing the current outgoing deal. This allows other screens to pre-populate the deal. + end + + UpdateOtherPlayerText(1); + SetDefaultLeaderDialogText(); + + local iAvailableItemCount = 0; + -- Available content to trade. Shouldn't change during the session, but it might, especially in multiplayer. + iAvailableItemCount = iAvailableItemCount + PopulatePlayerAvailablePanel(Controls.MyInventoryStack, g_LocalPlayer); + iAvailableItemCount = iAvailableItemCount + PopulatePlayerAvailablePanel(Controls.TheirInventoryStack, g_OtherPlayer); + + Controls.MyInventoryScroll:CalculateSize(); + Controls.TheirInventoryScroll:CalculateSize(); + + m_kPopupDialog:Close(); -- Close and reset the popup in case it's open + + if (iAvailableItemCount == 0) then + if (ms_bIsDemand) then + m_kPopupDialog:AddText(Locale.Lookup("LOC_DIPLO_DEMAND_NO_AVAILABLE_ITEMS")); + m_kPopupDialog:AddTitle( Locale.ToUpper(Locale.Lookup("LOC_DIPLO_CHOICE_MAKE_DEMAND"))) + m_kPopupDialog:AddButton( Locale.Lookup("LOC_OK_BUTTON"), OnRefuseDeal); + else + m_kPopupDialog:AddText( Locale.Lookup("LOC_DIPLO_DEAL_NO_AVAILABLE_ITEMS")); + m_kPopupDialog:AddTitle( Locale.ToUpper(Locale.Lookup("LOC_DIPLO_CHOICE_MAKE_DEAL"))) + m_kPopupDialog:AddButton( Locale.Lookup("LOC_OK_BUTTON"), OnRefuseDeal); + end + m_kPopupDialog:Open(); + end + + PopulatePlayerDealPanel(Controls.TheirOfferStack, g_OtherPlayer); + PopulatePlayerDealPanel(Controls.MyOfferStack, g_LocalPlayer); + UpdateDealStatus(); + + -- We may be coming into this screen with a deal already set, which needs to be sent to the AI for inspection. Check that. + -- Don't send AI proposals for inspection or they will think the player was the creator of the deal + if (IsAutoPropose() and (ms_InitiatedByPlayerID ~= ms_OtherPlayerID or ms_OtherPlayerIsHuman)) then + ProposeWorkingDeal(true); + end + + Controls.MyOfferScroll:CalculateSize(); + Controls.TheirOfferScroll:CalculateSize(); + + LuaEvents.DiploBasePopup_HideUI(true); + TTManager:ClearCurrent(); -- Clear any tool tips raised; + + Controls.DealOptionsStack:CalculateSize(); + Controls.DealOptionsStack:ReprocessAnchoring(); +end + +---------------------------------------------------------------- +function OnHide() + LuaEvents.DiploBasePopup_HideUI(false); +end + +-- =========================================================================== +-- Context CTOR +-- =========================================================================== +function OnInit( isHotload ) + LateInitialize(); + + if (isHotload and not ContextPtr:IsHidden()) then + OnShow(); + end +end + +-- =========================================================================== +-- Context DESTRUCTOR +-- Not called when screen is dismissed, only if the whole context is removed! +-- =========================================================================== +function OnShutdown() + +end + +-- =========================================================================== +function OnLocalPlayerTurnEnd() + if (not ContextPtr:IsHidden()) then + -- Were we just viewing the deal? + if (not Controls.ResumeGame:IsHidden()) then + OnResumeGame(); + else + OnRefuseDeal(true); + end + OnContinue(); + end +end + +-- =========================================================================== +function OnPlayerDefeat( player, defeat, eventID) + local localPlayer = Game.GetLocalPlayer(); + if (localPlayer and localPlayer >= 0) then -- Check to see if there is any local player + -- Was it the local player? + if (localPlayer == player) then + OnLocalPlayerTurnEnd(); + end + end +end + +-- =========================================================================== +function OnTeamVictory(team, victory, eventID) + + local localPlayer = Game.GetLocalPlayer(); + if (localPlayer and localPlayer >= 0) then -- Check to see if there is any local player + OnLocalPlayerTurnEnd(); + end +end + +-- =========================================================================== +-- Engine Event +-- =========================================================================== +function OnUserRequestClose() + -- Is this showing; if so then it needs to raise dialog to handle close + if (not ContextPtr:IsHidden()) then + m_kPopupDialog:Reset(); + m_kPopupDialog:AddText(Locale.Lookup("LOC_CONFIRM_EXIT_TXT")); + m_kPopupDialog:AddButton(Locale.Lookup("LOC_NO"), nil); + m_kPopupDialog:AddButton(Locale.Lookup("LOC_YES"), OnQuitYes, nil, nil, "PopupButtonInstanceRed"); + m_kPopupDialog:Open(); + end +end +function OnQuitYes() + Events.UserConfirmedClose(); +end + +-- =========================================================================== +function LateInitialize() + CreateGroupTypes(); + InitializeDealGroups(); + CreatePanels(); +end + +-- =========================================================================== +function Initialize() + + ContextPtr:SetInitHandler( OnInit ); + ContextPtr:SetInputHandler( InputHandler, true ); + ContextPtr:SetShutdown( OnShutdown ); + ContextPtr:SetShowHandler( OnShow ); + ContextPtr:SetHideHandler( OnHide ); + + Events.LocalPlayerTurnEnd.Add( OnLocalPlayerTurnEnd ); + Events.PlayerDefeat.Add( OnPlayerDefeat ); + Events.TeamVictory.Add( OnTeamVictory ); + + Events.UserRequestClose.Add( OnUserRequestClose ); + + m_kPopupDialog = PopupDialog:new( "DiplomacyDealView" ); +end + +Initialize(); diff --git a/Replacements/DiplomacyDealView_Expansion2.lua b/Replacements/DiplomacyDealView_Expansion2.lua new file mode 100644 index 0000000..2f93a01 --- /dev/null +++ b/Replacements/DiplomacyDealView_Expansion2.lua @@ -0,0 +1,290 @@ +--[[ +-- Created by Andrew Garrett +-- Copyright (c) Firaxis Games 2018 +--]] + +-- =========================================================================== +-- INCLUDES +-- =========================================================================== +include("DiplomacyDealView.lua"); + +-- =========================================================================== +-- VARIABLES +-- =========================================================================== +local ms_DefaultOneTimeFavorAmount = 1; + +-- =========================================================================== +-- CACHE BASE FUNCTIONS +-- =========================================================================== +BASE_GetItemTypeIcon = GetItemTypeIcon; +BASE_CreateGroupTypes = CreateGroupTypes; +BASE_IsItemValueEditable = IsItemValueEditable; +BASE_PopulateDealResources = PopulateDealResources; +BASE_CreatePlayerAvailablePanel = CreatePlayerAvailablePanel; +BASE_PopulatePlayerAvailablePanel = PopulatePlayerAvailablePanel; + +-- =========================================================================== +-- OVERRIDE BASE FUNCTIONS +-- =========================================================================== +function OnClickAvailableResource(player, resourceType) + + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Can't modifiy demand that is not ours + return; + end + + local pBaseResourceDef = GameInfo.Resources[resourceType]; + local pResourceDef = GameInfo.Resource_Consumption[pBaseResourceDef.ResourceType]; + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, Game.GetLocalPlayer(), GetOtherPlayer():GetID()); + if (pDeal ~= nil) then + + -- Already there? + local dealItems = pDeal:FindItemsByType(DealItemTypes.RESOURCES, DealItemSubTypes.NONE, player:GetID()); + local pDealItem; + if (dealItems ~= nil) then + for i, pDealItem in ipairs(dealItems) do + if pDealItem:GetValueType() == resourceType then + -- Check for non-zero duration. There may already be a one-time transfer of the resource if a city is in the deal. + if (pDealItem:GetDuration() ~= 0) then + return; -- Already in there. + end + if (pResourceDef ~= nil and pResourceDef.Accumulate) then + -- already have this, up the amount + local iAddAmount = pDealItem:GetAmount() + 1; + iAddAmount = clip(iAddAmount, nil, pDealItem:GetMaxAmount()); + if (iAddAmount ~= pDealItem:GetAmount()) then + pDealItem:SetAmount(iAddAmount); + + if not pDealItem:IsValid() then + pDealItem:SetAmount(iAddAmount-1); + return; + else + UI.PlaySound("UI_GreatWorks_Put_Down"); + UpdateDealPanel(player); + + UpdateProposedWorkingDeal(); + return; + end + else + return; + end + end + end + end + end + + -- we don't need to check how many the player has, the deal manager will reject if we try to add too many + local pPlayerResources = player:GetResources(); + pDealItem = pDeal:AddItemOfType(DealItemTypes.RESOURCES, player:GetID()); + if (pDealItem ~= nil) then + -- Add one + pDealItem:SetValueType(resourceType); + pDealItem:SetAmount(1); + if (pResourceDef ~= nil and pResourceDef.Accumulate) then + pDealItem:SetDuration(0); + else + pDealItem:SetDuration(30); -- Default to this many turns + end + + -- After we add the item, test to see if the item is valid, it is possible that we have exceeded the amount of resources we can trade. + if not pDealItem:IsValid() then + pDeal:RemoveItemByID(pDealItem:GetID()); + pDealItem = nil; + else + UI.PlaySound("UI_GreatWorks_Put_Down"); + end + + UpdateDealPanel(player); + UpdateProposedWorkingDeal(); + end + end +end + + +-- =========================================================================== +-- Check the state of the deal and show/hide the special proposal buttons for a possible gift (not actually possible until XP2) +function UpdateProposalButtonsForGift(iItemsFromLocal : number, iItemsFromOther : number) + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (iItemsFromLocal == 0 and iItemsFromOther > 0 and not pDeal:IsGift()) then + return true; + end + + return false; +end + +-- =========================================================================== +function GetItemTypeIcon(pDealItem: table) + if (pDealItem:GetType() == DealItemTypes.FAVOR) then + return "ICON_YIELD_FAVOR"; + end + return BASE_GetItemTypeIcon(pDealItem); +end + +-- =========================================================================== +function CreateGroupTypes() + BASE_CreateGroupTypes(); + AvailableDealItemGroupTypes.FAVOR = table.count(AvailableDealItemGroupTypes) + 1; + DealItemGroupTypes.FAVOR = table.count(DealItemGroupTypes) + 1; +end + +-- =========================================================================== +function IsItemValueEditable(itemType: number) + return BASE_IsItemValueEditable(itemType) or itemType == DealItemTypes.FAVOR; +end + +-- =========================================================================== +function PopulateDealResources(player: table, iconList: table) + + BASE_PopulateDealResources(player, iconList); + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local playerType = GetPlayerType(player); + if (pDeal ~= nil) then + for pDealItem in pDeal:Items() do + if (pDealItem:GetFromPlayerID() == player:GetID()) then + local type = pDealItem:GetType(); + local iDuration = pDealItem:GetDuration(); + local dealItemID = pDealItem:GetID(); + -- Gold? + if (type == DealItemTypes.FAVOR) then + local icon; + if (iDuration == 0) then + -- One time + icon = g_IconOnlyIM:GetInstance(iconList); + SetIconToSize(icon.Icon, "ICON_YIELD_FAVOR"); + icon.AmountText:SetText(tostring(pDealItem:GetAmount())); + icon.AmountText:SetHide(false); + icon.Icon:SetColor(1, 1, 1); + + -- Show/hide unacceptable item notification + icon.UnacceptableIcon:SetHide(not pDealItem:IsUnacceptable()); + + icon.SelectButton:RegisterCallback(Mouse.eRClick, function(void1, void2, self) OnRemoveDealItem(player, dealItemID, self); end); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function(void1, void2, self) OnSelectValueDealItem(player, dealItemID, self); end ); + icon.SelectButton:SetToolTipString(nil); -- We recycle the entries, so make sure this is clear. + icon.SelectButton:SetDisabled(false); + if (dealItemID == g_ValueEditDealItemID) then + g_ValueEditDealItemControlTable = icon; + end + else + -- Multi-turn + UI.DataError("Favor can only be traded in lump sums, but gamecore is indicating duration. This may be an issue @sbatista & @agarrett"); + end + end -- end for each item in deal + end -- end if deal + end + end + +end + +-- =========================================================================== +function CreatePlayerAvailablePanel(playerType: number, rootControl: table) + g_AvailableGroups[AvailableDealItemGroupTypes.FAVOR][playerType] = CreateHorizontalGroup(rootControl); + return BASE_CreatePlayerAvailablePanel(playerType, rootControl); +end + +-- =========================================================================== +function PopulatePlayerAvailablePanel(rootControl: table, player: table) + + local playerType = GetPlayerType(player); + local iAvailableItemCount = PopulateAvailableFavor(player, g_AvailableGroups[AvailableDealItemGroupTypes.FAVOR][playerType]); + iAvailableItemCount = iAvailableItemCount + BASE_PopulatePlayerAvailablePanel(rootControl, player); + return iAvailableItemCount; +end + +function PopulateAvailableFavor(player: table, iconList: table) + + local iAvailableItemCount = 0; + + local eFromPlayerID = player:GetID(); + local eToPlayerID = GetOtherPlayer(player):GetID(); + + local pForDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + local possibleResources = DealManager.GetPossibleDealItems(eFromPlayerID, eToPlayerID, DealItemTypes.FAVOR, pForDeal); + if ((possibleResources ~= nil) and (player:GetFavor() > 0)) then + for i, entry in ipairs(possibleResources) do + -- One time favor + local favorBalance:number = player:GetFavor(); + + if (not ms_bIsDemand) then + local icon = g_IconOnlyIM:GetInstance(iconList.ListStack); + icon.AmountText:SetText(favorBalance); + icon.SelectButton:SetToolTipString(Locale.Lookup("LOC_DIPLOMATIC_FAVOR_NAME")); -- We recycle the entries, so make sure this is clear. + SetIconToSize(icon.Icon, "ICON_YIELD_FAVOR"); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function() OnClickAvailableOneTimeFavor(player, ms_DefaultOneTimeFavorAmount); end ); + icon.SelectButton:RegisterCallback( Mouse.eLClick, function() OnClickAvailableOneTimeFavor(player, ms_DefaultOneTimeFavorAmount); end ); + icon.Icon:SetColor(1, 1, 1); + icon.SelectButton:SetDisabled(false); + + iAvailableItemCount = iAvailableItemCount + 1; + end + end + end + + return iAvailableItemCount; +end + +-- =========================================================================== +function OnClickAvailableOneTimeFavor(player, iAddAmount: number) + + if (ms_bIsDemand == true and ms_InitiatedByPlayerID == ms_OtherPlayerID) then + -- Can't modifiy demand that is not ours + return; + end + + local pDeal = DealManager.GetWorkingDeal(DealDirection.OUTGOING, g_LocalPlayer:GetID(), g_OtherPlayer:GetID()); + if (pDeal ~= nil) then + + local bFound = false; + + -- Already there? + local dealItems = pDeal:FindItemsByType(DealItemTypes.FAVOR, DealItemSubTypes.NONE, player:GetID()); + local pDealItem; + if (dealItems ~= nil) then + for i, pDealItem in ipairs(dealItems) do + if (pDealItem:GetDuration() == 0) then + -- Already have a one time favor. Up the amount + iAddAmount = pDealItem:GetAmount() + iAddAmount; + iAddAmount = clip(iAddAmount, nil, pDealItem:GetMaxAmount()); + if (iAddAmount ~= pDealItem:GetAmount()) then + pDealItem:SetAmount(iAddAmount); + bFound = true; + break; + else + return; -- No change, just exit + end + end + end + end + + -- Doesn't exist yet, add it. + if (not bFound) then + + -- Going to add anything? + pDealItem = pDeal:AddItemOfType(DealItemTypes.FAVOR, player:GetID()); + if (pDealItem ~= nil) then + + -- Set the duration, so the max amount calculation knows what we are doing + pDealItem:SetDuration(0); + + -- Adjust the favor to our max + iAddAmount = clip(iAddAmount, nil, pDealItem:GetMaxAmount()); + if (iAddAmount > 0) then + pDealItem:SetAmount(iAddAmount); + bFound = true; + else + -- It is empty, remove it. + local itemID = pDealItem:GetID(); + pDeal:RemoveItemByID(itemID); + end + end + end + + + if (bFound) then + UpdateProposedWorkingDeal(); + UpdateDealPanel(player); + end + end +end diff --git a/Replacements/DiplomacyRibbon.xml b/Replacements/DiplomacyRibbon.xml new file mode 100644 index 0000000..5834067 --- /dev/null +++ b/Replacements/DiplomacyRibbon.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Replacements/SelectedUnit_Expansion2.lua b/Replacements/SelectedUnit_Expansion2.lua new file mode 100644 index 0000000..b3b87ca --- /dev/null +++ b/Replacements/SelectedUnit_Expansion2.lua @@ -0,0 +1,73 @@ + +--[[ +-- Copyright (c) Firaxis Games 2018 +--]] + +-- =========================================================================== +-- INCLUDES +-- =========================================================================== +include("SelectedUnit"); + +-- =========================================================================== +-- OVERRIDE BASE FUNCTIONS +-- =========================================================================== +function RealizeGreatPersonLens(kUnit:table ) + UILens.ClearLayerHexes(m_HexColoringGreatPeople); + if UILens.IsLayerOn( m_HexColoringGreatPeople ) then + UILens.ToggleLayerOff(m_HexColoringGreatPeople); + end + if kUnit ~= nil and ( not UI.IsGameCoreBusy() ) then + local playerID:number = kUnit:GetOwner(); + if playerID == Game.GetLocalPlayer() then + local kUnitArchaeology:table = kUnit:GetArchaeology(); + local kUnitGreatPerson:table = kUnit:GetGreatPerson(); + local kUnitRockBand:table = kUnit:GetRockBand(); + if kUnitGreatPerson ~= nil and kUnitGreatPerson:IsGreatPerson() then + local greatPersonInfo:table = GameInfo.GreatPersonIndividuals[kUnitGreatPerson:GetIndividual()]; + -- Highlight an area around the Great Person (if they have an area of effect trait) + local areaHighlightPlots:table = {}; + if (greatPersonInfo ~= nil and greatPersonInfo.AreaHighlightRadius ~= nil) then + areaHighlightPlots = kUnitGreatPerson:GetAreaHighlightPlots(); + end + -- Highlight the plots the Great Person could use its action on + local activationPlots:table = {}; + if (greatPersonInfo ~= nil and greatPersonInfo.ActionEffectTileHighlighting ~= nil and greatPersonInfo.ActionEffectTileHighlighting) then + local rawActivationPlots:table = kUnitGreatPerson:GetActivationHighlightPlots(); + for _,plotIndex:number in ipairs(rawActivationPlots) do + table.insert(activationPlots, {"Great_People", plotIndex}); + end + end + UILens.SetLayerHexesArea(m_HexColoringGreatPeople, playerID, areaHighlightPlots, activationPlots); + UILens.ToggleLayerOn(m_HexColoringGreatPeople); + elseif( kUnitArchaeology ~= nil and GameInfo.Units[kUnit:GetUnitType()].ExtractsArtifacts == true) then + -- Highlight plots that can activated by Archaeologists + local activationPlots:table = {}; + local rawActivationPlots:table = kUnitArchaeology:GetActivationHighlightPlots(); + for _,plotIndex:number in ipairs(rawActivationPlots) do + table.insert(activationPlots, {"Great_People", plotIndex}); + end + + UILens.SetLayerHexesArea(m_HexColoringGreatPeople, playerID, {}, activationPlots); + UILens.ToggleLayerOn(m_HexColoringGreatPeople); + elseif GameInfo.Units[kUnit:GetUnitType()].ParkCharges > 0 and kUnit:GetParkCharges() > 0 then -- Highlight plots that can activated by Naturalists + local parkPlots:table = {}; + local rawParkPlots:table = Game.GetNationalParks():GetPossibleParkTiles(playerID); + for _,plotIndex:number in ipairs(rawParkPlots) do + table.insert(parkPlots, {"Great_People", plotIndex}); + end + UILens.SetLayerHexesArea(m_HexColoringGreatPeople, playerID, {}, parkPlots); + UILens.ToggleLayerOn(m_HexColoringGreatPeople); + elseif kUnitRockBand ~= nil and GameInfo.Units[kUnit:GetUnitType()].UnitType == "UNIT_ROCK_BAND" then -- Highlight plots that can activated by RockBands + -- Highlight the plots the RockBand could use its action on + local activationPlots:table = {}; + local rawActivationPlots:table = kUnitRockBand:GetActivationHighlightPlots(); + for _,plotIndex:number in ipairs(rawActivationPlots) do + table.insert(activationPlots, {"Great_People", plotIndex}); + end + + UILens.SetLayerHexesArea(m_HexColoringGreatPeople, playerID, {}, activationPlots); + UILens.ToggleLayerOn(m_HexColoringGreatPeople); + end + end + end +end diff --git a/Replacements/TechTreeNode.xml b/Replacements/TechTreeNode.xml index 03466d7..fa7511a 100644 --- a/Replacements/TechTreeNode.xml +++ b/Replacements/TechTreeNode.xml @@ -1,33 +1,34 @@ - + + - - - - - - - - - + + + + + @@ -74,7 +74,9 @@ - + @@ -137,15 +139,15 @@ - - - + + + - - + + @@ -222,17 +224,8 @@ - - - - - - - - -