-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathStrategicView_MapPlacement.lua
452 lines (381 loc) · 19.6 KB
/
StrategicView_MapPlacement.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
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
-- ===========================================================================
-- Input for placing items on the world map.
-- Copyright 2015-2016, Firaxis Games
--
-- To hot-reload, save this then re-save the file that imports the file
-- (e.g., WorldInput)
-- ===========================================================================
include("SupportFunctions.lua");
include("AdjacencyBonusSupport.lua");
include("PopupDialog");
-- ===========================================================================
-- MEMBERS
-- ===========================================================================
local m_hexesDistrictPlacement :table = {}; -- Re-usable collection of hexes; what is sent across the wire.
local m_cachedSelectedPlacementPlotId :number = -1; -- Hex the cursor is currently focused on
-- ===========================================================================
-- Code related to the Wonder Placement interface mode
-- ===========================================================================
function ConfirmPlaceWonder( pInputStruct:table )
local plotId = UI.GetCursorPlotID();
if (not Map.IsPlot(plotId)) then
return false;
end
local kPlot = Map.GetPlotByIndex(plotId);
local eBuilding = UI.GetInterfaceModeParameter(CityOperationTypes.PARAM_BUILDING_TYPE);
local tParameters = {};
tParameters[CityOperationTypes.PARAM_X] = kPlot:GetX();
tParameters[CityOperationTypes.PARAM_Y] = kPlot:GetY();
tParameters[CityOperationTypes.PARAM_BUILDING_TYPE] = eBuilding;
tParameters[CityOperationTypes.PARAM_INSERT_MODE] = CityOperationTypes.VALUE_EXCLUSIVE;
local pSelectedCity = UI.GetHeadSelectedCity();
if (pSelectedCity ~= nil) then
local pBuildingInfo = GameInfo.Buildings[eBuilding];
local bCanStart, tResults = CityManager.CanStartOperation( pSelectedCity, CityOperationTypes.BUILD, tParameters, true);
if pBuildingInfo ~= nil and bCanStart then
local sConfirmText :string = Locale.Lookup("LOC_DISTRICT_ZONE_CONFIRM_WONDER_POPUP", pBuildingInfo.Name);
if (tResults ~= nil and tResults[CityOperationResults.SUCCESS_CONDITIONS] ~= nil) then
if (table.count(tResults[CityOperationResults.SUCCESS_CONDITIONS]) ~= 0) then
sConfirmText = sConfirmText .. "[NEWLINE]";
end
for i,v in ipairs(tResults[CityOperationResults.SUCCESS_CONDITIONS]) do
sConfirmText = sConfirmText .. "[NEWLINE]" .. Locale.Lookup(v);
end
end
local pPopupDialog :table = PopupDialogInGame:new("PlaceWonderAt_X" .. kPlot:GetX() .. "_Y" .. kPlot:GetY()); -- unique identifier
pPopupDialog:AddText(sConfirmText);
pPopupDialog:AddButton(Locale.Lookup("LOC_YES"), function()
CityManager.RequestOperation(pSelectedCity, CityOperationTypes.BUILD, tParameters);
UI.PlaySound("Build_Wonder");
ExitPlacementMode();
end);
pPopupDialog:AddButton(Locale.Lookup("LOC_NO"), nil);
pPopupDialog:Open();
end
else
ExitPlacementMode( true );
end
return true;
end
-- ===========================================================================
-- Find the artdef (texture) for the plots we are considering
-- ===========================================================================
function RealizePlotArtForWonderPlacement()
-- Reset the master table of hexes, tracking what will be sent to the engine.
m_hexesDistrictPlacement = {};
m_cachedSelectedPlacementPlotId = -1;
local kNonShadowHexes:table = {}; -- Holds plot IDs of hexes to not be shadowed.
UIManager:SetUICursor(CursorTypes.RANGE_ATTACK);
UILens.SetActive("DistrictPlacement"); -- turn on all district layers and district adjacency bonus layers
local pSelectedCity = UI.GetHeadSelectedCity();
if pSelectedCity ~= nil then
local buildingHash:number = UI.GetInterfaceModeParameter(CityOperationTypes.PARAM_BUILDING_TYPE);
local building:table = GameInfo.Buildings[buildingHash];
local tParameters :table = {};
tParameters[CityOperationTypes.PARAM_BUILDING_TYPE] = buildingHash;
local tResults :table = CityManager.GetOperationTargets( pSelectedCity, CityOperationTypes.BUILD, tParameters );
-- Highlight the plots where the city can place the wonder
if (tResults[CityOperationResults.PLOTS] ~= nil and table.count(tResults[CityOperationResults.PLOTS]) ~= 0) then
local kPlots = tResults[CityOperationResults.PLOTS];
for i, plotId in ipairs(kPlots) do
local kPlot :table = Map.GetPlotByIndex(plotId);
local plotInfo :table = GetViewPlotInfo( kPlot );
plotInfo.hexArtdef = "Placement_Valid";
plotInfo.selectable = true;
m_hexesDistrictPlacement[plotId]= plotInfo;
table.insert( kNonShadowHexes, plotId );
end
end
-- Plots that aren't owned, but could be (and hence, could be a great spot for that wonder!)
tParameters = {};
tParameters[CityCommandTypes.PARAM_PLOT_PURCHASE] = UI.GetInterfaceModeParameter(CityCommandTypes.PARAM_PLOT_PURCHASE);
local tResults = CityManager.GetCommandTargets( pSelectedCity, CityCommandTypes.PURCHASE, tParameters );
if (tResults[CityCommandResults.PLOTS] ~= nil and table.count(tResults[CityCommandResults.PLOTS]) ~= 0) then
local kPurchasePlots = tResults[CityCommandResults.PLOTS];
for i, plotId in ipairs(kPurchasePlots) do
-- Highlight any purchaseable plot the Wonder could go on
local kPlot :table = Map.GetPlotByIndex(plotId);
if kPlot:CanHaveWonder(building.Index, pSelectedCity:GetOwner(), pSelectedCity:GetID()) then
local plotInfo :table = GetViewPlotInfo( kPlot );
plotInfo.hexArtdef = "Placement_Purchase";
plotInfo.selectable = true;
plotInfo.purchasable = true;
m_hexesDistrictPlacement[plotId]= plotInfo;
end
end
end
-- Send all the hex information to the engine for visualization.
local hexIndexes:table = {};
for i,plotInfo in pairs(m_hexesDistrictPlacement) do
UILens.SetAdjacencyBonusDistict( plotInfo.index, plotInfo.hexArtdef, plotInfo.adjacent );
end
LuaEvents.StrategicView_MapPlacement_AddDistrictPlacementShadowHexes( kNonShadowHexes );
end
end
-- ===========================================================================
-- Mode to place a Wonder Building
-- ===========================================================================
function OnInterfaceModeEnter_BuildingPlacement( eNewMode:number )
UI.SetFixedTiltMode( true );
UIManager:SetUICursor(CursorTypes.RANGE_ATTACK); --here?
RealizePlotArtForWonderPlacement();
end
-- ===========================================================================
-- Guaranteed to be called when leaving building placement
-- ===========================================================================
function OnInterfaceModeLeave_BuildingPlacement( eNewMode:number )
LuaEvents.StrategicView_MapPlacement_ClearDistrictPlacementShadowHexes();
UI.SetFixedTiltMode( false );
end
-- ===========================================================================
-- Explicitly leaving district placement; may not be called if the user
-- is entering another mode by selecting a different UI element which in-turn
-- triggers the exit.
-- ===========================================================================
function ExitPlacementMode( isCancelled:boolean )
UI.SetInterfaceMode(InterfaceModeTypes.SELECTION);
if isCancelled then
LuaEvents.StrageticView_MapPlacement_ProductionOpen();
end
end
-- ===========================================================================
-- Confirm before placing a district down
-- ===========================================================================
function ConfirmPlaceDistrict( pInputStruct:table)
local plotId = UI.GetCursorPlotID();
if (not Map.IsPlot(plotId)) then
return;
end
local kPlot = Map.GetPlotByIndex(plotId);
local districtHash:number = UI.GetInterfaceModeParameter(CityOperationTypes.PARAM_DISTRICT_TYPE);
local tParameters = {};
tParameters[CityOperationTypes.PARAM_X] = kPlot:GetX();
tParameters[CityOperationTypes.PARAM_Y] = kPlot:GetY();
tParameters[CityOperationTypes.PARAM_DISTRICT_TYPE] = districtHash;
tParameters[CityOperationTypes.PARAM_INSERT_MODE] = CityOperationTypes.VALUE_EXCLUSIVE;
local pSelectedCity = UI.GetHeadSelectedCity();
if (pSelectedCity ~= nil) then
local pDistrictInfo = GameInfo.Districts[districtHash];
local bCanStart, tResults = CityManager.CanStartOperation( pSelectedCity, CityOperationTypes.BUILD, tParameters, true);
if pDistrictInfo ~= nil and bCanStart then
local sConfirmText :string = Locale.Lookup("LOC_DISTRICT_ZONE_CONFIRM_DISTRICT_POPUP", pDistrictInfo.Name);
if (tResults ~= nil and tResults[CityOperationResults.SUCCESS_CONDITIONS] ~= nil) then
if (table.count(tResults[CityOperationResults.SUCCESS_CONDITIONS]) ~= 0) then
sConfirmText = sConfirmText .. "[NEWLINE]";
end
for i,v in ipairs(tResults[CityOperationResults.SUCCESS_CONDITIONS]) do
sConfirmText = sConfirmText .. "[NEWLINE]" .. Locale.Lookup(v);
end
end
local pPopupDialog :table = PopupDialogInGame:new("PlaceDistrictAt_X" .. kPlot:GetX() .. "_Y" .. kPlot:GetY()); -- unique identifier
pPopupDialog:AddText(sConfirmText);
pPopupDialog:AddButton(Locale.Lookup("LOC_YES"), function()
CityManager.RequestOperation(pSelectedCity, CityOperationTypes.BUILD, tParameters);
ExitPlacementMode();
end);
pPopupDialog:AddButton(Locale.Lookup("LOC_NO"), nil);
pPopupDialog:Open();
end
else
ExitPlacementMode( true );
end
end
-- ===========================================================================
-- Adds a plot and all the adjacencent plots, unless already added.
-- ARGS: plot, gamecore plot object
-- RETURNS: A new/updated plotInfo table
-- ===========================================================================
function GetViewPlotInfo( kPlot:table )
local plotId :number = kPlot:GetIndex();
local plotInfo :table = m_hexesDistrictPlacement[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
-- ===========================================================================
-- Obtain a table of adjacency bonuses
-- ===========================================================================
function AddAdjacentPlotBonuses( kPlot:table, districtType:string, pSelectedCity: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 );
--print( "Checking from: (" .. tostring(x) .. ", " .. tostring(y) .. ") to (" .. tostring(adjacentPlot:GetX()) .. ", " .. tostring(adjacentPlot:GetY()) .. ") Artdef:'"..artdefIconName.."'");
if artdefIconName ~= nil and artdefIconName ~= "" then
local districtViewInfo :table = GetViewPlotInfo( adjacentPlot );
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
}
);
m_hexesDistrictPlacement[adjacentPlot:GetIndex()] = districtViewInfo;
end
end
end
end
end
-- ===========================================================================
-- Find the artdef (texture) for the plot itself as well as the icons
-- that are on the borders signifying why a hex receives a certain bonus.
-- ===========================================================================
function RealizePlotArtForDistrictPlacement()
-- Reset the master table of hexes, tracking what will be sent to the engine.
m_hexesDistrictPlacement = {};
m_cachedSelectedPlacementPlotId = -1;
local kNonShadowHexes:table = {}; -- Holds plot IDs of hexes to not be shadowed.
UIManager:SetUICursor(CursorTypes.RANGE_ATTACK);
UILens.SetActive("DistrictPlacement"); -- turn on all district layers and district adjacency bonus layers
local pSelectedCity = UI.GetHeadSelectedCity();
if pSelectedCity ~= nil then
local districtHash:number = UI.GetInterfaceModeParameter(CityOperationTypes.PARAM_DISTRICT_TYPE);
local district:table = GameInfo.Districts[districtHash];
local tParameters :table = {};
tParameters[CityOperationTypes.PARAM_DISTRICT_TYPE] = districtHash;
local tResults :table = CityManager.GetOperationTargets( pSelectedCity, CityOperationTypes.BUILD, tParameters );
-- Highlight the plots where the city can place the district
if (tResults[CityOperationResults.PLOTS] ~= nil and table.count(tResults[CityOperationResults.PLOTS]) ~= 0) then
local kPlots = tResults[CityOperationResults.PLOTS];
for i, plotId in ipairs(kPlots) do
local kPlot :table = Map.GetPlotByIndex(plotId);
local plotInfo :table = GetViewPlotInfo( kPlot );
plotInfo.hexArtdef = "Placement_Valid";
plotInfo.selectable = true;
m_hexesDistrictPlacement[plotId]= plotInfo;
AddAdjacentPlotBonuses( kPlot, district.DistrictType, pSelectedCity );
table.insert( kNonShadowHexes, 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 can host a district, after some action(s) are first taken.
if (tResults[CityOperationResults.BLOCKED_PLOTS] ~= nil and table.count(tResults[CityOperationResults.BLOCKED_PLOTS]) ~= 0) then
local kPlots = tResults[CityOperationResults.BLOCKED_PLOTS];
for i, plotId in ipairs(kPlots) do
local kPlot :table = Map.GetPlotByIndex(plotId);
local plotInfo :table = GetViewPlotInfo( kPlot );
plotInfo.hexArtdef = "Placement_Blocked";
m_hexesDistrictPlacement[plotId]= plotInfo;
AddAdjacentPlotBonuses( kPlot, district.DistrictType, pSelectedCity );
table.insert( kNonShadowHexes, plotId );
end
end
--]]
-- Plots that a player will NEVER be able to place a district on
-- if (tResults[CityOperationResults.MOUNTAIN_PLOTS] ~= nil and table.count(tResults[CityOperationResults.MOUNTAIN_PLOTS]) ~= 0) then
-- local kPlots = tResults[CityOperationResults.MOUNTAIN_PLOTS];
-- for i, plotId in ipairs(kPlots) do
-- local kPlot :table = Map.GetPlotByIndex(plotId);
-- local plotInfo :table = GetViewPlotInfo( kPlot );
-- plotInfo.hexArtdef = "Placement_Invalid";
-- m_hexesDistrictPlacement[plotId]= plotInfo;
-- end
-- end
-- Plots that arent't owned, but could be (and hence, could be a great spot for that district!)
tParameters = {};
tParameters[CityCommandTypes.PARAM_PLOT_PURCHASE] = UI.GetInterfaceModeParameter(CityCommandTypes.PARAM_PLOT_PURCHASE);
local tResults = CityManager.GetCommandTargets( pSelectedCity, CityCommandTypes.PURCHASE, tParameters );
if (tResults[CityCommandResults.PLOTS] ~= nil and table.count(tResults[CityCommandResults.PLOTS]) ~= 0) then
local kPurchasePlots = tResults[CityCommandResults.PLOTS];
for i, plotId in ipairs(kPurchasePlots) do
-- Only highlight certain plots (usually if there is a bonus to be gained).
local kPlot :table = Map.GetPlotByIndex(plotId);
local isValid :boolean = IsShownIfPlotPurchaseable( district.Index, pSelectedCity, kPlot );
if isValid and kPlot:CanHaveDistrict(district.DistrictType, pSelectedCity:GetOwner(), pSelectedCity:GetID()) then
local plotInfo :table = GetViewPlotInfo( kPlot );
plotInfo.hexArtdef = "Placement_Purchase";
plotInfo.selectable = true;
plotInfo.purchasable = true;
m_hexesDistrictPlacement[plotId]= plotInfo;
end
end
end
-- Send all the hex information to the engine for visualization.
local hexIndexes:table = {};
for i,plotInfo in pairs(m_hexesDistrictPlacement) do
UILens.SetAdjacencyBonusDistict( plotInfo.index, plotInfo.hexArtdef, plotInfo.adjacent );
end
LuaEvents.StrategicView_MapPlacement_AddDistrictPlacementShadowHexes( kNonShadowHexes );
end
end
-- ===========================================================================
-- Show the different potential district placement areas...
-- ===========================================================================
function OnInterfaceModeEnter_DistrictPlacement( eNewMode:number )
RealizePlotArtForDistrictPlacement();
UI.SetFixedTiltMode( true );
end
function OnInterfaceModeLeave_DistrictPlacement( eNewMode:number )
LuaEvents.StrategicView_MapPlacement_ClearDistrictPlacementShadowHexes();
UI.SetFixedTiltMode( false );
end
-- ===========================================================================
--
-- ===========================================================================
function OnCityMadePurchase_StrategicView_MapPlacement(owner:number, cityID:number, plotX:number, plotY:number, purchaseType, objectType)
if owner ~= Game.GetLocalPlayer() then
return;
end
if purchaseType == EventSubTypes.PLOT then
-- Make sure city made purchase and it's the right mode.
if (UI.GetInterfaceMode() == InterfaceModeTypes.DISTRICT_PLACEMENT) then
-- Clear existing art then re-realize
UILens.ClearLayerHexes( LensLayers.ADJACENCY_BONUS_DISTRICTS );
UILens.ClearLayerHexes( LensLayers.DISTRICTS );
RealizePlotArtForDistrictPlacement();
elseif (UI.GetInterfaceMode() == InterfaceModeTypes.BUILDING_PLACEMENT) then
-- Clear existing art then re-realize
UILens.ClearLayerHexes( LensLayers.ADJACENCY_BONUS_DISTRICTS );
UILens.ClearLayerHexes( LensLayers.DISTRICTS );
RealizePlotArtForWonderPlacement();
end
end
end
-- ===========================================================================
-- Whenever the mouse moves while in district or wonder placement mode.
-- ===========================================================================
function RealizeCurrentPlaceDistrictOrWonderPlot()
local currentPlotId :number = UI.GetCursorPlotID();
if (not Map.IsPlot(currentPlotId)) then
return;
end
if currentPlotId == m_cachedSelectedPlacementPlotId then
return;
end
-- Reset the artdef for the currently selected hex
if m_cachedSelectedPlacementPlotId ~= nil and m_cachedSelectedPlacementPlotId ~= -1 then
local hex:table = m_hexesDistrictPlacement[m_cachedSelectedPlacementPlotId];
if hex ~= nil and hex.hexArtdef ~= nil and hex.selectable then
UILens.UnFocusHex( LensLayers.DISTRICTS, hex.index, hex.hexArtdef );
end
end
m_cachedSelectedPlacementPlotId = currentPlotId;
-- New HEX update it to the selected form.
if m_cachedSelectedPlacementPlotId ~= -1 then
local hex:table = m_hexesDistrictPlacement[m_cachedSelectedPlacementPlotId];
if hex ~= nil and hex.hexArtdef ~= nil and hex.selectable then
UILens.FocusHex( LensLayers.DISTRICTS, hex.index, hex.hexArtdef );
end
end
end