forked from Azurency/Civ6-UIFiles
-
Notifications
You must be signed in to change notification settings - Fork 1
/
AdjacencyBonusSupport.lua
364 lines (307 loc) · 15.1 KB
/
AdjacencyBonusSupport.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
-- ===========================================================================
-- Functions related to finding the yield bonuses (district) plots are given
-- due to some attribute of an adjacent plot.
-- ==========================================================================
include( "Civ6Common" ); -- GetYieldString()
include( "MapEnums" );
-- ===========================================================================
-- CONSTANTS
-- ===========================================================================
local START_INDEX :number = GameInfo.Yields["YIELD_FOOD"].Index;
local END_INDEX :number = GameInfo.Yields["YIELD_FAITH"].Index;
local m_DistrictsWithAdjacencyBonuses :table = {};
for row in GameInfo.District_Adjacencies() do
local districtIndex = GameInfo.Districts[row.DistrictType].Index;
if (districtIndex ~= nil) then
m_DistrictsWithAdjacencyBonuses[districtIndex] = true;
end
end
-- ===========================================================================
-- Obtain the artdef string name that shows an adjacency icon for a plot type.
-- RETURNS: Artdef string name for an icon to display between hexes
-- ===========================================================================
function GetAdjacentIconArtdefName( targetDistrictType:string, plot:table, pkCity:table, direction:number )
local eDistrict = GameInfo.Districts[targetDistrictType].Index;
local eType = -1;
local iSubType = -1;
eType, iSubType = plot:GetAdjacencyBonusType(Game.GetLocalPlayer(), pkCity:GetID(), eDistrict, direction);
if eType == AdjacencyBonusTypes.NO_ADJACENCY then
return "";
elseif eType == AdjacencyBonusTypes.ADJACENCY_DISTRICT then
return "Districts_Generic_District";
elseif eType == AdjacencyBonusTypes.ADJACENCY_FEATURE then
if iSubType == g_FEATURE_JUNGLE then
return "Terrain_Jungle";
elseif iSubType == g_FEATURE_FOREST then
return "Terrain_Forest";
elseif iSubType == g_FEATURE_GEOTHERMAL_FISSURE then
return "Terrain_Generic_Resource";
elseif iSubType == g_FEATURE_REEF then
return "Terrain_Reef";
end
elseif eType == AdjacencyBonusTypes.ADJACENCY_IMPROVEMENT then
if iSubType == 1 then
return "Improvements_Farm";
elseif iSubType == 2 then
return "Improvement_Mine";
elseif iSubType == 3 then
return "Improvement_Quarry";
end
elseif eType == AdjacencyBonusTypes.ADJACENCY_NATURAL_WONDER then
return "Wonders_Natural_Wonder";
elseif eType == AdjacencyBonusTypes.ADJACENCY_RESOURCE then
return "Terrain_Generic_Resource";
elseif eType == AdjacencyBonusTypes.ADJACENCY_RESOURCE_CLASS then
return "Terrain_Generic_Resource_Class";
elseif eType == AdjacencyBonusTypes.ADJACENCY_RIVER then
return "Terrain_River";
elseif eType == AdjacencyBonusTypes.ADJACENCY_SEA_RESOURCE then
return "Terrain_Sea";
elseif eType == AdjacencyBonusTypes.ADJACENCY_TERRAIN then
if iSubType == g_TERRAIN_TYPE_TUNDRA or iSubType == g_TERRAIN_TYPE_TUNDRA_HILLS then
return "Terrain_Tundra";
elseif iSubType == g_TERRAIN_TYPE_DESERT or iSubType == g_TERRAIN_TYPE_DESERT_HILLS then
return "Terrain_Desert";
elseif iSubType == g_TERRAIN_TYPE_COAST then -- TODO or TERRAIN_TYPE_OCEAN?
return "Terrain_Coast";
else -- TODO specify mountain and have an error asset if no match?
return "Terrain_Mountain";
end
elseif eType == AdjacencyBonusTypes.ADJACENCY_WONDER then
return "Generic_Wonder";
end
-- Default to generic icon
return "Terrain_Generic_Resource";
end
-- ===========================================================================
-- Obtain a table of adjacency bonuses
-- ===========================================================================
function AddAdjacentPlotBonuses( kPlot:table, districtType:string, pSelectedCity:table, tCurrentBonuses:table )
local adjacentPlotBonuses:table = {};
local x :number = kPlot:GetX();
local y :number = kPlot:GetY();
for _,direction in pairs(DirectionTypes) do
if direction ~= DirectionTypes.NO_DIRECTION and direction ~= DirectionTypes.NUM_DIRECTION_TYPES then
local adjacentPlot :table= Map.GetAdjacentPlot( x, y, direction);
if adjacentPlot ~= nil then
local artdefIconName:string = GetAdjacentIconArtdefName( districtType, adjacentPlot, pSelectedCity, direction );
if artdefIconName ~= nil and artdefIconName ~= "" then
local districtViewInfo:table = GetViewPlotInfo( adjacentPlot, tCurrentBonuses );
local oppositeDirection :number = -1;
if direction == DirectionTypes.DIRECTION_NORTHEAST then oppositeDirection = DirectionTypes.DIRECTION_SOUTHWEST; end
if direction == DirectionTypes.DIRECTION_EAST then oppositeDirection = DirectionTypes.DIRECTION_WEST; end
if direction == DirectionTypes.DIRECTION_SOUTHEAST then oppositeDirection = DirectionTypes.DIRECTION_NORTHWEST; end
if direction == DirectionTypes.DIRECTION_SOUTHWEST then oppositeDirection = DirectionTypes.DIRECTION_NORTHEAST; end
if direction == DirectionTypes.DIRECTION_WEST then oppositeDirection = DirectionTypes.DIRECTION_EAST; end
if direction == DirectionTypes.DIRECTION_NORTHWEST then oppositeDirection = DirectionTypes.DIRECTION_SOUTHEAST; end
table.insert( districtViewInfo.adjacent, {
direction = oppositeDirection,
iconArtdef = artdefIconName,
inBonus = false,
outBonus = true
}
);
adjacentPlotBonuses[adjacentPlot:GetIndex()] = districtViewInfo;
end
end
end
end
return adjacentPlotBonuses;
end
-- ===========================================================================
-- Adds a plot and all the adjacencent plots, unless already added.
-- ARGS: kPlot, gamecore plot object
-- ARGS: kExistingTable, table of existing plot into to check if we already have info about this plot
-- RETURNS: A new/updated plotInfo table
-- ===========================================================================
function GetViewPlotInfo( kPlot:table, kExistingTable:table )
local plotId :number = kPlot:GetIndex();
local plotInfo :table = kExistingTable[plotId];
if plotInfo == nil then
plotInfo = {
index = plotId,
x = kPlot:GetX(),
y = kPlot:GetY(),
adjacent= {}, -- adjacent edge bonuses
selectable = false, -- change state with mouse over?
purchasable = false
};
end
--print( " plot: " .. plotInfo.x .. "," .. plotInfo.y..": " .. tostring(plotInfo.iconArtdef) );
return plotInfo;
end
-- ===========================================================================
-- RETURNS: true or false, indicating whether this placement option should be
-- shown when the player can purchase the plot.
-- ===========================================================================
function IsShownIfPlotPurchaseable(eDistrict:number, pkCity:table, plot:table)
local yieldBonus:string = GetAdjacentYieldBonusString(eDistrict, pkCity, plot);
-- If we would get a bonus for placing here, then show it as an option
if (yieldBonus ~= nil and yieldBonus ~= "") then
return true;
end
-- If there are no adjacency bonuses for this district type (and so no bonuses to be had), then show it as an option
if (m_DistrictsWithAdjacencyBonuses[eDistrict] == nil or m_DistrictsWithAdjacencyBonuses[eDistrict] == false) then
return true;
end
return false;
end
-- ===========================================================================
-- RETURNS: "" if no bonus or...
-- 1. Text with the bonuses for a district if added to the given plot,
-- 2. parameter is a tooltip with detailed bonus informatin
-- 3. NIL if can be used or a string explaining what needs to be done for plot to be usable.
-- ===========================================================================
function GetAdjacentYieldBonusString( eDistrict:number, pkCity:table, plot:table )
local tooltipText :string = "";
local totalBonuses :string = "";
local requiredText :string = "";
local isFirstEntry :boolean = true;
local iconString:string = "";
-- Special handling for Neighborhoods
if (GameInfo.Districts[eDistrict].OnePerCity == false) then
tooltipText, requiredText = plot:GetAdjacencyBonusTooltip(Game.GetLocalPlayer(), pkCity:GetID(), eDistrict, 0);
-- Ensure required text is NIL if none was returned.
if requiredText ~= nil and string.len(requiredText) < 1 then
requiredText = nil;
end
local iAppeal = plot:GetAppeal();
local iBaseHousing = GameInfo.Districts[eDistrict].Housing;
-- Default is Mbanza case (no appeal change)
local iTotalHousing:number = iBaseHousing;
for row in GameInfo.AppealHousingChanges() do
if (row.DistrictType == GameInfo.Districts[eDistrict].DistrictType) then
local iMinimumValue = row.MinimumValue;
local iAppealChange = row.AppealChange;
local szDescription = row.Description;
if (iAppeal >= iMinimumValue) then
iTotalHousing = iBaseHousing + iAppealChange;
tooltipText = Locale.Lookup("LOC_DISTRICT_ZONE_NEIGHBORHOOD_TOOLTIP", iBaseHousing + iAppealChange, szDescription);
break;
end
end
end
if iTotalHousing ~= 0 then
iconString = "[ICON_Housing]+" .. tostring(iTotalHousing);
end
-- Normal handling for all other districts
else
-- Check each neighbor if it matches criteria with the adjacency rules
for iBonusYield = START_INDEX, END_INDEX do
local iBonus:number = plot:GetAdjacencyYield(Game.GetLocalPlayer(), pkCity:GetID(), eDistrict, iBonusYield);
if (iBonus > 0) then
local yieldTooltip, yieldRequireText = plot:GetAdjacencyBonusTooltip(Game.GetLocalPlayer(), pkCity:GetID(), eDistrict, iBonusYield);
if tooltipText == "" then
tooltipText = yieldTooltip;
else
tooltipText = tooltipText .. "[NEWLINE]" .. yieldTooltip;
end
-- There is always only one requiredText so just replace it
requiredText = yieldRequireText;
local yieldString:string = GetYieldString( GameInfo.Yields[iBonusYield].YieldType, iBonus );
if iconString == "" then
iconString = yieldString;
else
iconString = iconString .. "[NEWLINE]" .. yieldString;
end
end
end
-- Ensure required text is NIL if none was returned.
if requiredText ~= nil and string.len(requiredText) < 1 then
requiredText = nil;
end
end
return iconString, tooltipText, requiredText;
end
-- ===========================================================================
-- Obtain all the owned (or could be owned) plots of a city.
-- ARGS: pCity, the city to obtain plots from
-- RETURNS: table of plot indices
-- ===========================================================================
function GetCityRelatedPlotIndexes( pCity:table )
print("GetCityRelatedPlotIndexes() isn't updated with the latest purchaed plot if one was just purchased and this is being called on Event.CityMadePurchase !");
local plots:table = Map.GetCityPlots():GetPurchasedPlots( pCity );
-- Plots that arent't owned, but could be (and hence, could be a great spot for that district!)
local tParameters :table = {};
tParameters[CityCommandTypes.PARAM_PLOT_PURCHASE] = UI.GetInterfaceModeParameter(CityCommandTypes.PARAM_PLOT_PURCHASE);
local tResults = CityManager.GetCommandTargets( pCity, CityCommandTypes.PURCHASE, tParameters );
if (tResults[CityCommandResults.PLOTS] ~= nil and table.count(tResults[CityCommandResults.PLOTS]) ~= 0) then
for _,plotId in pairs(tResults[CityCommandResults.PLOTS]) do
table.insert(plots, plotId);
end
end
return plots;
end
-- ===========================================================================
-- Same as above but specific to districts and works despite the cache not having an updated value.
-- ===========================================================================
function GetCityRelatedPlotIndexesDistrictsAlternative( pCity:table, districtHash:number )
local district :table = GameInfo.Districts[districtHash];
local plots :table = {};
local tParameters :table = {};
tParameters[CityOperationTypes.PARAM_DISTRICT_TYPE] = districtHash;
-- Available to place plots.
local tResults :table = CityManager.GetOperationTargets( pCity, CityOperationTypes.BUILD, tParameters );
if (tResults[CityOperationResults.PLOTS] ~= nil and table.count(tResults[CityOperationResults.PLOTS]) ~= 0) then
local kPlots:table = tResults[CityOperationResults.PLOTS];
for i, plotId in ipairs(kPlots) do
table.insert(plots, plotId);
end
end
--[[
-- antonjs: Removing blocked plots from the UI display. Now that district placement can automatically remove features, resources, and improvements,
-- as long as the player has the tech, there is not much need to show blocked plots and they end up being confusing.
-- Plots that eventually can hold a district but are blocked by some required operation.
if (tResults[CityOperationResults.BLOCKED_PLOTS] ~= nil and table.count(tResults[CityOperationResults.BLOCKED_PLOTS]) ~= 0) then
for _, plotId in ipairs(tResults[CityOperationResults.BLOCKED_PLOTS]) do
table.insert(plots, plotId);
end
end
--]]
-- Plots that arent't owned, but if they were, would give a bonus.
tParameters = {};
tParameters[CityCommandTypes.PARAM_PLOT_PURCHASE] = UI.GetInterfaceModeParameter(CityCommandTypes.PARAM_PLOT_PURCHASE);
local tResults = CityManager.GetCommandTargets( pCity, CityCommandTypes.PURCHASE, tParameters );
if (tResults[CityCommandResults.PLOTS] ~= nil and table.count(tResults[CityCommandResults.PLOTS]) ~= 0) then
for _,plotId in pairs(tResults[CityCommandResults.PLOTS]) do
local kPlot :table = Map.GetPlotByIndex(plotId);
if kPlot:CanHaveDistrict(district.Index, pCity:GetOwner(), pCity:GetID()) then
local isValid :boolean = IsShownIfPlotPurchaseable(district.Index, pCity, kPlot);
if isValid then
table.insert(plots, plotId);
end
end
end
end
return plots;
end
-- ===========================================================================
-- Same as above but specific to wonders and works despite the cache not having an updated value.
-- ===========================================================================
function GetCityRelatedPlotIndexesWondersAlternative( pCity:table, buildingHash:number )
local building :table = GameInfo.Buildings[buildingHash];
local plots :table = {};
local tParameters :table = {};
tParameters[CityOperationTypes.PARAM_BUILDING_TYPE] = buildingHash;
-- Available to place plots.
local tResults :table = CityManager.GetOperationTargets( pCity, CityOperationTypes.BUILD, tParameters );
if (tResults[CityOperationResults.PLOTS] ~= nil and table.count(tResults[CityOperationResults.PLOTS]) ~= 0) then
local kPlots:table = tResults[CityOperationResults.PLOTS];
for i, plotId in ipairs(kPlots) do
table.insert(plots, plotId);
end
end
-- Plots that aren't owned, but if they were, would give a bonus.
tParameters = {};
tParameters[CityCommandTypes.PARAM_PLOT_PURCHASE] = UI.GetInterfaceModeParameter(CityCommandTypes.PARAM_PLOT_PURCHASE);
local tResults = CityManager.GetCommandTargets( pCity, CityCommandTypes.PURCHASE, tParameters );
if (tResults[CityCommandResults.PLOTS] ~= nil and table.count(tResults[CityCommandResults.PLOTS]) ~= 0) then
for _,plotId in pairs(tResults[CityCommandResults.PLOTS]) do
local kPlot :table = Map.GetPlotByIndex(plotId);
if kPlot:CanHaveWonder(building.Index, pCity:GetOwner(), pCity:GetID()) then
table.insert(plots, plotId);
end
end
end
return plots;
end