-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcontrol.lua
More file actions
264 lines (209 loc) · 7.61 KB
/
control.lua
File metadata and controls
264 lines (209 loc) · 7.61 KB
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
local radar_guide_mode = {
never = 0,
when_placing = 1,
always = 2,
}
local default_radar_grid = 7; --in chunks. default radar range = 3, grid = (range*2)+1
local default_radar_offset = { x=0, y=0 } --chunk of the central radar, in case 0,0 isn't where things start
local default_guide_mode = radar_guide_mode.always
local radar_entity_ranges = nil;
--see data-final-fixes.lua for more details
function getRadarRange(name)
if radar_entity_ranges == nil then
radar_entity_ranges = loadstring(game.entity_prototypes["RADAR_GRID_GUIDE:RANGE_DATA_HACK"].order)()
end
return radar_entity_ranges[name]
end
local chunk_size = 32;
local check_per_tick = 30;
local tick_offset = 24;
function modeToString(mode)
if mode == radar_guide_mode.never then
return "never"
elseif mode == radar_guide_mode.when_placing then
return "when placing"
elseif mode == radar_guide_mode.always then
return "always"
else
return "unknown("..mode..")"
end
end
function posToChunk(pos)
return { x=math.floor(pos.x/chunk_size), y=math.floor(pos.y/chunk_size) }
end
function nearestRadarChunk(player,chunk)
local radar_offset = getPlayerData(player,"radar-offset", default_radar_offset)
local radar_grid = getPlayerData(player,"radar-grid", default_radar_grid)
return { x=math.floor((chunk.x-radar_offset.x)/radar_grid+0.5)*radar_grid+radar_offset.x, y=math.floor((chunk.y-radar_offset.y)/radar_grid+0.5)*radar_grid+radar_offset.y }
end
function isRadar(name)
local proto = game.entity_prototypes[name]
if proto and proto.type == "radar" then
return true
end
return false
end
function isPlayerHoldingRadar(player)
local held = player.cursor_stack
if held and held.valid and held.valid_for_read then
-- is it a radar?
if isRadar(held.name) then
return true
end
-- is it a blueprint containing a radar?
if held.type == "blueprint" or held.type == "blueprint-book" then
if held.type == "blueprint-book" then
-- blueprint books might not have a blueprint in the active slot
local book_bp_active = held.get_inventory(defines.inventory.item_main)
if book_bp_active and book_bp_active.is_empty() then
return false
end
end
if not held.is_blueprint_setup() then
return false
end
local bp = held.get_blueprint_entities()
if not bp then
-- tile-only blueprints have nil entities, rather than an empty list
return false
end
for _, bpentity in pairs(bp) do
if isRadar(bpentity.name) then
return true
end
end
end
end
return false
end
function markChunk(chunk, surface)
if not surface.valid then
return
end
local key = surface.name .. ':' .. chunk.x .. ',' .. chunk.y
if global.marked_chunks[key] == nil then
pos_tl = { x = chunk.x * chunk_size, y = chunk.y * chunk_size }
data = {}
data.tl = surface.create_entity({ name = 'top-left-radar-grid-guide', position = {x=pos_tl.x, y=pos_tl.y} })
data.tr = surface.create_entity({ name = 'top-right-radar-grid-guide', position = {x=pos_tl.x+chunk_size, y=pos_tl.y} })
data.bl = surface.create_entity({ name = 'bottom-left-radar-grid-guide', position = {x=pos_tl.x, y=pos_tl.y+chunk_size} })
data.br = surface.create_entity({ name = 'bottom-right-radar-grid-guide', position = {x=pos_tl.x+chunk_size, y=pos_tl.y+chunk_size} })
global.marked_chunks[key] = data;
end
end
function clearAllMarks()
for _, data in pairs(global.marked_chunks) do
if data.tl.valid then
data.tl.destroy()
end
if data.tr.valid then
data.tr.destroy()
end
if data.bl.valid then
data.bl.destroy()
end
if data.br.valid then
data.br.destroy()
end
end
global.marked_chunks = {}
end
function updateRadarMarkers()
if global.marked_chunks == nil then
global.marked_chunks = {}
end
clearAllMarks()
for _, player in pairs(game.players) do
-- show the guide dependant on the user mode
local mode = getPlayerData(player, "radar-mode", default_radar_mode)
local show = false
if mode == radar_guide_mode.always then
show = true
elseif mode == radar_guide_mode.when_placing and isPlayerHoldingRadar(player) then
show = true
end
-- always show the guide when hovering over a radar
if player.selected and player.selected.type == "radar" then
show = true
end
if show then
chunk = posToChunk(player.position)
radar_chunk = nearestRadarChunk(player,chunk)
markChunk(radar_chunk, player.surface)
-- also update map
local chunk_area = {{radar_chunk.x*chunk_size, radar_chunk.y*chunk_size},{radar_chunk.x*chunk_size+chunk_size-1, radar_chunk.y*chunk_size+chunk_size-1}}
player.force.chart(player.surface, chunk_area)
end
end
end
function getPlayerData(player,key,default)
if global.player_config then
if global.player_config[player.name] then
if global.player_config[player.name][key] ~= nil then
return global.player_config[player.name][key]
end
end
end
return default
end
function setPlayerData(player,key,value)
if global.player_config == nil then
global.player_config = {}
end
if global.player_config[player.name] == nil then
global.player_config[player.name] = {}
end
global.player_config[player.name][key] = value
end
function onHotkey(event)
local player = event.player_index and game.players[event.player_index] or nil
if player then
if player.selected and player.selected.type == "radar" then
-- if a radar is selected when the key is pressed, take radar position and range for future grid guides
local chunk = posToChunk(player.selected.position)
--range = radar_proto.max_distance_of_nearby_sector_revealed
local range = getRadarRange(player.selected.name)
local grid = range*2 + 1
player.print("Radar Grid Guide: center position reconfigured to chunk ("..chunk.x..","..chunk.y.."), with a range of ±"..range.." chunks - grid size "..grid.." chunks")
setPlayerData(player, "radar-offset", chunk)
setPlayerData(player, "radar-grid", grid)
else
-- no radar selected, switch the guide mode
local mode = getPlayerData(player, "radar-mode", default_guide_mode)
if mode == radar_guide_mode.never then mode=radar_guide_mode.when_placing
elseif mode == radar_guide_mode.when_placing then mode = radar_guide_mode.always
else mode = radar_guide_mode.never
end
player.print("Radar Grid Guide: mode switched to: "..modeToString(mode))
setPlayerData(player, "radar-mode", mode)
end
end
--finally update markers to apply any changes instantly
updateRadarMarkers()
end
function onTick()
local need_update = false
--TODO: change to monitor changes to player positions, and only update wwhen they move far enough
if ((game.tick + tick_offset) % check_per_tick == 0) then
need_update = true
end
-- there's no 'on_selection_changed' event fired when player.selected changes - fake something close to that here
-- (but will be added in 0.15 - https://forums.factorio.com/viewtopic.php?f=65&t=32796)
for _,player in pairs(game.players) do
local last_sel_radar = getPlayerData(player,"selected-radar",false)
local this_sel_radar = player.selected ~= nil and player.selected.type == 'radar'
if last_sel_radar ~= this_sel_radar then
need_update = true
setPlayerData(player, "selected-radar", this_sel_radar)
end
end
if need_update then
updateRadarMarkers()
end
end
function onOtherEvent()
updateRadarMarkers()
end
script.on_event(defines.events.on_tick, onTick)
script.on_event(defines.events.on_player_cursor_stack_changed, onOtherEvent)
script.on_event("radar-grid-guide-hotkey", onHotkey)