From f655a0986dde21796fe00613912845a04ec61082 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 19 Apr 2012 11:03:29 +0400 Subject: [PATCH 01/18] Sync to changes in the data structure definitions. --- .../df/custom/block_burrow.methods.inc | 17 +++------ .../block_square_event_mineralst.methods.inc | 16 +++----- .../df/custom/tile_bitmask.methods.inc | 38 +++++++++++++++++++ library/modules/Maps.cpp | 2 +- library/xml | 2 +- plugins/devel/buildprobe.cpp | 2 +- 6 files changed, 52 insertions(+), 25 deletions(-) create mode 100644 library/include/df/custom/tile_bitmask.methods.inc diff --git a/library/include/df/custom/block_burrow.methods.inc b/library/include/df/custom/block_burrow.methods.inc index 216a58662..3959fcf35 100644 --- a/library/include/df/custom/block_burrow.methods.inc +++ b/library/include/df/custom/block_burrow.methods.inc @@ -1,26 +1,21 @@ inline bool getassignment( const df::coord2d &xy ) { - return getassignment(xy.x,xy.y); + return tile_bitmask.getassignment(xy); } inline bool getassignment( int x, int y ) { - return (tile_bitmask[y] & (1 << x)); + return tile_bitmask.getassignment(x,y); } inline void setassignment( const df::coord2d &xy, bool bit ) { - return setassignment(xy.x,xy.y, bit); + return tile_bitmask.setassignment(xy, bit); } inline void setassignment( int x, int y, bool bit ) { - if(bit) - tile_bitmask[y] |= (1 << x); - else - tile_bitmask[y] &= ~(1 << x); + return tile_bitmask.setassignment(x, y, bit); } bool has_assignments() { - for (int i = 0; i < 16; i++) - if (tile_bitmask[i]) - return true; - return false; + return tile_bitmask.has_assignments(); } + diff --git a/library/include/df/custom/block_square_event_mineralst.methods.inc b/library/include/df/custom/block_square_event_mineralst.methods.inc index 216a58662..4da4c65be 100644 --- a/library/include/df/custom/block_square_event_mineralst.methods.inc +++ b/library/include/df/custom/block_square_event_mineralst.methods.inc @@ -1,26 +1,20 @@ inline bool getassignment( const df::coord2d &xy ) { - return getassignment(xy.x,xy.y); + return tile_bitmask.getassignment(xy); } inline bool getassignment( int x, int y ) { - return (tile_bitmask[y] & (1 << x)); + return tile_bitmask.getassignment(x,y); } inline void setassignment( const df::coord2d &xy, bool bit ) { - return setassignment(xy.x,xy.y, bit); + return tile_bitmask.setassignment(xy, bit); } inline void setassignment( int x, int y, bool bit ) { - if(bit) - tile_bitmask[y] |= (1 << x); - else - tile_bitmask[y] &= ~(1 << x); + return tile_bitmask.setassignment(x, y, bit); } bool has_assignments() { - for (int i = 0; i < 16; i++) - if (tile_bitmask[i]) - return true; - return false; + return tile_bitmask.has_assignments(); } diff --git a/library/include/df/custom/tile_bitmask.methods.inc b/library/include/df/custom/tile_bitmask.methods.inc new file mode 100644 index 000000000..18b312a08 --- /dev/null +++ b/library/include/df/custom/tile_bitmask.methods.inc @@ -0,0 +1,38 @@ +inline uint16_t &operator[] (int y) +{ + return bits[y]; +} +void clear() +{ + memset(bits,0,sizeof(bits)); +} +void set_all() +{ + memset(bits,0xFF,sizeof(bits)); +} +inline bool getassignment( const df::coord2d &xy ) +{ + return getassignment(xy.x,xy.y); +} +inline bool getassignment( int x, int y ) +{ + return (bits[y] & (1 << x)); +} +inline void setassignment( const df::coord2d &xy, bool bit ) +{ + return setassignment(xy.x,xy.y, bit); +} +inline void setassignment( int x, int y, bool bit ) +{ + if(bit) + bits[y] |= (1 << x); + else + bits[y] &= ~(1 << x); +} +bool has_assignments() +{ + for (int i = 0; i < 16; i++) + if (bits[i]) + return true; + return false; +} diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index 327e26986..e795659ca 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -770,7 +770,7 @@ df::block_burrow *Maps::getBlockBurrowMask(df::burrow *burrow, df::map_block *bl link->item = new df::block_burrow; link->item->id = burrow->id; - memset(link->item->tile_bitmask,0,sizeof(link->item->tile_bitmask)); + link->item->tile_bitmask.clear(); link->item->link = link; link->next = NULL; diff --git a/library/xml b/library/xml index e8036d3f1..a1e342afe 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e8036d3f13c6be0141899baae90f605ad11d5385 +Subproject commit a1e342afe5a5e1e07672cd8b6553953bc251a05d diff --git a/plugins/devel/buildprobe.cpp b/plugins/devel/buildprobe.cpp index 6c360455a..17e95237f 100644 --- a/plugins/devel/buildprobe.cpp +++ b/plugins/devel/buildprobe.cpp @@ -119,7 +119,7 @@ command_result writeFlag (color_ostream &out, vector & parameters) MapExtras::MapCache * MCache = new MapExtras::MapCache(); t_occupancy oc = MCache->occupancyAt(cursor); - oc.bits.building = value; + oc.bits.building = df::tile_building_occ(value); MCache->setOccupancyAt(cursor, oc); MCache->WriteAll(); From 4b87f1bcaca65b7fa7542dfa6e638413c5b6d48f Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 19 Apr 2012 19:17:07 +0400 Subject: [PATCH 02/18] Refactor MapCache: make it parse everything that is known re tiles & mats. --- library/include/modules/MapCache.h | 249 +++++++++++++---- library/include/modules/Materials.h | 10 + library/modules/Maps.cpp | 410 ++++++++++++++++++++++++---- library/xml | 2 +- plugins/dig.cpp | 8 +- plugins/mapexport/mapexport.cpp | 4 +- plugins/probe.cpp | 58 ++-- plugins/prospector.cpp | 4 +- 8 files changed, 601 insertions(+), 144 deletions(-) diff --git a/library/include/modules/MapCache.h b/library/include/modules/MapCache.h index 8eac514be..4ddf0c984 100644 --- a/library/include/modules/MapCache.h +++ b/library/include/modules/MapCache.h @@ -31,12 +31,17 @@ distribution. #include #include #include "df/map_block.h" +#include "df/tile_bitmask.h" #include "df/block_square_event_mineralst.h" #include "df/construction.h" #include "df/item.h" using namespace DFHack; +namespace df { + struct world_region_details; +} + namespace MapExtras { @@ -50,6 +55,38 @@ inline bool is_valid_tile_coord(df::coord2d p) { return (p.x & ~15) == 0 && (p.y & ~15) == 0; } +class Block; + +class BlockInfo +{ + Block *mblock; + MapCache *parent; + df::map_block *block; + +public: + t_blockmaterials veinmats; + t_blockmaterials basemats; + t_blockmaterials grass; + std::map plants; + + df::feature_init *global_feature; + df::feature_init *local_feature; + + BlockInfo() + : mblock(NULL), parent(NULL), block(NULL), + global_feature(NULL), local_feature(NULL) {} + + void prepare(Block *mblock); + + t_matpair getBaseMaterial(df::tiletype tt, df::coord2d pos); + + static void SquashVeins(df::map_block *mb, t_blockmaterials & materials); + static void SquashFrozenLiquids (df::map_block *mb, tiletypes40d & frozen); + static void SquashRocks (df::map_block *mb, t_blockmaterials & materials, + std::vector< std::vector > * layerassign); + static void SquashGrass(df::map_block *mb, t_blockmaterials &materials); +}; + class DFHACK_EXPORT Block { public: @@ -62,39 +99,81 @@ public: //Arbitrary tag field for flood fills etc. int16_t &tag(df::coord2d p) { + if (!tags) init_tags(); return index_tile(tags, p); } + // Base layer + df::tiletype baseTiletypeAt(df::coord2d p) + { + if (!tiles) init_tiles(); + return index_tile(tiles->base_tiles,p); + } + t_matpair baseMaterialAt(df::coord2d p) + { + if (!basemats) init_tiles(true); + return t_matpair( + index_tile(basemats->mattype,p), + index_tile(basemats->matindex,p) + ); + } + bool isVeinAt(df::coord2d p) + { + using namespace df::enums::tiletype_material; + auto tm = tileMaterial(baseTiletypeAt(p)); + return tm == MINERAL; + } + bool isLayerAt(df::coord2d p) + { + using namespace df::enums::tiletype_material; + auto tm = tileMaterial(baseTiletypeAt(p)); + return tm == STONE || tm == SOIL; + } + int16_t veinMaterialAt(df::coord2d p) { - return index_tile(veinmats,p); + return isVeinAt(p) ? baseMaterialAt(p).mat_index : -1; } - int16_t baseMaterialAt(df::coord2d p) + int16_t layerMaterialAt(df::coord2d p) { - return index_tile(basemats,p); + if (!basemats) init_tiles(true); + return index_tile(basemats->layermat,p); } - df::tiletype BaseTileTypeAt(df::coord2d p) + // Static layer (base + constructions) + df::tiletype staticTiletypeAt(df::coord2d p) { - auto tt = index_tile(contiles,p); - if (tt != tiletype::Void) return tt; - tt = index_tile(icetiles,p); - if (tt != tiletype::Void) return tt; - return index_tile(rawtiles,p); + if (!tiles) init_tiles(); + if (tiles->con_info) + return index_tile(tiles->con_info->tiles,p); + return baseTiletypeAt(p); } - df::tiletype TileTypeAt(df::coord2d p) + t_matpair staticMaterialAt(df::coord2d p) { - return index_tile(rawtiles,p); + if (!basemats) init_tiles(true); + if (tiles->con_info) + return t_matpair( + index_tile(tiles->con_info->mattype,p), + index_tile(tiles->con_info->matindex,p) + ); + return baseMaterialAt(p); } - bool setTiletypeAt(df::coord2d p, df::tiletype tiletype) + bool hasConstructionAt(df::coord2d p) { - if(!valid) return false; - dirty_tiletypes = true; - //printf("setting block %d/%d/%d , %d %d\n",x,y,z, p.x, p.y); - index_tile(rawtiles,p) = tiletype; - return true; + if (!tiles) init_tiles(); + return tiles->con_info && + tiles->con_info->constructed.getassignment(p); } + df::tiletype tiletypeAt(df::coord2d p) + { + if (!block) return tiletype::Void; + if (tiles) + return index_tile(tiles->raw_tiles,p); + return index_tile(block->tiletype,p); + } + bool setTiletypeAt(df::coord2d, df::tiletype tt, bool force = false); + uint16_t temperature1At(df::coord2d p) { return index_tile(temp1,p); @@ -179,29 +258,29 @@ public: bool is_valid() { return valid; } df::map_block *getRaw() { return block; } + MapCache *getParent() { return parent; } + private: friend class MapCache; MapCache *parent; df::map_block *block; - static void SquashVeins(df::map_block *mb, t_blockmaterials & materials); - static void SquashFrozenLiquids (df::map_block *mb, tiletypes40d & frozen); - static void SquashConstructions (df::map_block *mb, tiletypes40d & constructions); - static void SquashRocks (df::map_block *mb, t_blockmaterials & materials, - std::vector< std::vector > * layerassign); - bool valid; bool dirty_designations:1; - bool dirty_tiletypes:1; + bool dirty_tiles:1; bool dirty_temperatures:1; bool dirty_blockflags:1; bool dirty_occupancies:1; DFCoord bcoord; - int16_t tags[16][16]; + // Custom tags for floodfill + typedef int16_t T_tags[16]; + T_tags *tags; + void init_tags(); + // On-ground item count info typedef int T_item_counts[16]; T_item_counts *item_counts; void init_item_counts(); @@ -209,30 +288,53 @@ private: bool addItemOnGround(df::item *item); bool removeItemOnGround(df::item *item); - tiletypes40d rawtiles; + struct ConInfo { + df::tile_bitmask constructed; + df::tiletype tiles[16][16]; + t_blockmaterials mattype; + t_blockmaterials matindex; + }; + struct TileInfo { + df::tile_bitmask frozen; + df::tile_bitmask dirty_raw; + df::tiletype raw_tiles[16][16]; + + ConInfo *con_info; + + df::tile_bitmask dirty_base; + df::tiletype base_tiles[16][16]; + + TileInfo(); + ~TileInfo(); + + void init_coninfo(); + }; + struct BasematInfo { + df::tile_bitmask dirty; + t_blockmaterials mattype; + t_blockmaterials matindex; + t_blockmaterials layermat; + + BasematInfo(); + }; + TileInfo *tiles; + BasematInfo *basemats; + void init_tiles(bool basemat = false); + void ParseTiles(TileInfo *tiles); + void ParseBasemats(TileInfo *tiles, BasematInfo *bmats); + designations40d designation; occupancies40d occupancy; t_blockflags blockflags; - t_blockmaterials veinmats; - t_blockmaterials basemats; t_temperatures temp1; t_temperatures temp2; - tiletypes40d contiles; // what's underneath constructions - tiletypes40d icetiles; // what's underneath ice }; class DFHACK_EXPORT MapCache { public: - MapCache() - { - valid = 0; - Maps::getSize(x_bmax, y_bmax, z_max); - x_tmax = x_bmax*16; y_tmax = y_bmax*16; - validgeo = Maps::ReadGeology(&layer_mats, &geoidx); - valid = true; - }; + MapCache(); ~MapCache() { trash(); @@ -251,19 +353,60 @@ class DFHACK_EXPORT MapCache df::tiletype baseTiletypeAt (DFCoord tilecoord) { - Block * b= BlockAtTile(tilecoord); - return b ? b->BaseTileTypeAt(tilecoord) : tiletype::Void; + Block *b = BlockAtTile(tilecoord); + return b ? b->baseTiletypeAt(tilecoord) : tiletype::Void; + } + t_matpair baseMaterialAt (DFCoord tilecoord) + { + Block *b = BlockAtTile(tilecoord); + return b ? b->baseMaterialAt(tilecoord) : t_matpair(); + } + int16_t veinMaterialAt (DFCoord tilecoord) + { + Block *b = BlockAtTile(tilecoord); + return b ? b->veinMaterialAt(tilecoord) : -1; + } + int16_t layerMaterialAt (DFCoord tilecoord) + { + Block *b = BlockAtTile(tilecoord); + return b ? b->layerMaterialAt(tilecoord) : -1; + } + bool isVeinAt (DFCoord tilecoord) + { + Block *b = BlockAtTile(tilecoord); + return b && b->isVeinAt(tilecoord); } + bool isLayerAt (DFCoord tilecoord) + { + Block *b = BlockAtTile(tilecoord); + return b && b->isLayerAt(tilecoord); + } + + df::tiletype staticTiletypeAt (DFCoord tilecoord) + { + Block *b = BlockAtTile(tilecoord); + return b ? b->staticTiletypeAt(tilecoord) : tiletype::Void; + } + t_matpair staticMaterialAt (DFCoord tilecoord) + { + Block *b = BlockAtTile(tilecoord); + return b ? b->staticMaterialAt(tilecoord) : t_matpair(); + } + bool hasConstructionAt (DFCoord tilecoord) + { + Block *b = BlockAtTile(tilecoord); + return b && b->hasConstructionAt(tilecoord); + } + df::tiletype tiletypeAt (DFCoord tilecoord) { - Block * b= BlockAtTile(tilecoord); - return b ? b->TileTypeAt(tilecoord) : tiletype::Void; + Block *b = BlockAtTile(tilecoord); + return b ? b->tiletypeAt(tilecoord) : tiletype::Void; } - bool setTiletypeAt(DFCoord tilecoord, df::tiletype tiletype) + bool setTiletypeAt (DFCoord tilecoord, df::tiletype tt, bool force = false) { - if (Block * b= BlockAtTile(tilecoord)) - return b->setTiletypeAt(tilecoord, tiletype); - return false; + Block *b = BlockAtTile(tilecoord); + return b && b->setTiletypeAt(tilecoord, tt, force); } uint16_t temperature1At (DFCoord tilecoord) @@ -290,17 +433,6 @@ class DFHACK_EXPORT MapCache return false; } - int16_t veinMaterialAt (DFCoord tilecoord) - { - Block * b= BlockAtTile(tilecoord); - return b ? b->veinMaterialAt(tilecoord) : -1; - } - int16_t baseMaterialAt (DFCoord tilecoord) - { - Block * b= BlockAtTile(tilecoord); - return b ? b->baseMaterialAt(tilecoord) : -1; - } - int16_t tagAt(DFCoord tilecoord) { Block * b= BlockAtTile(tilecoord); @@ -311,6 +443,7 @@ class DFHACK_EXPORT MapCache Block * b= BlockAtTile(tilecoord); if (b) b->tag(tilecoord) = val; } + void resetTags(); df::tile_designation designationAt (DFCoord tilecoord) { @@ -378,6 +511,7 @@ class DFHACK_EXPORT MapCache private: friend class Block; + friend class BlockInfo; bool valid; bool validgeo; @@ -388,6 +522,7 @@ private: uint32_t z_max; std::vector geoidx; std::vector< std::vector > layer_mats; + std::map region_details; std::map blocks; }; } diff --git a/library/include/modules/Materials.h b/library/include/modules/Materials.h index 3d70dc9fa..76c89de30 100644 --- a/library/include/modules/Materials.h +++ b/library/include/modules/Materials.h @@ -60,6 +60,14 @@ namespace df namespace DFHack { + struct t_matpair { + int16_t mat_type; + int32_t mat_index; + + t_matpair(int16_t type = -1, int32_t index = -1) + : mat_type(type), mat_index(index) {} + }; + struct DFHACK_EXPORT MaterialInfo { static const int NUM_BUILTIN = 19; static const int GROUP_SIZE = 200; @@ -91,6 +99,7 @@ namespace DFHack public: MaterialInfo(int16_t type = -1, int32_t index = -1) { decode(type, index); } + MaterialInfo(const t_matpair &mp) { decode(mp.mat_type, mp.mat_index); } template MaterialInfo(T *ptr) { decode(ptr); } bool isValid() const { return material != NULL; } @@ -107,6 +116,7 @@ namespace DFHack bool decode(int16_t type, int32_t index = -1); bool decode(df::item *item); bool decode(const df::material_vec_ref &vr, int idx); + bool decode(const t_matpair &mp) { return decode(mp.mat_type, mp.mat_index); } template bool decode(T *ptr) { // Assume and exploit a certain naming convention diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index e795659ca..06e525fea 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -51,6 +51,9 @@ using namespace std; #include "df/burrow.h" #include "df/block_burrow.h" #include "df/block_burrow_link.h" +#include "df/world_region_details.h" +#include "df/builtin_mats.h" +#include "df/block_square_event_grassst.h" using namespace DFHack; using namespace df::enums; @@ -158,7 +161,7 @@ df::world_data::T_region_map *Maps::getRegionBiome(df::coord2d rgn_pos) df::feature_init *Maps::getGlobalInitFeature(int32_t index) { auto data = world->world_data; - if (!data) + if (!data || index < 0) return NULL; auto rgn = vector_get(data->underground_regions, index); @@ -186,7 +189,7 @@ bool Maps::GetGlobalFeature(t_feature &feature, int32_t index) df::feature_init *Maps::getLocalInitFeature(df::coord2d rgn_pos, int32_t index) { auto data = world->world_data; - if (!data) + if (!data || index < 0) return NULL; if (rgn_pos.x < 0 || rgn_pos.x >= data->world_width || @@ -353,7 +356,7 @@ bool Maps::ReadGeology(vector > *layer_mats, vector int bioRX = world->map.region_x / 16 + ((i % 3) - 1); int bioRY = world->map.region_y / 16 + ((i / 3) - 1); - df::coord2d rgn_pos(clip_range(bioRX,0,world_width-1),clip_range(bioRX,0,world_height-1)); + df::coord2d rgn_pos(clip_range(bioRX,0,world_width-1),clip_range(bioRY,0,world_height-1)); (*geoidx)[i] = rgn_pos; @@ -389,7 +392,7 @@ bool Maps::ReadGeology(vector > *layer_mats, vector MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent) { dirty_designations = false; - dirty_tiletypes = false; + dirty_tiles = false; dirty_temperatures = false; dirty_blockflags = false; dirty_occupancies = false; @@ -397,12 +400,12 @@ MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent) bcoord = _bcoord; block = Maps::getBlock(bcoord); item_counts = NULL; - - memset(tags,0,sizeof(tags)); + tags = NULL; + tiles = NULL; + basemats = NULL; if(block) { - COPY(rawtiles, block->tiletype); COPY(designation, block->designation); COPY(occupancy, block->occupancy); blockflags = block->flags; @@ -410,33 +413,189 @@ MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent) COPY(temp1, block->temperature_1); COPY(temp2, block->temperature_2); - SquashVeins(block,veinmats); - SquashConstructions(block, contiles); - SquashFrozenLiquids(block, icetiles); - if(parent->validgeo) - SquashRocks(block,basemats,&parent->layer_mats); - else - memset(basemats,-1,sizeof(basemats)); valid = true; } else { blockflags.whole = 0; - memset(rawtiles,0,sizeof(rawtiles)); memset(designation,0,sizeof(designation)); memset(occupancy,0,sizeof(occupancy)); memset(temp1,0,sizeof(temp1)); memset(temp2,0,sizeof(temp2)); - memset(veinmats,-1,sizeof(veinmats)); - memset(contiles,0,sizeof(contiles)); - memset(icetiles,0,sizeof(icetiles)); - memset(basemats,-1,sizeof(basemats)); } } MapExtras::Block::~Block() { delete[] item_counts; + delete[] tags; + delete tiles; + delete basemats; +} + +void MapExtras::Block::init_tags() +{ + if (!tags) + tags = new T_tags[16]; + memset(tags,0,sizeof(T_tags)*16); +} + +void MapExtras::Block::init_tiles(bool basemat) +{ + if (!tiles) + { + tiles = new TileInfo(); + + if (block) + ParseTiles(tiles); + } + + if (basemat && !basemats) + { + basemats = new BasematInfo(); + + if (block) + ParseBasemats(tiles, basemats); + } +} + +MapExtras::Block::TileInfo::TileInfo() +{ + frozen.clear(); + dirty_raw.clear(); + memset(raw_tiles,0,sizeof(raw_tiles)); + con_info = NULL; + dirty_base.clear(); + memset(base_tiles,0,sizeof(base_tiles)); +} + +MapExtras::Block::TileInfo::~TileInfo() +{ + delete con_info; +} + +void MapExtras::Block::TileInfo::init_coninfo() +{ + if (con_info) + return; + + con_info = new ConInfo(); + con_info->constructed.clear(); + COPY(con_info->tiles, base_tiles); + memset(con_info->mattype, -1, sizeof(con_info->mattype)); + memset(con_info->matindex, -1, sizeof(con_info->matindex)); +} + +MapExtras::Block::BasematInfo::BasematInfo() +{ + dirty.clear(); + memset(mattype,0,sizeof(mattype)); + memset(matindex,-1,sizeof(matindex)); + memset(layermat,-1,sizeof(layermat)); +} + +bool MapExtras::Block::setTiletypeAt(df::coord2d pos, df::tiletype tt, bool force) +{ + if (!block) + return false; + + if (!basemats) + init_tiles(true); + + pos = pos & 15; + + dirty_tiles = true; + tiles->raw_tiles[pos.x][pos.y] = tt; + tiles->dirty_raw.setassignment(pos, true); + + return true; +} + +void MapExtras::Block::ParseTiles(TileInfo *tiles) +{ + tiletypes40d icetiles; + BlockInfo::SquashFrozenLiquids(block, icetiles); + + COPY(tiles->raw_tiles, block->tiletype); + + for (int x = 0; x < 16; x++) + { + for (int y = 0; y < 16; y++) + { + using namespace df::enums::tiletype_material; + + df::tiletype tt = tiles->raw_tiles[x][y]; + df::coord coord = block->map_pos + df::coord(x,y,0); + + // Frozen liquid comes topmost + if (tileMaterial(tt) == FROZEN_LIQUID) + { + tiles->frozen.setassignment(x,y,true); + if (icetiles[x][y] != tiletype::Void) + { + tt = icetiles[x][y]; + } + } + + // The next layer may be construction + bool is_con = false; + + if (tileMaterial(tt) == CONSTRUCTION) + { + df::construction *con = df::construction::find(coord); + if (con) + { + if (!tiles->con_info) + tiles->init_coninfo(); + + is_con = true; + tiles->con_info->constructed.setassignment(x,y,true); + tiles->con_info->tiles[x][y] = tt; + tiles->con_info->mattype[x][y] = con->mat_type; + tiles->con_info->matindex[x][y] = con->mat_index; + + tt = con->original_tile; + } + } + + // Finally, base material + tiles->base_tiles[x][y] = tt; + + // Copy base info back to construction layer + if (tiles->con_info && !is_con) + tiles->con_info->tiles[x][y] = tt; + } + } +} + +void MapExtras::Block::ParseBasemats(TileInfo *tiles, BasematInfo *bmats) +{ + BlockInfo info; + + info.prepare(this); + + COPY(bmats->layermat, info.basemats); + + for (int x = 0; x < 16; x++) + { + for (int y = 0; y < 16; y++) + { + using namespace df::enums::tiletype_material; + + auto tt = tiles->base_tiles[x][y]; + auto mat = info.getBaseMaterial(tt, df::coord2d(x,y)); + + bmats->mattype[x][y] = mat.mat_type; + bmats->matindex[x][y] = mat.mat_index; + + // Copy base info back to construction layer + if (tiles->con_info && !tiles->con_info->constructed.getassignment(x,y)) + { + tiles->con_info->mattype[x][y] = mat.mat_type; + tiles->con_info->matindex[x][y] = mat.mat_index; + } + } + } } bool MapExtras::Block::Write () @@ -454,10 +613,21 @@ bool MapExtras::Block::Write () block->flags.bits.designated = true; dirty_designations = false; } - if(dirty_tiletypes) + if(dirty_tiles && tiles) { - COPY(block->tiletype, rawtiles); - dirty_tiletypes = false; + dirty_tiles = false; + + for (int x = 0; x < 16; x++) + { + for (int y = 0; y < 16; y++) + { + if (tiles->dirty_raw.getassignment(x,y)) + block->tiletype[x][y] = tiles->raw_tiles[x][y]; + } + } + + delete tiles; tiles = NULL; + delete basemats; basemats = NULL; } if(dirty_temperatures) { @@ -473,65 +643,145 @@ bool MapExtras::Block::Write () return true; } -void MapExtras::Block::SquashVeins(df::map_block *mb, t_blockmaterials & materials) +void MapExtras::BlockInfo::prepare(Block *mblock) { - memset(materials,-1,sizeof(materials)); - std::vector veins; - Maps::SortBlockEvents(mb,&veins); - for (uint32_t x = 0;x<16;x++) for (uint32_t y = 0; y< 16;y++) + this->mblock = mblock; + + block = mblock->getRaw(); + parent = mblock->getParent(); + + SquashVeins(block,veinmats); + SquashGrass(block, grass); + + if (parent->validgeo) + SquashRocks(block,basemats,&parent->layer_mats); + else + memset(basemats,-1,sizeof(basemats)); + + for (size_t i = 0; i < block->plants.size(); i++) { - df::tiletype tt = mb->tiletype[x][y]; - if (tileMaterial(tt) == tiletype_material::MINERAL) + auto pp = block->plants[i]; + plants[pp->pos] = pp; + } + + global_feature = Maps::getGlobalInitFeature(block->global_feature); + local_feature = Maps::getLocalInitFeature(block->region_pos, block->local_feature); +} + +t_matpair MapExtras::BlockInfo::getBaseMaterial(df::tiletype tt, df::coord2d pos) +{ + using namespace df::enums::tiletype_material; + + t_matpair rv(0,-1); + int x = pos.x, y = pos.y; + + switch (tileMaterial(tt)) { + case CONSTRUCTION: // just a fallback + case SOIL: + case STONE: + rv.mat_index = basemats[x][y]; + break; + + case MINERAL: + rv.mat_index = veinmats[x][y]; + break; + + case LAVA_STONE: + if (auto details = parent->region_details[mblock->biomeRegionAt(pos)]) + rv.mat_index = details->lava_stone; + break; + + case PLANT: + rv.mat_type = MaterialInfo::PLANT_BASE; + if (auto plant = plants[block->map_pos + df::coord(x,y,0)]) { - for (size_t i = 0; i < veins.size(); i++) + if (auto raw = df::plant_raw::find(plant->material)) { - if (veins[i]->getassignment(x,y)) - materials[x][y] = veins[i]->inorganic_mat; + rv.mat_type = raw->material_defs.type_basic_mat; + rv.mat_index = raw->material_defs.idx_basic_mat; } } + break; + + case GRASS_LIGHT: + case GRASS_DARK: + case GRASS_DRY: + case GRASS_DEAD: + rv.mat_type = MaterialInfo::PLANT_BASE; + if (auto raw = df::plant_raw::find(grass[x][y])) + { + rv.mat_type = raw->material_defs.type_basic_mat; + rv.mat_index = raw->material_defs.idx_basic_mat; + } + break; + + case FEATURE: + { + auto dsgn = block->designation[x][y]; + + if (dsgn.bits.feature_local && local_feature) + local_feature->getMaterial(&rv.mat_type, &rv.mat_index); + else if (dsgn.bits.feature_global && global_feature) + global_feature->getMaterial(&rv.mat_type, &rv.mat_index); + + break; } + + case FROZEN_LIQUID: + case POOL: + case BROOK: + case RIVER: + rv.mat_type = builtin_mats::WATER; + break; + + case ASHES: + case FIRE: + case CAMPFIRE: + rv.mat_type = builtin_mats::ASH; + break; + + default: + rv.mat_type = -1; + } + + return rv; } -void MapExtras::Block::SquashFrozenLiquids(df::map_block *mb, tiletypes40d & frozen) +void MapExtras::BlockInfo::SquashVeins(df::map_block *mb, t_blockmaterials & materials) { - std::vector ices; - Maps::SortBlockEvents(mb,NULL,&ices); - for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) + std::vector veins; + Maps::SortBlockEvents(mb,&veins); + memset(materials,-1,sizeof(materials)); + for (uint32_t x = 0;x<16;x++) for (uint32_t y = 0; y< 16;y++) { - df::tiletype tt = mb->tiletype[x][y]; - frozen[x][y] = tiletype::Void; - if (tileMaterial(tt) == tiletype_material::FROZEN_LIQUID) + for (size_t i = 0; i < veins.size(); i++) { - for (size_t i = 0; i < ices.size(); i++) - { - df::tiletype tt2 = ices[i]->tiles[x][y]; - if (tt2 != tiletype::Void) - { - frozen[x][y] = tt2; - break; - } - } + if (veins[i]->getassignment(x,y)) + materials[x][y] = veins[i]->inorganic_mat; } } } -void MapExtras::Block::SquashConstructions (df::map_block *mb, tiletypes40d & constructions) +void MapExtras::BlockInfo::SquashFrozenLiquids(df::map_block *mb, tiletypes40d & frozen) { + std::vector ices; + Maps::SortBlockEvents(mb,NULL,&ices); + memset(frozen,0,sizeof(frozen)); for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) { - df::tiletype tt = mb->tiletype[x][y]; - constructions[x][y] = tiletype::Void; - if (tileMaterial(tt) == tiletype_material::CONSTRUCTION) + for (size_t i = 0; i < ices.size(); i++) { - DFCoord coord = mb->map_pos + df::coord(x,y,0); - df::construction *con = df::construction::find(coord); - if (con) - constructions[x][y] = con->original_tile; + df::tiletype tt2 = ices[i]->tiles[x][y]; + if (tt2 != tiletype::Void) + { + frozen[x][y] = tt2; + break; + } } } } -void MapExtras::Block::SquashRocks (df::map_block *mb, t_blockmaterials & materials, +void MapExtras::BlockInfo::SquashRocks (df::map_block *mb, t_blockmaterials & materials, std::vector< std::vector > * layerassign) { // get the layer materials @@ -547,6 +797,25 @@ void MapExtras::Block::SquashRocks (df::map_block *mb, t_blockmaterials & materi } } +void MapExtras::BlockInfo::SquashGrass(df::map_block *mb, t_blockmaterials &materials) +{ + std::vector grasses; + Maps::SortBlockEvents(mb, NULL, NULL, NULL, &grasses); + memset(materials,-1,sizeof(materials)); + for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) + { + int amount = 0; + for (size_t i = 0; i < grasses.size(); i++) + { + if (grasses[i]->amount[x][y] >= amount) + { + amount = grasses[i]->amount[x][y]; + materials[x][y] = grasses[i]->plant_index; + } + } + } +} + df::coord2d MapExtras::Block::biomeRegionAt(df::coord2d p) { if (!block) @@ -662,6 +931,24 @@ bool MapExtras::Block::removeItemOnGround(df::item *item) return true; } +MapExtras::MapCache::MapCache() +{ + valid = 0; + Maps::getSize(x_bmax, y_bmax, z_max); + x_tmax = x_bmax*16; y_tmax = y_bmax*16; + validgeo = Maps::ReadGeology(&layer_mats, &geoidx); + valid = true; + + if (auto data = df::global::world->world_data) + { + for (size_t i = 0; i < data->region_details.size(); i++) + { + auto info = data->region_details[i]; + region_details[info->pos] = info; + } + } +} + MapExtras::Block *MapExtras::MapCache::BlockAt(DFCoord blockcoord) { if(!valid) @@ -685,6 +972,15 @@ MapExtras::Block *MapExtras::MapCache::BlockAt(DFCoord blockcoord) } } +void MapExtras::MapCache::resetTags() +{ + for (auto it = blocks.begin(); it != blocks.end(); ++it) + { + delete[] it->second->tags; + it->second->tags = NULL; + } +} + df::burrow *Maps::findBurrowByName(std::string name) { auto &vec = df::burrow::get_vector(); diff --git a/library/xml b/library/xml index a1e342afe..25c2a3dad 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit a1e342afe5a5e1e07672cd8b6553953bc251a05d +Subproject commit 25c2a3dad964abbcceb5abd41558b71fb113e83b diff --git a/plugins/dig.cpp b/plugins/dig.cpp index 64161a3aa..21c199102 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -1196,7 +1196,7 @@ command_result digl (color_ostream &out, vector & parameters) df::tile_designation des = MCache->designationAt(xy); df::tiletype tt = MCache->tiletypeAt(xy); int16_t veinmat = MCache->veinMaterialAt(xy); - int16_t basemat = MCache->baseMaterialAt(xy); + int16_t basemat = MCache->layerMaterialAt(xy); if( veinmat != -1 ) { con.printerr("This is a vein. Use vdig instead!\n"); @@ -1215,7 +1215,7 @@ command_result digl (color_ostream &out, vector & parameters) if (MCache->tagAt(current)) continue; int16_t vmat2 = MCache->veinMaterialAt(current); - int16_t bmat2 = MCache->baseMaterialAt(current); + int16_t bmat2 = MCache->layerMaterialAt(current); tt = MCache->tiletypeAt(current); if(!DFHack::isWallTerrain(tt)) @@ -1282,7 +1282,7 @@ command_result digl (color_ostream &out, vector & parameters) //below = 1; des_minus = MCache->designationAt(current-1); vmat_minus = MCache->veinMaterialAt(current-1); - bmat_minus = MCache->baseMaterialAt(current-1); + bmat_minus = MCache->layerMaterialAt(current-1); tt_minus = MCache->tiletypeAt(current-1); if ( tileMaterial(tt_minus)==tiletype_material::STONE || tileMaterial(tt_minus)==tiletype_material::SOIL) @@ -1293,7 +1293,7 @@ command_result digl (color_ostream &out, vector & parameters) //above = 1; des_plus = MCache->designationAt(current+1); vmat_plus = MCache->veinMaterialAt(current+1); - bmat_plus = MCache->baseMaterialAt(current+1); + bmat_plus = MCache->layerMaterialAt(current+1); tt_plus = MCache->tiletypeAt(current+1); if ( tileMaterial(tt_plus)==tiletype_material::STONE || tileMaterial(tt_plus)==tiletype_material::SOIL) diff --git a/plugins/mapexport/mapexport.cpp b/plugins/mapexport/mapexport.cpp index e0a7e5e69..592c526db 100644 --- a/plugins/mapexport/mapexport.cpp +++ b/plugins/mapexport/mapexport.cpp @@ -193,7 +193,7 @@ command_result mapexport (color_ostream &out, std::vector & parame prototile->set_flow_size(des.bits.flow_size); } - df::tiletype type = b->TileTypeAt(coord); + df::tiletype type = b->tiletypeAt(coord); prototile->set_type((dfproto::Tile::TileType)tileShape(type)); prototile->set_tile_material((dfproto::Tile::TileMaterialType)tileMaterial(type)); @@ -204,7 +204,7 @@ command_result mapexport (color_ostream &out, std::vector & parame case tiletype_material::SOIL: case tiletype_material::STONE: prototile->set_material_type(0); - prototile->set_material_index(b->baseMaterialAt(coord)); + prototile->set_material_index(b->layerMaterialAt(coord)); break; case tiletype_material::MINERAL: prototile->set_material_type(0); diff --git a/plugins/probe.cpp b/plugins/probe.cpp index 4e041f180..8240d91f3 100644 --- a/plugins/probe.cpp +++ b/plugins/probe.cpp @@ -103,6 +103,30 @@ command_result df_cprobe (color_ostream &out, vector & parameters) return CR_OK; } +void describeTile(color_ostream &out, df::tiletype tiletype) +{ + out.print("%d", tiletype); + if(tileName(tiletype)) + out.print(" = %s",tileName(tiletype)); + out.print("\n"); + + df::tiletype_shape shape = tileShape(tiletype); + df::tiletype_material material = tileMaterial(tiletype); + df::tiletype_special special = tileSpecial(tiletype); + df::tiletype_variant variant = tileVariant(tiletype); + out.print("%-10s: %4d %s\n","Class" ,shape, + ENUM_KEY_STR(tiletype_shape, shape).c_str()); + out.print("%-10s: %4d %s\n","Material" , + material, ENUM_KEY_STR(tiletype_material, material).c_str()); + out.print("%-10s: %4d %s\n","Special" , + special, ENUM_KEY_STR(tiletype_special, special).c_str()); + out.print("%-10s: %4d %s\n" ,"Variant" , + variant, ENUM_KEY_STR(tiletype_variant, variant).c_str()); + out.print("%-10s: %s\n" ,"Direction", + tileDirection(tiletype).getStr()); + out.print("\n"); +} + command_result df_probe (color_ostream &out, vector & parameters) { //bool showBlock, showDesig, showOccup, showTile, showMisc; @@ -186,26 +210,12 @@ command_result df_probe (color_ostream &out, vector & parameters) */ // tiletype - out.print("tiletype: %d", tiletype); - if(tileName(tiletype)) - out.print(" = %s",tileName(tiletype)); - out.print("\n"); - - df::tiletype_shape shape = tileShape(tiletype); - df::tiletype_material material = tileMaterial(tiletype); - df::tiletype_special special = tileSpecial(tiletype); - df::tiletype_variant variant = tileVariant(tiletype); - out.print("%-10s: %4d %s\n","Class" ,shape, - ENUM_KEY_STR(tiletype_shape, shape).c_str()); - out.print("%-10s: %4d %s\n","Material" , - material, ENUM_KEY_STR(tiletype_material, material).c_str()); - out.print("%-10s: %4d %s\n","Special" , - special, ENUM_KEY_STR(tiletype_special, special).c_str()); - out.print("%-10s: %4d %s\n" ,"Variant" , - variant, ENUM_KEY_STR(tiletype_variant, variant).c_str()); - out.print("%-10s: %s\n" ,"Direction", - tileDirection(tiletype).getStr()); - out.print("\n"); + out.print("tiletype: "); + describeTile(out, tiletype); + out.print("static: "); + describeTile(out, mc.staticTiletypeAt(cursor)); + out.print("base: "); + describeTile(out, mc.baseTiletypeAt(cursor)); out.print("temperature1: %d U\n",mc.temperature1At(cursor)); out.print("temperature2: %d U\n",mc.temperature2At(cursor)); @@ -214,7 +224,7 @@ command_result df_probe (color_ostream &out, vector & parameters) out << "biome: " << des.bits.biome << std::endl; out << "geolayer: " << des.bits.geolayer_index << std::endl; - int16_t base_rock = mc.baseMaterialAt(cursor); + int16_t base_rock = mc.layerMaterialAt(cursor); if(base_rock != -1) { out << "Layer material: " << dec << base_rock; @@ -238,6 +248,12 @@ command_result df_probe (color_ostream &out, vector & parameters) else out << endl; } + MaterialInfo minfo(mc.baseMaterialAt(cursor)); + if (minfo.isValid()) + out << "Base material: " << minfo.getToken() << " / " << minfo.toString() << endl; + minfo.decode(mc.staticMaterialAt(cursor)); + if (minfo.isValid()) + out << "Static material: " << minfo.getToken() << " / " << minfo.toString() << endl; // liquids if(des.bits.flow_size) { diff --git a/plugins/prospector.cpp b/plugins/prospector.cpp index c90a66c5a..e2f1e9534 100644 --- a/plugins/prospector.cpp +++ b/plugins/prospector.cpp @@ -474,7 +474,7 @@ command_result prospector (color_ostream &con, vector & parameters) liquidWater.add(global_z); } - df::tiletype type = b->TileTypeAt(coord); + df::tiletype type = b->tiletypeAt(coord); df::tiletype_shape tileshape = tileShape(type); df::tiletype_material tilemat = tileMaterial(type); @@ -506,7 +506,7 @@ command_result prospector (color_ostream &con, vector & parameters) { case tiletype_material::SOIL: case tiletype_material::STONE: - layerMats[b->baseMaterialAt(coord)].add(global_z); + layerMats[b->layerMaterialAt(coord)].add(global_z); break; case tiletype_material::MINERAL: veinMats[b->veinMaterialAt(coord)].add(global_z); From 0b32d374db8a58547d554d758e4e77ad850f54c5 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 19 Apr 2012 23:02:30 +0400 Subject: [PATCH 03/18] Implement SOIL/STONE substitution logic, and add compat in mapexport. --- library/include/modules/MapCache.h | 5 ++ library/modules/Maps.cpp | 81 ++++++++++++++++++++++++++++-- plugins/mapexport/mapexport.cpp | 44 +++++++++++++++- 3 files changed, 123 insertions(+), 7 deletions(-) diff --git a/library/include/modules/MapCache.h b/library/include/modules/MapCache.h index 4ddf0c984..0b4e78b21 100644 --- a/library/include/modules/MapCache.h +++ b/library/include/modules/MapCache.h @@ -262,10 +262,13 @@ public: private: friend class MapCache; + friend class BlockInfo; MapCache *parent; df::map_block *block; + int biomeIndexAt(df::coord2d p); + bool valid; bool dirty_designations:1; bool dirty_tiles:1; @@ -521,6 +524,8 @@ private: uint32_t y_tmax; uint32_t z_max; std::vector geoidx; + std::vector default_soil; + std::vector default_stone; std::vector< std::vector > layer_mats; std::map region_details; std::map blocks; diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index 06e525fea..e130915d6 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -676,11 +676,42 @@ t_matpair MapExtras::BlockInfo::getBaseMaterial(df::tiletype tt, df::coord2d pos int x = pos.x, y = pos.y; switch (tileMaterial(tt)) { - case CONSTRUCTION: // just a fallback + case DRIFTWOOD: case SOIL: + { + rv.mat_index = basemats[x][y]; + + if (auto raw = df::inorganic_raw::find(rv.mat_index)) + { + if (raw->flags.is_set(inorganic_flags::SOIL_ANY)) + break; + + int biome = mblock->biomeIndexAt(pos); + int idx = vector_get(parent->default_soil, biome, -1); + if (idx >= 0) + rv.mat_index = idx; + } + + break; + } + case STONE: + { rv.mat_index = basemats[x][y]; + + if (auto raw = df::inorganic_raw::find(rv.mat_index)) + { + if (!raw->flags.is_set(inorganic_flags::SOIL_ANY)) + break; + + int biome = mblock->biomeIndexAt(pos); + int idx = vector_get(parent->default_stone, biome, -1); + if (idx >= 0) + rv.mat_index = idx; + } + break; + } case MINERAL: rv.mat_index = veinmats[x][y]; @@ -727,11 +758,17 @@ t_matpair MapExtras::BlockInfo::getBaseMaterial(df::tiletype tt, df::coord2d pos break; } + case CONSTRUCTION: // just a fallback + break; + case FROZEN_LIQUID: + rv.mat_type = builtin_mats::WATER; + break; + case POOL: case BROOK: case RIVER: - rv.mat_type = builtin_mats::WATER; + rv.mat_index = basemats[x][y]; break; case ASHES: @@ -816,18 +853,30 @@ void MapExtras::BlockInfo::SquashGrass(df::map_block *mb, t_blockmaterials &mate } } -df::coord2d MapExtras::Block::biomeRegionAt(df::coord2d p) +int MapExtras::Block::biomeIndexAt(df::coord2d p) { if (!block) - return df::coord2d(-30000,-30000); + return -1; auto des = index_tile(designation,p); uint8_t idx = des.bits.biome; if (idx >= 9) - return block->region_pos; + return -1; idx = block->region_offset[idx]; if (idx >= parent->geoidx.size()) + return -1; + return idx; +} + +df::coord2d MapExtras::Block::biomeRegionAt(df::coord2d p) +{ + if (!block) + return df::coord2d(-30000,-30000); + + int idx = biomeIndexAt(p); + if (idx < 0) return block->region_pos; + return parent->geoidx[idx]; } @@ -947,6 +996,28 @@ MapExtras::MapCache::MapCache() region_details[info->pos] = info; } } + + default_soil.resize(layer_mats.size()); + default_stone.resize(layer_mats.size()); + + for (size_t i = 0; i < layer_mats.size(); i++) + { + default_soil[i] = -1; + default_stone[i] = -1; + + for (size_t j = 0; j < layer_mats[i].size(); j++) + { + auto raw = df::inorganic_raw::find(layer_mats[i][j]); + if (!raw) + continue; + + bool is_soil = raw->flags.is_set(inorganic_flags::SOIL_ANY); + if (is_soil) + default_soil[i] = layer_mats[i][j]; + else if (default_stone[i] == -1) + default_stone[i] = layer_mats[i][j]; + } + } } MapExtras::Block *MapExtras::MapCache::BlockAt(DFCoord blockcoord) diff --git a/plugins/mapexport/mapexport.cpp b/plugins/mapexport/mapexport.cpp index 592c526db..fa1736ed7 100644 --- a/plugins/mapexport/mapexport.cpp +++ b/plugins/mapexport/mapexport.cpp @@ -2,7 +2,7 @@ #include "Console.h" #include "Export.h" #include "PluginManager.h" -#include "modules/MapCache.h" +#include "modules/MapCache.h"f using namespace DFHack; #include @@ -39,6 +39,46 @@ DFhackCExport command_result plugin_shutdown ( color_ostream &out ) return CR_OK; } +static dfproto::Tile::TileMaterialType toProto(df::tiletype_material mat) +{ + /* + * This is surely ugly, but casting enums without officially + * defined numerical values to protobuf enums is against the + * way protobufs are supposed to be used, because it defeats + * the backward compatible nature of the protocols. + */ + switch (mat) + { +#define CONVERT(name) case tiletype_material::name: return dfproto::Tile::name; + CONVERT(AIR) + case tiletype_material::PLANT: + CONVERT(SOIL) + CONVERT(STONE) + CONVERT(FEATURE) + CONVERT(LAVA_STONE) + CONVERT(MINERAL) + CONVERT(FROZEN_LIQUID) + CONVERT(CONSTRUCTION) + CONVERT(GRASS_LIGHT) + CONVERT(GRASS_DARK) + CONVERT(GRASS_DRY) + CONVERT(GRASS_DEAD) + CONVERT(HFS) + CONVERT(CAMPFIRE) + CONVERT(FIRE) + CONVERT(ASHES) + case tiletype_material::MAGMA: + return dfproto::Tile::MAGMA_TYPE; + CONVERT(DRIFTWOOD) + CONVERT(POOL) + CONVERT(BROOK) + CONVERT(RIVER) +#undef CONVERT + default: + return dfproto::Tile::AIR; + } +} + command_result mapexport (color_ostream &out, std::vector & parameters) { bool showHidden = false; @@ -195,7 +235,7 @@ command_result mapexport (color_ostream &out, std::vector & parame df::tiletype type = b->tiletypeAt(coord); prototile->set_type((dfproto::Tile::TileType)tileShape(type)); - prototile->set_tile_material((dfproto::Tile::TileMaterialType)tileMaterial(type)); + prototile->set_tile_material(toProto(tileMaterial(type))); df::coord map_pos = df::coord(b_x*16+x,b_y*16+y,z); From d95cc3435fe249e1c86e5af36b8a10e9009edd97 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 20 Apr 2012 13:04:03 +0400 Subject: [PATCH 04/18] Fix lua wrapper sizeof for static arrays. Since it actually depends on the element type, it is more tricky. --- library/DataDefs.cpp | 12 +++++++----- library/LuaWrapper.cpp | 17 +++++++++++++++-- library/include/DataDefs.h | 2 +- library/include/DataIdentity.h | 4 +++- 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index 05988e419..062635182 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -42,13 +42,14 @@ using namespace DFHack; void *type_identity::do_allocate_pod() { - void *p = malloc(size); - memset(p, 0, size); + size_t sz = byte_size(); + void *p = malloc(sz); + memset(p, 0, sz); return p; } void type_identity::do_copy_pod(void *tgt, const void *src) { - memmove(tgt, src, size); + memmove(tgt, src, byte_size()); }; bool type_identity::do_destroy_pod(void *obj) { @@ -81,8 +82,9 @@ bool type_identity::destroy(void *obj) { } void *enum_identity::do_allocate() { - void *p = malloc(byte_size()); - memcpy(p, &first_item_value, std::min(byte_size(), sizeof(int64_t))); + size_t sz = byte_size(); + void *p = malloc(sz); + memcpy(p, &first_item_value, std::min(sz, sizeof(int64_t))); return p; } diff --git a/library/LuaWrapper.cpp b/library/LuaWrapper.cpp index 1c3b61c15..0b958f37c 100644 --- a/library/LuaWrapper.cpp +++ b/library/LuaWrapper.cpp @@ -542,10 +542,23 @@ static int meta_sizeof(lua_State *state) return 2; } - type_identity *id = get_object_identity(state, 1, "df.sizeof()", true); + type_identity *id = get_object_identity(state, 1, "df.sizeof()", true, true); - lua_pushinteger(state, id->byte_size()); + // Static arrays need special handling + if (id->type() == IDTYPE_BUFFER) + { + auto buf = (df::buffer_container_identity*)id; + type_identity *item = buf->getItemType(); + int count = buf->getSize(); + + fetch_container_details(state, lua_gettop(state), &item, &count); + + lua_pushinteger(state, item->byte_size() * count); + } + else + lua_pushinteger(state, id->byte_size()); + // Add the address if (lua_isuserdata(state, 1)) { lua_pushnumber(state, (size_t)get_object_ref(state, 1)); diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index d4d757d94..02f988248 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -83,7 +83,7 @@ namespace DFHack public: virtual ~type_identity() {} - size_t byte_size() { return size; } + virtual size_t byte_size() { return size; } virtual identity_type type() = 0; diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index a775c85b2..e4197a506 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -289,9 +289,11 @@ namespace df {} buffer_container_identity(int size, type_identity *item, enum_identity *ienum = NULL) - : container_identity(item->byte_size()*size, NULL, item, ienum), size(size) + : container_identity(0, NULL, item, ienum), size(size) {} + size_t byte_size() { return getItemType()->byte_size()*size; } + std::string getFullName(type_identity *item); int getSize() { return size; } From 0a6982f4041f43d571bd2690f148ff369f2d8038 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Fri, 20 Apr 2012 13:30:37 +0400 Subject: [PATCH 05/18] Enable warnings correctly on linux and fix a lot of them. --- CMakeLists.txt | 2 +- depends/protobuf/CMakeLists.txt | 2 ++ library/Console-linux.cpp | 11 ++++++----- library/DataDefs.cpp | 8 ++++---- library/LuaApi.cpp | 1 + library/LuaTypes.cpp | 29 ----------------------------- library/RemoteTools.cpp | 7 +++++-- library/TileTypes.cpp | 2 ++ library/include/DataDefs.h | 4 ++-- library/include/RemoteTools.h | 2 +- library/include/modules/Windows.h | 12 ++++++------ library/modules/Constructions.cpp | 4 ++-- library/modules/Engravings.cpp | 4 ++-- library/modules/Gui.cpp | 2 +- library/modules/Items.cpp | 3 +++ library/modules/Maps.cpp | 17 +++++++++++------ library/modules/Materials.cpp | 10 +++++----- library/modules/Units.cpp | 2 +- library/modules/Vegetation.cpp | 4 ++-- library/modules/Windows.cpp | 2 +- library/xml | 2 +- plugins/burrows.cpp | 10 +++++----- plugins/jobutils.cpp | 4 ++-- plugins/mapexport/mapexport.cpp | 6 +++--- plugins/workflow.cpp | 6 ++++++ 25 files changed, 75 insertions(+), 81 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e83f20f54..d16390c45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,7 +108,7 @@ OPTION(BUILD_PLUGINS "Build the plugins." ON) # enable C++11 features IF(UNIX) add_definitions(-DLINUX_BUILD) - SET(CMAKE_CXX_FLAGS_DEBUG "-g -Wall") + SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-g -Wall -Wno-unused-variable") SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -m32 -march=i686 -mtune=generic -std=c++0x") SET(CMAKE_C_FLAGS "-fvisibility=hidden -m32 -march=i686 -mtune=generic") ENDIF() diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index f4a3b6d19..92504f059 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -200,6 +200,8 @@ google/protobuf/compiler/zip_writer.cc LIST(APPEND LIBPROTOBUF_FULL_SRCS ${LIBPROTOBUF_LITE_SRCS}) +SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -Wno-sign-compare") + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) SET(PROTOBUF_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS}) diff --git a/library/Console-linux.cpp b/library/Console-linux.cpp index 9a0905647..3c0ad8938 100644 --- a/library/Console-linux.cpp +++ b/library/Console-linux.cpp @@ -163,6 +163,7 @@ namespace DFHack return false; return true; } + return false; } public: @@ -489,7 +490,7 @@ namespace DFHack { right_arrow: /* right arrow */ - if (raw_cursor != raw_buffer.size()) + if (size_t(raw_cursor) != raw_buffer.size()) { raw_cursor++; prompt_refresh(); @@ -510,7 +511,7 @@ namespace DFHack history_index = 0; break; } - else if (history_index >= history.size()) + else if (size_t(history_index) >= history.size()) { history_index = history.size()-1; break; @@ -545,7 +546,7 @@ namespace DFHack if (seq[1] == '3' && seq2 == '~' ) { // delete - if (raw_buffer.size() > 0 && raw_cursor < raw_buffer.size()) + if (raw_buffer.size() > 0 && size_t(raw_cursor) < raw_buffer.size()) { raw_buffer.erase(raw_cursor,1); prompt_refresh(); @@ -555,11 +556,11 @@ namespace DFHack } break; default: - if (raw_buffer.size() == raw_cursor) + if (raw_buffer.size() == size_t(raw_cursor)) { raw_buffer.append(1,c); raw_cursor++; - if (plen+raw_buffer.size() < get_columns()) + if (plen+raw_buffer.size() < size_t(get_columns())) { /* Avoid a full update of the line in the * trivial case. */ diff --git a/library/DataDefs.cpp b/library/DataDefs.cpp index 062635182..061110ecc 100644 --- a/library/DataDefs.cpp +++ b/library/DataDefs.cpp @@ -98,7 +98,7 @@ std::vector compound_identity::top_scope; compound_identity::compound_identity(size_t size, TAllocateFn alloc, compound_identity *scope_parent, const char *dfhack_name) - : constructed_identity(size, alloc), scope_parent(scope_parent), dfhack_name(dfhack_name) + : constructed_identity(size, alloc), dfhack_name(dfhack_name), scope_parent(scope_parent) { next = list; list = this; } @@ -146,8 +146,8 @@ enum_identity::enum_identity(size_t size, const char *const *keys, const void *attrs, struct_identity *attr_type) : compound_identity(size, NULL, scope_parent, dfhack_name), - first_item_value(first_item_value), last_item_value(last_item_value), - keys(keys), base_type(base_type), attrs(attrs), attr_type(attr_type) + keys(keys), first_item_value(first_item_value), last_item_value(last_item_value), + base_type(base_type), attrs(attrs), attr_type(attr_type) { } @@ -382,7 +382,7 @@ int DFHack::findEnumItem(const std::string &name, int size, const char *const *i void DFHack::flagarrayToString(std::vector *pvec, const void *p, int bytes, int base, int size, const char *const *items) { - for (unsigned i = 0; i < bytes*8; i++) { + for (int i = 0; i < bytes*8; i++) { int value = getBitfieldField(p, i, 1); if (value) diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 5f2195760..ccd057c9c 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -353,6 +353,7 @@ static void push_matinfo(lua_State *state, MaterialInfo &info) case MaterialInfo::Plant: id = "plant"; break; case MaterialInfo::Creature: id = "creature"; break; case MaterialInfo::Inorganic: id = "inorganic"; break; + default: break; } lua_pushstring(state, id); diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index 2cfe8a84e..b4a4f5d4f 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -576,35 +576,6 @@ static void write_field(lua_State *state, const struct_field_info *field, void * } } -/** - * Metamethod: represent a type node as string. - */ -static int meta_type_tostring(lua_State *state) -{ - if (!lua_getmetatable(state, 1)) - return 0; - - lua_getfield(state, -1, "__metatable"); - const char *cname = lua_tostring(state, -1); - - lua_pushstring(state, stl_sprintf("", cname).c_str()); - return 1; -} - -/** - * Metamethod: represent a DF object reference as string. - */ -static int meta_ptr_tostring(lua_State *state) -{ - uint8_t *ptr = get_object_addr(state, 1, 0, "access"); - - lua_getfield(state, UPVAL_METATABLE, "__metatable"); - const char *cname = lua_tostring(state, -1); - - lua_pushstring(state, stl_sprintf("<%s: 0x%08x>", cname, (unsigned)ptr).c_str()); - return 1; -} - /** * Metamethod: __index for structures. */ diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp index c8af46cbf..5e11e0621 100644 --- a/library/RemoteTools.cpp +++ b/library/RemoteTools.cpp @@ -216,6 +216,9 @@ void DFHack::describeMaterial(BasicMaterialInfo *info, const MaterialInfo &mat, case MaterialInfo::Plant: info->set_plant_id(mat.index); break; + + default: + break; } } @@ -298,7 +301,7 @@ void DFHack::describeUnit(BasicUnitInfo *info, df::unit *unit, if (mask && mask->labors()) { - for (int i = 0; i < sizeof(unit->status.labors)/sizeof(bool); i++) + for (size_t i = 0; i < sizeof(unit->status.labors)/sizeof(bool); i++) if (unit->status.labors[i]) info->add_labors(i); } @@ -630,7 +633,7 @@ static command_result ListSquads(color_ostream &stream, static command_result SetUnitLabors(color_ostream &stream, const SetUnitLaborsIn *in) { - for (size_t i = 0; i < in->change_size(); i++) + for (int i = 0; i < in->change_size(); i++) { auto change = in->change(i); auto unit = df::unit::find(change.unit_id()); diff --git a/library/TileTypes.cpp b/library/TileTypes.cpp index fa5d99555..5564e5e3f 100644 --- a/library/TileTypes.cpp +++ b/library/TileTypes.cpp @@ -68,6 +68,8 @@ namespace DFHack return tiletype::LavaPillar; case tiletype_material::STONE: return tiletype::StonePillar; + default: + break; } } diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index 02f988248..a411ae667 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -372,14 +372,14 @@ namespace DFHack template int linear_index(const DFHack::enum_list_attr &lst, T val) { - for (int i = 0; i < lst.size; i++) + for (size_t i = 0; i < lst.size; i++) if (lst.items[i] == val) return i; return -1; } inline int linear_index(const DFHack::enum_list_attr &lst, const std::string &val) { - for (int i = 0; i < lst.size; i++) + for (size_t i = 0; i < lst.size; i++) if (lst.items[i] == val) return i; return -1; diff --git a/library/include/RemoteTools.h b/library/include/RemoteTools.h index bccbb5e62..65884badc 100644 --- a/library/include/RemoteTools.h +++ b/library/include/RemoteTools.h @@ -73,7 +73,7 @@ namespace DFHack */ template void flagarray_to_ints(RepeatedField *pf, const BitArray &val) { - for (int i = 0; i < val.size*8; i++) + for (size_t i = 0; i < val.size*8; i++) if (val.is_set(T(i))) pf->Add(i); } diff --git a/library/include/modules/Windows.h b/library/include/modules/Windows.h index 314b6e292..7dbc9f1ad 100644 --- a/library/include/modules/Windows.h +++ b/library/include/modules/Windows.h @@ -117,11 +117,11 @@ namespace Windows for ( auto iter = str.begin(); iter != str.end(); iter++) { auto elem = *iter; - if(cursor_y >= height) + if(cursor_y >= (int)height) break; if(wrap) { - if(cursor_x >= width) + if(cursor_x >= (int)width) cursor_x = wrap_column; } df_screentile & tile = buffer[cursor_x * height + cursor_y]; @@ -224,12 +224,12 @@ namespace Windows virtual void blit_to_parent () { df_tilebuf par = parent->getBuffer(); - for(int xi = 0; xi < width; xi++) + for(unsigned xi = 0; xi < width; xi++) { - for(int yi = 0; yi < height; yi++) + for(unsigned yi = 0; yi < height; yi++) { - int parx = left + xi; - int pary = top + yi; + unsigned parx = left + xi; + unsigned pary = top + yi; if(pary >= par.height) continue; if(parx >= par.width) continue; par.data[parx * par.height + pary] = buffer[xi * height + yi]; diff --git a/library/modules/Constructions.cpp b/library/modules/Constructions.cpp index 8dc81911c..4c2bf8ec1 100644 --- a/library/modules/Constructions.cpp +++ b/library/modules/Constructions.cpp @@ -52,14 +52,14 @@ uint32_t Constructions::getCount() df::construction * Constructions::getConstruction(const int32_t index) { - if (index < 0 || index >= getCount()) + if (uint32_t(index) >= getCount()) return NULL; return world->constructions[index]; } bool Constructions::copyConstruction(const int32_t index, t_construction &out) { - if (index < 0 || index >= getCount()) + if (uint32_t(index) >= getCount()) return false; out.origin = world->constructions[index]; diff --git a/library/modules/Engravings.cpp b/library/modules/Engravings.cpp index 3621bc736..bff17ef5f 100644 --- a/library/modules/Engravings.cpp +++ b/library/modules/Engravings.cpp @@ -53,14 +53,14 @@ uint32_t Engravings::getCount() df::engraving * Engravings::getEngraving(int index) { - if (index < 0 || index >= getCount()) + if (uint32_t(index) >= getCount()) return NULL; return world->engravings[index]; } bool Engravings::copyEngraving(const int32_t index, t_engraving &out) { - if (index < 0 || index >= getCount()) + if (uint32_t(index) >= getCount()) return false; out.origin = world->engravings[index]; diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 592f27c0b..2eaa4c27e 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -223,7 +223,7 @@ df::job *Gui::getSelectedWorkshopJob(color_ostream &out, bool quiet) df::building *selected = world->selected_building; int idx = *ui_workshop_job_cursor; - if (idx < 0 || idx >= selected->jobs.size()) + if (size_t(idx) >= selected->jobs.size()) { out.printerr("Invalid job cursor index: %d\n", idx); return NULL; diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 9d0657e19..96fcc19ce 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -536,6 +536,9 @@ df::coord Items::getPosition(df::item *item) if (auto bld = ref->getBuilding()) return df::coord(bld->centerx, bld->centery, bld->z); break; + + default: + break; } } } diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index e130915d6..3c4933fb7 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -676,6 +676,11 @@ t_matpair MapExtras::BlockInfo::getBaseMaterial(df::tiletype tt, df::coord2d pos int x = pos.x, y = pos.y; switch (tileMaterial(tt)) { + case NONE: + case AIR: + rv.mat_type = -1; + break; + case DRIFTWOOD: case SOIL: { @@ -759,6 +764,9 @@ t_matpair MapExtras::BlockInfo::getBaseMaterial(df::tiletype tt, df::coord2d pos } case CONSTRUCTION: // just a fallback + case MAGMA: + case HFS: + // use generic 'rock' break; case FROZEN_LIQUID: @@ -776,9 +784,6 @@ t_matpair MapExtras::BlockInfo::getBaseMaterial(df::tiletype tt, df::coord2d pos case CAMPFIRE: rv.mat_type = builtin_mats::ASH; break; - - default: - rv.mat_type = -1; } return rv; @@ -1031,9 +1036,9 @@ MapExtras::Block *MapExtras::MapCache::BlockAt(DFCoord blockcoord) } else { - if(blockcoord.x >= 0 && blockcoord.x < x_bmax && - blockcoord.y >= 0 && blockcoord.y < y_bmax && - blockcoord.z >= 0 && blockcoord.z < z_max) + if(unsigned(blockcoord.x) < x_bmax && + unsigned(blockcoord.y) < y_bmax && + unsigned(blockcoord.z) < z_max) { Block * nblo = new Block(this, blockcoord); blocks[blockcoord] = nblo; diff --git a/library/modules/Materials.cpp b/library/modules/Materials.cpp index 0172e24f8..f49dd82e2 100644 --- a/library/modules/Materials.cpp +++ b/library/modules/Materials.cpp @@ -80,7 +80,7 @@ bool MaterialInfo::decode(df::item *item) bool MaterialInfo::decode(const df::material_vec_ref &vr, int idx) { - if (idx < 0 || idx >= vr.mat_type.size() || idx >= vr.mat_index.size()) + if (size_t(idx) >= vr.mat_type.size() || size_t(idx) >= vr.mat_index.size()) return decode(-1); else return decode(vr.mat_type[idx], vr.mat_index[idx]); @@ -103,7 +103,7 @@ bool MaterialInfo::decode(int16_t type, int32_t index) df::world_raws &raws = world->raws; - if (type >= sizeof(raws.mat_table.builtin)/sizeof(void*)) + if (size_t(type) >= sizeof(raws.mat_table.builtin)/sizeof(void*)) return false; if (index < 0) @@ -127,7 +127,7 @@ bool MaterialInfo::decode(int16_t type, int32_t index) mode = Creature; subtype = type-CREATURE_BASE; creature = df::creature_raw::find(index); - if (!creature || subtype >= creature->material.size()) + if (!creature || size_t(subtype) >= creature->material.size()) return false; material = creature->material[subtype]; } @@ -139,7 +139,7 @@ bool MaterialInfo::decode(int16_t type, int32_t index) if (!figure) return false; creature = df::creature_raw::find(figure->race); - if (!creature || subtype >= creature->material.size()) + if (!creature || size_t(subtype) >= creature->material.size()) return false; material = creature->material[subtype]; } @@ -148,7 +148,7 @@ bool MaterialInfo::decode(int16_t type, int32_t index) mode = Plant; subtype = type-PLANT_BASE; plant = df::plant_raw::find(index); - if (!plant || subtype >= plant->material.size()) + if (!plant || size_t(subtype) >= plant->material.size()) return false; material = plant->material[subtype]; } diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 8b44d4cf9..55bd98dec 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -78,7 +78,7 @@ df::unit * Units::GetCreature (const int32_t index) if (!isValid()) return NULL; // read pointer from vector at position - if(index > world->units.all.size()) + if(size_t(index) > world->units.all.size()) return 0; return world->units.all[index]; } diff --git a/library/modules/Vegetation.cpp b/library/modules/Vegetation.cpp index bd0eeb656..a76c3a2cd 100644 --- a/library/modules/Vegetation.cpp +++ b/library/modules/Vegetation.cpp @@ -54,14 +54,14 @@ uint32_t Vegetation::getCount() df::plant * Vegetation::getPlant(const int32_t index) { - if (index < 0 || index >= getCount()) + if (uint32_t(index) >= getCount()) return NULL; return world->plants.all[index]; } bool Vegetation::copyPlant(const int32_t index, t_plant &out) { - if (index < 0 || index >= getCount()) + if (uint32_t(index) >= getCount()) return false; out.origin = world->plants.all[index]; diff --git a/library/modules/Windows.cpp b/library/modules/Windows.cpp index 0cdd7e831..e069d964e 100644 --- a/library/modules/Windows.cpp +++ b/library/modules/Windows.cpp @@ -41,7 +41,7 @@ Windows::df_screentile *Windows::getScreenBuffer() } Windows::df_window::df_window(int x, int y, unsigned int width, unsigned int height) -:buffer(0), parent(0), left(x), top(y), width(width), height(height), current_painter(NULL) +:buffer(0), width(width), height(height), parent(0), left(x), top(y), current_painter(NULL) { buffer = 0; }; diff --git a/library/xml b/library/xml index 25c2a3dad..521aad437 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 25c2a3dad964abbcceb5abd41558b71fb113e83b +Subproject commit 521aad43799ff65d772e5314972b8bc675500fb3 diff --git a/plugins/burrows.cpp b/plugins/burrows.cpp index a629e30c1..8080710c3 100644 --- a/plugins/burrows.cpp +++ b/plugins/burrows.cpp @@ -604,7 +604,7 @@ static command_result burrow(color_ostream &out, vector ¶meters) bool state = (cmd == "enable"); - for (int i = 1; i < parameters.size(); i++) + for (size_t i = 1; i < parameters.size(); i++) { string &option = parameters[i]; @@ -619,7 +619,7 @@ static command_result burrow(color_ostream &out, vector ¶meters) if (parameters.size() < 2) return CR_WRONG_USAGE; - for (int i = 1; i < parameters.size(); i++) + for (size_t i = 1; i < parameters.size(); i++) { auto target = findByName(out, parameters[i]); if (!target) @@ -642,7 +642,7 @@ static command_result burrow(color_ostream &out, vector ¶meters) bool enable = (cmd != "remove-units"); - for (int i = 2; i < parameters.size(); i++) + for (size_t i = 2; i < parameters.size(); i++) { auto source = findByName(out, parameters[i]); if (!source) @@ -656,7 +656,7 @@ static command_result burrow(color_ostream &out, vector ¶meters) if (parameters.size() < 2) return CR_WRONG_USAGE; - for (int i = 1; i < parameters.size(); i++) + for (size_t i = 1; i < parameters.size(); i++) { auto target = findByName(out, parameters[i]); if (!target) @@ -679,7 +679,7 @@ static command_result burrow(color_ostream &out, vector ¶meters) bool enable = (cmd != "remove-tiles"); - for (int i = 2; i < parameters.size(); i++) + for (size_t i = 2; i < parameters.size(); i++) { if (setTilesByKeyword(target, parameters[i], enable)) continue; diff --git a/plugins/jobutils.cpp b/plugins/jobutils.cpp index 511095943..de7f81366 100644 --- a/plugins/jobutils.cpp +++ b/plugins/jobutils.cpp @@ -193,7 +193,7 @@ static bool build_choice_matches(df::ui_build_item_req *req, df::build_req_choic { if (gen->mat_type == new_mat.type && gen->mat_index == new_mat.index && - (ignore_select || gen->used_count < gen->candidates.size())) + (ignore_select || size_t(gen->used_count) < gen->candidates.size())) { return true; } @@ -305,7 +305,7 @@ static df::job_item *getJobItem(color_ostream &out, df::job *job, std::string id return NULL; int v = atoi(idx.c_str()); - if (v < 1 || v > job->job_items.size()) { + if (v < 1 || size_t(v) > job->job_items.size()) { out.printerr("Invalid item index.\n"); return NULL; } diff --git a/plugins/mapexport/mapexport.cpp b/plugins/mapexport/mapexport.cpp index fa1736ed7..625f4a74d 100644 --- a/plugins/mapexport/mapexport.cpp +++ b/plugins/mapexport/mapexport.cpp @@ -2,7 +2,7 @@ #include "Console.h" #include "Export.h" #include "PluginManager.h" -#include "modules/MapCache.h"f +#include "modules/MapCache.h" using namespace DFHack; #include @@ -50,6 +50,7 @@ static dfproto::Tile::TileMaterialType toProto(df::tiletype_material mat) switch (mat) { #define CONVERT(name) case tiletype_material::name: return dfproto::Tile::name; + case tiletype_material::NONE: CONVERT(AIR) case tiletype_material::PLANT: CONVERT(SOIL) @@ -74,9 +75,8 @@ static dfproto::Tile::TileMaterialType toProto(df::tiletype_material mat) CONVERT(BROOK) CONVERT(RIVER) #undef CONVERT - default: - return dfproto::Tile::AIR; } + return dfproto::Tile::AIR; } command_result mapexport (color_ostream &out, std::vector & parameters) diff --git a/plugins/workflow.cpp b/plugins/workflow.cpp index aa3c94a55..5e5ca84bc 100644 --- a/plugins/workflow.cpp +++ b/plugins/workflow.cpp @@ -892,6 +892,9 @@ static void guess_job_material(df::job *job, MaterialInfo &mat, df::dfhack_mater case item_type::WOOD: mat_mask.bits.wood = mat_mask.bits.wood2 = true; break; + + default: + break; } } } @@ -1148,6 +1151,9 @@ static void map_job_items(color_ostream &out) if (item->getTotalDimension() < 10000) is_invalid = true; break; + + default: + break; } if (item->flags.bits.melt && !item->flags.bits.owned && !itemBusy(item)) From adbd351462f71db6a98b681eb9336524cc530092 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 21 Apr 2012 12:46:55 +0400 Subject: [PATCH 06/18] Rename units.other[0] to units.active. --- library/RemoteTools.cpp | 2 +- library/modules/Gui.cpp | 4 ++-- library/xml | 2 +- plugins/Dfusion/luafiles/adv_tools/init.lua | 2 +- plugins/Dfusion/luafiles/common.lua | 4 ++-- plugins/Dfusion/luafiles/tools/init.lua | 4 ++-- plugins/advtools.cpp | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/library/RemoteTools.cpp b/library/RemoteTools.cpp index 5e11e0621..b72c0c91d 100644 --- a/library/RemoteTools.cpp +++ b/library/RemoteTools.cpp @@ -402,7 +402,7 @@ static command_result GetWorldInfo(color_ostream &stream, case GAMETYPE_ADVENTURE_MAIN: out->set_mode(GetWorldInfoOut::MODE_ADVENTURE); - if (auto unit = vector_get(world->units.other[0], 0)) + if (auto unit = vector_get(world->units.active, 0)) out->set_player_unit_id(unit->id); if (!ui_advmode) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 2eaa4c27e..6841421b6 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -194,7 +194,7 @@ bool Gui::view_unit_hotkey(df::viewscreen *top) if (!ui_selected_unit) // allow missing return false; - return vector_get(world->units.other[0], *ui_selected_unit) != NULL; + return vector_get(world->units.active, *ui_selected_unit) != NULL; } bool Gui::unit_inventory_hotkey(df::viewscreen *top) @@ -303,7 +303,7 @@ static df::unit *getAnyUnit(df::viewscreen *top) if (!ui_selected_unit) return NULL; - return vector_get(world->units.other[0], *ui_selected_unit); + return vector_get(world->units.active, *ui_selected_unit); } case LookAround: { diff --git a/library/xml b/library/xml index 521aad437..ee172f69f 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 521aad43799ff65d772e5314972b8bc675500fb3 +Subproject commit ee172f69f613716c8d740bbd22054f48b1a22d5f diff --git a/plugins/Dfusion/luafiles/adv_tools/init.lua b/plugins/Dfusion/luafiles/adv_tools/init.lua index f5fd9a473..5504f32bc 100644 --- a/plugins/Dfusion/luafiles/adv_tools/init.lua +++ b/plugins/Dfusion/luafiles/adv_tools/init.lua @@ -5,7 +5,7 @@ function adv_tools.reincarnate(swap_soul) --only for adventurer i guess if swap_soul==nil then swap_soul=true end - local adv=df.global.world.units.other[0][0] + local adv=df.global.world.units.active[0] if adv.flags1.dead==false then error("You are not dead (yet)!") end diff --git a/plugins/Dfusion/luafiles/common.lua b/plugins/Dfusion/luafiles/common.lua index 7e41dc4e5..951468bc7 100644 --- a/plugins/Dfusion/luafiles/common.lua +++ b/plugins/Dfusion/luafiles/common.lua @@ -472,8 +472,8 @@ function getSelectedUnit() return nil end local unit_indx=df.global.ui_selected_unit - if unit_indx<#df.global.world.units.other[0]-1 then - return df.global.world.units.other[0][unit_indx] + if unit_indx<#df.global.world.units.active-1 then + return df.global.world.units.active[unit_indx] else return nil end diff --git a/plugins/Dfusion/luafiles/tools/init.lua b/plugins/Dfusion/luafiles/tools/init.lua index b01157c87..e3a4607cf 100644 --- a/plugins/Dfusion/luafiles/tools/init.lua +++ b/plugins/Dfusion/luafiles/tools/init.lua @@ -113,7 +113,7 @@ function tools.change_adv(unit,nemesis) if unit==nil then error("Invalid unit!") end - local other=df.global.world.units.other[0] + local other=df.global.world.units.active local unit_indx for k,v in pairs(other) do if v==unit then @@ -157,7 +157,7 @@ function tools.MakeFollow(unit,trgunit) error("Invalid creature") end if trgunit==nil then - trgunit=df.global.world.units.other[0][0] + trgunit=df.global.world.units.active[0] end unit.relations.group_leader_id=trgunit.id local u_nem=getNemesis(unit) diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp index 69841849a..4823d362c 100644 --- a/plugins/advtools.cpp +++ b/plugins/advtools.cpp @@ -169,7 +169,7 @@ bool bodySwap(color_ostream &out, df::unit *player) return false; } - auto &vec = world->units.other[0]; + auto &vec = world->units.active; int idx = linear_index(vec, player); if (idx < 0) @@ -195,7 +195,7 @@ df::nemesis_record *getPlayerNemesis(color_ostream &out, bool restore_swap) if (restore_swap) { - df::unit *ctl = world->units.other[0][0]; + df::unit *ctl = world->units.active[0]; auto ctl_nemesis = Units::getNemesis(ctl); if (ctl_nemesis != real_nemesis) From 3282ac3db216ef43cab5744631b57ed05bcf8a12 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 21 Apr 2012 15:43:52 +0400 Subject: [PATCH 07/18] Add a hotkey command that sorts units in lists using lua comparators. --- library/DataStaticsFields.cpp | 1 + library/LuaApi.cpp | 1 + library/include/DataIdentity.h | 1 + library/include/modules/Units.h | 2 + library/lua/utils.lua | 106 ++++++++++++++ library/modules/Units.cpp | 16 +++ library/xml | 2 +- plugins/CMakeLists.txt | 1 + plugins/lua/sort.lua | 32 +++++ plugins/lua/sort/units.lua | 20 +++ plugins/sort.cpp | 235 ++++++++++++++++++++++++++++++++ 11 files changed, 416 insertions(+), 1 deletion(-) create mode 100644 library/lua/utils.lua create mode 100644 plugins/lua/sort.lua create mode 100644 plugins/lua/sort/units.lua create mode 100644 plugins/sort.cpp diff --git a/library/DataStaticsFields.cpp b/library/DataStaticsFields.cpp index a34938f95..79aa3bcf1 100644 --- a/library/DataStaticsFields.cpp +++ b/library/DataStaticsFields.cpp @@ -28,6 +28,7 @@ namespace df { NUMBER_IDENTITY_TRAITS(int64_t); NUMBER_IDENTITY_TRAITS(uint64_t); NUMBER_IDENTITY_TRAITS(float); + NUMBER_IDENTITY_TRAITS(double); bool_identity identity_traits::identity; stl_string_identity identity_traits::identity; diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index ccd057c9c..00192c058 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -615,6 +615,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, clearBurrowMembers), WRAPM(Units, isInBurrow), WRAPM(Units, setInBurrow), + WRAPM(Units, getAge), { NULL, NULL } }; diff --git a/library/include/DataIdentity.h b/library/include/DataIdentity.h index e4197a506..dcd0ae979 100644 --- a/library/include/DataIdentity.h +++ b/library/include/DataIdentity.h @@ -447,6 +447,7 @@ namespace df NUMBER_IDENTITY_TRAITS(int64_t); NUMBER_IDENTITY_TRAITS(uint64_t); NUMBER_IDENTITY_TRAITS(float); + NUMBER_IDENTITY_TRAITS(double); template<> struct DFHACK_EXPORT identity_traits { static bool_identity identity; diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index e093ed1ef..775cc5181 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -214,6 +214,8 @@ DFHACK_EXPORT void clearBurrowMembers(df::burrow *burrow); DFHACK_EXPORT bool isInBurrow(df::unit *unit, df::burrow *burrow); DFHACK_EXPORT void setInBurrow(df::unit *unit, df::burrow *burrow, bool enable); +DFHACK_EXPORT double getAge(df::unit *unit); + } } #endif diff --git a/library/lua/utils.lua b/library/lua/utils.lua new file mode 100644 index 000000000..d884f2f62 --- /dev/null +++ b/library/lua/utils.lua @@ -0,0 +1,106 @@ +local _ENV = mkmodule('utils') + +-- Comparator function +function compare(a,b) + if a < b then + return -1 + elseif a > b then + return 1 + else + return 0 + end +end + +-- Sort strings; compare empty last +function compare_name(a,b) + if a == '' then + if b == '' then + return 0 + else + return 1 + end + elseif b == '' then + return -1 + else + return compare(a,b) + end +end + +--[[ + Sort items in data according to ordering. + + Each ordering spec is a table with possible fields: + + * key = function(value) + Computes comparison key from a data value. Not called on nil. + * key_table = function(data) + Computes a key table from the data table in one go. + * compare = function(a,b) + Comparison function. Defaults to compare above. + Called on non-nil keys; nil sorts last. + + Returns a table of integer indices into data. +--]] +function make_sort_order(data,ordering) + -- Compute sort keys and comparators + local keys = {} + local cmps = {} + + for i=1,#ordering do + local order = ordering[i] + + if order.key_table then + keys[i] = order.key_table(data) + elseif order.key then + local kt = {} + local kf = order.key + for j=1,#data do + if data[j] == nil then + kt[j] = nil + else + kt[j] = kf(data[j]) + end + end + keys[i] = kt + else + keys[i] = data + end + + cmps[i] = order.compare or compare + end + + -- Make an order table + local index = {} + for i=1,#data do + index[i] = i + end + + -- Sort the ordering table + table.sort(index, function(ia,ib) + for i=1,#keys do + local ka = keys[i][ia] + local kb = keys[i][ib] + + -- Sort nil keys to the end + if ka == nil then + if kb ~= nil then + return false + end + elseif kb == nil then + return true + else + local cmpv = cmps[i](ka,kb) + if cmpv < 0 then + return true + elseif cmpv > 0 then + return false + end + end + end + return ia < ib -- this should ensure stable sort + end) + + return index +end + +return _ENV \ No newline at end of file diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 55bd98dec..e9699edbe 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -734,3 +734,19 @@ void DFHack::Units::setInBurrow(df::unit *unit, df::burrow *burrow, bool enable) } } +double DFHack::Units::getAge(df::unit *unit) +{ + using df::global::cur_year; + using df::global::cur_year_tick; + + CHECK_NULL_POINTER(unit); + + if (!cur_year || !cur_year_tick) + return -1; + + double year_ticks = 403200.0; + double birth_time = unit->relations.birth_year + unit->relations.birth_time/year_ticks; + double cur_time = *cur_year + *cur_year_tick / year_ticks; + + return cur_time - birth_time; +} diff --git a/library/xml b/library/xml index ee172f69f..e217d28c4 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit ee172f69f613716c8d740bbd22054f48b1a22d5f +Subproject commit e217d28c4800fadd3b37e153a363656dc7beb3e3 diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 4bfb392a2..70b40cedb 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -106,6 +106,7 @@ if (BUILD_SUPPORTED) DFHACK_PLUGIN(regrass regrass.cpp) # this one exports functions to lua DFHACK_PLUGIN(burrows burrows.cpp LINK_LIBRARIES lua) + DFHACK_PLUGIN(sort sort.cpp LINK_LIBRARIES lua) # not yet. busy with other crud again... #DFHACK_PLUGIN(versionosd versionosd.cpp) endif() diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua new file mode 100644 index 000000000..2318d7e07 --- /dev/null +++ b/plugins/lua/sort.lua @@ -0,0 +1,32 @@ +local _ENV = mkmodule('plugins.sort') + +local utils = require('utils') +local units = require('plugins.sort.units') + +orders = orders or {} +orders.units = units.orders + +function parse_ordering_spec(type,...) + local group = orders[type] + if group == nil then + dfhack.printerr('Invalid ordering class: '..tostring(type)) + return nil + end + + local specs = table.pack(...) + local rv = { } + for _,spec in ipairs(specs) do + local cm = group[spec] + if cm == nil then + dfhack.printerr('Unknown order for '..type..': '..tostring(spec)) + return nil + end + rv[#rv+1] = cm + end + + return rv +end + +make_sort_order = utils.make_sort_order + +return _ENV \ No newline at end of file diff --git a/plugins/lua/sort/units.lua b/plugins/lua/sort/units.lua new file mode 100644 index 000000000..872e49429 --- /dev/null +++ b/plugins/lua/sort/units.lua @@ -0,0 +1,20 @@ +local _ENV = mkmodule('plugins.sort.units') + +local utils = require('utils') + +orders = orders or {} + +orders.name = { + key = function(unit) + return dfhack.TranslateName(unit.name) + end, + compare = utils.compare_name +} + +orders.age = { + key = function(unit) + return dfhack.units.getAge(unit) + end +} + +return _ENV \ No newline at end of file diff --git a/plugins/sort.cpp b/plugins/sort.cpp new file mode 100644 index 000000000..a373d54c3 --- /dev/null +++ b/plugins/sort.cpp @@ -0,0 +1,235 @@ +#include "Core.h" +#include "Console.h" +#include "Export.h" +#include "PluginManager.h" + +#include "modules/Gui.h" +#include "modules/Translation.h" +#include "modules/Units.h" + +#include "LuaTools.h" + +#include "DataDefs.h" +#include "df/ui.h" +#include "df/world.h" +#include "df/viewscreen_joblistst.h" +#include "df/viewscreen_unitlistst.h" +#include "df/viewscreen_dwarfmodest.h" + +#include "MiscUtils.h" + +#include + +using std::vector; +using std::string; +using std::endl; +using namespace DFHack; +using namespace df::enums; + +using df::global::ui; +using df::global::world; + +static bool unit_list_hotkey(df::viewscreen *top); + +static command_result sort_units(color_ostream &out, vector & parameters); + +DFHACK_PLUGIN("sort"); + +DFhackCExport command_result plugin_init (color_ostream &out, std::vector &commands) +{ + commands.push_back(PluginCommand( + "sort-units", "Sort the visible unit list.", sort_units, unit_list_hotkey, + " sort-units filter...\n" + " Sort the unit list using the given sequence of comparisons.\n" + )); + return CR_OK; +} + +DFhackCExport command_result plugin_shutdown ( color_ostream &out ) +{ + return CR_OK; +} + +template +void reorder_vector(std::vector *pvec, const std::vector &order) +{ + assert(pvec->size() == order.size()); + + std::vector tmp(*pvec); + for (size_t i = 0; i < order.size(); i++) + (*pvec)[i] = tmp[order[i]]; +} + +bool parse_ordering_spec(color_ostream &out, lua_State *L, std::string type, const std::vector ¶ms) +{ + if (!lua_checkstack(L, params.size() + 2)) + return false; + + if (!Lua::PushModulePublic(out, L, "plugins.sort", "parse_ordering_spec")) + return false; + + Lua::Push(L, type); + for (size_t i = 0; i < params.size(); i++) + Lua::Push(L, params[i]); + + if (!Lua::SafeCall(out, L, params.size()+1, 1)) + return false; + + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); + return false; + } + + return true; +} + +bool read_order(color_ostream &out, lua_State *L, std::vector *order, size_t size) +{ + std::vector found; + + if (!lua_istable(L, -1)) + { + out.printerr("Not a table returned as ordering.\n"); + goto fail; + } + + if (lua_rawlen(L, -1) != size) + { + out.printerr("Invalid ordering size: expected %d, actual %d\n", size, lua_rawlen(L, -1)); + goto fail; + } + + order->clear(); + order->resize(size); + found.resize(size); + + for (size_t i = 1; i <= size; i++) + { + lua_rawgeti(L, -1, i); + int v = lua_tointeger(L, -1); + lua_pop(L, 1); + + if (v < 1 || size_t(v) > size) + { + out.printerr("Order value out of range: %d\n", v); + goto fail; + } + + if (found[v-1]) + { + out.printerr("Duplicate order value: %d\n", v); + goto fail; + } + + found[v-1] = 1; + (*order)[i-1] = v-1; + } + + lua_pop(L, 1); + return true; +fail: + lua_pop(L, 1); + return false; +} + +template +bool compute_order(color_ostream &out, lua_State *L, int base, std::vector *order, const std::vector &key) +{ + lua_pushvalue(L, base+1); + Lua::PushVector(L, key); + lua_pushvalue(L, base+2); + + if (!Lua::SafeCall(out, L, 2, 1)) + return false; + + return read_order(out, L, order, key.size()); +} + + +static bool unit_list_hotkey(df::viewscreen *screen) +{ + if (strict_virtual_cast(screen)) + return true; + if (strict_virtual_cast(screen)) + return true; + + if (strict_virtual_cast(screen)) + { + using namespace df::enums::ui_sidebar_mode; + + switch (ui->main.mode) + { + case Burrows: + return ui->burrows.in_add_units_mode; + default: + return false; + } + } + + return false; +} + +static command_result sort_units(color_ostream &out, vector ¶meters) +{ + if (parameters.empty()) + return CR_WRONG_USAGE; + + auto L = Lua::Core::State; + int top = lua_gettop(L); + + if (!Lua::Core::PushModulePublic(out, "plugins.sort", "make_sort_order")) + { + out.printerr("Cannot access the sorter function.\n"); + return CR_WRONG_USAGE; + } + + if (!parse_ordering_spec(out, L, "units", parameters)) + { + out.printerr("Invalid unit ordering specification.\n"); + lua_settop(L, top); + return CR_WRONG_USAGE; + } + + auto screen = Core::getInstance().getTopViewscreen(); + std::vector order; + + if (auto units = strict_virtual_cast(screen)) + { + for (int i = 0; i < 4; i++) + { + if (compute_order(out, L, top, &order, units->units[i])) + { + reorder_vector(&units->units[i], order); + reorder_vector(&units->jobs[i], order); + } + } + } + else if (auto jobs = strict_virtual_cast(screen)) + { + if (compute_order(out, L, top, &order, jobs->units)) + { + reorder_vector(&jobs->units, order); + reorder_vector(&jobs->jobs, order); + } + } + else if (strict_virtual_cast(screen)) + { + switch (ui->main.mode) + { + case ui_sidebar_mode::Burrows: + if (compute_order(out, L, top, &order, ui->burrows.list_units)) + { + reorder_vector(&ui->burrows.list_units, order); + reorder_vector(&ui->burrows.sel_units, order); + } + break; + + default: + break;; + } + } + + lua_settop(L, top); + return CR_OK; +} From 4af051bab3e455a9115a44e43b8c3da0cd189f43 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 21 Apr 2012 16:53:17 +0400 Subject: [PATCH 08/18] Add a few more unit orderings, and a way to reverse direction. --- library/lua/utils.lua | 11 ++++++-- plugins/Dfusion/dfusion.cpp | 22 +++++++++++++--- plugins/lua/sort.lua | 21 ++++++++++++++++ plugins/lua/sort/units.lua | 50 ++++++++++++++++++++++++++++++++++++- plugins/sort.cpp | 7 +++++- 5 files changed, 104 insertions(+), 7 deletions(-) diff --git a/library/lua/utils.lua b/library/lua/utils.lua index d884f2f62..3becdbb6d 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -38,6 +38,10 @@ end * compare = function(a,b) Comparison function. Defaults to compare above. Called on non-nil keys; nil sorts last. + * nil_first + If true, nil keys are sorted first instead of last. + * reverse + If true, sort non-nil keys in descending order. Returns a table of integer indices into data. --]] @@ -84,12 +88,15 @@ function make_sort_order(data,ordering) -- Sort nil keys to the end if ka == nil then if kb ~= nil then - return false + return ordering[i].nil_first end elseif kb == nil then - return true + return not ordering[i].nil_first else local cmpv = cmps[i](ka,kb) + if ordering[i].reverse then + cmpv = -cmpv + end if cmpv < 0 then return true elseif cmpv > 0 then diff --git a/plugins/Dfusion/dfusion.cpp b/plugins/Dfusion/dfusion.cpp index d8710c2db..2b36a9747 100644 --- a/plugins/Dfusion/dfusion.cpp +++ b/plugins/Dfusion/dfusion.cpp @@ -121,10 +121,26 @@ command_result lua_run_file (color_ostream &out, std::vector ¶ } command_result lua_run (color_ostream &out, std::vector ¶meters) { - if (!parameters.empty() && parameters[0] == "--core-context") + if (!parameters.empty()) { - Lua::InterpreterLoop(out, Lua::Core::State, "core lua"); - return CR_OK; + if (parameters[0] == "--core-context") + { + Lua::InterpreterLoop(out, Lua::Core::State, "core lua"); + return CR_OK; + } + else if (parameters[0] == "--core-reload") + { + CoreSuspender suspend; + + for (size_t i = 1; i < parameters.size(); i++) + { + lua_getglobal(Lua::Core::State, "reload"); + lua_pushstring(Lua::Core::State, parameters[i].c_str()); + Lua::SafeCall(out, Lua::Core::State, 1, 0); + } + + return CR_OK; + } } mymutex->lock(); diff --git a/plugins/lua/sort.lua b/plugins/lua/sort.lua index 2318d7e07..f042e85cd 100644 --- a/plugins/lua/sort.lua +++ b/plugins/lua/sort.lua @@ -15,12 +15,33 @@ function parse_ordering_spec(type,...) local specs = table.pack(...) local rv = { } + for _,spec in ipairs(specs) do + local nil_first = false + if string.sub(spec,1,1) == '<' then + nil_first = true + spec = string.sub(spec,2) + end + + local reverse = false + if string.sub(spec,1,1) == '>' then + reverse = true + spec = string.sub(spec,2) + end + local cm = group[spec] + if cm == nil then dfhack.printerr('Unknown order for '..type..': '..tostring(spec)) return nil end + + if nil_first or reverse then + cm = copyall(cm) + cm.nil_first = nil_first + cm.reverse = reverse + end + rv[#rv+1] = cm end diff --git a/plugins/lua/sort/units.lua b/plugins/lua/sort/units.lua index 872e49429..b92fc6c82 100644 --- a/plugins/lua/sort/units.lua +++ b/plugins/lua/sort/units.lua @@ -6,7 +6,9 @@ orders = orders or {} orders.name = { key = function(unit) - return dfhack.TranslateName(unit.name) + if unit.name.has_name then + return dfhack.TranslateName(unit.name) + end end, compare = utils.compare_name } @@ -17,4 +19,50 @@ orders.age = { end } +-- This assumes that units are added to active in arrival order +orders.arrival = { + key_table = function(units) + local tmp={} + for i,v in ipairs(units) do + tmp[v.id] = i + end + local idx={} + for i,v in ipairs(df.global.world.units.active) do + local ix = tmp[v.id] + if ix ~= nil then + idx[ix] = i + end + end + return idx + end +} + +orders.profession = { + key = function(unit) + local cp = unit.custom_profession + if cp == '' then + cp = df.profession.attrs[unit.profession].caption + end + return cp + end +} + +orders.squad = { + key = function(unit) + local sidx = unit.military.squad_index + if sidx >= 0 then + return sidx + end + end +} + +orders.squad_position = { + key = function(unit) + local sidx = unit.military.squad_index + if sidx >= 0 then + return sidx * 1000 + unit.military.squad_position + end + end +} + return _ENV \ No newline at end of file diff --git a/plugins/sort.cpp b/plugins/sort.cpp index a373d54c3..48e4bcaca 100644 --- a/plugins/sort.cpp +++ b/plugins/sort.cpp @@ -39,8 +39,13 @@ DFhackCExport command_result plugin_init (color_ostream &out, std::vector ' prefix reverses the sort order for defined values.\n" + " Unit order examples:\n" + " name, age, arrival, squad, squad_position, profession\n" + "The orderings are defined in hack/lua/plugins/sort/*.lua\n" )); return CR_OK; } From 2ef321a2086f03de30d184c06c527f504893cd07 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 21 Apr 2012 20:15:57 +0400 Subject: [PATCH 09/18] Preserve the original lua global environment for modules. The intent is to prevent accidental pollution of module namespaces by globals defined from careless scripts running in the _G environment. --- library/LuaTools.cpp | 45 ++++++++++++++++++++++++++++++++++++------ library/lua/dfhack.lua | 11 ++++++++++- 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/library/LuaTools.cpp b/library/LuaTools.cpp index 469caa65f..253af099c 100644 --- a/library/LuaTools.cpp +++ b/library/LuaTools.cpp @@ -162,11 +162,13 @@ static Console *get_console(lua_State *state) return static_cast(pstream); } +static int DFHACK_TOSTRING_TOKEN = 0; + static std::string lua_print_fmt(lua_State *L) { /* Copied from lua source to fully replicate builtin print */ int n = lua_gettop(L); /* number of arguments */ - lua_getglobal(L, "tostring"); + lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_TOSTRING_TOKEN); std::stringstream ss; @@ -319,7 +321,7 @@ static int DFHACK_EXCEPTION_META_TOKEN = 0; static void error_tostring(lua_State *L, bool keep_old = false) { - lua_getglobal(L, "tostring"); + lua_rawgetp(L, LUA_REGISTRYINDEX, &DFHACK_TOSTRING_TOKEN); if (keep_old) lua_pushvalue(L, -2); else @@ -682,6 +684,9 @@ int DFHack::Lua::SafeResume(color_ostream &out, lua_State *from, int nargs, int */ static int DFHACK_LOADED_TOKEN = 0; +static int DFHACK_DFHACK_TOKEN = 0; +static int DFHACK_BASE_G_TOKEN = 0; +static int DFHACK_REQUIRE_TOKEN = 0; bool DFHack::Lua::PushModule(color_ostream &out, lua_State *state, const char *module) { @@ -699,7 +704,7 @@ bool DFHack::Lua::PushModule(color_ostream &out, lua_State *state, const char *m } lua_pop(state, 2); - lua_getglobal(state, "require"); + lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_REQUIRE_TOKEN); lua_pushstring(state, module); return Lua::SafeCall(out, state, 1, 1); @@ -730,7 +735,11 @@ bool DFHack::Lua::Require(color_ostream &out, lua_State *state, return false; if (setglobal) - lua_setglobal(state, module.c_str()); + { + lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_BASE_G_TOKEN); + lua_swap(state); + lua_setfield(state, -2, module.c_str()); + } else lua_pop(state, 1); @@ -900,7 +909,7 @@ namespace { static bool init_interpreter(color_ostream &out, lua_State *state, void *info) { auto args = (InterpreterArgs*)info; - lua_getglobal(state, "dfhack"); + lua_rawgetp(state, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN); lua_getfield(state, -1, "interpreter"); lua_remove(state, -2); lua_pushstring(state, args->prompt); @@ -1252,9 +1261,22 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state) lua_pushcfunction(state, lua_dfhack_println); lua_setglobal(state, "print"); + lua_getglobal(state, "require"); + lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_REQUIRE_TOKEN); + lua_getglobal(state, "tostring"); + lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_TOSTRING_TOKEN); + // Create the dfhack global lua_newtable(state); + lua_dup(state); + lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN); + + lua_rawgeti(state, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); + lua_dup(state); + lua_rawsetp(state, LUA_REGISTRYINDEX, &DFHACK_BASE_G_TOKEN); + lua_setfield(state, -2, "BASE_G"); + lua_pushboolean(state, IsCoreContext(state)); lua_setfield(state, -2, "is_core_context"); @@ -1295,6 +1317,17 @@ lua_State *DFHack::Lua::Open(color_ostream &out, lua_State *state) luaL_setfuncs(state, dfhack_coro_funcs, 0); lua_pop(state, 1); + // split the global environment + lua_newtable(state); + lua_newtable(state); + lua_rawgeti(state, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); + lua_setfield(state, -2, "__index"); + lua_setmetatable(state, -2); + lua_dup(state); + lua_setglobal(state, "_G"); + lua_dup(state); + lua_rawseti(state, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS); + // load dfhack.lua Require(out, state, "dfhack"); @@ -1322,7 +1355,7 @@ void DFHack::Lua::Core::Init(color_ostream &out) Lua::Open(out, State); // Register events - lua_getglobal(State, "dfhack"); + lua_rawgetp(State, LUA_REGISTRYINDEX, &DFHACK_DFHACK_TOKEN); MakeEvent(State, (void*)onStateChange); lua_setfield(State, -2, "onStateChange"); diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index c7e2669c5..5c10b002c 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -1,6 +1,15 @@ -- Common startup file for all dfhack plugins with lua support -- The global dfhack table is already created by C++ init code. +-- Setup the global environment. +-- BASE_G is the original lua global environment, +-- preserved as a common denominator for all modules. +-- This file uses it instead of the new default one. + +local dfhack = dfhack +local base_env = dfhack.BASE_G +local _ENV = base_env + -- Console color constants COLOR_RESET = -1 @@ -70,7 +79,7 @@ function mkmodule(module,env) if plugname then dfhack.open_plugin(pkg,plugname) end - setmetatable(pkg, { __index = (env or _G) }) + setmetatable(pkg, { __index = (env or base_env) }) return pkg end From 125cd6622a1d2ce7a8dfa7caf40a85049baf4977 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sun, 22 Apr 2012 19:22:00 +0400 Subject: [PATCH 10/18] Support sorting units in many more ui contexts. --- library/include/LuaTools.h | 30 ++- library/lua/utils.lua | 5 +- library/xml | 2 +- plugins/lua/sort/units.lua | 7 + plugins/sort.cpp | 367 +++++++++++++++++++++++++++++++------ 5 files changed, 354 insertions(+), 57 deletions(-) diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index b2d440a6b..a41b58d1c 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -248,9 +248,15 @@ namespace DFHack {namespace Lua { } template - void PushVector(lua_State *state, const T &pvec) + void PushVector(lua_State *state, const T &pvec, bool addn = false) { - lua_createtable(state,pvec.size(),0); + lua_createtable(state,pvec.size(), addn?1:0); + + if (addn) + { + lua_pushinteger(state, pvec.size()); + lua_setfield(state, -2, "n"); + } for (size_t i = 0; i < pvec.size(); i++) { @@ -267,6 +273,26 @@ namespace DFHack {namespace Lua { DFHACK_EXPORT void MakeEvent(lua_State *state, void *key); DFHACK_EXPORT void InvokeEvent(color_ostream &out, lua_State *state, void *key, int num_args); + class StackUnwinder { + lua_State *state; + int top; + public: + StackUnwinder(lua_State *state, int bias = 0) : state(state), top(0) { + if (state) top = lua_gettop(state) - bias; + } + ~StackUnwinder() { + if (state) lua_settop(state, top); + } + operator int () { return top; } + int operator+ (int v) { return top + v; } + int operator- (int v) { return top + v; } + int operator[] (int v) { return top + v; } + StackUnwinder &operator += (int v) { top += v; return *this; } + StackUnwinder &operator -= (int v) { top += v; return *this; } + StackUnwinder &operator ++ () { top++; return *this; } + StackUnwinder &operator -- () { top--; return *this; } + }; + /** * Namespace for the common lua interpreter state. * All accesses must be done under CoreSuspender. diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 3becdbb6d..00e42f9da 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -49,6 +49,7 @@ function make_sort_order(data,ordering) -- Compute sort keys and comparators local keys = {} local cmps = {} + local size = data.n or #data for i=1,#ordering do local order = ordering[i] @@ -58,7 +59,7 @@ function make_sort_order(data,ordering) elseif order.key then local kt = {} local kf = order.key - for j=1,#data do + for j=1,size do if data[j] == nil then kt[j] = nil else @@ -75,7 +76,7 @@ function make_sort_order(data,ordering) -- Make an order table local index = {} - for i=1,#data do + for i=1,size do index[i] = i end diff --git a/library/xml b/library/xml index e217d28c4..0ec109ce5 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit e217d28c4800fadd3b37e153a363656dc7beb3e3 +Subproject commit 0ec109ce5643be2c3ebcd4d652aeafaf78f33da7 diff --git a/plugins/lua/sort/units.lua b/plugins/lua/sort/units.lua index b92fc6c82..84beff8ed 100644 --- a/plugins/lua/sort/units.lua +++ b/plugins/lua/sort/units.lua @@ -4,6 +4,13 @@ local utils = require('utils') orders = orders or {} +-- Relies on NULL being auto-translated to NULL, and then sorted +orders.exists = { + key = function(unit) + return 1 + end +} + orders.name = { key = function(unit) if unit.name.has_name then diff --git a/plugins/sort.cpp b/plugins/sort.cpp index 48e4bcaca..965702b57 100644 --- a/plugins/sort.cpp +++ b/plugins/sort.cpp @@ -14,7 +14,13 @@ #include "df/world.h" #include "df/viewscreen_joblistst.h" #include "df/viewscreen_unitlistst.h" +#include "df/viewscreen_layer_militaryst.h" +#include "df/viewscreen_layer_workshop_profilest.h" +#include "df/viewscreen_layer_noblelistst.h" +#include "df/viewscreen_layer_overall_healthst.h" #include "df/viewscreen_dwarfmodest.h" +#include "df/viewscreen_petst.h" +#include "df/layer_object_listst.h" #include "MiscUtils.h" @@ -28,6 +34,9 @@ using namespace df::enums; using df::global::ui; using df::global::world; +using df::global::ui_building_in_owner; +using df::global::ui_building_item_cursor; +using df::global::ui_owner_candidates; static bool unit_list_hotkey(df::viewscreen *top); @@ -65,6 +74,22 @@ void reorder_vector(std::vector *pvec, const std::vector &order) (*pvec)[i] = tmp[order[i]]; } +template +void reorder_cursor(T *cursor, const std::vector &order) +{ + if (*cursor == 0) + return; + + for (size_t i = 0; i < order.size(); i++) + { + if (unsigned(*cursor) == order[i]) + { + *cursor = T(i); + break; + } + } +} + bool parse_ordering_spec(color_ostream &out, lua_State *L, std::string type, const std::vector ¶ms) { if (!lua_checkstack(L, params.size() + 2)) @@ -93,16 +118,18 @@ bool read_order(color_ostream &out, lua_State *L, std::vector *order, { std::vector found; + Lua::StackUnwinder frame(L, 1); + if (!lua_istable(L, -1)) { out.printerr("Not a table returned as ordering.\n"); - goto fail; + return false; } if (lua_rawlen(L, -1) != size) { out.printerr("Invalid ordering size: expected %d, actual %d\n", size, lua_rawlen(L, -1)); - goto fail; + return false; } order->clear(); @@ -111,38 +138,34 @@ bool read_order(color_ostream &out, lua_State *L, std::vector *order, for (size_t i = 1; i <= size; i++) { - lua_rawgeti(L, -1, i); + lua_rawgeti(L, frame[1], i); int v = lua_tointeger(L, -1); lua_pop(L, 1); if (v < 1 || size_t(v) > size) { out.printerr("Order value out of range: %d\n", v); - goto fail; + return false; } if (found[v-1]) { out.printerr("Duplicate order value: %d\n", v); - goto fail; + return false; } found[v-1] = 1; (*order)[i-1] = v-1; } - lua_pop(L, 1); return true; -fail: - lua_pop(L, 1); - return false; } template bool compute_order(color_ostream &out, lua_State *L, int base, std::vector *order, const std::vector &key) { lua_pushvalue(L, base+1); - Lua::PushVector(L, key); + Lua::PushVector(L, key, true); lua_pushvalue(L, base+2); if (!Lua::SafeCall(out, L, 2, 1)) @@ -151,90 +174,330 @@ bool compute_order(color_ostream &out, lua_State *L, int base, std::vector ¶ms) +{ + if (!parse_ordering_spec(out, L, "units", params)) + { + out.printerr("Invalid ordering specification for %s.\n", type); + return false; + } + + return true; +} + +#define PARSE_SPEC(type, params) \ + if (!ParseSpec(*pout, L, type, params)) return false; -static bool unit_list_hotkey(df::viewscreen *screen) +static void sort_null_first(vector ¶meters) { - if (strict_virtual_cast(screen)) - return true; - if (strict_virtual_cast(screen)) - return true; + vector_insert_at(parameters, 0, std::string("(screen)) - { - using namespace df::enums::ui_sidebar_mode; +static df::layer_object_listst *getLayerList(df::viewscreen_layerst *layer, int idx) +{ + return virtual_cast(vector_get(layer->layer_objects,idx)); +} - switch (ui->main.mode) +static bool maybe_sort_units(color_ostream *pout, lua_State *L, + df::viewscreen *screen, vector ¶meters) +{ + Lua::StackUnwinder top(L); + + if (L) + { + if (!Lua::PushModulePublic(*pout, L, "plugins.sort", "make_sort_order")) { - case Burrows: - return ui->burrows.in_add_units_mode; - default: + pout->printerr("Cannot access the sorter function.\n"); return false; } } - return false; -} + std::vector order; -static command_result sort_units(color_ostream &out, vector ¶meters) -{ - if (parameters.empty()) - return CR_WRONG_USAGE; + if (auto units = strict_virtual_cast(screen)) + { + if (!L) return true; - auto L = Lua::Core::State; - int top = lua_gettop(L); + /* + * Sort units in the 'u'nit list screen. + */ + + PARSE_SPEC("units", parameters); + + int page = units->page; + + if (compute_order(*pout, L, top, &order, units->units[page])) + { + reorder_cursor(&units->cursor_pos[page], order); + reorder_vector(&units->units[page], order); + reorder_vector(&units->jobs[page], order); + } - if (!Lua::Core::PushModulePublic(out, "plugins.sort", "make_sort_order")) + return true; + } + else if (auto jobs = strict_virtual_cast(screen)) { - out.printerr("Cannot access the sorter function.\n"); - return CR_WRONG_USAGE; + if (!L) return true; + + /* + * Sort units in the 'j'ob list screen. + */ + + PARSE_SPEC("units", parameters); + + if (compute_order(*pout, L, top, &order, jobs->units)) + { + reorder_cursor(&jobs->cursor_pos, order); + reorder_vector(&jobs->units, order); + reorder_vector(&jobs->jobs, order); + } + + return true; } + else if (auto military = strict_virtual_cast(screen)) + { + switch (military->page) + { + case df::viewscreen_layer_militaryst::Positions: + { + auto &candidates = military->positions.candidates; + auto list3 = getLayerList(military, 2); + + /* + * Sort candidate units in the 'p'osition page of the 'm'ilitary screen. + */ + + if (list3 && !candidates.empty() && list3->bright) + { + if (!L) return true; + + PARSE_SPEC("units", parameters); + + if (compute_order(*pout, L, top, &order, candidates)) + { + reorder_cursor(&list3->cursor, order); + reorder_vector(&candidates, order); + } - if (!parse_ordering_spec(out, L, "units", parameters)) + return true; + } + + return false; + } + + default: + return false; + } + } + else if (auto profile = strict_virtual_cast(screen)) { - out.printerr("Invalid unit ordering specification.\n"); - lua_settop(L, top); - return CR_WRONG_USAGE; + auto list1 = getLayerList(profile, 0); + + if (!list1) return false; + if (!L) return true; + + /* + * Sort units in the workshop 'q'uery 'P'rofile modification screen. + */ + + PARSE_SPEC("units", parameters); + + if (compute_order(*pout, L, top, &order, profile->workers)) + { + reorder_cursor(&list1->cursor, order); + reorder_vector(&profile->workers, order); + } + + return true; } + else if (auto nobles = strict_virtual_cast(screen)) + { + switch (nobles->mode) + { + case df::viewscreen_layer_noblelistst::Appoint: + { + auto list2 = getLayerList(nobles, 1); - auto screen = Core::getInstance().getTopViewscreen(); - std::vector order; + /* + * Sort units in the appointment candidate list of the 'n'obles screen. + */ - if (auto units = strict_virtual_cast(screen)) + if (list2) + { + if (!L) return true; + + sort_null_first(parameters); + PARSE_SPEC("units", parameters); + + std::vector units; + for (size_t i = 0; i < nobles->candidates.size(); i++) + units.push_back(nobles->candidates[i]->unit); + + if (compute_order(*pout, L, top, &order, units)) + { + reorder_cursor(&list2->cursor, order); + reorder_vector(&nobles->candidates, order); + } + + return true; + } + + return false; + } + + default: + return false; + } + } + else if (auto animals = strict_virtual_cast(screen)) { - for (int i = 0; i < 4; i++) + switch (animals->mode) { - if (compute_order(out, L, top, &order, units->units[i])) + case df::viewscreen_petst::List: { - reorder_vector(&units->units[i], order); - reorder_vector(&units->jobs[i], order); + if (!L) return true; + + /* + * Sort animal units in the Animal page of the 'z' status screen. + */ + + PARSE_SPEC("units", parameters); + + std::vector units; + for (size_t i = 0; i < animals->animal.size(); i++) + units.push_back(animals->is_vermin[i] ? NULL : (df::unit*)animals->animal[i]); + + if (compute_order(*pout, L, top, &order, units)) + { + reorder_cursor(&animals->cursor, order); + reorder_vector(&animals->animal, order); + reorder_vector(&animals->is_vermin, order); + reorder_vector(&animals->pet_info, order); + reorder_vector(&animals->is_tame, order); + reorder_vector(&animals->is_adopting, order); + } + + return true; } + + case df::viewscreen_petst::SelectTrainer: + { + if (!L) return true; + + /* + * Sort candidate trainers in the Animal page of the 'z' status screen. + */ + + sort_null_first(parameters); + PARSE_SPEC("units", parameters); + + if (compute_order(*pout, L, top, &order, animals->trainer_unit)) + { + reorder_cursor(&animals->trainer_cursor, order); + reorder_vector(&animals->trainer_unit, order); + reorder_vector(&animals->trainer_mode, order); + } + + return true; + } + + default: + return false; } } - else if (auto jobs = strict_virtual_cast(screen)) + else if (auto health = strict_virtual_cast(screen)) { - if (compute_order(out, L, top, &order, jobs->units)) + auto list1 = getLayerList(health, 0); + + if (!list1) return false; + if (!L) return true; + + /* + * Sort units in the Health page of the 'z' status screen. + */ + + PARSE_SPEC("units", parameters); + + if (compute_order(*pout, L, top, &order, health->unit)) { - reorder_vector(&jobs->units, order); - reorder_vector(&jobs->jobs, order); + reorder_cursor(&list1->cursor, order); + reorder_vector(&health->unit, order); + reorder_vector(&health->bits1, order); + reorder_vector(&health->bits2, order); + reorder_vector(&health->bits3, order); } + + return true; } else if (strict_virtual_cast(screen)) { switch (ui->main.mode) { case ui_sidebar_mode::Burrows: - if (compute_order(out, L, top, &order, ui->burrows.list_units)) + if (!L) return true; + + /* + * Sort burrow member candidate units in the 'w' sidebar mode. + */ + + PARSE_SPEC("units", parameters); + + if (compute_order(*pout, L, top, &order, ui->burrows.list_units)) { + reorder_cursor(&ui->burrows.unit_cursor_pos, order); reorder_vector(&ui->burrows.list_units, order); reorder_vector(&ui->burrows.sel_units, order); } - break; + + return true; + + case ui_sidebar_mode::QueryBuilding: + if (ui_building_in_owner && *ui_building_in_owner && + ui_owner_candidates && ui_building_item_cursor) + { + if (!L) return true; + + /* + * Sort building owner candidate units in the 'q' sidebar mode. + */ + + sort_null_first(parameters); + PARSE_SPEC("units", parameters); + + if (compute_order(*pout, L, top, &order, *ui_owner_candidates)) + { + reorder_cursor(ui_building_item_cursor, order); + reorder_vector(ui_owner_candidates, order); + } + + return true; + } + return false; default: - break;; + return false; } } + else + return false; +} + +static bool unit_list_hotkey(df::viewscreen *screen) +{ + vector dummy; + return maybe_sort_units(NULL, NULL, screen, dummy); +} + +static command_result sort_units(color_ostream &out, vector ¶meters) +{ + if (parameters.empty()) + return CR_WRONG_USAGE; + + auto L = Lua::Core::State; + auto screen = Core::getInstance().getTopViewscreen(); + + if (!maybe_sort_units(&out, L, screen, parameters)) + return CR_WRONG_USAGE; - lua_settop(L, top); return CR_OK; } From 763a301b4f928bf20c78fb67f864e1623409c710 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Mon, 23 Apr 2012 21:30:53 +0400 Subject: [PATCH 11/18] Add a few more lua api functions, documentation, and unit sort orders. Units::getProfessionName appears to work correctly for everything except nobles. --- LUA_API.rst | 97 ++++++++++++- Lua API.html | 89 ++++++++++-- library/LuaApi.cpp | 4 + library/include/modules/Translation.h | 2 + library/include/modules/Units.h | 6 +- library/lua/dfhack.lua | 56 +++++--- library/modules/Translation.cpp | 23 ++- library/modules/Units.cpp | 200 +++++++++++++++++++++----- plugins/lua/sort/units.lua | 52 +++++-- 9 files changed, 449 insertions(+), 80 deletions(-) diff --git a/LUA_API.rst b/LUA_API.rst index 050714c72..32716fbf8 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -594,41 +594,44 @@ C++ function wrappers ===================== Thin wrappers around C++ functions, similar to the ones for virtual methods. +One notable difference is that these explicit wrappers allow argument count +adjustment according to the usual lua rules, so trailing false/nil arguments +can be omitted. -* ``dfhack.TranslateName(name,in_english,only_last_name)`` +* ``dfhack.TranslateName(name[,in_english,only_last_name])`` Convert a language_name or only the last name part to string. Gui module ---------- -* ``dfhack.gui.getSelectedWorkshopJob(silent)`` +* ``dfhack.gui.getSelectedWorkshopJob([silent])`` When a job is selected in *'q'* mode, returns the job, else prints error unless silent and returns *nil*. -* ``dfhack.gui.getSelectedJob(silent)`` +* ``dfhack.gui.getSelectedJob([silent])`` Returns the job selected in a workshop or unit/jobs screen. -* ``dfhack.gui.getSelectedUnit(silent)`` +* ``dfhack.gui.getSelectedUnit([silent])`` Returns the unit selected via *'v'*, *'k'*, unit/jobs, or a full-screen item view of a cage or suchlike. -* ``dfhack.gui.getSelectedItem(silent)`` +* ``dfhack.gui.getSelectedItem([silent])`` Returns the item selected via *'v'* ->inventory, *'k'*, *'t'*, or a full-screen item view of a container. Note that in the last case, the highlighted *contained item* is returned, not the container itself. -* ``dfhack.gui.showAnnouncement(text,color,is_bright)`` +* ``dfhack.gui.showAnnouncement(text,color[,is_bright])`` Adds a regular announcement with given text, color, and brightness. The is_bright boolean actually seems to invert the brightness. -* ``dfhack.gui.showPopupAnnouncement(text,color,is_bright)`` +* ``dfhack.gui.showPopupAnnouncement(text,color[,is_bright])`` Pops up a titan-style modal announcement window. @@ -688,6 +691,10 @@ Units module Returns the language_name object visible in game, accounting for false identities. +* ``dfhack.units.getIdentity(unit)`` + + Returns the false identity of the unit if it has one, or *nil*. + * ``dfhack.units.getNemesis(unit)`` Returns the nemesis record of the unit if it has one, or *nil*. @@ -716,6 +723,19 @@ Units module Adds or removes the unit from the burrow. +* ``dfhack.units.getAge(unit[,true_age])`` + + Returns the age of the unit in years as a floating-point value. + If ``true_age`` is true, ignores false identities. + +* ``dfhack.units.getProfessionName(unit[,plural])`` + + Retrieves the profession name using custom profession or raws. + +* ``dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])`` + + Retrieves the profession name for the given race/caste using raws. + Items module ------------ @@ -856,3 +876,66 @@ Features: Invokes all listeners contained in the event in an arbitrary order using ``dfhack.safecall``. + +======= +Plugins +======= + +DFHack plugins may export native functions and events +to lua contexts. They are automatically imported by +``mkmodule('plugins.')``; this means that a lua +module file is still necessary for ``require`` to read. + +The following plugins have lua support. + +burrows +======= + +Implements extended burrow manipulations. + +Events: + +* ``onBurrowRename.foo = function(burrow)`` + + Emitted when a burrow might have been renamed either through + the game UI, or ``renameBurrow()``. + +* ``onDigComplete.foo = function(job_type,pos,old_tiletype,new_tiletype)`` + + Emitted when a tile might have been dug out. Only tracked if the + auto-growing burrows feature is enabled. + +Native functions: + +* ``renameBurrow(burrow,name)`` + + Renames the burrow, emitting ``onBurrowRename`` and updating auto-grow state properly. + +* ``findByName(burrow,name)`` + + Finds a burrow by name, using the same rules as the plugin command line interface. + Namely, trailing ``'+'`` characters marking auto-grow burrows are ignored. + +* ``copyUnits(target,source,enable)`` + + Applies units from ``source`` burrow to ``target``. The ``enable`` + parameter specifies if they are to be added or removed. + +* ``copyTiles(target,source,enable)`` + + Applies tiles from ``source`` burrow to ``target``. The ``enable`` + parameter specifies if they are to be added or removed. + +* ``setTilesByKeyword(target,keyword,enable)`` + + Adds or removes tiles matching a predefined keyword. The keyword + set is the same as used by the command line. + +The lua module file also re-exports or wraps some of the +functions implemented by the dfhack core for convenience. + +sort +==== + +Does not export any native functions as of now. Instead, it +calls lua code to perform the actual ordering of list items. diff --git a/Lua API.html b/Lua API.html index cbf35f0eb..916c6eef8 100644 --- a/Lua API.html +++ b/Lua API.html @@ -350,6 +350,11 @@ ul.auto-toc { +
  • Plugins +
  • @@ -842,37 +847,40 @@ Accept dfhack_material_category auto-assign table.

    C++ function wrappers

    -

    Thin wrappers around C++ functions, similar to the ones for virtual methods.

    +

    Thin wrappers around C++ functions, similar to the ones for virtual methods. +One notable difference is that these explicit wrappers allow argument count +adjustment according to the usual lua rules, so trailing false/nil arguments +can be omitted.

      -
    • dfhack.TranslateName(name,in_english,only_last_name)

      +
    • dfhack.TranslateName(name[,in_english,only_last_name])

      Convert a language_name or only the last name part to string.

    Gui module

      -
    • dfhack.gui.getSelectedWorkshopJob(silent)

      +
    • dfhack.gui.getSelectedWorkshopJob([silent])

      When a job is selected in 'q' mode, returns the job, else prints error unless silent and returns nil.

    • -
    • dfhack.gui.getSelectedJob(silent)

      +
    • dfhack.gui.getSelectedJob([silent])

      Returns the job selected in a workshop or unit/jobs screen.

    • -
    • dfhack.gui.getSelectedUnit(silent)

      +
    • dfhack.gui.getSelectedUnit([silent])

      Returns the unit selected via 'v', 'k', unit/jobs, or a full-screen item view of a cage or suchlike.

    • -
    • dfhack.gui.getSelectedItem(silent)

      +
    • dfhack.gui.getSelectedItem([silent])

      Returns the item selected via 'v' ->inventory, 'k', 't', or a full-screen item view of a container. Note that in the last case, the highlighted contained item is returned, not the container itself.

    • -
    • dfhack.gui.showAnnouncement(text,color,is_bright)

      +
    • dfhack.gui.showAnnouncement(text,color[,is_bright])

      Adds a regular announcement with given text, color, and brightness. The is_bright boolean actually seems to invert the brightness.

    • -
    • dfhack.gui.showPopupAnnouncement(text,color,is_bright)

      +
    • dfhack.gui.showPopupAnnouncement(text,color[,is_bright])

      Pops up a titan-style modal announcement window.

    @@ -923,6 +931,9 @@ a lua list containing them.

  • dfhack.units.getVisibleName(unit)

    Returns the language_name object visible in game, accounting for false identities.

  • +
  • dfhack.units.getIdentity(unit)

    +

    Returns the false identity of the unit if it has one, or nil.

    +
  • dfhack.units.getNemesis(unit)

    Returns the nemesis record of the unit if it has one, or nil.

  • @@ -944,6 +955,16 @@ a lua list containing them.

  • dfhack.units.setInBurrow(unit,burrow,enable)

    Adds or removes the unit from the burrow.

  • +
  • dfhack.units.getAge(unit[,true_age])

    +

    Returns the age of the unit in years as a floating-point value. +If true_age is true, ignores false identities.

    +
  • +
  • dfhack.units.getProfessionName(unit[,plural])

    +

    Retrieves the profession name using custom profession or raws.

    +
  • +
  • dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])

    +

    Retrieves the profession name for the given race/caste using raws.

    +
  • @@ -1061,6 +1082,58 @@ order using dfhack.safecall.

    +
    +

    Plugins

    +

    DFHack plugins may export native functions and events +to lua contexts. They are automatically imported by +mkmodule('plugins.<name>'); this means that a lua +module file is still necessary for require to read.

    +

    The following plugins have lua support.

    +
    +

    burrows

    +

    Implements extended burrow manipulations.

    +

    Events:

    +
      +
    • onBurrowRename.foo = function(burrow)

      +

      Emitted when a burrow might have been renamed either through +the game UI, or renameBurrow().

      +
    • +
    • onDigComplete.foo = function(job_type,pos,old_tiletype,new_tiletype)

      +

      Emitted when a tile might have been dug out. Only tracked if the +auto-growing burrows feature is enabled.

      +
    • +
    +

    Native functions:

    +
      +
    • renameBurrow(burrow,name)

      +

      Renames the burrow, emitting onBurrowRename and updating auto-grow state properly.

      +
    • +
    • findByName(burrow,name)

      +

      Finds a burrow by name, using the same rules as the plugin command line interface. +Namely, trailing '+' characters marking auto-grow burrows are ignored.

      +
    • +
    • copyUnits(target,source,enable)

      +

      Applies units from source burrow to target. The enable +parameter specifies if they are to be added or removed.

      +
    • +
    • copyTiles(target,source,enable)

      +

      Applies tiles from source burrow to target. The enable +parameter specifies if they are to be added or removed.

      +
    • +
    • setTilesByKeyword(target,keyword,enable)

      +

      Adds or removes tiles matching a predefined keyword. The keyword +set is the same as used by the command line.

      +
    • +
    +

    The lua module file also re-exports or wraps some of the +functions implemented by the dfhack core for convenience.

    +
    +
    +

    sort

    +

    Does not export any native functions as of now. Instead, it +calls lua code to perform the actual ordering of list items.

    +
    +
    diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 00192c058..71df50e22 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -58,6 +58,7 @@ distribution. #include "df/unit.h" #include "df/item.h" #include "df/material.h" +#include "df/assumed_identity.h" #include "df/nemesis_record.h" #include "df/historical_figure.h" #include "df/plant_raw.h" @@ -608,6 +609,7 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, getContainer), WRAPM(Units, setNickname), WRAPM(Units, getVisibleName), + WRAPM(Units, getIdentity), WRAPM(Units, getNemesis), WRAPM(Units, isDead), WRAPM(Units, isAlive), @@ -616,6 +618,8 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, isInBurrow), WRAPM(Units, setInBurrow), WRAPM(Units, getAge), + WRAPM(Units, getProfessionName), + WRAPM(Units, getCasteProfessionName), { NULL, NULL } }; diff --git a/library/include/modules/Translation.h b/library/include/modules/Translation.h index 6d74431e3..f75bf6339 100644 --- a/library/include/modules/Translation.h +++ b/library/include/modules/Translation.h @@ -52,6 +52,8 @@ DFHACK_EXPORT bool copyName(df::language_name * address, df::language_name * tar DFHACK_EXPORT void setNickname(df::language_name *name, std::string nick); +DFHACK_EXPORT std::string capitalize(const std::string &str, bool all_words = false); + // translate a name using the loaded dictionaries DFHACK_EXPORT std::string TranslateName (const df::language_name * name, bool inEnglish = true, bool onlyLastPart = false); diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 775cc5181..8e4fe2ade 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -37,6 +37,7 @@ namespace df { struct nemesis_record; struct burrow; + struct assumed_identity; } /** @@ -201,6 +202,7 @@ DFHACK_EXPORT df::item *getContainer(df::unit *unit); DFHACK_EXPORT void setNickname(df::unit *unit, std::string nick); DFHACK_EXPORT df::language_name *getVisibleName(df::unit *unit); +DFHACK_EXPORT df::assumed_identity *getIdentity(df::unit *unit); DFHACK_EXPORT df::nemesis_record *getNemesis(df::unit *unit); DFHACK_EXPORT bool isDead(df::unit *unit); @@ -214,8 +216,10 @@ DFHACK_EXPORT void clearBurrowMembers(df::burrow *burrow); DFHACK_EXPORT bool isInBurrow(df::unit *unit, df::burrow *burrow); DFHACK_EXPORT void setInBurrow(df::unit *unit, df::burrow *burrow, bool enable); -DFHACK_EXPORT double getAge(df::unit *unit); +DFHACK_EXPORT double getAge(df::unit *unit, bool true_age = false); +DFHACK_EXPORT std::string getProfessionName(df::unit *unit, bool plural = false); +DFHACK_EXPORT std::string getCasteProfessionName(int race, int caste, df::profession pid, bool plural = false); } } #endif diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 5c10b002c..100aea59c 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -125,6 +125,23 @@ function xyz2pos(x,y,z) end end +function safe_index(obj,idx,...) + if obj == nil or idx == nil then + return nil + end + if type(idx) == 'number' and (idx < 0 or idx >= #obj) then + return nil + end + obj = obj[idx] + if select('#',...) > 0 then + return safe_index(obj,...) + else + return obj + end +end + +-- String conversions + function dfhack.event:__tostring() return "" end @@ -168,12 +185,14 @@ function dfhack.interpreter(prompt,hfile,env) end local prompt_str = "["..(prompt or 'lua').."]# " + local prompt_cont = string.rep(' ',#prompt_str-4)..">>> " local prompt_env = {} - local t_prompt + local cmdlinelist = {} + local t_prompt = nil local vcnt = 1 setmetatable(prompt_env, { __index = env or _G }) - local cmdlinelist={} + while true do local cmdline = dfhack.lineedit(t_prompt or prompt_str, hfile) @@ -182,26 +201,29 @@ function dfhack.interpreter(prompt,hfile,env) elseif cmdline ~= '' then local pfix = string.sub(cmdline,1,1) - if pfix == '!' or pfix == '=' then + if not t_prompt and (pfix == '!' or pfix == '=') then cmdline = 'return '..string.sub(cmdline,2) + else + pfix = nil end - table.insert(cmdlinelist,cmdline) - local code,err = load(table.concat(cmdlinelist,'\n'), '=(interactive)', 't', prompt_env) + + table.insert(cmdlinelist,cmdline) + cmdline = table.concat(cmdlinelist,'\n') + + local code,err = load(cmdline, '=(interactive)', 't', prompt_env) if code == nil then - if err:sub(-5)=="" then - t_prompt="[cont]" - - else - dfhack.printerr(err) - cmdlinelist={} - t_prompt=nil - end + if not pfix and err:sub(-5)=="" then + t_prompt=prompt_cont + else + dfhack.printerr(err) + cmdlinelist={} + t_prompt=nil + end else - - cmdlinelist={} - t_prompt=nil - + cmdlinelist={} + t_prompt=nil + local data = table.pack(safecall(code)) if data[1] and data.n > 1 then diff --git a/library/modules/Translation.cpp b/library/modules/Translation.cpp index 6b055a4ac..db1305161 100644 --- a/library/modules/Translation.cpp +++ b/library/modules/Translation.cpp @@ -81,15 +81,32 @@ bool Translation::copyName(df::language_name * source, df::language_name * targe return true; } +std::string Translation::capitalize(const std::string &str, bool all_words) +{ + string upper = str; + + if (!upper.empty()) + { + upper[0] = toupper(upper[0]); + + if (all_words) + { + for (size_t i = 1; i < upper.size(); i++) + if (isspace(upper[i-1])) + upper[i] = toupper(upper[i]); + } + } + + return upper; +} + void addNameWord (string &out, const string &word) { if (word.empty()) return; - string upper = word; - upper[0] = toupper(upper[0]); if (out.length() > 0) out.append(" "); - out.append(upper); + out.append(Translation::capitalize(word)); } void Translation::setNickname(df::language_name *name, std::string nick) diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index e9699edbe..a691dc5d9 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -57,6 +57,8 @@ using namespace std; #include "df/historical_figure_info.h" #include "df/assumed_identity.h" #include "df/burrow.h" +#include "df/creature_raw.h" +#include "df/caste_raw.h" using namespace DFHack; using namespace df::enums; @@ -529,6 +531,23 @@ df::item *Units::getContainer(df::unit *unit) return NULL; } +static df::assumed_identity *getFigureIdentity(df::historical_figure *figure) +{ + if (figure && figure->info && figure->info->reputation) + return df::assumed_identity::find(figure->info->reputation->cur_identity); + + return NULL; +} + +df::assumed_identity *Units::getIdentity(df::unit *unit) +{ + CHECK_NULL_POINTER(unit); + + df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id); + + return getFigureIdentity(figure); +} + void Units::setNickname(df::unit *unit, std::string nick) { CHECK_NULL_POINTER(unit); @@ -547,25 +566,19 @@ void Units::setNickname(df::unit *unit, std::string nick) { Translation::setNickname(&figure->name, nick); - // v0.34.01: added the vampire's assumed identity - if (figure->info && figure->info->reputation) + if (auto identity = getFigureIdentity(figure)) { - auto identity = df::assumed_identity::find(figure->info->reputation->cur_identity); + auto id_hfig = df::historical_figure::find(identity->histfig_id); - if (identity) + if (id_hfig) { - auto id_hfig = df::historical_figure::find(identity->histfig_id); - - if (id_hfig) - { - // Even DF doesn't do this bit, because it's apparently - // only used for demons masquerading as gods, so you - // can't ever change their nickname in-game. - Translation::setNickname(&id_hfig->name, nick); - } - else - Translation::setNickname(&identity->name, nick); + // Even DF doesn't do this bit, because it's apparently + // only used for demons masquerading as gods, so you + // can't ever change their nickname in-game. + Translation::setNickname(&id_hfig->name, nick); } + else + Translation::setNickname(&identity->name, nick); } } } @@ -574,25 +587,14 @@ df::language_name *Units::getVisibleName(df::unit *unit) { CHECK_NULL_POINTER(unit); - df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id); - - if (figure) + if (auto identity = getIdentity(unit)) { - // v0.34.01: added the vampire's assumed identity - if (figure->info && figure->info->reputation) - { - auto identity = df::assumed_identity::find(figure->info->reputation->cur_identity); + auto id_hfig = df::historical_figure::find(identity->histfig_id); - if (identity) - { - auto id_hfig = df::historical_figure::find(identity->histfig_id); + if (id_hfig) + return &id_hfig->name; - if (id_hfig) - return &id_hfig->name; - - return &identity->name; - } - } + return &identity->name; } return &unit->name; @@ -734,7 +736,7 @@ void DFHack::Units::setInBurrow(df::unit *unit, df::burrow *burrow, bool enable) } } -double DFHack::Units::getAge(df::unit *unit) +double DFHack::Units::getAge(df::unit *unit, bool true_age) { using df::global::cur_year; using df::global::cur_year_tick; @@ -748,5 +750,139 @@ double DFHack::Units::getAge(df::unit *unit) double birth_time = unit->relations.birth_year + unit->relations.birth_time/year_ticks; double cur_time = *cur_year + *cur_year_tick / year_ticks; + if (!true_age && unit->relations.curse_year >= 0) + { + if (auto identity = getIdentity(unit)) + { + if (identity->histfig_id < 0) + birth_time = identity->birth_year + identity->birth_second/year_ticks; + } + } + return cur_time - birth_time; } + +std::string DFHack::Units::getProfessionName(df::unit *unit, bool plural) +{ + std::string prof = unit->custom_profession; + + if (prof.empty()) + prof = getCasteProfessionName(unit->race, unit->caste, unit->profession, plural); + + return prof; +} + +std::string DFHack::Units::getCasteProfessionName(int race, int casteid, df::profession pid, bool plural) +{ + std::string prof, race_prefix; + + if (pid < 0 || !is_valid_enum_item(pid)) + return ""; + + bool use_race_prefix = (race >= 0 && race != df::global::ui->race_id); + + if (auto creature = df::creature_raw::find(race)) + { + if (auto caste = vector_get(creature->caste, casteid)) + { + race_prefix = caste->caste_name[0]; + + if (plural) + prof = caste->caste_profession_name.plural[pid]; + else + prof = caste->caste_profession_name.singular[pid]; + + if (prof.empty()) + { + switch (pid) + { + case profession::CHILD: + prof = caste->child_name[plural ? 1 : 0]; + if (!prof.empty()) + use_race_prefix = false; + break; + + case profession::BABY: + prof = caste->baby_name[plural ? 1 : 0]; + if (!prof.empty()) + use_race_prefix = false; + break; + + default: + break; + } + } + } + + if (race_prefix.empty()) + race_prefix = creature->name[0]; + + if (prof.empty()) + { + if (plural) + prof = creature->profession_name.plural[pid]; + else + prof = creature->profession_name.singular[pid]; + + if (prof.empty()) + { + switch (pid) + { + case profession::CHILD: + prof = creature->general_child_name[plural ? 1 : 0]; + if (!prof.empty()) + use_race_prefix = false; + break; + + case profession::BABY: + prof = creature->general_baby_name[plural ? 1 : 0]; + if (!prof.empty()) + use_race_prefix = false; + break; + + default: + break; + } + } + } + } + + if (race_prefix.empty()) + race_prefix = "Animal"; + + if (prof.empty()) + { + switch (pid) + { + case profession::TRAINED_WAR: + prof = "War " + (use_race_prefix ? race_prefix : "Peasant"); + use_race_prefix = false; + break; + + case profession::TRAINED_HUNTER: + prof = "Hunting " + (use_race_prefix ? race_prefix : "Peasant"); + use_race_prefix = false; + break; + + case profession::STANDARD: + if (!use_race_prefix) + prof = "Peasant"; + break; + + default: + if (auto caption = ENUM_ATTR(profession, caption, pid)) + prof = caption; + else + prof = ENUM_KEY_STR(profession, pid); + } + } + + if (use_race_prefix) + { + if (!prof.empty()) + race_prefix += " "; + prof = race_prefix + prof; + } + + return Translation::capitalize(prof, true); +} diff --git a/plugins/lua/sort/units.lua b/plugins/lua/sort/units.lua index 84beff8ed..7a332d094 100644 --- a/plugins/lua/sort/units.lua +++ b/plugins/lua/sort/units.lua @@ -13,8 +13,9 @@ orders.exists = { orders.name = { key = function(unit) - if unit.name.has_name then - return dfhack.TranslateName(unit.name) + local name = dfhack.units.getVisibleName(unit) + if name and name.has_name then + return dfhack.TranslateName(name) end end, compare = utils.compare_name @@ -29,28 +30,55 @@ orders.age = { -- This assumes that units are added to active in arrival order orders.arrival = { key_table = function(units) - local tmp={} - for i,v in ipairs(units) do - tmp[v.id] = i + local size = units.n or #units + local lookup={} + for i=1,size do + if units[i] then + lookup[units[i].id] = i + end end local idx={} for i,v in ipairs(df.global.world.units.active) do - local ix = tmp[v.id] - if ix ~= nil then - idx[ix] = i + if lookup[v.id] then + idx[lookup[v.id]] = i end end return idx end } +local function findRaceCaste(unit) + local rraw = df.creature_raw.find(unit.race) + return rraw, safe_index(rraw, 'caste', unit.caste) +end + orders.profession = { key = function(unit) - local cp = unit.custom_profession - if cp == '' then - cp = df.profession.attrs[unit.profession].caption + local cp = dfhack.units.getProfessionName(unit) + if cp and cp ~= '' then + return string.lower(cp) + end + end +} + +orders.profession_class = { + key = function(unit) + local pid = unit.profession + local parent = df.profession.attrs[pid].parent + if parent >= 0 then + return parent + else + return pid + end + end +} + +orders.race = { + key = function(unit) + local rraw = findRaceCaste(unit) + if rraw then + return rraw.name[0] end - return cp end } From 1cd802d426831d1f1939648bf0e8d224a7c4b862 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 25 Apr 2012 18:28:00 +0400 Subject: [PATCH 12/18] Implement unit sorting for the pen zone assignment interface. --- library/xml | 2 +- plugins/sort.cpp | 41 +++++++++++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/library/xml b/library/xml index 0ec109ce5..f649d3100 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 0ec109ce5643be2c3ebcd4d652aeafaf78f33da7 +Subproject commit f649d31001e6023a9df5fe83c7971c17afe0d87d diff --git a/plugins/sort.cpp b/plugins/sort.cpp index 965702b57..9d63b2c6c 100644 --- a/plugins/sort.cpp +++ b/plugins/sort.cpp @@ -34,9 +34,12 @@ using namespace df::enums; using df::global::ui; using df::global::world; -using df::global::ui_building_in_owner; +using df::global::ui_building_in_assign; using df::global::ui_building_item_cursor; -using df::global::ui_owner_candidates; +using df::global::ui_building_assign_type; +using df::global::ui_building_assign_is_marked; +using df::global::ui_building_assign_units; +using df::global::ui_building_assign_items; static bool unit_list_hotkey(df::viewscreen *top); @@ -452,22 +455,44 @@ static bool maybe_sort_units(color_ostream *pout, lua_State *L, return true; case ui_sidebar_mode::QueryBuilding: - if (ui_building_in_owner && *ui_building_in_owner && - ui_owner_candidates && ui_building_item_cursor) + if (!ui_building_in_assign || !*ui_building_in_assign) + return false; + // fall through for building owner / chain assign animal + + case ui_sidebar_mode::ZonesPenInfo: + if (ui_building_item_cursor && + ui_building_assign_type && + ui_building_assign_is_marked && + ui_building_assign_units && + ui_building_assign_items && + ui_building_assign_type->size() == ui_building_assign_units->size() && + !ui_building_assign_type->empty()) { if (!L) return true; /* - * Sort building owner candidate units in the 'q' sidebar mode. + * Sort building owner candidate units in the 'q' sidebar mode, + * or pen assignment candidate units in 'z'->'N', or cage assignment. */ - sort_null_first(parameters); + // TODO: better way + bool is_assign_owner = ((*ui_building_assign_type)[0] == -1); + + if (is_assign_owner) + sort_null_first(parameters); + PARSE_SPEC("units", parameters); - if (compute_order(*pout, L, top, &order, *ui_owner_candidates)) + if (compute_order(*pout, L, top, &order, *ui_building_assign_units)) { reorder_cursor(ui_building_item_cursor, order); - reorder_vector(ui_owner_candidates, order); + reorder_vector(ui_building_assign_type, order); + reorder_vector(ui_building_assign_units, order); + + if (ui_building_assign_units->size() == ui_building_assign_items->size()) + reorder_vector(ui_building_assign_items, order); + if (ui_building_assign_units->size() == ui_building_assign_is_marked->size()) + reorder_vector(ui_building_assign_is_marked, order); } return true; From 23a0b17ff35261d5aca4bf9329250b6e544bb24b Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 25 Apr 2012 18:38:43 +0400 Subject: [PATCH 13/18] Make liquids and tiletypes force rebuild of pathfinding data. --- plugins/liquids.cpp | 4 ++++ plugins/tiletypes.cpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp index 167e51ce8..8ca66daf5 100644 --- a/plugins/liquids.cpp +++ b/plugins/liquids.cpp @@ -374,6 +374,10 @@ command_result df_liquids_execute(color_ostream &out) DFHack::DFCoord cursor(x,y,z); coord_vec all_tiles = brush->points(mcache,cursor); out << "working..." << endl; + + // Force the game to recompute its walkability cache + df::global::world->reindex_pathfinding = true; + if(mode == "obsidian") { coord_vec::iterator iter = all_tiles.begin(); diff --git a/plugins/tiletypes.cpp b/plugins/tiletypes.cpp index 73ec9f963..ae2dd7b3d 100644 --- a/plugins/tiletypes.cpp +++ b/plugins/tiletypes.cpp @@ -614,6 +614,9 @@ command_result executePaintJob(color_ostream &out) coord_vec all_tiles = brush->points(map, cursor); out.print("working...\n"); + // Force the game to recompute its walkability cache + df::global::world->reindex_pathfinding = true; + for (coord_vec::iterator iter = all_tiles.begin(); iter != all_tiles.end(); ++iter) { const df::tiletype source = map.tiletypeAt(*iter); From 9489c6ed1afd33790adc2e0b4e3c0152da8203e0 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 26 Apr 2012 11:05:35 +0400 Subject: [PATCH 14/18] Add support for a few more viewscreens to Units::getSelectedUnit. --- library/modules/Gui.cpp | 67 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/library/modules/Gui.cpp b/library/modules/Gui.cpp index 6841421b6..2d9402fca 100644 --- a/library/modules/Gui.cpp +++ b/library/modules/Gui.cpp @@ -50,6 +50,11 @@ using namespace DFHack; #include "df/viewscreen_joblistst.h" #include "df/viewscreen_unitlistst.h" #include "df/viewscreen_itemst.h" +#include "df/viewscreen_layerst.h" +#include "df/viewscreen_layer_workshop_profilest.h" +#include "df/viewscreen_layer_noblelistst.h" +#include "df/viewscreen_layer_overall_healthst.h" +#include "df/viewscreen_petst.h" #include "df/ui_unit_view_mode.h" #include "df/ui_sidebar_menus.h" #include "df/ui_look_list.h" @@ -63,12 +68,18 @@ using namespace DFHack; #include "df/popup_message.h" #include "df/interfacest.h" #include "df/graphic.h" +#include "df/layer_object_listst.h" using namespace df::enums; using df::global::gview; using df::global::init; using df::global::gps; +static df::layer_object_listst *getLayerList(df::viewscreen_layerst *layer, int idx) +{ + return virtual_cast(vector_get(layer->layer_objects,idx)); +} + // Predefined common guard functions bool Gui::default_hotkey(df::viewscreen *top) @@ -294,6 +305,62 @@ static df::unit *getAnyUnit(df::viewscreen *top) return ref ? ref->getUnit() : NULL; } + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_workshop_profilest, top)) + { + if (auto list1 = getLayerList(screen, 0)) + return vector_get(screen->workers, list1->cursor); + return NULL; + } + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_noblelistst, top)) + { + switch (screen->mode) + { + case df::viewscreen_layer_noblelistst::List: + if (auto list1 = getLayerList(screen, 0)) + { + if (auto info = vector_get(screen->info, list1->cursor)) + return info->unit; + } + return NULL; + + case df::viewscreen_layer_noblelistst::Appoint: + if (auto list2 = getLayerList(screen, 1)) + { + if (auto info = vector_get(screen->candidates, list2->cursor)) + return info->unit; + } + return NULL; + + default: + return NULL; + } + } + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_petst, top)) + { + switch (screen->mode) + { + case df::viewscreen_petst::List: + if (!vector_get(screen->is_vermin, screen->cursor)) + return (df::unit*)vector_get(screen->animal, screen->cursor); + return NULL; + + case df::viewscreen_petst::SelectTrainer: + return vector_get(screen->trainer_unit, screen->trainer_cursor); + + default: + return NULL; + } + } + + if (VIRTUAL_CAST_VAR(screen, df::viewscreen_layer_overall_healthst, top)) + { + if (auto list1 = getLayerList(screen, 0)) + return vector_get(screen->unit, list1->cursor); + return NULL; + } + if (!Gui::dwarfmode_hotkey(top)) return NULL; From 6ab270d129e098f0200824a798ad2117a6ec33c8 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 26 Apr 2012 12:03:56 +0400 Subject: [PATCH 15/18] Retrieve unit noble position info, and use it in getProfessionName. --- LUA_API.rst | 10 +++- Lua API.html | 9 +++- library/LuaApi.cpp | 31 +++++++++++++ library/include/modules/Units.h | 13 +++++- library/modules/Units.cpp | 82 +++++++++++++++++++++++++++++++-- plugins/lua/sort/units.lua | 9 ++++ 6 files changed, 145 insertions(+), 9 deletions(-) diff --git a/LUA_API.rst b/LUA_API.rst index 32716fbf8..acbba3272 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -728,9 +728,15 @@ Units module Returns the age of the unit in years as a floating-point value. If ``true_age`` is true, ignores false identities. -* ``dfhack.units.getProfessionName(unit[,plural])`` +* ``dfhack.units.getNoblePositions(unit)`` - Retrieves the profession name using custom profession or raws. + Returns a list of tables describing noble position assignments, or *nil*. + Every table has fields ``entity``, ``assignment`` and ``position``. + +* ``dfhack.units.getProfessionName(unit[,ignore_noble,plural])`` + + Retrieves the profession name using custom profession, noble assignments + or raws. The ``ignore_noble`` boolean disables the use of noble positions. * ``dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])`` diff --git a/Lua API.html b/Lua API.html index 916c6eef8..def3790c9 100644 --- a/Lua API.html +++ b/Lua API.html @@ -959,8 +959,13 @@ a lua list containing them.

    Returns the age of the unit in years as a floating-point value. If true_age is true, ignores false identities.

    -
  • dfhack.units.getProfessionName(unit[,plural])

    -

    Retrieves the profession name using custom profession or raws.

    +
  • dfhack.units.getNoblePositions(unit)

    +

    Returns a list of tables describing noble position assignments, or nil. +Every table has fields entity, assignment and position.

    +
  • +
  • dfhack.units.getProfessionName(unit[,ignore_noble,plural])

    +

    Retrieves the profession name using custom profession, noble assignments +or raws. The ignore_noble boolean disables the use of noble positions.

  • dfhack.units.getCasteProfessionName(race,caste,prof_id[,plural])

    Retrieves the profession name for the given race/caste using raws.

    diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 71df50e22..8c56379a7 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -61,6 +61,10 @@ distribution. #include "df/assumed_identity.h" #include "df/nemesis_record.h" #include "df/historical_figure.h" +#include "df/historical_entity.h" +#include "df/entity_position.h" +#include "df/entity_position_assignment.h" +#include "df/histfig_entity_link_positionst.h" #include "df/plant_raw.h" #include "df/creature_raw.h" #include "df/inorganic_raw.h" @@ -628,8 +632,35 @@ static int units_getPosition(lua_State *state) return Lua::PushPosXYZ(state, Units::getPosition(Lua::CheckDFObject(state,1))); } +static int units_getNoblePositions(lua_State *state) +{ + std::vector np; + + if (Units::getNoblePositions(&np, Lua::CheckDFObject(state,1))) + { + lua_createtable(state, np.size(), 0); + + for (size_t i = 0; i < np.size(); i++) + { + lua_createtable(state, 0, 3); + Lua::PushDFObject(state, np[i].entity); + lua_setfield(state, -2, "entity"); + Lua::PushDFObject(state, np[i].assignment); + lua_setfield(state, -2, "assignment"); + Lua::PushDFObject(state, np[i].position); + lua_setfield(state, -2, "position"); + lua_rawseti(state, -2, i+1); + } + } + else + lua_pushnil(state); + + return 1; +} + static const luaL_Reg dfhack_units_funcs[] = { { "getPosition", units_getPosition }, + { "getNoblePositions", units_getNoblePositions }, { NULL, NULL } }; diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 8e4fe2ade..e1f8baa12 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -38,6 +38,9 @@ namespace df struct nemesis_record; struct burrow; struct assumed_identity; + struct historical_entity; + struct entity_position_assignment; + struct entity_position; } /** @@ -218,7 +221,15 @@ DFHACK_EXPORT void setInBurrow(df::unit *unit, df::burrow *burrow, bool enable); DFHACK_EXPORT double getAge(df::unit *unit, bool true_age = false); -DFHACK_EXPORT std::string getProfessionName(df::unit *unit, bool plural = false); +struct NoblePosition { + df::historical_entity *entity; + df::entity_position_assignment *assignment; + df::entity_position *position; +}; + +DFHACK_EXPORT bool getNoblePositions(std::vector *pvec, df::unit *unit); + +DFHACK_EXPORT std::string getProfessionName(df::unit *unit, bool ignore_noble = false, bool plural = false); DFHACK_EXPORT std::string getCasteProfessionName(int race, int caste, df::profession pid, bool plural = false); } } diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index a691dc5d9..4ea225ade 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -55,6 +55,9 @@ using namespace std; #include "df/historical_entity.h" #include "df/historical_figure.h" #include "df/historical_figure_info.h" +#include "df/entity_position.h" +#include "df/entity_position_assignment.h" +#include "df/histfig_entity_link_positionst.h" #include "df/assumed_identity.h" #include "df/burrow.h" #include "df/creature_raw.h" @@ -762,14 +765,85 @@ double DFHack::Units::getAge(df::unit *unit, bool true_age) return cur_time - birth_time; } -std::string DFHack::Units::getProfessionName(df::unit *unit, bool plural) +static bool noble_pos_compare(const Units::NoblePosition &a, const Units::NoblePosition &b) +{ + if (a.position->precedence < b.position->precedence) + return true; + if (a.position->precedence > b.position->precedence) + return false; + return a.position->id < b.position->id; +} + +bool DFHack::Units::getNoblePositions(std::vector *pvec, df::unit *unit) +{ + CHECK_NULL_POINTER(unit); + + pvec->clear(); + + auto histfig = df::historical_figure::find(unit->hist_figure_id); + if (!histfig) + return false; + + for (size_t i = 0; i < histfig->entity_links.size(); i++) + { + auto link = histfig->entity_links[i]; + auto epos = strict_virtual_cast(link); + if (!epos) + continue; + + NoblePosition pos; + + pos.entity = df::historical_entity::find(epos->entity_id); + if (!pos.entity) + continue; + + pos.assignment = binsearch_in_vector(pos.entity->positions.assignments, epos->assignment_id); + if (!pos.assignment) + continue; + + pos.position = binsearch_in_vector(pos.entity->positions.own, pos.assignment->position_id); + if (!pos.position) + continue; + + pvec->push_back(pos); + } + + if (pvec->empty()) + return false; + + std::sort(pvec->begin(), pvec->end(), noble_pos_compare); + return true; +} + +std::string DFHack::Units::getProfessionName(df::unit *unit, bool ignore_noble, bool plural) { std::string prof = unit->custom_profession; + if (!prof.empty()) + return prof; - if (prof.empty()) - prof = getCasteProfessionName(unit->race, unit->caste, unit->profession, plural); + std::vector np; + + if (!ignore_noble && getNoblePositions(&np, unit)) + { + switch (unit->sex) + { + case 0: + prof = np[0].position->name_female[plural ? 1 : 0]; + break; + case 1: + prof = np[0].position->name_male[plural ? 1 : 0]; + break; + default: + break; + } + + if (prof.empty()) + prof = np[0].position->name[plural ? 1 : 0]; + if (!prof.empty()) + return prof; + } - return prof; + return getCasteProfessionName(unit->race, unit->caste, unit->profession, plural); } std::string DFHack::Units::getCasteProfessionName(int race, int casteid, df::profession pid, bool plural) diff --git a/plugins/lua/sort/units.lua b/plugins/lua/sort/units.lua index 7a332d094..35795502d 100644 --- a/plugins/lua/sort/units.lua +++ b/plugins/lua/sort/units.lua @@ -52,6 +52,15 @@ local function findRaceCaste(unit) return rraw, safe_index(rraw, 'caste', unit.caste) end +orders.noble = { + key = function(unit) + local info = dfhack.units.getNoblePositions(unit) + if info then + return info[1].position.precedence + end + end +} + orders.profession = { key = function(unit) local cp = dfhack.units.getProfessionName(unit) From 16ee049664765f2644d2ef83ad15d5ab101cd4e2 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 26 Apr 2012 12:56:28 +0400 Subject: [PATCH 16/18] Split off the burrows api from Maps and Units. --- LUA_API.rst | 47 ++--- Lua API.html | 63 +++---- library/CMakeLists.txt | 2 + library/LuaApi.cpp | 55 +++--- library/include/modules/Burrows.h | 78 +++++++++ library/include/modules/Maps.h | 29 ---- library/include/modules/Units.h | 5 - library/lua/dfhack.lua | 8 + library/modules/Burrows.cpp | 278 ++++++++++++++++++++++++++++++ library/modules/Maps.cpp | 166 ------------------ library/modules/Units.cpp | 62 ------- plugins/burrows.cpp | 31 ++-- plugins/lua/burrows.lua | 22 +-- 13 files changed, 479 insertions(+), 367 deletions(-) create mode 100644 library/include/modules/Burrows.h create mode 100644 library/modules/Burrows.cpp diff --git a/LUA_API.rst b/LUA_API.rst index acbba3272..38b0e2025 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -711,18 +711,6 @@ Units module The unit is capable of rational action, i.e. not dead, insane or zombie. -* ``dfhack.units.clearBurrowMembers(burrow)`` - - Removes all units from the burrow. - -* ``dfhack.units.isInBurrow(unit,burrow)`` - - Checks if the unit is in the burrow. - -* ``dfhack.units.setInBurrow(unit,burrow,enable)`` - - Adds or removes the unit from the burrow. - * ``dfhack.units.getAge(unit[,true_age])`` Returns the age of the unit in years as a floating-point value. @@ -807,31 +795,47 @@ Maps module Returns the local feature object with the given region coords and index. -* ``dfhack.maps.findBurrowByName(name)`` + +Burrows module +-------------- + +* ``dfhack.burrows.findByName(name)`` Returns the burrow pointer or *nil*. -* ``dfhack.maps.listBurrowBlocks(burrow)`` +* ``dfhack.burrows.clearUnits(burrow)`` - Returns a table of map block pointers. + Removes all units from the burrow. + +* ``dfhack.burrows.isAssignedUnit(burrow,unit)`` -* ``dfhack.maps.clearBurrowTiles(burrow)`` + Checks if the unit is in the burrow. + +* ``dfhack.burrows.setAssignedUnit(burrow,unit,enable)`` + + Adds or removes the unit from the burrow. + +* ``dfhack.burrows.clearTiles(burrow)`` Removes all tiles from the burrow. -* ``dfhack.maps.isBurrowTile(burrow,tile_coord)`` +* ``dfhack.burrows.listBlocks(burrow)`` + + Returns a table of map block pointers. + +* ``dfhack.burrows.isAssignedTile(burrow,tile_coord)`` Checks if the tile is in burrow. -* ``dfhack.maps.setBurrowTile(burrow,tile_coord,enable)`` +* ``dfhack.burrows.setAssignedTile(burrow,tile_coord,enable)`` Adds or removes the tile from the burrow. Returns *false* if invalid coords. -* ``dfhack.maps.isBlockBurrowTile(burrow,block,x,y)`` +* ``dfhack.burrows.isAssignedBlockTile(burrow,block,x,y)`` Checks if the tile within the block is in burrow. -* ``dfhack.maps.setBlockBurrowTile(burrow,block,x,y,enable)`` +* ``dfhack.burrows.setAssignedBlockTile(burrow,block,x,y,enable)`` Adds or removes the tile from the burrow. Returns *false* if invalid coords. @@ -937,8 +941,7 @@ Native functions: Adds or removes tiles matching a predefined keyword. The keyword set is the same as used by the command line. -The lua module file also re-exports or wraps some of the -functions implemented by the dfhack core for convenience. +The lua module file also re-exports functions from ``dfhack.burrows``. sort ==== diff --git a/Lua API.html b/Lua API.html index def3790c9..3e08b3bef 100644 --- a/Lua API.html +++ b/Lua API.html @@ -342,17 +342,18 @@ ul.auto-toc {
  • Units module
  • Items module
  • Maps module
  • +
  • Burrows module
  • -
  • Core interpreter context
  • -
  • Plugins @@ -946,15 +947,6 @@ a lua list containing them.

  • dfhack.units.isSane(unit)

    The unit is capable of rational action, i.e. not dead, insane or zombie.

  • -
  • dfhack.units.clearBurrowMembers(burrow)

    -

    Removes all units from the burrow.

    -
  • -
  • dfhack.units.isInBurrow(unit,burrow)

    -

    Checks if the unit is in the burrow.

    -
  • -
  • dfhack.units.setInBurrow(unit,burrow,enable)

    -

    Adds or removes the unit from the burrow.

    -
  • dfhack.units.getAge(unit[,true_age])

    Returns the age of the unit in years as a floating-point value. If true_age is true, ignores false identities.

    @@ -1023,32 +1015,46 @@ Returns false in case of error.

  • dfhack.maps.getLocalInitFeature(region_coord2d,index)

    Returns the local feature object with the given region coords and index.

  • -
  • dfhack.maps.findBurrowByName(name)

    + + +
    +

    Burrows module

    +
      +
    • dfhack.burrows.findByName(name)

      Returns the burrow pointer or nil.

    • -
    • dfhack.maps.listBurrowBlocks(burrow)

      -

      Returns a table of map block pointers.

      +
    • dfhack.burrows.clearUnits(burrow)

      +

      Removes all units from the burrow.

      +
    • +
    • dfhack.burrows.isAssignedUnit(burrow,unit)

      +

      Checks if the unit is in the burrow.

    • -
    • dfhack.maps.clearBurrowTiles(burrow)

      +
    • dfhack.burrows.setAssignedUnit(burrow,unit,enable)

      +

      Adds or removes the unit from the burrow.

      +
    • +
    • dfhack.burrows.clearTiles(burrow)

      Removes all tiles from the burrow.

    • -
    • dfhack.maps.isBurrowTile(burrow,tile_coord)

      +
    • dfhack.burrows.listBlocks(burrow)

      +

      Returns a table of map block pointers.

      +
    • +
    • dfhack.burrows.isAssignedTile(burrow,tile_coord)

      Checks if the tile is in burrow.

    • -
    • dfhack.maps.setBurrowTile(burrow,tile_coord,enable)

      +
    • dfhack.burrows.setAssignedTile(burrow,tile_coord,enable)

      Adds or removes the tile from the burrow. Returns false if invalid coords.

    • -
    • dfhack.maps.isBlockBurrowTile(burrow,block,x,y)

      +
    • dfhack.burrows.isAssignedBlockTile(burrow,block,x,y)

      Checks if the tile within the block is in burrow.

    • -
    • dfhack.maps.setBlockBurrowTile(burrow,block,x,y,enable)

      +
    • dfhack.burrows.setAssignedBlockTile(burrow,block,x,y,enable)

      Adds or removes the tile from the burrow. Returns false if invalid coords.

    -

    Core interpreter context

    +

    Core interpreter context

    While plugins can create any number of interpreter instances, there is one special context managed by dfhack core. It is the only context that can receive events from DF and plugins.

    @@ -1062,7 +1068,7 @@ only context that can receive events from DF and plugins.

  • -

    Event type

    +

    Event type

    An event is just a lua table with a predefined metatable that contains a __call metamethod. When it is invoked, it loops through the table with next and calls all contained values. @@ -1088,14 +1094,14 @@ order using dfhack.safecall.

    -

    Plugins

    +

    Plugins

    DFHack plugins may export native functions and events to lua contexts. They are automatically imported by mkmodule('plugins.<name>'); this means that a lua module file is still necessary for require to read.

    The following plugins have lua support.

    -

    burrows

    +

    burrows

    Implements extended burrow manipulations.

    Events:

      @@ -1130,11 +1136,10 @@ parameter specifies if they are to be added or removed.

      set is the same as used by the command line.

    -

    The lua module file also re-exports or wraps some of the -functions implemented by the dfhack core for convenience.

    +

    The lua module file also re-exports functions from dfhack.burrows.

    -

    sort

    +

    sort

    Does not export any native functions as of now. Instead, it calls lua code to perform the actual ordering of list items.

    diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index b4ea751e7..c052df9c8 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -100,6 +100,7 @@ Process-linux.cpp SET(MODULE_HEADERS include/modules/Buildings.h +include/modules/Burrows.h include/modules/Constructions.h include/modules/Units.h include/modules/Engravings.h @@ -120,6 +121,7 @@ include/modules/Graphic.h SET( MODULE_SOURCES modules/Buildings.cpp +modules/Burrows.cpp modules/Constructions.cpp modules/Units.cpp modules/Engravings.cpp diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 8c56379a7..507494669 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -46,6 +46,7 @@ distribution. #include "modules/Materials.h" #include "modules/Maps.h" #include "modules/MapCache.h" +#include "modules/Burrows.h" #include "LuaWrapper.h" #include "LuaTools.h" @@ -618,9 +619,6 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, isDead), WRAPM(Units, isAlive), WRAPM(Units, isSane), - WRAPM(Units, clearBurrowMembers), - WRAPM(Units, isInBurrow), - WRAPM(Units, setInBurrow), WRAPM(Units, getAge), WRAPM(Units, getProfessionName), WRAPM(Units, getCasteProfessionName), @@ -704,42 +702,52 @@ static const luaL_Reg dfhack_items_funcs[] = { { NULL, NULL } }; +static const LuaWrapper::FunctionReg dfhack_maps_module[] = { + WRAPN(getBlock, (df::map_block* (*)(int32_t,int32_t,int32_t))Maps::getBlock), + WRAPN(getTileBlock, (df::map_block* (*)(df::coord))Maps::getTileBlock), + WRAPM(Maps, getRegionBiome), + WRAPM(Maps, getGlobalInitFeature), + WRAPM(Maps, getLocalInitFeature), + { NULL, NULL } +}; -static bool maps_isBlockBurrowTile(df::burrow *burrow, df::map_block *block, int x, int y) +static const luaL_Reg dfhack_maps_funcs[] = { + { NULL, NULL } +}; + +static bool burrows_isAssignedBlockTile(df::burrow *burrow, df::map_block *block, int x, int y) { - return Maps::isBlockBurrowTile(burrow, block, df::coord2d(x,y)); + return Burrows::isAssignedBlockTile(burrow, block, df::coord2d(x,y)); } -static bool maps_setBlockBurrowTile(df::burrow *burrow, df::map_block *block, int x, int y, bool enable) +static bool burrows_setAssignedBlockTile(df::burrow *burrow, df::map_block *block, int x, int y, bool enable) { - return Maps::setBlockBurrowTile(burrow, block, df::coord2d(x,y), enable); + return Burrows::setAssignedBlockTile(burrow, block, df::coord2d(x,y), enable); } -static const LuaWrapper::FunctionReg dfhack_maps_module[] = { - WRAPN(getBlock, (df::map_block* (*)(int32_t,int32_t,int32_t))Maps::getBlock), - WRAPN(getTileBlock, (df::map_block* (*)(df::coord))Maps::getTileBlock), - WRAPM(Maps, getRegionBiome), - WRAPM(Maps, getGlobalInitFeature), - WRAPM(Maps, getLocalInitFeature), - WRAPM(Maps, findBurrowByName), - WRAPM(Maps, clearBurrowTiles), - WRAPN(isBlockBurrowTile, maps_isBlockBurrowTile), - WRAPN(setBlockBurrowTile, maps_setBlockBurrowTile), - WRAPM(Maps, isBurrowTile), - WRAPM(Maps, setBurrowTile), +static const LuaWrapper::FunctionReg dfhack_burrows_module[] = { + WRAPM(Burrows, findByName), + WRAPM(Burrows, clearUnits), + WRAPM(Burrows, isAssignedUnit), + WRAPM(Burrows, setAssignedUnit), + WRAPM(Burrows, clearTiles), + WRAPN(isAssignedBlockTile, burrows_isAssignedBlockTile), + WRAPN(setAssignedBlockTile, burrows_setAssignedBlockTile), + WRAPM(Burrows, isAssignedTile), + WRAPM(Burrows, setAssignedTile), { NULL, NULL } }; -static int maps_listBurrowBlocks(lua_State *state) +static int burrows_listBlocks(lua_State *state) { std::vector pvec; - Maps::listBurrowBlocks(&pvec, Lua::CheckDFObject(state,1)); + Burrows::listBlocks(&pvec, Lua::CheckDFObject(state,1)); Lua::PushVector(state, pvec); return 1; } -static const luaL_Reg dfhack_maps_funcs[] = { - { "listBurrowBlocks", maps_listBurrowBlocks }, +static const luaL_Reg dfhack_burrows_funcs[] = { + { "listBlocks", burrows_listBlocks }, { NULL, NULL } }; @@ -759,4 +767,5 @@ void OpenDFHackApi(lua_State *state) OpenModule(state, "units", dfhack_units_module, dfhack_units_funcs); OpenModule(state, "items", dfhack_items_module, dfhack_items_funcs); OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs); + OpenModule(state, "burrows", dfhack_burrows_module, dfhack_burrows_funcs); } diff --git a/library/include/modules/Burrows.h b/library/include/modules/Burrows.h new file mode 100644 index 000000000..e26a2dc20 --- /dev/null +++ b/library/include/modules/Burrows.h @@ -0,0 +1,78 @@ +/* +https://github.com/peterix/dfhack +Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + +#pragma once +#include "Export.h" +#include "DataDefs.h" +#include "modules/Maps.h" + +#include + +/** + * \defgroup grp_burrows Burrows module and its types + * @ingroup grp_modules + */ + +namespace df +{ + struct unit; + struct burrow; + struct block_burrow; +} + +namespace DFHack +{ +namespace Burrows +{ + DFHACK_EXPORT df::burrow *findByName(std::string name); + + // Units + DFHACK_EXPORT void clearUnits(df::burrow *burrow); + + DFHACK_EXPORT bool isAssignedUnit(df::burrow *burrow, df::unit *unit); + DFHACK_EXPORT void setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable); + + // Tiles + DFHACK_EXPORT void clearTiles(df::burrow *burrow); + + DFHACK_EXPORT void listBlocks(std::vector *pvec, df::burrow *burrow); + + DFHACK_EXPORT bool isAssignedBlockTile(df::burrow *burrow, df::map_block *block, df::coord2d tile); + DFHACK_EXPORT bool setAssignedBlockTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable); + + inline bool isAssignedTile(df::burrow *burrow, df::coord tile) { + return isAssignedBlockTile(burrow, Maps::getTileBlock(tile), tile); + } + inline bool setAssignedTile(df::burrow *burrow, df::coord tile, bool enable) { + return setAssignedBlockTile(burrow, Maps::getTileBlock(tile), tile, enable); + } + + DFHACK_EXPORT df::block_burrow *getBlockMask(df::burrow *burrow, df::map_block *block, bool create = false); + DFHACK_EXPORT bool deleteBlockMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask); + + inline bool deleteBlockMask(df::burrow *burrow, df::map_block *block) { + return deleteBlockMask(burrow, block, getBlockMask(burrow, block)); + } +} +} diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index b7341f87c..b6077a85e 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -255,35 +255,6 @@ extern DFHACK_EXPORT bool SortBlockEvents(df::map_block *block, /// remove a block event from the block by address extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, df::block_square_event * which ); - -/* - * BURROWS - */ - -DFHACK_EXPORT df::burrow *findBurrowByName(std::string name); - -DFHACK_EXPORT void listBurrowBlocks(std::vector *pvec, df::burrow *burrow); -DFHACK_EXPORT void clearBurrowTiles(df::burrow *burrow); - -DFHACK_EXPORT df::block_burrow *getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create = false); -DFHACK_EXPORT bool deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask); - -inline bool deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block) -{ - return deleteBlockBurrowMask(burrow, block, getBlockBurrowMask(burrow, block)); -} - - -DFHACK_EXPORT bool isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile); -DFHACK_EXPORT bool setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable); - -inline bool isBurrowTile(df::burrow *burrow, df::coord tile) { - return isBlockBurrowTile(burrow, getTileBlock(tile), tile); -} -inline bool setBurrowTile(df::burrow *burrow, df::coord tile, bool enable) { - return setBlockBurrowTile(burrow, getTileBlock(tile), tile, enable); -} - } } #endif diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index e1f8baa12..7bf4f101b 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -214,11 +214,6 @@ DFHACK_EXPORT bool isSane(df::unit *unit); DFHACK_EXPORT bool isCitizen(df::unit *unit); DFHACK_EXPORT bool isDwarf(df::unit *unit); -DFHACK_EXPORT void clearBurrowMembers(df::burrow *burrow); - -DFHACK_EXPORT bool isInBurrow(df::unit *unit, df::burrow *burrow); -DFHACK_EXPORT void setInBurrow(df::unit *unit, df::burrow *burrow, bool enable); - DFHACK_EXPORT double getAge(df::unit *unit, bool true_age = false); struct NoblePosition { diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index 100aea59c..aedd460b1 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -125,6 +125,14 @@ function xyz2pos(x,y,z) end end +function rawset_default(target,source) + for k,v in pairs(source) do + if rawget(target,k) == nil then + rawset(target,k,v) + end + end +end + function safe_index(obj,idx,...) if obj == nil or idx == nil then return nil diff --git a/library/modules/Burrows.cpp b/library/modules/Burrows.cpp new file mode 100644 index 000000000..62f62779a --- /dev/null +++ b/library/modules/Burrows.cpp @@ -0,0 +1,278 @@ +/* +https://github.com/peterix/dfhack +Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com) + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any +damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must +not claim that you wrote the original software. If you use this +software in a product, an acknowledgment in the product documentation +would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and +must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. +*/ + + +#include "Internal.h" + +#include +#include +using namespace std; + +#include "Error.h" +#include "Core.h" + +#include "modules/Burrows.h" +#include "modules/Maps.h" +#include "modules/Units.h" + +#include "MiscUtils.h" + +#include "DataDefs.h" +#include "df/ui.h" +#include "df/burrow.h" +#include "df/block_burrow.h" +#include "df/block_burrow_link.h" + +using namespace DFHack; +using namespace df::enums; + +using df::global::world; +using df::global::ui; + +df::burrow *Burrows::findByName(std::string name) +{ + auto &vec = df::burrow::get_vector(); + + for (size_t i = 0; i < vec.size(); i++) + if (vec[i]->name == name) + return vec[i]; + + return NULL; +} + +void Burrows::clearUnits(df::burrow *burrow) +{ + CHECK_NULL_POINTER(burrow); + + for (size_t i = 0; i < burrow->units.size(); i++) + { + auto unit = df::unit::find(burrow->units[i]); + + if (unit) + erase_from_vector(unit->burrows, burrow->id); + } + + burrow->units.clear(); + + // Sync ui if active + if (ui && ui->main.mode == ui_sidebar_mode::Burrows && + ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id) + { + auto &sel = ui->burrows.sel_units; + + for (size_t i = 0; i < sel.size(); i++) + sel[i] = false; + } +} + +bool Burrows::isAssignedUnit(df::burrow *burrow, df::unit *unit) +{ + CHECK_NULL_POINTER(unit); + CHECK_NULL_POINTER(burrow); + + return binsearch_index(unit->burrows, burrow->id) >= 0; +} + +void Burrows::setAssignedUnit(df::burrow *burrow, df::unit *unit, bool enable) +{ + using df::global::ui; + + CHECK_NULL_POINTER(unit); + CHECK_NULL_POINTER(burrow); + + if (enable) + { + insert_into_vector(unit->burrows, burrow->id); + insert_into_vector(burrow->units, unit->id); + } + else + { + erase_from_vector(unit->burrows, burrow->id); + erase_from_vector(burrow->units, unit->id); + } + + // Sync ui if active + if (ui && ui->main.mode == ui_sidebar_mode::Burrows && + ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id) + { + int idx = linear_index(ui->burrows.list_units, unit); + if (idx >= 0) + ui->burrows.sel_units[idx] = enable; + } +} + +void Burrows::listBlocks(std::vector *pvec, df::burrow *burrow) +{ + CHECK_NULL_POINTER(burrow); + + pvec->clear(); + pvec->reserve(burrow->block_x.size()); + + df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z); + + for (size_t i = 0; i < burrow->block_x.size(); i++) + { + df::coord pos(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]); + + auto block = Maps::getBlock(pos - base); + if (block) + pvec->push_back(block); + } +} + +static void destroyBurrowMask(df::block_burrow *mask) +{ + if (!mask) return; + + auto link = mask->link; + + link->prev->next = link->next; + if (link->next) + link->next->prev = link->prev; + delete link; + + delete mask; +} + +void Burrows::clearTiles(df::burrow *burrow) +{ + CHECK_NULL_POINTER(burrow); + + df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z); + + for (size_t i = 0; i < burrow->block_x.size(); i++) + { + df::coord pos(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]); + + auto block = Maps::getBlock(pos - base); + if (!block) + continue; + + destroyBurrowMask(getBlockMask(burrow, block)); + } + + burrow->block_x.clear(); + burrow->block_y.clear(); + burrow->block_z.clear(); +} + +df::block_burrow *Burrows::getBlockMask(df::burrow *burrow, df::map_block *block, bool create) +{ + CHECK_NULL_POINTER(burrow); + CHECK_NULL_POINTER(block); + + int32_t id = burrow->id; + df::block_burrow_link *prev = &block->block_burrows; + df::block_burrow_link *link = prev->next; + + for (; link; prev = link, link = link->next) + if (link->item->id == id) + return link->item; + + if (create) + { + link = new df::block_burrow_link; + link->item = new df::block_burrow; + + link->item->id = burrow->id; + link->item->tile_bitmask.clear(); + link->item->link = link; + + link->next = NULL; + link->prev = prev; + prev->next = link; + + df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z); + df::coord pos = base + block->map_pos/16; + + burrow->block_x.push_back(pos.x); + burrow->block_y.push_back(pos.y); + burrow->block_z.push_back(pos.z); + + return link->item; + } + + return NULL; +} + +bool Burrows::deleteBlockMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask) +{ + CHECK_NULL_POINTER(burrow); + CHECK_NULL_POINTER(block); + + if (!mask) + return false; + + df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z); + df::coord pos = base + block->map_pos/16; + + destroyBurrowMask(mask); + + for (size_t i = 0; i < burrow->block_x.size(); i++) + { + df::coord cur(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]); + + if (cur == pos) + { + vector_erase_at(burrow->block_x, i); + vector_erase_at(burrow->block_y, i); + vector_erase_at(burrow->block_z, i); + + break; + } + } + + return true; +} + +bool Burrows::isAssignedBlockTile(df::burrow *burrow, df::map_block *block, df::coord2d tile) +{ + CHECK_NULL_POINTER(burrow); + + if (!block) return false; + + auto mask = getBlockMask(burrow, block); + + return mask ? mask->getassignment(tile & 15) : false; +} + +bool Burrows::setAssignedBlockTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable) +{ + CHECK_NULL_POINTER(burrow); + + if (!block) return false; + + auto mask = getBlockMask(burrow, block, enable); + + if (mask) + { + mask->setassignment(tile & 15, enable); + + if (!enable && !mask->has_assignments()) + deleteBlockMask(burrow, block, mask); + } + + return true; +} + diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index 3c4933fb7..e7d49deda 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -1056,169 +1056,3 @@ void MapExtras::MapCache::resetTags() it->second->tags = NULL; } } - -df::burrow *Maps::findBurrowByName(std::string name) -{ - auto &vec = df::burrow::get_vector(); - - for (size_t i = 0; i < vec.size(); i++) - if (vec[i]->name == name) - return vec[i]; - - return NULL; -} - -void Maps::listBurrowBlocks(std::vector *pvec, df::burrow *burrow) -{ - CHECK_NULL_POINTER(burrow); - - pvec->clear(); - pvec->reserve(burrow->block_x.size()); - - df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z); - - for (size_t i = 0; i < burrow->block_x.size(); i++) - { - df::coord pos(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]); - - auto block = getBlock(pos - base); - if (block) - pvec->push_back(block); - } -} - -static void destroyBurrowMask(df::block_burrow *mask) -{ - if (!mask) return; - - auto link = mask->link; - - link->prev->next = link->next; - if (link->next) - link->next->prev = link->prev; - delete link; - - delete mask; -} - -void Maps::clearBurrowTiles(df::burrow *burrow) -{ - CHECK_NULL_POINTER(burrow); - - df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z); - - for (size_t i = 0; i < burrow->block_x.size(); i++) - { - df::coord pos(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]); - - auto block = getBlock(pos - base); - if (!block) - continue; - - destroyBurrowMask(getBlockBurrowMask(burrow, block)); - } - - burrow->block_x.clear(); - burrow->block_y.clear(); - burrow->block_z.clear(); -} - -df::block_burrow *Maps::getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create) -{ - CHECK_NULL_POINTER(burrow); - CHECK_NULL_POINTER(block); - - int32_t id = burrow->id; - df::block_burrow_link *prev = &block->block_burrows; - df::block_burrow_link *link = prev->next; - - for (; link; prev = link, link = link->next) - if (link->item->id == id) - return link->item; - - if (create) - { - link = new df::block_burrow_link; - link->item = new df::block_burrow; - - link->item->id = burrow->id; - link->item->tile_bitmask.clear(); - link->item->link = link; - - link->next = NULL; - link->prev = prev; - prev->next = link; - - df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z); - df::coord pos = base + block->map_pos/16; - - burrow->block_x.push_back(pos.x); - burrow->block_y.push_back(pos.y); - burrow->block_z.push_back(pos.z); - - return link->item; - } - - return NULL; -} - -bool Maps::deleteBlockBurrowMask(df::burrow *burrow, df::map_block *block, df::block_burrow *mask) -{ - CHECK_NULL_POINTER(burrow); - CHECK_NULL_POINTER(block); - - if (!mask) - return false; - - df::coord base(world->map.region_x*3,world->map.region_y*3,world->map.region_z); - df::coord pos = base + block->map_pos/16; - - destroyBurrowMask(mask); - - for (size_t i = 0; i < burrow->block_x.size(); i++) - { - df::coord cur(burrow->block_x[i], burrow->block_y[i], burrow->block_z[i]); - - if (cur == pos) - { - vector_erase_at(burrow->block_x, i); - vector_erase_at(burrow->block_y, i); - vector_erase_at(burrow->block_z, i); - - break; - } - } - - return true; -} - -bool Maps::isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile) -{ - CHECK_NULL_POINTER(burrow); - - if (!block) return false; - - auto mask = getBlockBurrowMask(burrow, block); - - return mask ? mask->getassignment(tile & 15) : false; -} - -bool Maps::setBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile, bool enable) -{ - CHECK_NULL_POINTER(burrow); - - if (!block) return false; - - auto mask = getBlockBurrowMask(burrow, block, enable); - - if (mask) - { - mask->setassignment(tile & 15, enable); - - if (!enable && !mask->has_assignments()) - deleteBlockBurrowMask(burrow, block, mask); - } - - return true; -} - diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index 4ea225ade..77a836c9f 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -677,68 +677,6 @@ bool DFHack::Units::isDwarf(df::unit *unit) return unit->race == ui->race_id; } -void DFHack::Units::clearBurrowMembers(df::burrow *burrow) -{ - CHECK_NULL_POINTER(burrow); - - for (size_t i = 0; i < burrow->units.size(); i++) - { - auto unit = df::unit::find(burrow->units[i]); - - if (unit) - erase_from_vector(unit->burrows, burrow->id); - } - - burrow->units.clear(); - - // Sync ui if active - if (ui && ui->main.mode == ui_sidebar_mode::Burrows && - ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id) - { - auto &sel = ui->burrows.sel_units; - - for (size_t i = 0; i < sel.size(); i++) - sel[i] = false; - } -} - - -bool DFHack::Units::isInBurrow(df::unit *unit, df::burrow *burrow) -{ - CHECK_NULL_POINTER(unit); - CHECK_NULL_POINTER(burrow); - - return binsearch_index(unit->burrows, burrow->id) >= 0; -} - -void DFHack::Units::setInBurrow(df::unit *unit, df::burrow *burrow, bool enable) -{ - using df::global::ui; - - CHECK_NULL_POINTER(unit); - CHECK_NULL_POINTER(burrow); - - if (enable) - { - insert_into_vector(unit->burrows, burrow->id); - insert_into_vector(burrow->units, unit->id); - } - else - { - erase_from_vector(unit->burrows, burrow->id); - erase_from_vector(burrow->units, unit->id); - } - - // Sync ui if active - if (ui && ui->main.mode == ui_sidebar_mode::Burrows && - ui->burrows.in_add_units_mode && ui->burrows.sel_id == burrow->id) - { - int idx = linear_index(ui->burrows.list_units, unit); - if (idx >= 0) - ui->burrows.sel_units[idx] = enable; - } -} - double DFHack::Units::getAge(df::unit *unit, bool true_age) { using df::global::cur_year; diff --git a/plugins/burrows.cpp b/plugins/burrows.cpp index 8080710c3..a6df3524b 100644 --- a/plugins/burrows.cpp +++ b/plugins/burrows.cpp @@ -13,6 +13,7 @@ #include "modules/MapCache.h" #include "modules/World.h" #include "modules/Units.h" +#include "modules/Burrows.h" #include "TileTypes.h" #include "DataDefs.h" @@ -345,7 +346,7 @@ static void handle_burrow_rename(color_ostream &out, df::burrow *burrow) static void add_to_burrows(std::vector &burrows, df::coord pos) { for (size_t i = 0; i < burrows.size(); i++) - Maps::setBurrowTile(burrows[i], pos, true); + Burrows::setAssignedTile(burrows[i], pos, true); } static void add_walls_to_burrows(color_ostream &out, std::vector &burrows, @@ -379,7 +380,7 @@ static void handle_dig_complete(color_ostream &out, df::job_type job, df::coord for (size_t i = 0; i < grow_burrows.size(); i++) { auto b = df::burrow::find(grow_burrows[i]); - if (b && Maps::isBurrowTile(b, pos)) + if (b && Burrows::isAssignedTile(b, pos)) to_grow.push_back(b); } @@ -446,7 +447,7 @@ static void copyUnits(df::burrow *target, df::burrow *source, bool enable) if (source == target) { if (!enable) - Units::clearBurrowMembers(target); + Burrows::clearUnits(target); return; } @@ -456,7 +457,7 @@ static void copyUnits(df::burrow *target, df::burrow *source, bool enable) auto unit = df::unit::find(source->units[i]); if (unit) - Units::setInBurrow(unit, target, enable); + Burrows::setAssignedUnit(target, unit, enable); } } @@ -468,22 +469,22 @@ static void copyTiles(df::burrow *target, df::burrow *source, bool enable) if (source == target) { if (!enable) - Maps::clearBurrowTiles(target); + Burrows::clearTiles(target); return; } std::vector pvec; - Maps::listBurrowBlocks(&pvec, source); + Burrows::listBlocks(&pvec, source); for (size_t i = 0; i < pvec.size(); i++) { auto block = pvec[i]; - auto smask = Maps::getBlockBurrowMask(source, block); + auto smask = Burrows::getBlockMask(source, block); if (!smask) continue; - auto tmask = Maps::getBlockBurrowMask(target, block, enable); + auto tmask = Burrows::getBlockMask(target, block, enable); if (!tmask) continue; @@ -498,7 +499,7 @@ static void copyTiles(df::burrow *target, df::burrow *source, bool enable) tmask->tile_bitmask[j] &= ~smask->tile_bitmask[j]; if (!tmask->has_assignments()) - Maps::deleteBlockBurrowMask(target, block, tmask); + Burrows::deleteBlockMask(target, block, tmask); } } } @@ -523,7 +524,7 @@ static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mas continue; if (!mask) - mask = Maps::getBlockBurrowMask(target, block, enable); + mask = Burrows::getBlockMask(target, block, enable); if (!mask) goto next_block; @@ -532,7 +533,7 @@ static void setTilesByDesignation(df::burrow *target, df::tile_designation d_mas } if (mask && !enable && !mask->has_assignments()) - Maps::deleteBlockBurrowMask(target, block, mask); + Burrows::deleteBlockMask(target, block, mask); next_block:; } @@ -625,7 +626,7 @@ static command_result burrow(color_ostream &out, vector ¶meters) if (!target) return CR_WRONG_USAGE; - Units::clearBurrowMembers(target); + Burrows::clearUnits(target); } } else if (cmd == "set-units" || cmd == "add-units" || cmd == "remove-units") @@ -638,7 +639,7 @@ static command_result burrow(color_ostream &out, vector ¶meters) return CR_WRONG_USAGE; if (cmd == "set-units") - Units::clearBurrowMembers(target); + Burrows::clearUnits(target); bool enable = (cmd != "remove-units"); @@ -662,7 +663,7 @@ static command_result burrow(color_ostream &out, vector ¶meters) if (!target) return CR_WRONG_USAGE; - Maps::clearBurrowTiles(target); + Burrows::clearTiles(target); } } else if (cmd == "set-tiles" || cmd == "add-tiles" || cmd == "remove-tiles") @@ -675,7 +676,7 @@ static command_result burrow(color_ostream &out, vector ¶meters) return CR_WRONG_USAGE; if (cmd == "set-tiles") - Maps::clearBurrowTiles(target); + Burrows::clearTiles(target); bool enable = (cmd != "remove-tiles"); diff --git a/plugins/lua/burrows.lua b/plugins/lua/burrows.lua index b1d51f6a6..871295fdc 100644 --- a/plugins/lua/burrows.lua +++ b/plugins/lua/burrows.lua @@ -2,6 +2,11 @@ local _ENV = mkmodule('plugins.burrows') --[[ + Native events: + + * onBurrowRename(burrow) + * onDigComplete(job_type,pos,old_tiletype,new_tiletype) + Native functions: * findByName(name) -> burrow @@ -13,21 +18,6 @@ local _ENV = mkmodule('plugins.burrows') --]] -clearUnits = dfhack.units.clearBurrowMembers - -function isBurrowUnit(burrow,unit) - return dfhack.units.isInBurrow(unit,burrow) -end -function setBurrowUnit(burrow,unit,enable) - return dfhack.units.setInBurrow(unit,burrow,enable) -end - -clearTiles = dfhack.maps.clearBurrowTiles -listBlocks = dfhack.maps.listBurrowBlocks - -isBurrowTile = dfhack.maps.isBurrowTile -setBurrowTile = dfhack.maps.setBurrowTile -isBlockBurrowTile = dfhack.maps.isBlockBurrowTile -setBlockBurrowTile = dfhack.maps.setBlockBurrowTile +rawset_default(_ENV, dfhack.burrows) return _ENV \ No newline at end of file From 82a0e52a3eeb55d62dd51cf92b5b1b26d0cc4c66 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Thu, 26 Apr 2012 18:51:39 +0400 Subject: [PATCH 17/18] Add api to check the walkable cache, and update flow_forbid in liquids. --- LUA_API.rst | 10 +++++++++ Lua API.html | 9 ++++++++ library/LuaApi.cpp | 41 +++++++++++++++++++++------------- library/include/LuaTools.h | 5 +++++ library/include/modules/Maps.h | 2 ++ library/modules/Maps.cpp | 14 ++++++++++++ plugins/liquids.cpp | 4 ++++ 7 files changed, 70 insertions(+), 15 deletions(-) diff --git a/LUA_API.rst b/LUA_API.rst index 38b0e2025..d2afacd42 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -795,6 +795,16 @@ Maps module Returns the local feature object with the given region coords and index. +* ``dfhack.maps.canWalkBetween(pos1, pos2)`` + + Checks if a dwarf may be able to walk between the two tiles, + using a pathfinding cache maintained by the game. Note that + this cache is only updated when the game is unpaused, and thus + can get out of date if doors are forbidden or unforbidden, or + tools like liquids or tiletypes are used. It also cannot possibly + take into account anything that depends on the actual units, like + burrows, or the presence of invaders. + Burrows module -------------- diff --git a/Lua API.html b/Lua API.html index 3e08b3bef..fd2004b8d 100644 --- a/Lua API.html +++ b/Lua API.html @@ -1015,6 +1015,15 @@ Returns false in case of error.

  • dfhack.maps.getLocalInitFeature(region_coord2d,index)

    Returns the local feature object with the given region coords and index.

  • +
  • dfhack.maps.canWalkBetween(pos1, pos2)

    +

    Checks if a dwarf may be able to walk between the two tiles, +using a pathfinding cache maintained by the game. Note that +this cache is only updated when the game is unpaused, and thus +can get out of date if doors are forbidden or unforbidden, or +tools like liquids or tiletypes are used. It also cannot possibly +take into account anything that depends on the actual units, like +burrows, or the presence of invaders.

    +
  • diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index 507494669..8855a50da 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -80,6 +80,17 @@ distribution. using namespace DFHack; using namespace DFHack::LuaWrapper; +void Lua::Push(lua_State *state, const Units::NoblePosition &pos) +{ + lua_createtable(state, 0, 3); + Lua::PushDFObject(state, pos.entity); + lua_setfield(state, -2, "entity"); + Lua::PushDFObject(state, pos.assignment); + lua_setfield(state, -2, "assignment"); + Lua::PushDFObject(state, pos.position); + lua_setfield(state, -2, "position"); +} + int Lua::PushPosXYZ(lua_State *state, df::coord pos) { if (!pos.isValid()) @@ -558,11 +569,15 @@ static void OpenModule(lua_State *state, const char *mname, #define WRAP(function) { #function, df::wrap_function(function,true) } #define WRAPN(name, function) { #name, df::wrap_function(function,true) } +/***** Translation module *****/ + static const LuaWrapper::FunctionReg dfhack_module[] = { WRAPM(Translation, TranslateName), { NULL, NULL } }; +/***** Gui module *****/ + static const LuaWrapper::FunctionReg dfhack_gui_module[] = { WRAPM(Gui, getSelectedWorkshopJob), WRAPM(Gui, getSelectedJob), @@ -573,6 +588,8 @@ static const LuaWrapper::FunctionReg dfhack_gui_module[] = { { NULL, NULL } }; +/***** Job module *****/ + static bool jobEqual(df::job *job1, df::job *job2) { return *job1 == *job2; } static bool jobItemEqual(df::job_item *job1, df::job_item *job2) { return *job1 == *job2; } @@ -609,6 +626,7 @@ static const luaL_Reg dfhack_job_funcs[] = { { NULL, NULL } }; +/***** Units module *****/ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, getContainer), @@ -635,21 +653,7 @@ static int units_getNoblePositions(lua_State *state) std::vector np; if (Units::getNoblePositions(&np, Lua::CheckDFObject(state,1))) - { - lua_createtable(state, np.size(), 0); - - for (size_t i = 0; i < np.size(); i++) - { - lua_createtable(state, 0, 3); - Lua::PushDFObject(state, np[i].entity); - lua_setfield(state, -2, "entity"); - Lua::PushDFObject(state, np[i].assignment); - lua_setfield(state, -2, "assignment"); - Lua::PushDFObject(state, np[i].position); - lua_setfield(state, -2, "position"); - lua_rawseti(state, -2, i+1); - } - } + Lua::PushVector(state, np); else lua_pushnil(state); @@ -662,6 +666,8 @@ static const luaL_Reg dfhack_units_funcs[] = { { NULL, NULL } }; +/***** Items module *****/ + static bool items_moveToGround(df::item *item, df::coord pos) { MapExtras::MapCache mc; @@ -702,12 +708,15 @@ static const luaL_Reg dfhack_items_funcs[] = { { NULL, NULL } }; +/***** Maps module *****/ + static const LuaWrapper::FunctionReg dfhack_maps_module[] = { WRAPN(getBlock, (df::map_block* (*)(int32_t,int32_t,int32_t))Maps::getBlock), WRAPN(getTileBlock, (df::map_block* (*)(df::coord))Maps::getTileBlock), WRAPM(Maps, getRegionBiome), WRAPM(Maps, getGlobalInitFeature), WRAPM(Maps, getLocalInitFeature), + WRAPM(Maps, canWalkBetween), { NULL, NULL } }; @@ -715,6 +724,8 @@ static const luaL_Reg dfhack_maps_funcs[] = { { NULL, NULL } }; +/***** Burrows module *****/ + static bool burrows_isAssignedBlockTile(df::burrow *burrow, df::map_block *block, int x, int y) { return Burrows::isAssignedBlockTile(burrow, block, df::coord2d(x,y)); diff --git a/library/include/LuaTools.h b/library/include/LuaTools.h index a41b58d1c..1ca79d331 100644 --- a/library/include/LuaTools.h +++ b/library/include/LuaTools.h @@ -36,6 +36,10 @@ distribution. namespace DFHack { class function_identity_base; + + namespace Units { + struct NoblePosition; + } } namespace DFHack {namespace Lua { @@ -243,6 +247,7 @@ namespace DFHack {namespace Lua { } inline void Push(lua_State *state, df::coord &obj) { PushDFObject(state, &obj); } inline void Push(lua_State *state, df::coord2d &obj) { PushDFObject(state, &obj); } + void Push(lua_State *state, const Units::NoblePosition &pos); template inline void Push(lua_State *state, T *ptr) { PushDFObject(state, ptr); } diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index b6077a85e..332954cda 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -255,6 +255,8 @@ extern DFHACK_EXPORT bool SortBlockEvents(df::map_block *block, /// remove a block event from the block by address extern DFHACK_EXPORT bool RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, df::block_square_event * which ); + +DFHACK_EXPORT bool canWalkBetween(df::coord pos1, df::coord pos2); } } #endif diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index e7d49deda..ddf5d5069 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -387,6 +387,20 @@ bool Maps::ReadGeology(vector > *layer_mats, vector return true; } +bool Maps::canWalkBetween(df::coord pos1, df::coord pos2) +{ + auto block1 = getTileBlock(pos1); + auto block2 = getTileBlock(pos2); + + if (!block1 || !block2) + return false; + + auto tile1 = MapExtras::index_tile(block1->walkable, pos1); + auto tile2 = MapExtras::index_tile(block2->walkable, pos2); + + return tile1 && tile1 == tile2; +} + #define COPY(a,b) memcpy(&a,&b,sizeof(a)) MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent) diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp index 8ca66daf5..f644398f5 100644 --- a/plugins/liquids.cpp +++ b/plugins/liquids.cpp @@ -388,6 +388,7 @@ command_result df_liquids_execute(color_ostream &out) mcache.setTemp2At(*iter,10015); df::tile_designation des = mcache.designationAt(*iter); des.bits.flow_size = 0; + des.bits.flow_forbid = false; mcache.setDesignationAt(*iter, des); iter ++; } @@ -494,6 +495,9 @@ command_result df_liquids_execute(color_ostream &out) mcache.setTemp1At(current,10015); mcache.setTemp2At(current,10015); } + // mark the tile passable or impassable like the game does + des.bits.flow_forbid = des.bits.flow_size && + (des.bits.liquid_type == tile_liquid::Magma || des.bits.flow_size > 3); mcache.setDesignationAt(current,des); } seen_blocks.insert(mcache.BlockAt(current / 16)); From 9c94b7c1e748743309dae75ec95e374f26624d5f Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 28 Apr 2012 11:53:26 +0400 Subject: [PATCH 18/18] Make the hash map implementation error more useful. It instructs to update GCC, but actually the most common reason for the error is missing 32-bit development libs. --- depends/protobuf/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depends/protobuf/CMakeLists.txt b/depends/protobuf/CMakeLists.txt index 92504f059..dddefb06b 100644 --- a/depends/protobuf/CMakeLists.txt +++ b/depends/protobuf/CMakeLists.txt @@ -57,7 +57,7 @@ IF(CMAKE_COMPILER_IS_GNUCC) ENDIF() IF (HAVE_HASH_MAP EQUAL 0) - MESSAGE(SEND_ERROR "Could not find a working hash map implementation. Please update GCC.") + MESSAGE(SEND_ERROR "Could not find a working hash map implementation. Please install GCC >= 4.4, and all necessary 32-bit C++ development libraries.") ENDIF() FIND_PACKAGE(Threads)