diff --git a/changelog.txt b/changelog.txt index e76c5e2..469f1bc 100755 --- a/changelog.txt +++ b/changelog.txt @@ -6,6 +6,7 @@ Date: 10. 13. 2019 - Squad formation now has a gathering delay to allow all members to make the initial group Bugfixes: - Fixed old savegames penalties having nil chunk index + - Fixed that mining a resource by hand unregister all remaining resource on a tile --------------------------------------------------------------------------------------------------- Version: 0.17.28 diff --git a/control.lua b/control.lua index e5c4aef..0e27c8f 100755 --- a/control.lua +++ b/control.lua @@ -595,10 +595,8 @@ local function onBuild(event) local entity = event.created_entity or event.entity if (entity.surface.index == natives.activeSurface) then if (entity.type == "resource") and (entity.force.name == "neutral") then - -- print("registering resource", entity.name) registerResource(entity, map) else - -- print("registering entity", entity.name) accountPlayerEntity(map, entity, natives, true, false) if natives.safeBuildings then if natives.safeEntities[entity.type] or natives.safeEntityName[entity.name] then @@ -614,7 +612,9 @@ local function onMine(event) local surface = entity.surface if (surface.index == natives.activeSurface) then if (entity.type == "resource") and (entity.force.name == "neutral") then - unregisterResource(entity, map) + if (entity.amount == 0) then + unregisterResource(entity, map) + end else accountPlayerEntity(map, entity, natives, false, false) end diff --git a/libs/Constants.lua b/libs/Constants.lua index 439eec0..028b79a 100755 --- a/libs/Constants.lua +++ b/libs/Constants.lua @@ -475,12 +475,12 @@ constants.PATH_FINDER_SHORT_CACHE_SIZE = 25 constants.PATH_FINDER_LONG_REQUEST_RATIO = 5 constants.PATH_FINDER_MIN_STEPS_TO_CHECK_PATH = 1000 -constants.MAX_FAILED_BEHAVIORS = 100 +constants.MAX_FAILED_BEHAVIORS = 1000 constants.UNIT_GROUP_DISOWN_DISTANCE = 100 constants.UNIT_GROUP_TICK_TOLERANCE = 3600000 -constants.UNIT_GROUP_MAX_RADIUS = 25 +constants.UNIT_GROUP_MAX_RADIUS = 15 constants.UNIT_GROUP_MAX_SPEED_UP = 2 constants.UNIT_GROUP_MAX_SLOWDOWN = 1.0 constants.UNIT_GROUP_SLOWDOWN_FACTOR = 1.0 diff --git a/tests.lua b/tests.lua index 481d8b5..7988667 100755 --- a/tests.lua +++ b/tests.lua @@ -13,16 +13,16 @@ function tests.pheromoneLevels(size) local playerChunkX = math.floor(player.position.x / 32) * constants.CHUNK_SIZE local playerChunkY = math.floor(player.position.y / 32) * constants.CHUNK_SIZE if not size then - size = 3 * constants.CHUNK_SIZE + size = 3 * constants.CHUNK_SIZE else - size = size * constants.CHUNK_SIZE + size = size * constants.CHUNK_SIZE end print("------") print(#global.map.processQueue) print(playerChunkX .. ", " .. playerChunkY) print("--") for y=playerChunkY-size, playerChunkY+size,32 do - for x=playerChunkX-size, playerChunkX+size,32 do + for x=playerChunkX-size, playerChunkX+size,32 do if (global.map[x] ~= nil) then local chunk = global.map[x][y] if (chunk ~= nil) then @@ -30,34 +30,34 @@ function tests.pheromoneLevels(size) for i=1,#chunk do str = str .. " " .. tostring(i) .. "/" .. tostring(chunk[i]) end - str = str .. " " .. "p/" .. game.surfaces[global.natives.activeSurface].get_pollution(chunk) .. " " .. "n/" .. chunkPropertyUtils.getNestCount(global.map, chunk) .. " " .. "w/" .. chunkPropertyUtils.getWormCount(global.map, chunk) .. " pg/" .. chunkPropertyUtils.getPlayerBaseGenerator(global.map, chunk) - if (chunk.x == playerChunkX) and (chunk.y == playerChunkY) then - print("=============") - print(chunk.x, chunk.y, str) - print("=============") - else - print(chunk.x, chunk.y, str) - end - -- print(str) - print("----") + str = str .. " " .. "p/" .. game.surfaces[global.natives.activeSurface].get_pollution(chunk) .. " " .. "n/" .. chunkPropertyUtils.getNestCount(global.map, chunk) .. " " .. "w/" .. chunkPropertyUtils.getWormCount(global.map, chunk) .. " pg/" .. chunkPropertyUtils.getPlayerBaseGenerator(global.map, chunk) + if (chunk.x == playerChunkX) and (chunk.y == playerChunkY) then + print("=============") + print(chunk.x, chunk.y, str) + print("=============") + else + print(chunk.x, chunk.y, str) + end + -- print(str) + print("----") end end end - print("------------------") + print("------------------") end end function tests.killActiveSquads() print("--") for i=1, #global.natives.squads do - local squad = global.natives.squads[i] - if (squad.group.valid) then - local members = squad.group.members - for x=1, #members do - local member = members[x] - local val = member.valid and member.die() - end - end + local squad = global.natives.squads[i] + if (squad.group.valid) then + local members = squad.group.members + for x=1, #members do + local member = members[x] + local val = member.valid and member.die() + end + end end end @@ -65,69 +65,69 @@ function tests.activeSquads() print("-----") print("Squads", #global.natives.squads) for i=1, #global.natives.squads do - print("-") + print("-") local squad = global.natives.squads[i] - local squadHealth = 0 - local squadMakeup = {} + local squadHealth = 0 + local squadMakeup = {} if squad.group.valid then - for x=1,#squad.group.members do - local member = squad.group.members[x].prototype - if not squadMakeup[member.name] then - squadMakeup[member.name] = 0 - end + for x=1,#squad.group.members do + local member = squad.group.members[x].prototype + if not squadMakeup[member.name] then + squadMakeup[member.name] = 0 + end - squadHealth = squadHealth + member.max_health - squadMakeup[member.name] = squadMakeup[member.name] + 1 - end + squadHealth = squadHealth + member.max_health + squadMakeup[member.name] = squadMakeup[member.name] + 1 + end print(math.floor(squad.group.position.x * 0.03125), math.floor(squad.group.position.y * 0.03125), squad.status, squad.group.state, #squad.group.members, squad.cycles, squad.group.group_number, squadHealth) - -- print(serpent.dump(squadResistances)) - print(serpent.dump(squadMakeup)) + -- print(serpent.dump(squadResistances)) + print(serpent.dump(squadMakeup)) print(serpent.dump(squad)) end end print("---") print("pending", #global.natives.pendingAttack) for i=1, #global.natives.pendingAttack do - print("-") + print("-") local squad = global.natives.pendingAttack[i] - local squadHealth = 0 - local squadMakeup = {} + local squadHealth = 0 + local squadMakeup = {} if squad.group.valid then - for x=1,#squad.group.members do - local member = squad.group.members[x].prototype - if not squadMakeup[member.name] then - squadMakeup[member.name] = 0 - end + for x=1,#squad.group.members do + local member = squad.group.members[x].prototype + if not squadMakeup[member.name] then + squadMakeup[member.name] = 0 + end - squadHealth = squadHealth + member.max_health - squadMakeup[member.name] = squadMakeup[member.name] + 1 - end + squadHealth = squadHealth + member.max_health + squadMakeup[member.name] = squadMakeup[member.name] + 1 + end print(math.floor(squad.group.position.x * 0.03125), math.floor(squad.group.position.y * 0.03125), squad.status, squad.group.state, #squad.group.members, squad.cycles, squadHealth, squad.group.group_number) - -- print(serpent.dump(squadResistances)) - print(serpent.dump(squadMakeup)) + -- print(serpent.dump(squadResistances)) + print(serpent.dump(squadMakeup)) print(serpent.dump(squad)) end end print("---") print("building", #global.natives.building) for i=1, #global.natives.building do - print("-") + print("-") local squad = global.natives.building[i] - local squadHealth = 0 - local squadMakeup = {} + local squadHealth = 0 + local squadMakeup = {} if squad.group.valid then - for x=1,#squad.group.members do - local member = squad.group.members[x].prototype - if not squadMakeup[member.name] then - squadMakeup[member.name] = 0 - end + for x=1,#squad.group.members do + local member = squad.group.members[x].prototype + if not squadMakeup[member.name] then + squadMakeup[member.name] = 0 + end - squadHealth = squadHealth + member.max_health - squadMakeup[member.name] = squadMakeup[member.name] + 1 - end + squadHealth = squadHealth + member.max_health + squadMakeup[member.name] = squadMakeup[member.name] + 1 + end print(math.floor(squad.group.position.x * 0.03125), math.floor(squad.group.position.y * 0.03125), squad.status, squad.group.state, #squad.group.members, squad.cycles, squad.group.group_number, squadHealth) - -- print(serpent.dump(squadResistances)) - print(serpent.dump(squadMakeup)) + -- print(serpent.dump(squadResistances)) + print(serpent.dump(squadMakeup)) print(serpent.dump(squad)) end end @@ -138,8 +138,8 @@ function tests.entitiesOnPlayerChunk() local chunkX = math.floor(playerPosition.x * 0.03125) * 32 local chunkY = math.floor(playerPosition.y * 0.03125) * 32 local entities = game.surfaces[global.natives.activeSurface].find_entities_filtered({area={{chunkX, chunkY}, - {chunkX + constants.CHUNK_SIZE, chunkY + constants.CHUNK_SIZE}}, - force="player"}) + {chunkX + constants.CHUNK_SIZE, chunkY + constants.CHUNK_SIZE}}, + force="player"}) for i=1, #entities do print(entities[i].name) end @@ -151,8 +151,8 @@ function tests.findNearestPlayerEnemy() local chunkX = math.floor(playerPosition.x * 0.03125) * 32 local chunkY = math.floor(playerPosition.y * 0.03125) * 32 local entity = game.surfaces[global.natives.activeSurface].find_nearest_enemy({position={chunkX, chunkY}, - max_distance=constants.CHUNK_SIZE, - force = "enemy"}) + max_distance=constants.CHUNK_SIZE, + force = "enemy"}) if (entity ~= nil) then print(entity.name) end @@ -180,10 +180,10 @@ function tests.fillableDirtTest() local chunkX = math.floor(playerPosition.x * 0.03125) * 32 local chunkY = math.floor(playerPosition.y * 0.03125) * 32 game.surfaces[global.natives.activeSurface].set_tiles({{name="fillableDirt", position={chunkX-1, chunkY-1}}, - {name="fillableDirt", position={chunkX, chunkY-1}}, - {name="fillableDirt", position={chunkX-1, chunkY}}, - {name="fillableDirt", position={chunkX, chunkY}}}, - false) + {name="fillableDirt", position={chunkX, chunkY-1}}, + {name="fillableDirt", position={chunkX-1, chunkY}}, + {name="fillableDirt", position={chunkX, chunkY}}}, + false) end function tests.tunnelTest() @@ -199,7 +199,7 @@ function tests.createEnemy(x,d) local chunkY = math.floor(playerPosition.y * 0.03125) * 32 local a = {name=x, position={chunkX, chunkY}, force="enemy"} if d then - a['direction'] = d + a['direction'] = d end return game.surfaces[global.natives.activeSurface].create_entity(a) end @@ -207,13 +207,13 @@ end function tests.registeredNest(x) local entity = tests.createEnemy(x) chunk.registerEnemyBaseStructure(global.map, - entity, - nil) + entity, + nil) end function tests.attackOrigin() local enemy = game.surfaces[global.natives.activeSurface].find_nearest_enemy({position={0,0}, - max_distance = 1000}) + max_distance = 1000}) if (enemy ~= nil) and enemy.valid then print(enemy, enemy.unit_number) enemy.set_command({type=defines.command.attack_area, @@ -234,29 +234,29 @@ end function tests.gaussianRandomTest() local result = {} for x=0,100,1 do - result[x] = 0 + result[x] = 0 end for _=1,10000 do - local s = mathUtils.roundToNearest(mathUtils.gaussianRandomRange(50, 25, 0, 100), 1) - result[s] = result[s] + 1 + local s = mathUtils.roundToNearest(mathUtils.gaussianRandomRange(50, 25, 0, 100), 1) + result[s] = result[s] + 1 end for x=0,100,1 do - print(x, result[x]) + print(x, result[x]) end end function tests.reveal (size) local pos = game.player.character.position game.player.force.chart(game.player.surface, - {{x=-size+pos.x, y=-size+pos.y}, {x=size+pos.x, y=size+pos.y}}) + {{x=-size+pos.x, y=-size+pos.y}, {x=size+pos.x, y=size+pos.y}}) end function tests.baseStats() local natives = global.natives print ("x", "y", "distanceThreshold", "tick", "points", "temperament", "temperamentTick", "state", "stateTick", "alignments") for i=1, #natives.bases do - local base = natives.bases[i] - print(base.x, + local base = natives.bases[i] + print(base.x, base.y, base.distanceThreshold, base.tick, @@ -266,7 +266,7 @@ function tests.baseStats() base.state, base.stateTick, serpent.dump(base.alignment)) - print("---") + print("---") end end @@ -274,34 +274,34 @@ function tests.clearBases() local surface = game.surfaces[global.natives.activeSurface] for x=#global.natives.bases,1,-1 do - local base = global.natives.bases[x] - for c=1,#base.chunks do - local chunk = base.chunks[c] - chunkUtils.clearChunkNests(chunk, surface) - end + local base = global.natives.bases[x] + for c=1,#base.chunks do + local chunk = base.chunks[c] + chunkUtils.clearChunkNests(chunk, surface) + end - base.chunks = {} + base.chunks = {} - if (surface.can_place_entity({name="biter-spawner-powered", position={base.cX * 32, base.cY * 32}})) then - surface.create_entity({name="biter-spawner-powered", position={base.cX * 32, base.cY * 32}}) - local slice = math.pi / 12 - local pos = 0 - for i=1,24 do - if (math.random() < 0.8) then - local distance = mathUtils.roundToNearest(mathUtils.gaussianRandomRange(45, 5, 37, 60), 1) - if (surface.can_place_entity({name="biter-spawner", position={base.cX * 32 + (distance*math.sin(pos)), base.cY * 32 + (distance*math.cos(pos))}})) then - if (math.random() < 0.3) then - surface.create_entity({name="small-worm-turret", position={base.cX * 32 + (distance*math.sin(pos)), base.cY * 32 + (distance*math.cos(pos))}}) - else - surface.create_entity({name="biter-spawner", position={base.cX * 32 + (distance*math.sin(pos)), base.cY * 32 + (distance*math.cos(pos))}}) - end - end - end - pos = pos + slice - end - else - table.remove(global.natives.bases, x) - end + if (surface.can_place_entity({name="biter-spawner-powered", position={base.cX * 32, base.cY * 32}})) then + surface.create_entity({name="biter-spawner-powered", position={base.cX * 32, base.cY * 32}}) + local slice = math.pi / 12 + local pos = 0 + for i=1,24 do + if (math.random() < 0.8) then + local distance = mathUtils.roundToNearest(mathUtils.gaussianRandomRange(45, 5, 37, 60), 1) + if (surface.can_place_entity({name="biter-spawner", position={base.cX * 32 + (distance*math.sin(pos)), base.cY * 32 + (distance*math.cos(pos))}})) then + if (math.random() < 0.3) then + surface.create_entity({name="small-worm-turret", position={base.cX * 32 + (distance*math.sin(pos)), base.cY * 32 + (distance*math.cos(pos))}}) + else + surface.create_entity({name="biter-spawner", position={base.cX * 32 + (distance*math.sin(pos)), base.cY * 32 + (distance*math.cos(pos))}}) + end + end + end + pos = pos + slice + end + else + table.remove(global.natives.bases, x) + end end end @@ -317,55 +317,55 @@ function tests.showBaseGrid() local n = {} for k,v in pairs(global.natives.bases) do - n[v] = k % 4 + n[v] = k % 4 end local chunks = global.map.chunkToBase for chunk,base in pairs(chunks) do - local pick = n[base] - local color = "concrete" - if base.alignment == constants.BASE_ALIGNMENT_NE then - color = "hazard-concrete-left" - elseif (pick == 1) then - color = "water" - elseif (pick == 2) then - color = "deepwater" - elseif (pick == 3) then - color = "water-green" - end - chunkUtils.colorChunk(chunk.x, chunk.y, color, game.surfaces[global.natives.activeSurface]) + local pick = n[base] + local color = "concrete" + if base.alignment == constants.BASE_ALIGNMENT_NE then + color = "hazard-concrete-left" + elseif (pick == 1) then + color = "water" + elseif (pick == 2) then + color = "deepwater" + elseif (pick == 3) then + color = "water-green" + end + chunkUtils.colorChunk(chunk.x, chunk.y, color, game.surfaces[global.natives.activeSurface]) end end function tests.showMovementGrid() local chunks = global.map.processQueue for i=1,#chunks do - local chunk = chunks[i] - local color = "concrete" - if (chunkPropertyUtils.getPassable(global.map, chunk) == constants.CHUNK_ALL_DIRECTIONS) then - color = "hazard-concrete-left" - elseif (chunkPropertyUtils.getPassable(global.map, chunk) == constants.CHUNK_NORTH_SOUTH) then - color = "deepwater" - elseif (chunkPropertyUtils.getPassable(global.map, chunk) == constants.CHUNK_EAST_WEST) then - color = "water-green" - end - chunkUtils.colorChunk(chunk.x, chunk.y, color, game.surfaces[global.natives.activeSurface]) + local chunk = chunks[i] + local color = "concrete" + if (chunkPropertyUtils.getPassable(global.map, chunk) == constants.CHUNK_ALL_DIRECTIONS) then + color = "hazard-concrete-left" + elseif (chunkPropertyUtils.getPassable(global.map, chunk) == constants.CHUNK_NORTH_SOUTH) then + color = "concrete" + elseif (chunkPropertyUtils.getPassable(global.map, chunk) == constants.CHUNK_EAST_WEST) then + color = "stone-path" + end + chunkUtils.colorChunk(chunk.x, chunk.y, color, game.surfaces[global.natives.activeSurface]) end end function tests.colorResourcePoints() local chunks = global.map.processQueue for i=1,#chunks do - local chunk = chunks[i] - local color = "concrete" - if (chunk[constants.RESOURCE_GENERATOR] ~= 0) and (chunk[constants.NEST_COUNT] ~= 0) then - color = "hazard-concrete-left" - elseif (chunk[constants.RESOURCE_GENERATOR] ~= 0) then - color = "deepwater" - elseif (chunk[constants.NEST_COUNT] ~= 0) then - color = "water-green" - end - chunkUtils.colorChunk(chunk.x, chunk.y, color, game.surfaces[global.natives.activeSurface]) + local chunk = chunks[i] + local color = "concrete" + if (chunk[constants.RESOURCE_GENERATOR] ~= 0) and (chunk[constants.NEST_COUNT] ~= 0) then + color = "hazard-concrete-left" + elseif (chunk[constants.RESOURCE_GENERATOR] ~= 0) then + color = "deepwater" + elseif (chunk[constants.NEST_COUNT] ~= 0) then + color = "stone-path" + end + chunkUtils.colorChunk(chunk.x, chunk.y, color, game.surfaces[global.natives.activeSurface]) end end @@ -375,7 +375,7 @@ function tests.entityStats(name, d) local chunkY = math.floor(playerPosition.y * 0.03125) * 32 local a = game.surfaces[global.natives.activeSurface].create_entity({name=name, position={chunkX, chunkY}}) if d then - a['direction'] = d + a['direction'] = d end print(serpent.dump(a)) a.destroy() @@ -384,10 +384,10 @@ end function tests.exportAiState() local printState = function () - local chunks = global.map.processQueue - local s = "" - for i=1,#chunks do - local chunk = chunks[i] + local chunks = global.map.processQueue + local s = "" + for i=1,#chunks do + local chunk = chunks[i] local base = chunkPropertyUtils.getChunkBase(global.map, chunk) local alignmentCount = 0 @@ -399,43 +399,43 @@ function tests.exportAiState() end end - s = s .. table.concat({chunk[constants.MOVEMENT_PHEROMONE], - chunk[constants.BASE_PHEROMONE], - chunk[constants.PLAYER_PHEROMONE], - chunk[constants.RESOURCE_PHEROMONE], - chunkPropertyUtils.getPassable(global.map, chunk), - chunk[constants.CHUNK_TICK], - chunkPropertyUtils.getPathRating(global.map, chunk), - chunk.x, - chunk.y, - chunkPropertyUtils.getNestCount(global.map, chunk), - chunkPropertyUtils.getWormCount(global.map, chunk), - chunkPropertyUtils.getRallyTick(global.map, chunk), - chunkPropertyUtils.getRetreatTick(global.map, chunk), - chunkPropertyUtils.getResourceGenerator(global.map, chunk), - chunkPropertyUtils.getPlayerBaseGenerator(global.map, chunk), - chunkPropertyUtils.getDeathGenerator(global.map, chunk), + s = s .. table.concat({chunk[constants.MOVEMENT_PHEROMONE], + chunk[constants.BASE_PHEROMONE], + chunk[constants.PLAYER_PHEROMONE], + chunk[constants.RESOURCE_PHEROMONE], + chunkPropertyUtils.getPassable(global.map, chunk), + chunk[constants.CHUNK_TICK], + chunkPropertyUtils.getPathRating(global.map, chunk), + chunk.x, + chunk.y, + chunkPropertyUtils.getNestCount(global.map, chunk), + chunkPropertyUtils.getWormCount(global.map, chunk), + chunkPropertyUtils.getRallyTick(global.map, chunk), + chunkPropertyUtils.getRetreatTick(global.map, chunk), + chunkPropertyUtils.getResourceGenerator(global.map, chunk), + chunkPropertyUtils.getPlayerBaseGenerator(global.map, chunk), + chunkPropertyUtils.getDeathGenerator(global.map, chunk), game.surfaces[global.natives.activeSurface].get_pollution(chunk), chunkPropertyUtils.getNestActiveness(global.map, chunk), chunkPropertyUtils.getRaidNestActiveness(global.map, chunk), #chunkPropertyUtils.getSquadsOnChunk(global.map, chunk), alignmentCount}, ",") .. "\n" - end - game.write_file("rampantState.txt", s, false) + end + game.write_file("rampantState.txt", s, false) end return function(interval) - if not interval then - interval = 0 - else - interval = tonumber(interval) - end + if not interval then + interval = 0 + else + interval = tonumber(interval) + end - printState() + printState() - if (interval > 0) then - script.on_nth_tick(interval, printState) - end + if (interval > 0) then + script.on_nth_tick(interval, printState) + end end end @@ -446,16 +446,16 @@ function tests.createEnergyTest(x) local chunkX = math.floor(playerPosition.x * 0.03125) * 32 local chunkY = math.floor(playerPosition.y * 0.03125) * 32 local entities = game.surfaces[global.natives.activeSurface].find_entities_filtered({area={{chunkX, chunkY}, - {chunkX + constants.CHUNK_SIZE, chunkY + constants.CHUNK_SIZE}}, - type = "electric-pole", - force="player"}) + {chunkX + constants.CHUNK_SIZE, chunkY + constants.CHUNK_SIZE}}, + type = "electric-pole", + force="player"}) -- for i=1, #entities do -- print(entities[i].name) -- end local wires if #entities > 0 then - entity.connect_neighbour(entities[1]) + entity.connect_neighbour(entities[1]) end -- if wires then @@ -474,14 +474,14 @@ function tests.unitGroupBuild() local group = surface.create_unit_group({position={-32, -32}}) for i=1,10 do - group.add_member(surface.create_entity({name="small-biter", position={-32, -32}})) + group.add_member(surface.create_entity({name="small-biter", position={-32, -32}})) end group.set_command({ - type = defines.command.build_base, - destination = {-64, -64}, - distraction = defines.distraction.by_enemy, - ignore_planner = true + type = defines.command.build_base, + destination = {-64, -64}, + distraction = defines.distraction.by_enemy, + ignore_planner = true }) end diff --git a/visual.rkt b/visual.rkt index 04b190e..8c1f28a 100755 --- a/visual.rkt +++ b/visual.rkt @@ -171,12 +171,12 @@ (refresh dc) (thread (lambda () - (sync (filesystem-change-evt "/data/games/factorio/script-output/rampantState.txt")) - (showVisual dc (readState "/data/games/factorio/script-output/rampantState.txt")))))) + (sync (filesystem-change-evt "/mnt/gallery/gameFiles/factorio/script-output/rampantState.txt")) + (showVisual dc (readState "/mnt/gallery/gameFiles/factorio/script-output/rampantState.txt")))))) (define dcMap (first dcs)) - (showVisual dcMap (readState "/data/games/factorio/script-output/rampantState.txt")) + (showVisual dcMap (readState "/mnt/gallery/gameFiles/factorio/script-output/rampantState.txt")) (define (chunkX->screenX x) (roundTo (* (normalize x minX maxX)