From 19c16ed0ba1aa9678d098c0747e4a1a9415e5cf5 Mon Sep 17 00:00:00 2001 From: haonoq Date: Thu, 6 Feb 2014 15:58:46 +0400 Subject: [PATCH 1/2] Place newly produced droids correctly when building is rotated. --- src/structure.cpp | 147 ++++++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 69 deletions(-) diff --git a/src/structure.cpp b/src/structure.cpp index 82ac81492..1066d87d0 100644 --- a/src/structure.cpp +++ b/src/structure.cpp @@ -2236,28 +2236,24 @@ static bool structClearTile(UWORD x, UWORD y) return true; } -/*find a location near to a structure to start the droid of*/ +/* An auxiliary function for std::stable_sort in placeDroid */ +static bool comparePlacementPoints(Vector2i a, Vector2i b) +{ + return abs(a.x) + abs(a.y) < abs(b.x) + abs(b.y); +} + +/* Find a location near to a structure to start the droid of */ bool placeDroid(STRUCTURE *psStructure, UDWORD *droidX, UDWORD *droidY) { - SWORD sx,sy, xmin,xmax, ymin,ymax, x,y, xmid; - bool placed; - unsigned sWidth = getStructureWidth(psStructure); - unsigned sBreadth = getStructureBreadth(psStructure); CHECK_STRUCTURE(psStructure); - /* Get the tile coords for the top left of the structure */ - sx = (SWORD)(psStructure->pos.x - sWidth * TILE_UNITS/2); - sx = map_coord(sx); - sy = (SWORD)(psStructure->pos.y - sBreadth * TILE_UNITS/2); - sy = map_coord(sy); - /* Find the four corners of the square */ - xmin = (SWORD)(sx - 1); - xmax = (SWORD)(sx + sWidth); - xmid = (SWORD)(sx + (sWidth-1)/2); - ymin = (SWORD)(sy - 1); - ymax = (SWORD)(sy + sBreadth); + StructureBounds bounds = getStructureBounds(psStructure); + int xmin = bounds.map.x - 1; + int xmax = bounds.map.x + bounds.size.x; + int ymin = bounds.map.y - 1; + int ymax = bounds.map.y + bounds.size.y; if (xmin < 0) { xmin = 0; @@ -2275,73 +2271,86 @@ bool placeDroid(STRUCTURE *psStructure, UDWORD *droidX, UDWORD *droidY) ymax = (SWORD)mapHeight; } - /* Look for a clear location for the droid across the bottom */ - /* start in the middle */ - placed = false; - y = ymax; - /* middle to right */ - for(x = xmid; x < xmax; x++) + /* Round direction to nearest 90°. */ + uint16_t direction = (psStructure->rot.direction + 0x2000)&0xC000; + + /* We sort all adjacent tiles by their Manhattan distance to the + target droid exit tile, misplaced by (1/3, 1/4) tiles. + Since only whole coordinates are sorted, this makes sure sorting + is deterministic. Target coordinates, multiplied by 12 to eliminate + floats, are stored in (sx, sy). */ + int sx, sy; + + if (direction == 0x0) { - if (structClearTile(x, y)) - { - placed = true; - break; - } + sx = 12 * (xmin + 1) + 4; + sy = 12 * ymax + 3; } - /* left to middle */ - if (!placed) + else if (direction == 0x4000) { - for(x = xmin; x < xmid; x++) + sx = 12 * xmax + 3; + sy = 12 * (ymax - 1) - 4; + } + else if (direction == 0x8000) + { + sx = 12 * (xmax - 1) - 4; + sy = 12 * ymin - 3; + } + else + { + sx = 12 * xmin - 3; + sy = 12 * (ymin + 1) + 4; + } + + std::vector tiles; + for (int x = xmin; x <= xmax; ++x) + { + for (int y = ymin; y <= ymax; ++y) { if (structClearTile(x, y)) { - placed = true; - break; + tiles.push_back(Vector2i(12 * x - sx, 12 * y - sy)); } } } - /* across the top */ - if (!placed) + + if (tiles.size() == 0) { - y = ymin; - for(x = xmin; x < xmax; x++) - { - if (structClearTile(x, y)) - { - placed = true; - break; - } - } + return false; } - /* the left */ - if (!placed) + + std::sort(tiles.begin(), tiles.end(), comparePlacementPoints); + + /* Store best tile coordinates in (sx, sy), + which are also map coordinates of its north-west corner. + Store world coordinates of this tile's center in (wx, wy) */ + sx = (tiles[0].x + sx) / 12; + sy = (tiles[0].y + sy) / 12; + int wx = world_coord(sx) + TILE_UNITS / 2; + int wy = world_coord(sy) + TILE_UNITS / 2; + + /* Finally, find world coordinates of the structure point closest to (mx, my). + For simplicity, round to grid vertices. */ + if (2 * sx <= xmin + xmax) { - x = xmin; - for(y = ymin; y < ymax; y++) - { - if (structClearTile(x, y)) - { - placed = true; - break; - } - } + wx += TILE_UNITS / 2; } - /* the right */ - if (!placed) + if (2 * sx >= xmin + xmax) { - x = xmax; - for(y = ymin; y < ymax; y++) - { - if (structClearTile(x, y)) - { - placed = true; - break; - } - } + wx -= TILE_UNITS / 2; } - *droidX = x; - *droidY = y; - return placed; + if (2 * sy <= ymin + ymax) + { + wy += TILE_UNITS / 2; + } + if (2 * sy >= ymin + ymax) + { + wy -= TILE_UNITS / 2; + } + + *droidX = wx; + *droidY = wy; + return true; } /* Place a newly manufactured droid next to a factory and then send if off @@ -2367,7 +2376,7 @@ static bool structPlaceDroid(STRUCTURE *psStructure, DROID_TEMPLATE *psTempl, DR //create a droid near to the structure syncDebug("Placing new droid at (%d,%d)", x, y); turnOffMultiMsg(true); - psNewDroid = buildDroid(psTempl, world_coord(x), world_coord(y), psStructure->player, false, &initialOrders); + psNewDroid = buildDroid(psTempl, x, y, psStructure->player, false, &initialOrders); turnOffMultiMsg(false); if (!psNewDroid) { From add2e1177c0bc8c974a3cec16f6d81cb98d87272 Mon Sep 17 00:00:00 2001 From: per Date: Sat, 8 Feb 2014 15:27:35 +0100 Subject: [PATCH 2/2] ini2json: Make filters start with 'filter' to make it clear what they are. Also make them take arrays. Finally, the research effects effects start with lower case letters. --- tools/conversion/ini2json/ini2json_research.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/conversion/ini2json/ini2json_research.py b/tools/conversion/ini2json/ini2json_research.py index a4c74ece0..0ed7452c4 100644 --- a/tools/conversion/ini2json/ini2json_research.py +++ b/tools/conversion/ini2json/ini2json_research.py @@ -9,6 +9,9 @@ if len(sys.argv) < 3: config = ConfigParser.ConfigParser() config.read(sys.argv[1]) +def lowcase_first_letter(s): + return s[0].lower() + s[1:] + def is_number(s): try: int(s) @@ -58,20 +61,20 @@ for section in config.sections(): tmp = {} comps = result.split(':') if comps[0].isupper(): - tmp['weaponSubClass'] = comps[0] + tmp['filterWeaponSubClass'] = [ comps[0] ] elif comps[0] in ['Cyborgs', 'Droids', 'Transport']: - tmp['bodyClass'] = comps[0] + tmp['filterBodyClass'] = [ comps[0] ] elif comps[0] in ['Wall', 'Structure', 'Defense']: - tmp['structureType'] = comps[0] + tmp['filterStructureType'] = [ comps[0] ] elif comps[0] in ['RearmPoints', 'ProductionPoints', 'ResearchPoints', 'RepairPoints', 'Sensor', 'ECM', 'PowerPoints', 'Construct']: pass # affects a global state else: # forgot something... print 'Unknown filter: %s' % comps[0] sys.exit(1) if len(comps) > 2: - tmp[comps[1]] = int(comps[2]) + tmp[lowcase_first_letter(comps[1])] = int(comps[2]) else: - tmp[comps[0]] = int(comps[1]) + tmp[lowcase_first_letter(comps[0])] = int(comps[1]) accum.append(tmp) entry['results'] = accum entry['id'] = section # for backwards compatibility