diff --git a/LUA_API.rst b/LUA_API.rst index ee3b1077c..fc86070c3 100644 --- a/LUA_API.rst +++ b/LUA_API.rst @@ -686,3 +686,80 @@ Units module * ``dfhack.units.isSane(unit)`` The unit is capable of rational action, i.e. not dead, insane or zombie. + +* ``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. + + +Items module +------------ + +* ``dfhack.items.getOwner(item)`` + + Returns the owner unit or *nil*. + +* ``dfhack.items.setOwner(item,unit)`` + + Replaces the owner of the item. If unit is *nil*, removes ownership. + Returns *false* in case of error. + + +Maps module +----------- + +* ``dfhack.maps.getSize()`` + + Returns map size in blocks: *x, y, z* + +* ``dfhack.maps.getTileSize()`` + + Returns map size in tiles: *x, y, z* + +* ``dfhack.maps.getBlock(x,y,z)`` + + Returns a map block object for given x,y,z in local block coordinates. + +* ``dfhack.maps.getTileBlock(coords)`` + + Returns a map block object for given df::coord in local tile coordinates. + +* ``dfhack.maps.getRegionBiome(region_coord2d)`` + + Returns the biome info struct for the given global map region. + +* ``dfhack.maps.getGlobalInitFeature(index)`` + + Returns the global feature object with the given index. + +* ``dfhack.maps.getLocalInitFeature(region_coord2d,index)`` + + Returns the local feature object with the given region coords and index. + +* ``dfhack.maps.findBurrowByName(name)`` + + Returns the burrow pointer or *nil*. + +* ``dfhack.maps.listBurrowBlocks(burrow)`` + + Returns a table of map block pointers. + +* ``dfhack.maps.isBurrowTile(burrow,tile_coord)`` + + Checks if the tile is in burrow. + +* ``dfhack.maps.setBurrowTile(burrow,tile_coord,enable)`` + + Adds or removes the tile from the burrow. Returns *false* if invalid coords. + +* ``dfhack.maps.isBlockBurrowTile(burrow,block,x,y)`` + + Checks if the tile within the block is in burrow. + +* ``dfhack.maps.setBlockBurrowTile(burrow,block,x,y,enable)`` + + Adds or removes the tile from the burrow. Returns *false* if invalid coords. diff --git a/Lua API.html b/Lua API.html index 89e158037..7c3eeddb9 100644 --- a/Lua API.html +++ b/Lua API.html @@ -340,6 +340,8 @@ ul.auto-toc {
  • Gui module
  • Job module
  • Units module
  • +
  • Items module
  • +
  • Maps module
  • @@ -916,6 +918,68 @@ 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.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.

    +
  • + + +
    +

    Items module

    + +
    +
    +

    Maps module

    +
    diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index c336e309c..febc59026 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -42,7 +42,9 @@ distribution. #include "modules/Job.h" #include "modules/Translation.h" #include "modules/Units.h" +#include "modules/Items.h" #include "modules/Materials.h" +#include "modules/Maps.h" #include "LuaWrapper.h" #include "LuaTools.h" @@ -62,6 +64,7 @@ distribution. #include "df/inorganic_raw.h" #include "df/dfhack_material_category.h" #include "df/job_material_category.h" +#include "df/burrow.h" #include #include @@ -70,6 +73,18 @@ distribution. using namespace DFHack; using namespace DFHack::LuaWrapper; +template +void push_pointer_vector(lua_State *state, const std::vector &pvec) +{ + lua_createtable(state,pvec.size(),0); + + for (size_t i = 0; i < pvec.size(); i++) + { + Lua::PushDFObject(state, pvec[i]); + lua_rawseti(state, -2, i+1); + } +} + /************************************************** * Per-world persistent configuration storage API * **************************************************/ @@ -527,9 +542,9 @@ static void OpenModule(lua_State *state, const char *mname, lua_pop(state, 1); } -#define WRAPM(module, function) { #function, df::wrap_function(&module::function) } -#define WRAP(function) { #function, df::wrap_function(&function) } -#define WRAPN(name, function) { #name, df::wrap_function(&function) } +#define WRAPM(module, function) { #function, df::wrap_function(module::function) } +#define WRAP(function) { #function, df::wrap_function(function) } +#define WRAPN(name, function) { #name, df::wrap_function(function) } static const LuaWrapper::FunctionReg dfhack_module[] = { WRAPM(Translation, TranslateName), @@ -570,14 +585,7 @@ static int job_listNewlyCreated(lua_State *state) if (Job::listNewlyCreated(&pvec, &nxid)) { lua_pushinteger(state, nxid); - lua_newtable(state); - - for (size_t i = 0; i < pvec.size(); i++) - { - Lua::PushDFObject(state, pvec[i]); - lua_rawseti(state, -2, i+1); - } - + push_pointer_vector(state, pvec); return 2; } else @@ -597,9 +605,61 @@ static const LuaWrapper::FunctionReg dfhack_units_module[] = { WRAPM(Units, isDead), WRAPM(Units, isAlive), WRAPM(Units, isSane), + WRAPM(Units, isInBurrow), + WRAPM(Units, setInBurrow), { NULL, NULL } }; +static const LuaWrapper::FunctionReg dfhack_items_module[] = { + WRAPM(Items, getOwner), + WRAPM(Items, setOwner), + { NULL, NULL } +}; + +static bool maps_isBlockBurrowTile(df::burrow *burrow, df::map_block *block, int x, int y) +{ + return Maps::isBlockBurrowTile(burrow, block, df::coord2d(x,y)); +} + +static bool maps_setBlockBurrowTile(df::burrow *burrow, df::map_block *block, int x, int y, bool enable) +{ + return Maps::setBlockBurrowTile(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), + WRAPN(isBlockBurrowTile, maps_isBlockBurrowTile), + WRAPN(setBlockBurrowTile, maps_setBlockBurrowTile), + WRAPM(Maps, isBurrowTile), + WRAPM(Maps, setBurrowTile), + { NULL, NULL } +}; + +static int maps_listBurrowBlocks(lua_State *state) +{ + luaL_checkany(state, 1); + + auto ptr = Lua::GetDFObject(state, 1); + if (!ptr) + luaL_argerror(state, 1, "invalid burrow type"); + + std::vector pvec; + Maps::listBurrowBlocks(&pvec, ptr); + push_pointer_vector(state, pvec); + return 1; +} + +static const luaL_Reg dfhack_maps_funcs[] = { + { "listBurrowBlocks", maps_listBurrowBlocks }, + { NULL, NULL } +}; + + /************************ * Main Open function * ************************/ @@ -613,4 +673,6 @@ void OpenDFHackApi(lua_State *state) OpenModule(state, "gui", dfhack_gui_module); OpenModule(state, "job", dfhack_job_module, dfhack_job_funcs); OpenModule(state, "units", dfhack_units_module); + OpenModule(state, "items", dfhack_items_module); + OpenModule(state, "maps", dfhack_maps_module, dfhack_maps_funcs); } diff --git a/library/LuaTypes.cpp b/library/LuaTypes.cpp index 2f9ef9e81..40269da80 100644 --- a/library/LuaTypes.cpp +++ b/library/LuaTypes.cpp @@ -80,6 +80,15 @@ void constructed_identity::lua_write(lua_State *state, int fname_idx, void *ptr, { invoke_assign(state, this, ptr, val_index); } + // Allow by-value assignment for wrapped function parameters + else if (fname_idx == UPVAL_METHOD_NAME && lua_isuserdata(state, val_index)) + { + void *nval = get_object_internal(state, this, val_index, false); + if (!nval) + field_error(state, fname_idx, "incompatible type in complex assignment", "write"); + if (!copy(ptr, nval)) + field_error(state, fname_idx, "no copy support", "write"); + } else field_error(state, fname_idx, "complex object", "write"); } diff --git a/library/include/DataDefs.h b/library/include/DataDefs.h index b9b4707d9..d4d757d94 100644 --- a/library/include/DataDefs.h +++ b/library/include/DataDefs.h @@ -425,6 +425,9 @@ namespace df static compound_identity *get() { return &T::_identity; } }; + template + inline T* allocate() { return (T*)identity_traits::get()->allocate(); } + template struct enum_traits {}; diff --git a/library/include/DataFuncs.h b/library/include/DataFuncs.h index 6cd7d42f4..d78fe9e27 100644 --- a/library/include/DataFuncs.h +++ b/library/include/DataFuncs.h @@ -139,6 +139,14 @@ INSTANTIATE_WRAPPERS(3, (OSTREAM_ARG,A1,A2,A3), (out,vA1,vA2,vA3), INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4)) INSTANTIATE_WRAPPERS(4, (A1,A2,A3,A4), (vA1,vA2,vA3,vA4), LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); LOAD_ARG(A4);) +INSTANTIATE_WRAPPERS(4, (OSTREAM_ARG,A1,A2,A3,A4), (out,vA1,vA2,vA3,vA4), + LOAD_OSTREAM(out); LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); LOAD_ARG(A4);) +#undef FW_TARGS + +#define FW_TARGS class A1, class A2, class A3, class A4, class A5 +INSTANTIATE_RETURN_TYPE((A1,A2,A3,A4,A5)) +INSTANTIATE_WRAPPERS(5, (A1,A2,A3,A4,A5), (vA1,vA2,vA3,vA4,vA5), + LOAD_ARG(A1); LOAD_ARG(A2); LOAD_ARG(A3); LOAD_ARG(A4); LOAD_ARG(A5);) #undef FW_TARGS #undef FW_TARGSC diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index c2a153eb1..0cf34c489 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -207,6 +207,22 @@ unsigned insert_into_vector(std::vector &vec, FT CT::*field, CT *obj, bool return pos; } +template +bool erase_from_vector(std::vector &vec, FT key) +{ + int pos = binsearch_index(vec, key); + vector_erase_at(vec, pos); + return pos >= 0; +} + +template +bool erase_from_vector(std::vector &vec, FT CT::*field, FT key) +{ + int pos = binsearch_index(vec, field, key); + vector_erase_at(vec, pos); + return pos >= 0; +} + template CT *binsearch_in_vector(const std::vector &vec, KT value) { diff --git a/library/include/df/custom/block_burrow.methods.inc b/library/include/df/custom/block_burrow.methods.inc new file mode 100644 index 000000000..7754ab0db --- /dev/null +++ b/library/include/df/custom/block_burrow.methods.inc @@ -0,0 +1,19 @@ +inline bool getassignment( const df::coord2d &xy ) +{ + return getassignment(xy.x,xy.y); +} +inline bool getassignment( int x, int y ) +{ + return (tile_bitmask[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) + tile_bitmask[y] |= (1 << x); + else + tile_bitmask[y] &= ~(1 << x); +} \ No newline at end of file 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 e01d22f72..7754ab0db 100644 --- a/library/include/df/custom/block_square_event_mineralst.methods.inc +++ b/library/include/df/custom/block_square_event_mineralst.methods.inc @@ -15,5 +15,5 @@ inline void setassignment( int x, int y, bool bit ) if(bit) tile_bitmask[y] |= (1 << x); else - tile_bitmask[y] &= 0xFFFF ^ (1 << x); + tile_bitmask[y] &= ~(1 << x); } \ No newline at end of file diff --git a/library/include/df/custom/coord2d.methods.inc b/library/include/df/custom/coord2d.methods.inc index c27629458..f15475b6f 100644 --- a/library/include/df/custom/coord2d.methods.inc +++ b/library/include/df/custom/coord2d.methods.inc @@ -39,3 +39,7 @@ coord2d operator%(int number) const { return coord2d((x+number)%number, (y+number)%number); } +coord2d operator&(int number) const +{ + return coord2d(x&number, y&number); +} \ No newline at end of file diff --git a/library/include/modules/Items.h b/library/include/modules/Items.h index e58c9214b..9bab02cc8 100644 --- a/library/include/modules/Items.h +++ b/library/include/modules/Items.h @@ -122,16 +122,17 @@ DFHACK_EXPORT bool copyItem(df::item * source, dfh_item & target); /// write copied item back to its origin DFHACK_EXPORT bool writeItem(const dfh_item & item); -/// who owns this item we already read? -DFHACK_EXPORT int32_t getItemOwnerID(const df::item * item); -DFHACK_EXPORT df::unit *getItemOwner(const df::item * item); +/// Retrieve the owner of the item. +DFHACK_EXPORT df::unit *getOwner(df::item *item); +/// Set the owner of the item. Pass NULL as unit to remove the owner. +DFHACK_EXPORT bool setOwner(df::item *item, df::unit *unit); + /// which item is it contained in? DFHACK_EXPORT int32_t getItemContainerID(const df::item * item); DFHACK_EXPORT df::item *getItemContainer(const df::item * item); /// which items does it contain? DFHACK_EXPORT bool getContainedItems(const df::item * item, /*output*/ std::vector &items); -/// wipe out the owner records -DFHACK_EXPORT bool removeItemOwner(df::item * item); + /// read item references, filtered by class DFHACK_EXPORT bool readItemRefs(const df::item * item, const df::general_ref_type type, /*output*/ std::vector &values); diff --git a/library/include/modules/MapCache.h b/library/include/modules/MapCache.h index b847d63f5..8eac514be 100644 --- a/library/include/modules/MapCache.h +++ b/library/include/modules/MapCache.h @@ -33,251 +33,187 @@ distribution. #include "df/map_block.h" #include "df/block_square_event_mineralst.h" #include "df/construction.h" +#include "df/item.h" + using namespace DFHack; + namespace MapExtras { -void SquashVeins (DFCoord bcoord, mapblock40d & mb, t_blockmaterials & materials) -{ - memset(materials,-1,sizeof(materials)); - std::vector veins; - Maps::SortBlockEvents(bcoord.x,bcoord.y,bcoord.z,&veins); - for (uint32_t x = 0;x<16;x++) for (uint32_t y = 0; y< 16;y++) - { - df::tiletype tt = mb.tiletypes[x][y]; - if (tileMaterial(tt) == tiletype_material::MINERAL) - { - for (size_t i = 0; i < veins.size(); i++) - { - if (veins[i]->getassignment(x,y)) - materials[x][y] = veins[i]->inorganic_mat; - } - } - } -} -void SquashFrozenLiquids (DFCoord bcoord, mapblock40d & mb, tiletypes40d & frozen) -{ - std::vector ices; - Maps::SortBlockEvents(bcoord.x,bcoord.y,bcoord.z,NULL,&ices); - for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) - { - df::tiletype tt = mb.tiletypes[x][y]; - frozen[x][y] = tiletype::Void; - if (tileMaterial(tt) == tiletype_material::FROZEN_LIQUID) - { - 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; - } - } - } - } -} +class DFHACK_EXPORT MapCache; -void SquashConstructions (DFCoord bcoord, mapblock40d & mb, tiletypes40d & constructions) -{ - for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) - { - df::tiletype tt = mb.tiletypes[x][y]; - constructions[x][y] = tiletype::Void; - if (tileMaterial(tt) == tiletype_material::CONSTRUCTION) - { - DFCoord coord(bcoord.x*16 + x, bcoord.y*16 + y, bcoord.z); - df::construction *con = df::construction::find(coord); - if (con) - constructions[x][y] = con->original_tile; - } - } +template inline R index_tile(T &v, df::coord2d p) { + return v[p.x&15][p.y&15]; } -void SquashRocks ( std::vector< std::vector > * layerassign, mapblock40d & mb, t_blockmaterials & materials) -{ - // get the layer materials - for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) - { - materials[x][y] = -1; - uint8_t test = mb.designation[x][y].bits.biome; - if ((test < sizeof(mb.biome_indices)) && (mb.biome_indices[test] < layerassign->size())) - materials[x][y] = layerassign->at(mb.biome_indices[test])[mb.designation[x][y].bits.geolayer_index]; - } +inline bool is_valid_tile_coord(df::coord2d p) { + return (p.x & ~15) == 0 && (p.y & ~15) == 0; } -class Block +class DFHACK_EXPORT Block { - public: - Block(DFCoord _bcoord, std::vector< std::vector > * layerassign = 0) - { - dirty_designations = false; - dirty_tiletypes = false; - dirty_temperatures = false; - dirty_blockflags = false; - dirty_occupancies = false; - valid = false; - bcoord = _bcoord; - if(Maps::ReadBlock40d(bcoord.x,bcoord.y,bcoord.z,&raw)) - { - Maps::ReadTemperatures(bcoord.x,bcoord.y, bcoord.z,&temp1,&temp2); - SquashVeins(bcoord,raw,veinmats); - SquashConstructions(bcoord, raw, contiles); - SquashFrozenLiquids(bcoord, raw, icetiles); - if(layerassign) - SquashRocks(layerassign,raw,basemats); - else - memset(basemats,-1,sizeof(basemats)); - valid = true; - } +public: + Block(MapCache *parent, DFCoord _bcoord); + ~Block(); + + /* + * All coordinates are taken mod 16. + */ + + //Arbitrary tag field for flood fills etc. + int16_t &tag(df::coord2d p) { + return index_tile(tags, p); } + int16_t veinMaterialAt(df::coord2d p) { - return veinmats[p.x][p.y]; + return index_tile(veinmats,p); } int16_t baseMaterialAt(df::coord2d p) { - return basemats[p.x][p.y]; - } - - // the clear methods are used by the floodfill in digv and digl to mark tiles which were processed - void ClearBaseMaterialAt(df::coord2d p) - { - basemats[p.x][p.y] = -1; - } - void ClearVeinMaterialAt(df::coord2d p) - { - veinmats[p.x][p.y] = -1; + return index_tile(basemats,p); } df::tiletype BaseTileTypeAt(df::coord2d p) { - if (contiles[p.x][p.y] != tiletype::Void) - return contiles[p.x][p.y]; - else if (icetiles[p.x][p.y] != tiletype::Void) - return icetiles[p.x][p.y]; - else - return raw.tiletypes[p.x][p.y]; + 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); } df::tiletype TileTypeAt(df::coord2d p) { - return raw.tiletypes[p.x][p.y]; + return index_tile(rawtiles,p); } bool setTiletypeAt(df::coord2d p, df::tiletype tiletype) { if(!valid) return false; dirty_tiletypes = true; //printf("setting block %d/%d/%d , %d %d\n",x,y,z, p.x, p.y); - raw.tiletypes[p.x][p.y] = tiletype; + index_tile(rawtiles,p) = tiletype; return true; } uint16_t temperature1At(df::coord2d p) { - return temp1[p.x][p.y]; + return index_tile(temp1,p); } bool setTemp1At(df::coord2d p, uint16_t temp) { if(!valid) return false; dirty_temperatures = true; - temp1[p.x][p.y] = temp; + index_tile(temp1,p) = temp; return true; } uint16_t temperature2At(df::coord2d p) { - return temp2[p.x][p.y]; + return index_tile(temp2,p); } bool setTemp2At(df::coord2d p, uint16_t temp) { if(!valid) return false; dirty_temperatures = true; - temp2[p.x][p.y] = temp; + index_tile(temp2,p) = temp; return true; } df::tile_designation DesignationAt(df::coord2d p) { - return raw.designation[p.x][p.y]; + return index_tile(designation,p); } bool setDesignationAt(df::coord2d p, df::tile_designation des) { if(!valid) return false; dirty_designations = true; //printf("setting block %d/%d/%d , %d %d\n",x,y,z, p.x, p.y); - raw.designation[p.x][p.y] = des; + index_tile(designation,p) = des; if(des.bits.dig) { dirty_blockflags = true; - raw.blockflags.bits.designated = true; + blockflags.bits.designated = true; } return true; } df::tile_occupancy OccupancyAt(df::coord2d p) { - return raw.occupancy[p.x][p.y]; + return index_tile(occupancy,p); } bool setOccupancyAt(df::coord2d p, df::tile_occupancy des) { if(!valid) return false; dirty_occupancies = true; - raw.occupancy[p.x][p.y] = des; + index_tile(occupancy,p) = des; return true; } + int itemCountAt(df::coord2d p) + { + if (!item_counts) init_item_counts(); + return index_tile(item_counts,p); + } + t_blockflags BlockFlags() { - return raw.blockflags; + return blockflags; } bool setBlockFlags(t_blockflags des) { if(!valid) return false; dirty_blockflags = true; //printf("setting block %d/%d/%d , %d %d\n",x,y,z, p.x, p.y); - raw.blockflags = des; + blockflags = des; return true; } - bool Write () - { - if(!valid) return false; - if(dirty_designations) - { - Maps::WriteDesignations(bcoord.x,bcoord.y,bcoord.z, &raw.designation); - Maps::WriteDirtyBit(bcoord.x,bcoord.y,bcoord.z,true); - dirty_designations = false; - } - if(dirty_tiletypes) - { - Maps::WriteTileTypes(bcoord.x,bcoord.y,bcoord.z, &raw.tiletypes); - dirty_tiletypes = false; - } - if(dirty_temperatures) - { - Maps::WriteTemperatures(bcoord.x,bcoord.y,bcoord.z, &temp1, &temp2); - dirty_temperatures = false; - } - if(dirty_blockflags) - { - Maps::WriteBlockFlags(bcoord.x,bcoord.y,bcoord.z,raw.blockflags); - dirty_blockflags = false; - } - if(dirty_occupancies) - { - Maps::WriteOccupancy(bcoord.x,bcoord.y,bcoord.z,&raw.occupancy); - dirty_occupancies = false; - } - return true; - } - bool valid:1; + bool Write(); + + df::coord2d biomeRegionAt(df::coord2d p); + int16_t GeoIndexAt(df::coord2d p); + + bool GetGlobalFeature(t_feature *out); + bool GetLocalFeature(t_feature *out); + + bool is_valid() { return valid; } + df::map_block *getRaw() { return block; } + +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_temperatures:1; bool dirty_blockflags:1; bool dirty_occupancies:1; - mapblock40d raw; + DFCoord bcoord; + + int16_t tags[16][16]; + + typedef int T_item_counts[16]; + T_item_counts *item_counts; + void init_item_counts(); + + bool addItemOnGround(df::item *item); + bool removeItemOnGround(df::item *item); + + tiletypes40d rawtiles; + designations40d designation; + occupancies40d occupancy; + t_blockflags blockflags; + t_blockmaterials veinmats; t_blockmaterials basemats; t_temperatures temp1; @@ -286,14 +222,15 @@ class Block tiletypes40d icetiles; // what's underneath ice }; -class MapCache +class DFHACK_EXPORT MapCache { public: MapCache() { valid = 0; Maps::getSize(x_bmax, y_bmax, z_max); - validgeo = Maps::ReadGeology( layerassign ); + x_tmax = x_bmax*16; y_tmax = y_bmax*16; + validgeo = Maps::ReadGeology(&layer_mats, &geoidx); valid = true; }; ~MapCache() @@ -304,192 +241,116 @@ class MapCache { return valid; } + /// get the map block at a *block* coord. Block coord = tile coord / 16 - Block * BlockAt (DFCoord blockcoord) - { - if(!valid) - return 0; - std::map ::iterator iter = blocks.find(blockcoord); - if(iter != blocks.end()) - { - return (*iter).second; - } - else - { - if(blockcoord.x >= 0 && blockcoord.x < x_bmax && - blockcoord.y >= 0 && blockcoord.y < y_bmax && - blockcoord.z >= 0 && blockcoord.z < z_max) - { - Block * nblo; - if(validgeo) - nblo = new Block(blockcoord, &layerassign); - else - nblo = new Block(blockcoord); - blocks[blockcoord] = nblo; - return nblo; - } - return 0; - } + Block *BlockAt(DFCoord blockcoord); + /// get the map block at a tile coord. + Block *BlockAtTile(DFCoord coord) { + return BlockAt(df::coord(coord.x>>4,coord.y>>4,coord.z)); } + df::tiletype baseTiletypeAt (DFCoord tilecoord) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - return b->BaseTileTypeAt(tilecoord % 16); - } - return tiletype::Void; + Block * b= BlockAtTile(tilecoord); + return b ? b->BaseTileTypeAt(tilecoord) : tiletype::Void; } df::tiletype tiletypeAt (DFCoord tilecoord) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - return b->TileTypeAt(tilecoord % 16); - } - return tiletype::Void; + Block * b= BlockAtTile(tilecoord); + return b ? b->TileTypeAt(tilecoord) : tiletype::Void; } bool setTiletypeAt(DFCoord tilecoord, df::tiletype tiletype) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - b->setTiletypeAt(tilecoord % 16, tiletype); - return true; - } + if (Block * b= BlockAtTile(tilecoord)) + return b->setTiletypeAt(tilecoord, tiletype); return false; } uint16_t temperature1At (DFCoord tilecoord) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - return b->temperature1At(tilecoord % 16); - } - return 0; + Block * b= BlockAtTile(tilecoord); + return b ? b->temperature1At(tilecoord) : 0; } bool setTemp1At(DFCoord tilecoord, uint16_t temperature) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - b->setTemp1At(tilecoord % 16, temperature); - return true; - } + if (Block * b= BlockAtTile(tilecoord)) + return b->setTemp1At(tilecoord, temperature); return false; } uint16_t temperature2At (DFCoord tilecoord) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - return b->temperature2At(tilecoord % 16); - } - return 0; + Block * b= BlockAtTile(tilecoord); + return b ? b->temperature2At(tilecoord) : 0; } bool setTemp2At(DFCoord tilecoord, uint16_t temperature) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - b->setTemp2At(tilecoord % 16, temperature); - return true; - } + if (Block * b= BlockAtTile(tilecoord)) + return b->setTemp2At(tilecoord, temperature); return false; } int16_t veinMaterialAt (DFCoord tilecoord) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - return b->veinMaterialAt(tilecoord % 16); - } - return 0; + Block * b= BlockAtTile(tilecoord); + return b ? b->veinMaterialAt(tilecoord) : -1; } int16_t baseMaterialAt (DFCoord tilecoord) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - return b->baseMaterialAt(tilecoord % 16); - } - return 0; + Block * b= BlockAtTile(tilecoord); + return b ? b->baseMaterialAt(tilecoord) : -1; } - bool clearVeinMaterialAt (DFCoord tilecoord) + + int16_t tagAt(DFCoord tilecoord) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - b->ClearVeinMaterialAt(tilecoord % 16); - } - return 0; + Block * b= BlockAtTile(tilecoord); + return b ? b->tag(tilecoord) : 0; } - bool clearBaseMaterialAt (DFCoord tilecoord) + void setTagAt(DFCoord tilecoord, int16_t val) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - b->ClearBaseMaterialAt(tilecoord % 16); - } - return 0; + Block * b= BlockAtTile(tilecoord); + if (b) b->tag(tilecoord) = val; } - + df::tile_designation designationAt (DFCoord tilecoord) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - return b->DesignationAt(tilecoord % 16); - } - df::tile_designation temp; - temp.whole = 0; - return temp; + Block * b= BlockAtTile(tilecoord); + return b ? b->DesignationAt(tilecoord) : df::tile_designation(0); } bool setDesignationAt (DFCoord tilecoord, df::tile_designation des) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - b->setDesignationAt(tilecoord % 16, des); - return true; - } + if(Block * b= BlockAtTile(tilecoord)) + return b->setDesignationAt(tilecoord, des); return false; } - + df::tile_occupancy occupancyAt (DFCoord tilecoord) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - return b->OccupancyAt(tilecoord % 16); - } - df::tile_occupancy temp; - temp.whole = 0; - return temp; + Block * b= BlockAtTile(tilecoord); + return b ? b->OccupancyAt(tilecoord) : df::tile_occupancy(0); } bool setOccupancyAt (DFCoord tilecoord, df::tile_occupancy occ) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - b->setOccupancyAt(tilecoord % 16, occ); - return true; - } + if (Block * b= BlockAtTile(tilecoord)) + return b->setOccupancyAt(tilecoord, occ); return false; } - + bool testCoord (DFCoord tilecoord) { - Block * b= BlockAt(tilecoord / 16); - if(b && b->valid) - { - return true; - } - return false; + Block * b= BlockAtTile(tilecoord); + return (b && b->valid); } + + bool addItemOnGround(df::item *item) { + Block * b= BlockAtTile(item->pos); + return b ? b->addItemOnGround(item) : false; + } + bool removeItemOnGround(df::item *item) { + Block * b= BlockAtTile(item->pos); + return b ? b->removeItemOnGround(item) : false; + } + bool WriteAll() { std::map::iterator p; @@ -508,15 +369,25 @@ class MapCache } blocks.clear(); } - private: - volatile bool valid; - volatile bool validgeo; + + uint32_t maxBlockX() { return x_bmax; } + uint32_t maxBlockY() { return y_bmax; } + uint32_t maxTileX() { return x_tmax; } + uint32_t maxTileY() { return y_tmax; } + uint32_t maxZ() { return z_max; } + +private: + friend class Block; + + bool valid; + bool validgeo; uint32_t x_bmax; uint32_t y_bmax; uint32_t x_tmax; uint32_t y_tmax; uint32_t z_max; - std::vector< std::vector > layerassign; + std::vector geoidx; + std::vector< std::vector > layer_mats; std::map blocks; }; } diff --git a/library/include/modules/Maps.h b/library/include/modules/Maps.h index 873da7a9e..0de262264 100644 --- a/library/include/modules/Maps.h +++ b/library/include/modules/Maps.h @@ -38,7 +38,7 @@ distribution. #include "modules/Materials.h" #include "df/world.h" -#include "df/feature_init.h" +#include "df/world_data.h" #include "df/map_block.h" #include "df/block_square_event.h" #include "df/block_square_event_mineralst.h" @@ -49,12 +49,20 @@ distribution. #include "df/tile_liquid.h" #include "df/tile_dig_designation.h" #include "df/tile_traffic.h" +#include "df/feature_init.h" /** * \defgroup grp_maps Maps module and its types * @ingroup grp_modules */ +namespace df +{ + struct burrow; + struct world_data; + struct block_burrow; +} + namespace DFHack { /*************************************************************************** @@ -103,31 +111,11 @@ enum BiomeOffset eBiomeCount }; -/** - * map block flags - * \ingroup grp_maps - */ -struct naked_blockflags -{ - /// designated for jobs (digging and stuff like that) - unsigned int designated : 1; - /// possibly related to the designated flag - unsigned int unk_1 : 1; - /// two flags required for liquid flow. - unsigned int liquid_1 : 1; - unsigned int liquid_2 : 1; - /// rest of the flags is completely unknown - unsigned int unk_2: 4; -}; /** * map block flags wrapper * \ingroup grp_maps */ -union t_blockflags -{ - uint32_t whole; - naked_blockflags bits; -}; +typedef df::block_flags t_blockflags; /** * 16x16 array of tile types @@ -161,30 +149,6 @@ typedef uint8_t biome_indices40d [9]; * \ingroup grp_maps */ typedef uint16_t t_temperatures [16][16]; -/** - * structure for holding whole blocks - * \ingroup grp_maps - */ -typedef struct -{ - DFCoord position; - /// type of the tiles - tiletypes40d tiletypes; - /// flags determining the state of the tiles - designations40d designation; - /// flags determining what's on the tiles - occupancies40d occupancy; - /// values used for geology/biome assignment - biome_indices40d biome_indices; - /// the address where the block came from - df::map_block * origin; - t_blockflags blockflags; - /// index into the global feature vector - int32_t global_feature; - /// index into the local feature vector... complicated - int32_t local_feature; - int32_t mystery; -} mapblock40d; /** * The Maps module @@ -231,30 +195,33 @@ void DfMap::applyGeoMatgloss(Block * b) * @endcode */ -extern DFHACK_EXPORT bool ReadGeology( std::vector < std::vector >& assign ); - +extern DFHACK_EXPORT bool ReadGeology(std::vector > *layer_mats, + std::vector *geoidx); /** - * Get the feature indexes of a block + * Get pointers to features of a block */ -extern DFHACK_EXPORT bool ReadFeatures(uint32_t x, uint32_t y, uint32_t z, int32_t & local, int32_t & global); +extern DFHACK_EXPORT bool ReadFeatures(uint32_t x, uint32_t y, uint32_t z, t_feature * local, t_feature * global); /** - * Set the feature indexes of a block + * Get pointers to features of an already read block */ -extern DFHACK_EXPORT bool WriteFeatures(uint32_t x, uint32_t y, uint32_t z, const int32_t & local, const int32_t & global); +extern DFHACK_EXPORT bool ReadFeatures(df::map_block * block,t_feature * local, t_feature * global); + + /** - * Get pointers to features of a block + * Get a pointer to a specific global feature directly. */ -extern DFHACK_EXPORT bool ReadFeatures(uint32_t x, uint32_t y, uint32_t z, t_feature * local, t_feature * global); +DFHACK_EXPORT df::feature_init *getGlobalInitFeature(int32_t index); /** - * Get pointers to features of an already read block + * Get a pointer to a specific local feature directly. rgn_coord is in the world region grid. */ -extern DFHACK_EXPORT bool ReadFeatures(mapblock40d * block,t_feature * local, t_feature * global); +DFHACK_EXPORT df::feature_init *getLocalInitFeature(df::coord2d rgn_coord, int32_t index); /** * Read a specific global or local feature directly */ extern DFHACK_EXPORT bool GetGlobalFeature(t_feature &feature, int32_t index); -extern DFHACK_EXPORT bool GetLocalFeature(t_feature &feature, df::coord2d coord, int32_t index); +//extern DFHACK_EXPORT bool GetLocalFeature(t_feature &feature, df::coord2d rgn_coord, int32_t index); + /* * BLOCK DATA @@ -269,48 +236,16 @@ extern DFHACK_EXPORT void getPosition(int32_t& x, int32_t& y, int32_t& z); * Get the map block or NULL if block is not valid */ extern DFHACK_EXPORT df::map_block * getBlock (int32_t blockx, int32_t blocky, int32_t blockz); -extern DFHACK_EXPORT df::map_block * getBlockAbs (int32_t x, int32_t y, int32_t z); +extern DFHACK_EXPORT df::map_block * getTileBlock (int32_t x, int32_t y, int32_t z); inline df::map_block * getBlock (df::coord pos) { return getBlock(pos.x, pos.y, pos.z); } -inline df::map_block * getBlockAbs (df::coord pos) { return getBlockAbs(pos.x, pos.y, pos.z); } - -/// copy the whole map block at block coords (see DFTypes.h for the block structure) -extern DFHACK_EXPORT bool ReadBlock40d(uint32_t blockx, uint32_t blocky, uint32_t blockz, mapblock40d * buffer); - -/// copy/write block tile types -extern DFHACK_EXPORT bool ReadTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, tiletypes40d *buffer); -extern DFHACK_EXPORT bool WriteTileTypes(uint32_t blockx, uint32_t blocky, uint32_t blockz, tiletypes40d *buffer); - -/// copy/write block designations -extern DFHACK_EXPORT bool ReadDesignations(uint32_t blockx, uint32_t blocky, uint32_t blockz, designations40d *buffer); -extern DFHACK_EXPORT bool WriteDesignations (uint32_t blockx, uint32_t blocky, uint32_t blockz, designations40d *buffer); - -/// copy/write temperatures -extern DFHACK_EXPORT bool ReadTemperatures(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_temperatures *temp1, t_temperatures *temp2); -extern DFHACK_EXPORT bool WriteTemperatures (uint32_t blockx, uint32_t blocky, uint32_t blockz, t_temperatures *temp1, t_temperatures *temp2); - -/// copy/write block occupancies -extern DFHACK_EXPORT bool ReadOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, occupancies40d *buffer); -extern DFHACK_EXPORT bool WriteOccupancy(uint32_t blockx, uint32_t blocky, uint32_t blockz, occupancies40d *buffer); - -/// copy/write the block dirty bit - this is used to mark a map block so that DF scans it for designated jobs like digging -extern DFHACK_EXPORT bool ReadDirtyBit(uint32_t blockx, uint32_t blocky, uint32_t blockz, bool &dirtybit); -extern DFHACK_EXPORT bool WriteDirtyBit(uint32_t blockx, uint32_t blocky, uint32_t blockz, bool dirtybit); - -/// copy/write the block flags -extern DFHACK_EXPORT bool ReadBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_blockflags &blockflags); -extern DFHACK_EXPORT bool WriteBlockFlags(uint32_t blockx, uint32_t blocky, uint32_t blockz, t_blockflags blockflags); +inline df::map_block * getTileBlock (df::coord pos) { return getTileBlock(pos.x, pos.y, pos.z); } -/// copy/write features -extern DFHACK_EXPORT bool SetBlockLocalFeature(uint32_t blockx, uint32_t blocky, uint32_t blockz, int32_t local = -1); -extern DFHACK_EXPORT bool SetBlockGlobalFeature(uint32_t blockx, uint32_t blocky, uint32_t blockz, int32_t global = -1); - -/// copy region offsets of a block - used for determining layer stone matgloss -extern DFHACK_EXPORT bool ReadRegionOffsets(uint32_t blockx, uint32_t blocky, uint32_t blockz, biome_indices40d *buffer); +DFHACK_EXPORT df::world_data::T_region_map *getRegionBiome(df::coord2d rgn_pos); /// sorts the block event vector into multiple vectors by type /// mineral veins, what's under ice, blood smears and mud -extern DFHACK_EXPORT bool SortBlockEvents(uint32_t x, uint32_t y, uint32_t z, +extern DFHACK_EXPORT bool SortBlockEvents(df::map_block *block, std::vector* veins, std::vector* ices = 0, std::vector* splatter = 0, @@ -321,8 +256,25 @@ extern DFHACK_EXPORT bool SortBlockEvents(uint32_t x, uint32_t y, uint32_t z, /// 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 ); -/// read all plants in this block -extern DFHACK_EXPORT bool ReadVegetation(uint32_t x, uint32_t y, uint32_t z, std::vector*& plants); +/* + * BURROWS + */ + +DFHACK_EXPORT df::burrow *findBurrowByName(std::string name); + +void listBurrowBlocks(std::vector *pvec, df::burrow *burrow); + +df::block_burrow *getBlockBurrowMask(df::burrow *burrow, df::map_block *block, bool create = false); + +bool isBlockBurrowTile(df::burrow *burrow, df::map_block *block, df::coord2d tile); +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); +} } } diff --git a/library/include/modules/Units.h b/library/include/modules/Units.h index 838d1d596..12e687112 100644 --- a/library/include/modules/Units.h +++ b/library/include/modules/Units.h @@ -36,6 +36,7 @@ distribution. namespace df { struct nemesis_record; + struct burrow; } /** @@ -184,9 +185,6 @@ DFHACK_EXPORT bool ReadJob(const df::unit * unit, std::vector & mat) DFHACK_EXPORT bool ReadInventoryByIdx(const uint32_t index, std::vector & item); DFHACK_EXPORT bool ReadInventoryByPtr(const df::unit * unit, std::vector & item); -DFHACK_EXPORT bool ReadOwnedItemsByIdx(const uint32_t index, std::vector & item); -DFHACK_EXPORT bool ReadOwnedItemsByPtr(const df::unit * unit, std::vector & item); - DFHACK_EXPORT int32_t FindIndexById(int32_t id); /* Getters */ @@ -195,9 +193,6 @@ DFHACK_EXPORT int32_t GetDwarfCivId ( void ); DFHACK_EXPORT void CopyNameTo(df::unit *creature, df::language_name * target); -DFHACK_EXPORT bool RemoveOwnedItemByIdx(const uint32_t index, int32_t id); -DFHACK_EXPORT bool RemoveOwnedItemByPtr(df::unit * unit, int32_t id); - DFHACK_EXPORT void setNickname(df::unit *unit, std::string nick); DFHACK_EXPORT df::language_name *getVisibleName(df::unit *unit); @@ -206,6 +201,10 @@ DFHACK_EXPORT df::nemesis_record *getNemesis(df::unit *unit); DFHACK_EXPORT bool isDead(df::unit *unit); DFHACK_EXPORT bool isAlive(df::unit *unit); DFHACK_EXPORT bool isSane(df::unit *unit); + +DFHACK_EXPORT bool isInBurrow(df::unit *unit, df::burrow *burrow); +DFHACK_EXPORT void setInBurrow(df::unit *unit, df::burrow *burrow, bool enable); + } } #endif diff --git a/library/lua/dfhack.lua b/library/lua/dfhack.lua index b37183cb6..a6606d152 100644 --- a/library/lua/dfhack.lua +++ b/library/lua/dfhack.lua @@ -80,6 +80,12 @@ function printall(table) end end +function copyall(table) + local rv = {} + for k,v in pairs(table) do rv[k] = v end + return rv +end + function dfhack.persistent:__tostring() return "" @@ -89,5 +95,15 @@ function dfhack.matinfo:__tostring() return "" end +function dfhack.maps.getSize() + local map = df.global.world.map + return map.x_count_block, map.y_count_block, map.z_count_block +end + +function dfhack.maps.getTileSize() + local map = df.global.world.map + return map.x_count, map.y_count, map.z_count +end + -- Feed the table back to the require() mechanism. return dfhack diff --git a/library/modules/Items.cpp b/library/modules/Items.cpp index 19618fc10..d884a734e 100644 --- a/library/modules/Items.cpp +++ b/library/modules/Items.cpp @@ -41,6 +41,7 @@ using namespace std; #include "modules/Units.h" #include "ModuleFactory.h" #include "Core.h" +#include "Error.h" #include "MiscUtils.h" #include "df/world.h" @@ -63,6 +64,7 @@ using namespace std; #include "df/trapcomp_flags.h" #include "df/job_item.h" #include "df/general_ref.h" +#include "df/general_ref_unit_itemownerst.h" using namespace DFHack; using namespace df::enums; @@ -415,28 +417,62 @@ bool Items::copyItem(df::item * itembase, DFHack::dfh_item &item) return true; } -int32_t Items::getItemOwnerID(const df::item * item) +df::unit *Items::getOwner(df::item * item) { + CHECK_NULL_POINTER(item); + for (size_t i = 0; i < item->itemrefs.size(); i++) { df::general_ref *ref = item->itemrefs[i]; - if (ref->getType() == general_ref_type::UNIT_ITEMOWNER) - return ref->getID(); + if (strict_virtual_cast(ref)) + return ref->getUnit(); } - return -1; + + return NULL; } -df::unit *Items::getItemOwner(const df::item * item) +bool Items::setOwner(df::item *item, df::unit *unit) { - for (size_t i = 0; i < item->itemrefs.size(); i++) + CHECK_NULL_POINTER(item); + + for (int i = item->itemrefs.size()-1; i >= 0; i--) { df::general_ref *ref = item->itemrefs[i]; - if (ref->getType() == general_ref_type::UNIT_ITEMOWNER) - return ref->getUnit(); + + if (!strict_virtual_cast(ref)) + continue; + + if (auto cur = ref->getUnit()) + { + if (cur == unit) + return true; + + erase_from_vector(cur->owned_items, item->id); + } + + delete ref; + vector_erase_at(item->itemrefs, i); } - return NULL; + + if (unit) + { + auto ref = df::allocate(); + if (!ref) + return false; + + item->flags.bits.owned = true; + ref->unit_id = unit->id; + + insert_into_vector(unit->owned_items, item->id); + item->itemrefs.push_back(ref); + } + else + item->flags.bits.owned = false; + + return true; } + int32_t Items::getItemContainerID(const df::item * item) { for (size_t i = 0; i < item->itemrefs.size(); i++) @@ -477,27 +513,3 @@ bool Items::readItemRefs(const df::item * item, df::general_ref_type type, std:: return !values.empty(); } - -bool Items::removeItemOwner(df::item * item) -{ - for (size_t i = 0; i < item->itemrefs.size(); i++) - { - df::general_ref *ref = item->itemrefs[i]; - if (ref->getType() != general_ref_type::UNIT_ITEMOWNER) - continue; - - df::unit *unit = ref->getUnit(); - - if (unit == NULL || !Units::RemoveOwnedItemByPtr(unit, item->id)) - { - cerr << "RemoveOwnedItemIdx: CREATURE " << ref->getID() << " ID " << item->id << " FAILED!" << endl; - return false; - } - delete ref; - item->itemrefs.erase(item->itemrefs.begin() + i--); - } - - item->flags.bits.owned = 0; - - return true; -} diff --git a/library/modules/Maps.cpp b/library/modules/Maps.cpp index db66086e0..c0aa9b634 100644 --- a/library/modules/Maps.cpp +++ b/library/modules/Maps.cpp @@ -33,11 +33,13 @@ distribution. using namespace std; #include "modules/Maps.h" +#include "modules/MapCache.h" #include "Error.h" #include "VersionInfo.h" #include "MemAccess.h" #include "ModuleFactory.h" #include "Core.h" +#include "MiscUtils.h" #include "DataDefs.h" #include "df/world_data.h" @@ -45,6 +47,10 @@ using namespace std; #include "df/world_geo_biome.h" #include "df/world_geo_layer.h" #include "df/feature_init.h" +#include "df/world_data.h" +#include "df/burrow.h" +#include "df/block_burrow.h" +#include "df/block_burrow_link.h" using namespace DFHack; using namespace df::enums; @@ -125,7 +131,7 @@ df::map_block *Maps::getBlock (int32_t blockx, int32_t blocky, int32_t blockz) return world->map.block_index[blockx][blocky][blockz]; } -df::map_block *Maps::getBlockAbs (int32_t x, int32_t y, int32_t z) +df::map_block *Maps::getTileBlock (int32_t x, int32_t y, int32_t z) { if (!IsValid()) return NULL; @@ -136,207 +142,40 @@ df::map_block *Maps::getBlockAbs (int32_t x, int32_t y, int32_t z) return world->map.block_index[x >> 4][y >> 4][z]; } -bool Maps::ReadBlock40d(uint32_t x, uint32_t y, uint32_t z, mapblock40d * buffer) -{ - df::map_block * block = getBlock(x,y,z); - if (block) - { - buffer->position = DFCoord(x,y,z); - memcpy(buffer->tiletypes,block->tiletype, sizeof(tiletypes40d)); - memcpy(buffer->designation,block->designation, sizeof(designations40d)); - memcpy(buffer->occupancy,block->occupancy, sizeof(occupancies40d)); - memcpy(buffer->biome_indices,block->region_offset, sizeof(block->region_offset)); - buffer->global_feature = block->global_feature; - buffer->local_feature = block->local_feature; - buffer->mystery = block->unk2; - buffer->origin = block; - buffer->blockflags.whole = block->flags.whole; - return true; - } - return false; -} - -/* - * Tiletypes - */ - -bool Maps::ReadTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - memcpy(buffer, block->tiletype, sizeof(tiletypes40d)); - return true; - } - return false; -} - -bool Maps::WriteTileTypes (uint32_t x, uint32_t y, uint32_t z, tiletypes40d *buffer) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - memcpy(block->tiletype, buffer, sizeof(tiletypes40d)); - return true; - } - return false; -} - -/* - * Dirty bit - */ -bool Maps::ReadDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool &dirtybit) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - dirtybit = block->flags.bits.designated; - return true; - } - return false; -} - -bool Maps::WriteDirtyBit(uint32_t x, uint32_t y, uint32_t z, bool dirtybit) +df::world_data::T_region_map *Maps::getRegionBiome(df::coord2d rgn_pos) { - df::map_block *block = getBlock(x,y,z); - if (block) - { - block->flags.bits.designated = true; - return true; - } - return false; -} -/* - * Block flags - */ -// FIXME: maybe truncates, still bullshit -bool Maps::ReadBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags &blockflags) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - blockflags.whole = block->flags.whole; - return true; - } - return false; -} -//FIXME: maybe truncated, still bullshit -bool Maps::WriteBlockFlags(uint32_t x, uint32_t y, uint32_t z, t_blockflags blockflags) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - block->flags.whole = blockflags.whole; - return true; - } - return false; -} - -/* - * Designations - */ -bool Maps::ReadDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - memcpy(buffer, block->designation, sizeof(designations40d)); - return true; - } - return false; -} + auto data = world->world_data; + if (!data) + return NULL; -bool Maps::WriteDesignations (uint32_t x, uint32_t y, uint32_t z, designations40d *buffer) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - memcpy(block->designation, buffer, sizeof(designations40d)); - return true; - } - return false; -} + if (rgn_pos.x < 0 || rgn_pos.x >= data->world_width || + rgn_pos.y < 0 || rgn_pos.y >= data->world_height) + return NULL; -/* - * Occupancies - */ -bool Maps::ReadOccupancy (uint32_t x, uint32_t y, uint32_t z, occupancies40d *buffer) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - memcpy(buffer, block->occupancy, sizeof(occupancies40d)); - return true; - } - return false; + return &data->region_map[rgn_pos.x][rgn_pos.y]; } -bool Maps::WriteOccupancy (uint32_t x, uint32_t y, uint32_t z, occupancies40d *buffer) +df::feature_init *Maps::getGlobalInitFeature(int32_t index) { - df::map_block *block = getBlock(x,y,z); - if (block) - { - memcpy(block->occupancy, buffer, sizeof(occupancies40d)); - return true; - } - return false; -} + auto data = world->world_data; + if (!data) + return NULL; -/* - * Temperatures - */ -bool Maps::ReadTemperatures(uint32_t x, uint32_t y, uint32_t z, t_temperatures *temp1, t_temperatures *temp2) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - if(temp1) - memcpy(temp1, block->temperature_1, sizeof(t_temperatures)); - if(temp2) - memcpy(temp2, block->temperature_2, sizeof(t_temperatures)); - return true; - } - return false; -} -bool Maps::WriteTemperatures (uint32_t x, uint32_t y, uint32_t z, t_temperatures *temp1, t_temperatures *temp2) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - if(temp1) - memcpy(block->temperature_1, temp1, sizeof(t_temperatures)); - if(temp2) - memcpy(block->temperature_2, temp2, sizeof(t_temperatures)); - return true; - } - return false; -} + auto rgn = vector_get(data->underground_regions, index); + if (!rgn) + return NULL; -/* - * Region Offsets - used for layer geology - */ -bool Maps::ReadRegionOffsets (uint32_t x, uint32_t y, uint32_t z, biome_indices40d *buffer) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - memcpy(buffer, block->region_offset,sizeof(biome_indices40d)); - return true; - } - return false; + return rgn->feature_init; } bool Maps::GetGlobalFeature(t_feature &feature, int32_t index) { feature.type = (df::feature_type)-1; - if (!world->world_data) - return false; - if ((index < 0) || (index >= world->world_data->underground_regions.size())) + auto f = Maps::getGlobalInitFeature(index); + if (!f) return false; - df::feature_init *f = world->world_data->underground_regions[index]->feature_init; - feature.discovered = false; feature.origin = f; feature.type = f->getType(); @@ -344,35 +183,38 @@ bool Maps::GetGlobalFeature(t_feature &feature, int32_t index) return true; } -bool Maps::GetLocalFeature(t_feature &feature, df::coord2d coord, int32_t index) +df::feature_init *Maps::getLocalInitFeature(df::coord2d rgn_pos, int32_t index) { - feature.type = (df::feature_type)-1; - if (!world->world_data) - return false; - - // regionX and regionY are in embark squares! - // we convert to full region tiles - // this also works in adventure mode - // region X coord - whole regions - uint32_t region_x = ( (coord.x / 3) + world->map.region_x ) / 16; - // region Y coord - whole regions - uint32_t region_y = ( (coord.y / 3) + world->map.region_y ) / 16; + auto data = world->world_data; + if (!data) + return NULL; - uint32_t bigregion_x = region_x / 16; - uint32_t bigregion_y = region_y / 16; + if (rgn_pos.x < 0 || rgn_pos.x >= data->world_width || + rgn_pos.y < 0 || rgn_pos.y >= data->world_height) + return NULL; - uint32_t sub_x = region_x % 16; - uint32_t sub_y = region_y % 16; // megaregions = 16x16 squares of regions = 256x256 squares of embark squares + df::coord2d bigregion = rgn_pos / 16; // bigregion is 16x16 regions. for each bigregion in X dimension: - if (!world->world_data->unk_204[bigregion_x][bigregion_y].features) - return false; + auto fptr = data->unk_204[bigregion.x][bigregion.y].features; + if (!fptr) + return NULL; + + df::coord2d sub = rgn_pos & 15; + + vector &features = fptr->feature_init[sub.x][sub.y]; + + return vector_get(features, index); +} + +static bool GetLocalFeature(t_feature &feature, df::coord2d rgn_pos, int32_t index) +{ + feature.type = (df::feature_type)-1; - vector &features = world->world_data->unk_204[bigregion_x][bigregion_y].features->feature_init[sub_x][sub_y]; - if ((index < 0) || (index >= features.size())) + auto f = Maps::getLocalInitFeature(rgn_pos, index); + if (!f) return false; - df::feature_init *f = features[index]; feature.discovered = false; feature.origin = f; @@ -381,58 +223,15 @@ bool Maps::GetLocalFeature(t_feature &feature, df::coord2d coord, int32_t index) return true; } -bool Maps::ReadFeatures(uint32_t x, uint32_t y, uint32_t z, int32_t & local, int32_t & global) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - local = block->local_feature; - global = block->global_feature; - return true; - } - return false; -} - -bool Maps::WriteFeatures(uint32_t x, uint32_t y, uint32_t z, const int32_t & local, const int32_t & global) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - block->local_feature = local; - block->global_feature = global; - return true; - } - return false; -} - bool Maps::ReadFeatures(uint32_t x, uint32_t y, uint32_t z, t_feature *local, t_feature *global) { - int32_t loc, glob; - if (!ReadFeatures(x, y, z, loc, glob)) + df::map_block *block = getBlock(x,y,z); + if (!block) return false; - - bool result = true; - if (global) - { - if (glob != -1) - result &= GetGlobalFeature(*global, glob); - else - global->type = (df::feature_type)-1; - } - if (local) - { - if (loc != -1) - { - df::coord2d coord(x,y); - result &= GetLocalFeature(*local, coord, loc); - } - else - local->type = (df::feature_type)-1; - } - return result; + return ReadFeatures(block, local, global); } -bool Maps::ReadFeatures(mapblock40d * block, t_feature * local, t_feature * global) +bool Maps::ReadFeatures(df::map_block * block, t_feature * local, t_feature * global) { bool result = true; if (global) @@ -445,39 +244,17 @@ bool Maps::ReadFeatures(mapblock40d * block, t_feature * local, t_feature * glob if (local) { if (block->local_feature != -1) - result &= GetLocalFeature(*local, block->position, block->local_feature); + result &= GetLocalFeature(*local, block->region_pos, block->local_feature); else local->type = (df::feature_type)-1; } return result; } -bool Maps::SetBlockLocalFeature(uint32_t x, uint32_t y, uint32_t z, int32_t local) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - block->local_feature = local; - return true; - } - return false; -} - -bool Maps::SetBlockGlobalFeature(uint32_t x, uint32_t y, uint32_t z, int32_t global) -{ - df::map_block *block = getBlock(x,y,z); - if (block) - { - block->global_feature = global; - return true; - } - return false; -} - /* * Block events */ -bool Maps::SortBlockEvents(uint32_t x, uint32_t y, uint32_t z, +bool Maps::SortBlockEvents(df::map_block *block, vector * veins, vector * ices, vector *splatter, @@ -495,7 +272,6 @@ bool Maps::SortBlockEvents(uint32_t x, uint32_t y, uint32_t z, if (constructions) constructions->clear(); - df::map_block * block = getBlock(x,y,z); if (!block) return false; @@ -535,27 +311,38 @@ bool Maps::RemoveBlockEvent(uint32_t x, uint32_t y, uint32_t z, df::block_square df::map_block * block = getBlock(x,y,z); if (!block) return false; - for (size_t i = 0; i < block->block_events.size(); i++) + + int idx = linear_index(block->block_events, which); + if (idx >= 0) { - if (block->block_events[i] == which) - { - delete which; - block->block_events.erase(block->block_events.begin() + i); - return true; - } + delete which; + vector_erase_at(block->block_events, idx); + return true; } - return false; + else + return false; } /* * Layer geology */ -bool Maps::ReadGeology (vector < vector >& assign) +bool Maps::ReadGeology(vector > *layer_mats, vector *geoidx) { if (!world->world_data) return false; - vector v_geology[eBiomeCount]; + layer_mats->resize(eBiomeCount); + geoidx->resize(eBiomeCount); + + for (int i = 0; i < eBiomeCount; i++) + { + (*layer_mats)[i].clear(); + (*geoidx)[i] = df::coord2d(-30000,-30000); + } + + int world_width = world->world_data->world_width; + int world_height = world->world_data->world_height; + // iterate over 8 surrounding regions + local region for (int i = eNorthWest; i < eBiomeCount; i++) { @@ -564,14 +351,18 @@ bool Maps::ReadGeology (vector < vector >& assign) // regionX/16 is in 16x16 embark square regions // i provides -1 .. +1 offset from the current region int bioRX = world->map.region_x / 16 + ((i % 3) - 1); - if (bioRX < 0) bioRX = 0; - if (bioRX >= world->world_data->world_width) bioRX = world->world_data->world_width - 1; int bioRY = world->map.region_y / 16 + ((i / 3) - 1); - if (bioRY < 0) bioRY = 0; - if (bioRY >= world->world_data->world_height) bioRY = world->world_data->world_height - 1; + + df::coord2d rgn_pos(clip_range(bioRX,0,world_width-1),clip_range(bioRX,0,world_height-1)); + + (*geoidx)[i] = rgn_pos; + + auto biome = getRegionBiome(rgn_pos); + if (!biome) + continue; // get index into geoblock vector - uint16_t geoindex = world->world_data->region_map[bioRX][bioRY].geo_index; + int16_t geoindex = biome->geo_index; /// geology blocks have a vector of layer descriptors // get the vector with pointer to layers @@ -579,29 +370,412 @@ bool Maps::ReadGeology (vector < vector >& assign) if (!geo_biome) continue; - vector &geolayers = geo_biome->layers; + auto &geolayers = geo_biome->layers; + auto &matvec = (*layer_mats)[i]; /// layer descriptor has a field that determines the type of stone/soil - v_geology[i].reserve(geolayers.size()); + matvec.resize(geolayers.size()); // finally, read the layer matgloss for (size_t j = 0; j < geolayers.size(); j++) - v_geology[i].push_back(geolayers[j]->mat_index); + matvec[j] = geolayers[j]->mat_index; } - assign.clear(); - assign.reserve(eBiomeCount); - for (int i = 0; i < eBiomeCount; i++) - assign.push_back(v_geology[i]); return true; } -bool Maps::ReadVegetation(uint32_t x, uint32_t y, uint32_t z, std::vector*& plants) +#define COPY(a,b) memcpy(&a,&b,sizeof(a)) + +MapExtras::Block::Block(MapCache *parent, DFCoord _bcoord) : parent(parent) +{ + dirty_designations = false; + dirty_tiletypes = false; + dirty_temperatures = false; + dirty_blockflags = false; + dirty_occupancies = false; + valid = false; + bcoord = _bcoord; + block = Maps::getBlock(bcoord); + item_counts = NULL; + + memset(tags,0,sizeof(tags)); + + if(block) + { + COPY(rawtiles, block->tiletype); + COPY(designation, block->designation); + COPY(occupancy, block->occupancy); + blockflags = block->flags; + + 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; +} + +bool MapExtras::Block::Write () +{ + if(!valid) return false; + + if(dirty_blockflags) + { + block->flags = blockflags; + dirty_blockflags = false; + } + if(dirty_designations) + { + COPY(block->designation, designation); + block->flags.bits.designated = true; + dirty_designations = false; + } + if(dirty_tiletypes) + { + COPY(block->tiletype, rawtiles); + dirty_tiletypes = false; + } + if(dirty_temperatures) + { + COPY(block->temperature_1, temp1); + COPY(block->temperature_2, temp2); + dirty_temperatures = false; + } + if(dirty_occupancies) + { + COPY(block->occupancy, occupancy); + dirty_occupancies = false; + } + return true; +} + +void MapExtras::Block::SquashVeins(df::map_block *mb, t_blockmaterials & materials) +{ + 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++) + { + df::tiletype tt = mb->tiletype[x][y]; + if (tileMaterial(tt) == tiletype_material::MINERAL) + { + for (size_t i = 0; i < veins.size(); i++) + { + if (veins[i]->getassignment(x,y)) + materials[x][y] = veins[i]->inorganic_mat; + } + } + } +} + +void MapExtras::Block::SquashFrozenLiquids(df::map_block *mb, tiletypes40d & frozen) +{ + std::vector ices; + Maps::SortBlockEvents(mb,NULL,&ices); + 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 < ices.size(); i++) + { + df::tiletype tt2 = ices[i]->tiles[x][y]; + if (tt2 != tiletype::Void) + { + frozen[x][y] = tt2; + break; + } + } + } + } +} + +void MapExtras::Block::SquashConstructions (df::map_block *mb, tiletypes40d & constructions) +{ + 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) + { + 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; + } + } +} + +void MapExtras::Block::SquashRocks (df::map_block *mb, t_blockmaterials & materials, + std::vector< std::vector > * layerassign) +{ + // get the layer materials + for (uint32_t x = 0; x < 16; x++) for (uint32_t y = 0; y < 16; y++) + { + materials[x][y] = -1; + uint8_t test = mb->designation[x][y].bits.biome; + if (test >= 9) + continue; + uint8_t idx = mb->region_offset[test]; + if (idx < layerassign->size()) + materials[x][y] = layerassign->at(idx)[mb->designation[x][y].bits.geolayer_index]; + } +} + +df::coord2d MapExtras::Block::biomeRegionAt(df::coord2d p) +{ + if (!block) + return df::coord2d(-30000,-30000); + + auto des = index_tile(designation,p); + uint8_t idx = des.bits.biome; + if (idx >= 9) + return block->region_pos; + idx = block->region_offset[idx]; + if (idx >= parent->geoidx.size()) + return block->region_pos; + return parent->geoidx[idx]; +} + +int16_t MapExtras::Block::GeoIndexAt(df::coord2d p) +{ + df::coord2d biome = biomeRegionAt(p); + if (!biome.isValid()) + return -1; + + auto pinfo = Maps::getRegionBiome(biome); + if (!pinfo) + return -1; + + return pinfo->geo_index; +} + +bool MapExtras::Block::GetGlobalFeature(t_feature *out) +{ + out->type = (df::feature_type)-1; + if (!valid || block->global_feature < 0) + return false; + return Maps::GetGlobalFeature(*out, block->global_feature); +} + +bool MapExtras::Block::GetLocalFeature(t_feature *out) +{ + out->type = (df::feature_type)-1; + if (!valid || block->local_feature < 0) + return false; + return ::GetLocalFeature(*out, block->region_pos, block->local_feature); +} + +void MapExtras::Block::init_item_counts() +{ + if (item_counts) return; + + item_counts = new T_item_counts[16]; + memset(item_counts, 0, sizeof(T_item_counts)); + + if (!block) return; + + for (size_t i = 0; i < block->items.size(); i++) + { + auto it = df::item::find(block->items[i]); + if (!it || !it->flags.bits.on_ground) + continue; + + df::coord tidx = it->pos - block->map_pos; + if (!is_valid_tile_coord(tidx) || tidx.z != 0) + continue; + + item_counts[tidx.x][tidx.y]++; + } +} + +bool MapExtras::Block::addItemOnGround(df::item *item) +{ + if (!block) + return false; + + init_item_counts(); + + bool inserted; + insert_into_vector(block->items, item->id, &inserted); + + if (inserted) + { + int &count = index_tile(item_counts,item->pos); + + if (count++ == 0) + { + index_tile(occupancy,item->pos).bits.item = true; + index_tile(block->occupancy,item->pos).bits.item = true; + } + } + + return inserted; +} + +bool MapExtras::Block::removeItemOnGround(df::item *item) { - df::map_block *block = getBlock(x,y,z); if (!block) return false; - plants = &block->plants; + init_item_counts(); + + int idx = binsearch_index(block->items, item->id); + if (idx < 0) + return false; + + vector_erase_at(block->items, idx); + + int &count = index_tile(item_counts,item->pos); + + if (--count == 0) + { + index_tile(occupancy,item->pos).bits.item = false; + index_tile(block->occupancy,item->pos).bits.item = false; + } + return true; } + +MapExtras::Block *MapExtras::MapCache::BlockAt(DFCoord blockcoord) +{ + if(!valid) + return 0; + std::map ::iterator iter = blocks.find(blockcoord); + if(iter != blocks.end()) + { + return (*iter).second; + } + else + { + if(blockcoord.x >= 0 && blockcoord.x < x_bmax && + blockcoord.y >= 0 && blockcoord.y < y_bmax && + blockcoord.z >= 0 && blockcoord.z < z_max) + { + Block * nblo = new Block(this, blockcoord); + blocks[blockcoord] = nblo; + return nblo; + } + return 0; + } +} + +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); + } +} + +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; + memset(link->item->tile_bitmask,0,sizeof(link->item->tile_bitmask)); + 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::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); + + return true; +} + diff --git a/library/modules/Units.cpp b/library/modules/Units.cpp index e210a9028..3e58e0d5c 100644 --- a/library/modules/Units.cpp +++ b/library/modules/Units.cpp @@ -44,6 +44,7 @@ using namespace std; #include "modules/Translation.h" #include "ModuleFactory.h" #include "Core.h" +#include "MiscUtils.h" #include "df/world.h" #include "df/ui.h" @@ -54,6 +55,7 @@ using namespace std; #include "df/historical_figure.h" #include "df/historical_figure_info.h" #include "df/assumed_identity.h" +#include "df/burrow.h" using namespace DFHack; using namespace df::enums; @@ -493,37 +495,6 @@ bool Units::ReadInventoryByPtr(const df::unit * unit, std::vector & return true; } -bool Units::ReadOwnedItemsByIdx(const uint32_t index, std::vector & item) -{ - if(index >= world->units.all.size()) return false; - df::unit * temp = world->units.all[index]; - return ReadOwnedItemsByPtr(temp, item); -} - -bool Units::ReadOwnedItemsByPtr(const df::unit * unit, std::vector & items) -{ - if(!isValid()) return false; - if(!unit) return false; - items = unit->owned_items; - return true; -} - -bool Units::RemoveOwnedItemByIdx(const uint32_t index, int32_t id) -{ - if(index >= world->units.all.size()) return false; - df::unit * temp = world->units.all[index]; - return RemoveOwnedItemByPtr(temp, id); -} - -bool Units::RemoveOwnedItemByPtr(df::unit * unit, int32_t id) -{ - if(!isValid()) return false; - if(!unit) return false; - vector & vec = unit->owned_items; - vec.erase(std::remove(vec.begin(), vec.end(), id), vec.end()); - return true; -} - void Units::CopyNameTo(df::unit * creature, df::language_name * target) { Translation::copyName(&creature->name, target); @@ -652,3 +623,40 @@ bool DFHack::Units::isSane(df::unit *unit) return true; } + +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; + } +} + diff --git a/library/xml b/library/xml index baeee2ce1..27fec9797 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit baeee2ce115e0b3432e5b66b843e8883e5f03b34 +Subproject commit 27fec9797d7d1215bd3f5530b44a55a9d394fe75 diff --git a/plugins/advtools.cpp b/plugins/advtools.cpp index ffb428fd8..69841849a 100644 --- a/plugins/advtools.cpp +++ b/plugins/advtools.cpp @@ -780,7 +780,7 @@ command_result adv_tools (color_ostream &out, std::vector & parame if (!num) continue; - df::map_block *block = Maps::getBlockAbs(item->pos); + df::map_block *block = Maps::getTileBlock(item->pos); if (!block) continue; diff --git a/plugins/autodump.cpp b/plugins/autodump.cpp index 9d42694a3..a71555b7a 100644 --- a/plugins/autodump.cpp +++ b/plugins/autodump.cpp @@ -147,26 +147,13 @@ static command_result autodump_main(color_ostream &out, vector & parame } } } - coordmap counts; + // proceed with the dumpification operation for(size_t i=0; i< numItems; i++) { df::item * itm = world->items.all[i]; DFCoord pos_item(itm->pos.x, itm->pos.y, itm->pos.z); - // keep track how many items are at places. all items. - coordmap::iterator it = counts.find(pos_item); - if(it == counts.end()) - { - pair< coordmap::iterator, bool > inserted = counts.insert(make_pair(pos_item,1)); - it = inserted.first; - } - else - { - it->second ++; - } - // iterator is valid here, we use it later to decrement the pile counter if the item is moved - // only dump the stuff marked for dumping and laying on the ground if ( !itm->flags.bits.dump || !itm->flags.bits.on_ground @@ -194,38 +181,16 @@ static command_result autodump_main(color_ostream &out, vector & parame itm->flags.bits.forbid = true; // Don't move items if they're already at the cursor - if (pos_cursor == pos_item) - continue; - - // Do we need to fix block-local item ID vector? - if(pos_item/16 != pos_cursor/16) + if (pos_cursor != pos_item) { - // yes... - cerr << "Moving from block to block!" << endl; - df::map_block * bl_src = Maps::getBlockAbs(itm->pos.x, itm->pos.y, itm->pos.z); - df::map_block * bl_tgt = Maps::getBlockAbs(cx, cy, cz); - if(bl_src) - { - remove(bl_src->items.begin(), bl_src->items.end(),itm->id); - } - else - { - cerr << "No source block" << endl; - } - if(bl_tgt) - { - bl_tgt->items.push_back(itm->id); - } - else - { - cerr << "No target block" << endl; - } - } + if (!MC.removeItemOnGround(itm)) + out.printerr("Item %d wasn't in the source block.\n", itm->id); - // Move the item - itm->pos.x = pos_cursor.x; - itm->pos.y = pos_cursor.y; - itm->pos.z = pos_cursor.z; + itm->pos = pos_cursor; + + if (!MC.addItemOnGround(itm)) + out.printerr("Could not add item %d to destination block.\n", itm->id); + } } else // destroy { @@ -238,42 +203,14 @@ static command_result autodump_main(color_ostream &out, vector & parame itm->flags.bits.forbid = true; itm->flags.bits.hidden = true; } - // keeping track of item pile sizes ;) - it->second --; + dumped_total++; } - if(!destroy) // TODO: do we have to do any of this when destroying items? - { - // for each item pile, see if it reached zero. if so, unset item flag on the tile it's on - coordmap::iterator it = counts.begin(); - coordmap::iterator end = counts.end(); - while(it != end) - { - if(it->second == 0) - { - df::tile_occupancy occ = MC.occupancyAt(it->first); - occ.bits.item = false; - MC.setOccupancyAt(it->first, occ); - } - it++; - } - // Set "item here" flag on target tile, if we moved any items to the target tile. - if (dumped_total > 0) - { - // assume there is a possibility the cursor points at some weird location with missing block data - Block * b = MC.BlockAt(pos_cursor / 16); - if(b) - { - df::tile_occupancy occ = MC.occupancyAt(pos_cursor); - occ.bits.item = 1; - MC.setOccupancyAt(pos_cursor,occ); - } - } - // write map changes back to DF. + + // write map changes back to DF. + if(!destroy) MC.WriteAll(); - // Is this necessary? Is "forbid" a dirtyable attribute like "dig" is? - Maps::WriteDirtyBit(cx/16, cy/16, cz, true); - } + out.print("Done. %d items %s.\n", dumped_total, destroy ? "marked for destruction" : "quickdumped"); return CR_OK; } diff --git a/plugins/changelayer.cpp b/plugins/changelayer.cpp index d56360d83..317a0fa36 100644 --- a/plugins/changelayer.cpp +++ b/plugins/changelayer.cpp @@ -189,13 +189,13 @@ command_result changelayer (color_ostream &out, std::vector & para uint32_t tileY = cursorY % 16; MapExtras::Block * b = mc.BlockAt(cursor/16); - if(!b && !b->valid) + if(!b || !b->is_valid()) { out.printerr("No data.\n"); return CR_OK; } - mapblock40d & block = b->raw; - df::tile_designation &des = block.designation[tileX][tileY]; + + df::tile_designation des = b->DesignationAt(cursor%16); // get biome and geolayer at cursor position uint32_t biome = des.bits.biome; diff --git a/plugins/changevein.cpp b/plugins/changevein.cpp index 133d7ef4a..1d08cfeaf 100644 --- a/plugins/changevein.cpp +++ b/plugins/changevein.cpp @@ -50,7 +50,7 @@ command_result df_changevein (color_ostream &out, vector & parameters) return CR_FAILURE; } - df::map_block *block = Maps::getBlockAbs(cursor->x, cursor->y, cursor->z); + df::map_block *block = Maps::getTileBlock(cursor->x, cursor->y, cursor->z); if (!block) { out.printerr("Invalid tile selected.\n"); diff --git a/plugins/cleaners.cpp b/plugins/cleaners.cpp index ea5edc991..30befab2f 100644 --- a/plugins/cleaners.cpp +++ b/plugins/cleaners.cpp @@ -127,7 +127,7 @@ command_result spotclean (color_ostream &out, vector & parameters) out.printerr("Map is not available.\n"); return CR_FAILURE; } - df::map_block *block = Maps::getBlockAbs(cursor->x, cursor->y, cursor->z); + df::map_block *block = Maps::getTileBlock(cursor->x, cursor->y, cursor->z); if (block == NULL) { out.printerr("Invalid map block selected!\n"); diff --git a/plugins/cleanowned.cpp b/plugins/cleanowned.cpp index 280f2e1c5..c1521b8de 100644 --- a/plugins/cleanowned.cpp +++ b/plugins/cleanowned.cpp @@ -98,8 +98,7 @@ command_result df_cleanowned (color_ostream &out, vector & parameters) if (!item->flags.bits.owned) { - int32_t owner = Items::getItemOwnerID(item); - if (owner >= 0) + if (Items::getOwner(item)) { out.print("Fixing a misflagged item: \t"); confiscate = true; @@ -168,14 +167,14 @@ command_result df_cleanowned (color_ostream &out, vector & parameters) item->getWear() ); - df::unit *owner = Items::getItemOwner(item); + df::unit *owner = Items::getOwner(item); if (owner) out.print(", owner %s", Translation::TranslateName(&owner->name,false).c_str()); if (!dry_run) { - if (!Items::removeItemOwner(item)) + if (!Items::setOwner(item,NULL)) out.print("(unsuccessfully) "); if (dump) item->flags.bits.dump = 1; diff --git a/plugins/deramp.cpp b/plugins/deramp.cpp index c872f33dd..e5d0331d9 100644 --- a/plugins/deramp.cpp +++ b/plugins/deramp.cpp @@ -38,7 +38,7 @@ command_result df_deramp (color_ostream &out, vector & parameters) for (int i = 0; i < blocks_total; i++) { df::map_block *block = world->map.map_blocks[i]; - df::map_block *above = Maps::getBlockAbs(block->map_pos.x, block->map_pos.y, block->map_pos.z + 1); + df::map_block *above = Maps::getTileBlock(block->map_pos + df::coord(0,0,1)); for (int x = 0; x < 16; x++) { diff --git a/plugins/dig.cpp b/plugins/dig.cpp index 91d963fc3..64161a3aa 100644 --- a/plugins/dig.cpp +++ b/plugins/dig.cpp @@ -90,7 +90,7 @@ bool dig (MapExtras::MapCache & MCache, { DFCoord at (x,y,z); auto b = MCache.BlockAt(at/16); - if(!b || !b->valid) + if(!b || !b->is_valid()) return false; if(x == 0 || x == x_max * 16 - 1) { @@ -1027,6 +1027,8 @@ command_result digv (color_ostream &out, vector & parameters) { DFHack::DFCoord current = flood.top(); flood.pop(); + if (MCache->tagAt(current)) + continue; int16_t vmat2 = MCache->veinMaterialAt(current); tt = MCache->tiletypeAt(current); if(!DFHack::isWallTerrain(tt)) @@ -1061,7 +1063,8 @@ command_result digv (color_ostream &out, vector & parameters) } if(MCache->testCoord(current)) { - MCache->clearVeinMaterialAt(current); + MCache->setTagAt(current, 1); + if(current.x < tx_max - 2) { flood.push(DFHack::DFCoord(current.x + 1, current.y, current.z)); @@ -1209,6 +1212,8 @@ command_result digl (color_ostream &out, vector & parameters) { DFHack::DFCoord current = flood.top(); flood.pop(); + if (MCache->tagAt(current)) + continue; int16_t vmat2 = MCache->veinMaterialAt(current); int16_t bmat2 = MCache->baseMaterialAt(current); tt = MCache->tiletypeAt(current); @@ -1239,7 +1244,7 @@ command_result digl (color_ostream &out, vector & parameters) if(MCache->testCoord(current)) { - MCache->clearBaseMaterialAt(current); + MCache->setTagAt(current, 1); if(current.x < tx_max - 2) { flood.push(DFHack::DFCoord(current.x + 1, current.y, current.z)); diff --git a/plugins/fixveins.cpp b/plugins/fixveins.cpp index 474201a81..f02f61673 100644 --- a/plugins/fixveins.cpp +++ b/plugins/fixveins.cpp @@ -65,8 +65,7 @@ command_result df_fixveins (color_ostream &out, vector & parameters) has_mineral[k] |= mineral->tile_bitmask[k]; } t_feature local, global; - Maps::GetGlobalFeature(global, block->global_feature); - Maps::GetLocalFeature(local, df::coord2d(block->map_pos.x / 16, block->map_pos.y / 16), block->local_feature); + Maps::ReadFeatures(block, &local, &global); for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) diff --git a/plugins/liquids.cpp b/plugins/liquids.cpp index a7483a886..6be432a5b 100644 --- a/plugins/liquids.cpp +++ b/plugins/liquids.cpp @@ -413,8 +413,8 @@ command_result df_liquids_execute(color_ostream &out) Block * b = mcache.BlockAt((*iter)/16); DFHack::t_blockflags bf = b->BlockFlags(); - bf.bits.liquid_1 = true; - bf.bits.liquid_2 = true; + bf.bits.update_liquid = true; + bf.bits.update_liquid_twice = true; b->setBlockFlags(bf); iter++; @@ -500,20 +500,20 @@ command_result df_liquids_execute(color_ostream &out) DFHack::t_blockflags bflags = (*biter)->BlockFlags(); if(flowmode == "f+") { - bflags.bits.liquid_1 = true; - bflags.bits.liquid_2 = true; + bflags.bits.update_liquid = true; + bflags.bits.update_liquid_twice = true; (*biter)->setBlockFlags(bflags); } else if(flowmode == "f-") { - bflags.bits.liquid_1 = false; - bflags.bits.liquid_2 = false; + bflags.bits.update_liquid = false; + bflags.bits.update_liquid_twice = false; (*biter)->setBlockFlags(bflags); } else { - out << "flow bit 1 = " << bflags.bits.liquid_1 << endl; - out << "flow bit 2 = " << bflags.bits.liquid_2 << endl; + out << "flow bit 1 = " << bflags.bits.update_liquid << endl; + out << "flow bit 2 = " << bflags.bits.update_liquid_twice << endl; } biter ++; } diff --git a/plugins/mapexport/mapexport.cpp b/plugins/mapexport/mapexport.cpp index d7d9daea9..e0a7e5e69 100644 --- a/plugins/mapexport/mapexport.cpp +++ b/plugins/mapexport/mapexport.cpp @@ -151,7 +151,7 @@ command_result mapexport (color_ostream &out, std::vector & parame // Get the map block df::coord2d blockCoord(b_x, b_y); MapExtras::Block *b = map.BlockAt(DFHack::DFCoord(b_x, b_y, z)); - if (!b || !b->valid) + if (!b || !b->is_valid()) { continue; } @@ -161,15 +161,9 @@ command_result mapexport (color_ostream &out, std::vector & parame protoblock.set_y(b_y); protoblock.set_z(z); - { // Find features - uint32_t index = b->raw.global_feature; - if (index != -1) - Maps::GetGlobalFeature(blockFeatureGlobal, index); - - index = b->raw.local_feature; - if (index != -1) - Maps::GetLocalFeature(blockFeatureLocal, blockCoord, index); - } + // Find features + b->GetGlobalFeature(&blockFeatureGlobal); + b->GetLocalFeature(&blockFeatureLocal); int global_z = df::global::world->map.region_z + z; @@ -247,9 +241,9 @@ command_result mapexport (color_ostream &out, std::vector & parame } } - PlantList *plants; - if (Maps::ReadVegetation(b_x, b_y, z, plants)) + if (b->getRaw()) { + PlantList *plants = &b->getRaw()->plants; for (PlantList::const_iterator it = plants->begin(); it != plants->end(); it++) { const df::plant & plant = *(*it); diff --git a/plugins/plants.cpp b/plugins/plants.cpp index 09220c653..5ab09868f 100644 --- a/plugins/plants.cpp +++ b/plugins/plants.cpp @@ -125,8 +125,9 @@ static command_result immolations (color_ostream &out, do_what what, bool shrubs int32_t x,y,z; if(Gui::getCursorCoords(x,y,z)) { - vector * alltrees; - if(Maps::ReadVegetation(x/16,y/16,z,alltrees)) + auto block = Maps::getTileBlock(x,y,z); + vector *alltrees = block ? &block->plants : NULL; + if(alltrees) { bool didit = false; for(size_t i = 0 ; i < alltrees->size(); i++) @@ -206,8 +207,9 @@ command_result df_grow (color_ostream &out, vector & parameters) int32_t x,y,z; if(Gui::getCursorCoords(x,y,z)) { - vector * alltrees; - if(Maps::ReadVegetation(x/16,y/16,z,alltrees)) + auto block = Maps::getTileBlock(x,y,z); + vector *alltrees = block ? &block->plants : NULL; + if(alltrees) { for(size_t i = 0 ; i < alltrees->size(); i++) { diff --git a/plugins/probe.cpp b/plugins/probe.cpp index d5f03b81f..37df180da 100644 --- a/plugins/probe.cpp +++ b/plugins/probe.cpp @@ -147,13 +147,14 @@ command_result df_probe (color_ostream &out, vector & parameters) uint32_t tileY = cursorY % 16; MapExtras::Block * b = mc.BlockAt(cursor/16); - if(!b && !b->valid) + if(!b || !b->is_valid()) { out.printerr("No data.\n"); return CR_OK; } - mapblock40d & block = b->raw; - out.print("block addr: 0x%x\n\n", block.origin); + + auto &block = *b->getRaw(); + out.print("block addr: 0x%x\n\n", &block); /* if (showBlock) { @@ -270,7 +271,7 @@ command_result df_probe (color_ostream &out, vector & parameters) t_feature local; t_feature global; - Maps::ReadFeatures(&(b->raw),&local,&global); + Maps::ReadFeatures(&block,&local,&global); PRINT_FLAG( des, feature_local ); if(local.type != -1) { @@ -293,7 +294,6 @@ command_result df_probe (color_ostream &out, vector & parameters) << endl; out << "global feature idx: " << block.global_feature << endl; - out << "mystery: " << block.mystery << endl; out << std::endl; return CR_OK; } diff --git a/plugins/prospector.cpp b/plugins/prospector.cpp index 5afbd2d0a..c90a66c5a 100644 --- a/plugins/prospector.cpp +++ b/plugins/prospector.cpp @@ -426,20 +426,14 @@ command_result prospector (color_ostream &con, vector & parameters) // Get the map block df::coord2d blockCoord(b_x, b_y); MapExtras::Block *b = map.BlockAt(DFHack::DFCoord(b_x, b_y, z)); - if (!b || !b->valid) + if (!b || !b->is_valid()) { continue; } - { // Find features - uint32_t index = b->raw.global_feature; - if (index != -1) - Maps::GetGlobalFeature(blockFeatureGlobal, index); - - index = b->raw.local_feature; - if (index != -1) - Maps::GetLocalFeature(blockFeatureLocal, blockCoord, index); - } + // Find features + b->GetGlobalFeature(&blockFeatureGlobal); + b->GetLocalFeature(&blockFeatureLocal); int global_z = world->map.region_z + z; @@ -550,8 +544,9 @@ command_result prospector (color_ostream &con, vector & parameters) // and we can check visibility more easily here if (showPlants) { - PlantList * plants; - if (Maps::ReadVegetation(b_x, b_y, z, plants)) + auto block = Maps::getBlock(b_x,b_y,z); + vector *plants = block ? &block->plants : NULL; + if(plants) { for (PlantList::const_iterator it = plants->begin(); it != plants->end(); it++) { diff --git a/plugins/reveal.cpp b/plugins/reveal.cpp index 39a2ed9cd..513eededb 100644 --- a/plugins/reveal.cpp +++ b/plugins/reveal.cpp @@ -290,7 +290,7 @@ command_result unreveal(color_ostream &out, vector & params) for(size_t i = 0; i < hidesaved.size();i++) { hideblock & hb = hidesaved[i]; - df::map_block * b = Maps::getBlockAbs(hb.c.x,hb.c.y,hb.c.z); + df::map_block * b = Maps::getTileBlock(hb.c.x,hb.c.y,hb.c.z); for (uint32_t x = 0; x < 16;x++) for (uint32_t y = 0; y < 16;y++) { b->designation[x][y].bits.hidden = hb.hiddens[x][y]; diff --git a/plugins/tubefill.cpp b/plugins/tubefill.cpp index 0dd045343..0d20136de 100644 --- a/plugins/tubefill.cpp +++ b/plugins/tubefill.cpp @@ -59,12 +59,9 @@ command_result tubefill(color_ostream &out, std::vector & params) for (size_t i = 0; i < world->map.map_blocks.size(); i++) { df::map_block *block = world->map.map_blocks[i]; - df::map_block *above = Maps::getBlockAbs(block->map_pos.x, block->map_pos.y, block->map_pos.z + 1); - if (block->local_feature == -1) - continue; + df::map_block *above = Maps::getTileBlock(block->map_pos + df::coord(0,0,1)); DFHack::t_feature feature; - DFCoord coord(block->map_pos.x >> 4, block->map_pos.y >> 4, block->map_pos.z); - if (!Maps::GetLocalFeature(feature, coord, block->local_feature)) + if (!Maps::ReadFeatures(block, &feature, NULL)) continue; if (feature.type != feature_type::deep_special_tube) continue;