From 3db8c9e13aaf22ea1949fe22c483425fdf655fa2 Mon Sep 17 00:00:00 2001 From: fgenesis Date: Fri, 16 May 2014 00:11:52 +0200 Subject: [PATCH] Pathfinding & map grid improvements. There were still only 6 of 8 bits of the map grid in use. The last 2 bits are now available as non-colliding user bits, and are ignored unless specially treated. The findPath() function can now be told which bits to respect, which allows to prevent pathfinding to pass through fish tunnels, for example. A function for fast user bit map dilation is added as well. --- Aquaria/Avatar.cpp | 8 +- Aquaria/Entity.cpp | 11 +-- Aquaria/Game.cpp | 159 ++++++++++++++++++++++-------------- Aquaria/Game.h | 56 ++++++++----- Aquaria/GridRender.cpp | 30 +------ Aquaria/PathFinding.cpp | 16 ++-- Aquaria/PathFinding.h | 2 +- Aquaria/ScriptInterface.cpp | 27 +++++- 8 files changed, 185 insertions(+), 124 deletions(-) diff --git a/Aquaria/Avatar.cpp b/Aquaria/Avatar.cpp index ea5856e..43d334c 100644 --- a/Aquaria/Avatar.cpp +++ b/Aquaria/Avatar.cpp @@ -3561,7 +3561,7 @@ void Avatar::lockToWall() while(0); } - if (dsq->game->getGrid(t)==OT_HURT && isDamageTarget(DT_WALLHURT)) + if (dsq->game->isObstructed(t, OT_HURT) && isDamageTarget(DT_WALLHURT)) { good = false; } @@ -3612,16 +3612,16 @@ void Avatar::lockToWall() Vector offdiff = t.worldVector() - position; if (!offdiff.isZero()) { - if (tileType != OT_INVISIBLEIN) + if (tileType & OT_INVISIBLEIN) { Vector adjust = offdiff; - adjust.setLength2D(TILE_SIZE*2); + adjust.setLength2D(TILE_SIZE/2); offdiff -= adjust; } else { Vector adjust = offdiff; - adjust.setLength2D(TILE_SIZE/2); + adjust.setLength2D(TILE_SIZE*2); offdiff -= adjust; } } diff --git a/Aquaria/Entity.cpp b/Aquaria/Entity.cpp index d89a13d..b34b0af 100644 --- a/Aquaria/Entity.cpp +++ b/Aquaria/Entity.cpp @@ -1509,13 +1509,13 @@ bool Entity::isSittingOnInvisibleIn() { for (int y = 0; y < 4; y++) { - if (dsq->game->getGrid(TileVector(t.x+x, t.y+y))==OT_INVISIBLEIN) + if (dsq->game->isObstructed(TileVector(t.x+x, t.y+y), OT_INVISIBLEIN)) return true; - if (dsq->game->getGrid(TileVector(t.x-x, t.y+y))==OT_INVISIBLEIN) + if (dsq->game->isObstructed(TileVector(t.x-x, t.y+y), OT_INVISIBLEIN)) return true; - if (dsq->game->getGrid(TileVector(t.x+x, t.y-y))==OT_INVISIBLEIN) + if (dsq->game->isObstructed(TileVector(t.x+x, t.y-y), OT_INVISIBLEIN)) return true; - if (dsq->game->getGrid(TileVector(t.x-x, t.y-y))==OT_INVISIBLEIN) + if (dsq->game->isObstructed(TileVector(t.x-x, t.y-y), OT_INVISIBLEIN)) return true; } } @@ -3055,6 +3055,7 @@ bool Entity::doCollisionAvoidance(float dt, int search, float mod, Vector *vp, i int minDist=-1; TileVector t(position); TileVector useTile; + const int blockObs = ~ignoreObs; float totalDist = sqrtf(float(sqr((search*2)*TILE_SIZE)+sqr((search*2)*TILE_SIZE))); for (int x = -search; x <= search; x++) @@ -3069,7 +3070,7 @@ bool Entity::doCollisionAvoidance(float dt, int search, float mod, Vector *vp, i } if (waterBlocked || dsq->game->isObstructed(checkT)) { - if (dsq->game->getGrid(checkT) != ignoreObs) + if (dsq->game->isObstructed(checkT, blockObs)) { Vector vtc(t.x+x, t.y+y); Vector vt(t.x, t.y); diff --git a/Aquaria/Game.cpp b/Aquaria/Game.cpp index ddd07e3..8d246b9 100644 --- a/Aquaria/Game.cpp +++ b/Aquaria/Game.cpp @@ -2075,8 +2075,8 @@ void Game::fillGridFromQuad(Quad *q, ObsType obsType, bool trim) //dsq->game->setGrid(TileVector(tpos.x+(w2*TILE_SIZE)+(x/TILE_SIZE), tpos.y+(h2*TILE_SIZE)+(y/TILE_SIZE)), obsType); TileVector tvec(tpos.x+w2+x, tpos.y+h2+y); - if (dsq->game->getGrid(tvec) == OT_EMPTY) - dsq->game->setGrid(tvec, obsType); + if (!dsq->game->isObstructed(tvec)) + dsq->game->addGrid(tvec, obsType); } glPopMatrix(); @@ -2103,7 +2103,7 @@ void Game::clearDynamicGrid(unsigned char maskbyte /* = OT_MASK_BLACK */) // otherwise there is a chance to write a few bytes over the end of the buffer -- FG compile_assert(sizeof(grid) % sizeof(uint32) == 0); - signed char *gridstart = &grid[0][0]; + unsigned char *gridstart = &grid[0][0]; uint32 *gridend = (uint32*)(gridstart + sizeof(grid)); uint32 *gridptr = (uint32*)gridstart; // mask out specific bytes @@ -2165,9 +2165,9 @@ void Game::trimGrid() // from beeing drawn. (The maps were designed with this mind...) for (int x = 0; x < MAX_GRID; x++) { - const signed char *curCol = dsq->game->getGridColumn(x); - const signed char *leftCol = dsq->game->getGridColumn(x-1); - const signed char *rightCol = dsq->game->getGridColumn(x+1); + const unsigned char *curCol = grid[x]; // safe + const unsigned char *leftCol = dsq->game->getGridColumn(x-1); // unsafe + const unsigned char *rightCol = dsq->game->getGridColumn(x+1); // unsafe for (int y = 0; y < MAX_GRID; y++) { if (curCol[y] & OT_MASK_BLACK) @@ -2179,6 +2179,66 @@ void Game::trimGrid() } } +void Game::dilateGrid(unsigned int radius, ObsType test, ObsType set, ObsType allowOverwrite) +{ + if(!radius) + return; + const int lim = MAX_GRID - radius; + const unsigned int denyOverwrite = ~allowOverwrite; + // Box dilation is separable, so we do a two-pass by axis + int dilate = 0; + + // dilate rows + for (int y = 0; y < MAX_GRID; ++y) + { + for (int x = radius; x < lim; ++x) + { + if (grid[x][y] & test) + { + dilate = 2 * radius; + goto doDilate1; + } + if(dilate) + { + --dilate; + doDilate1: + if((grid[x - radius][y] & denyOverwrite) == OT_EMPTY) + grid[x - radius][y] |= set; + } + } + assert(lim + dilate < MAX_GRID); + for(int x = 0; x < dilate; ++x) + if(!(grid[x][y - radius] & test)) + grid[x][y - radius] |= set; + } + + // dilate colums + dilate = 0; + for (int x = 0; x < MAX_GRID; ++x) + { + unsigned char * const curCol = grid[x]; + for (int y = radius; y < lim; ++y) + { + if (curCol[y] & test) + { + dilate = 2 * radius; + goto doDilate2; + } + if(dilate) + { + --dilate; + doDilate2: + if((curCol[y - radius] & denyOverwrite) == OT_EMPTY) + curCol[y - radius] |= set; + } + } + assert(lim + dilate < MAX_GRID); + for(int y = 0; y < dilate; ++y) + if(!(curCol[y - radius] & test)) + curCol[y - radius] |= set; + } +} + float Game::getCoverage(Vector pos, int sampleArea) { TileVector t(pos); @@ -6451,30 +6511,46 @@ void Game::applyState() addRenderObject(songLineRender, LR_HUD); gridRender = new GridRender(OT_INVISIBLE); + gridRender->color = Vector(1, 0, 0); addRenderObject(gridRender, LR_DEBUG_TEXT); gridRender->alpha = 0; gridRender2 = new GridRender(OT_HURT); + gridRender2->color = Vector(1, 1, 0); addRenderObject(gridRender2, LR_DEBUG_TEXT); gridRender2->alpha = 0; gridRender3 = new GridRender(OT_INVISIBLEIN); + gridRender3->color = Vector(1, 0.5f, 0); addRenderObject(gridRender3, LR_DEBUG_TEXT); gridRender3->alpha = 0; edgeRender = new GridRender(OT_BLACKINVIS); + edgeRender->color = Vector(0.3f, 0, 0.6f); addRenderObject(edgeRender, LR_DEBUG_TEXT); edgeRender->alpha = 0; gridRenderEnt = new GridRender(OT_INVISIBLEENT); + gridRenderEnt->color = Vector(0, 1, 0.5); addRenderObject(gridRenderEnt, LR_DEBUG_TEXT); gridRenderEnt->alpha = 0; + gridRenderUser1 = new GridRender(OT_USER1); + addRenderObject(gridRenderUser1, LR_DEBUG_TEXT); + gridRenderUser1->color = Vector(1, 0, 1); + gridRenderUser1->alpha = 0; + + gridRenderUser2 = new GridRender(OT_USER2); + addRenderObject(gridRenderUser2, LR_DEBUG_TEXT); + gridRenderUser2->color = Vector(1, 1, 1); + gridRenderUser2->alpha = 0; + waterSurfaceRender = new WaterSurfaceRender(); //waterSurfaceRender->setRenderPass(-1); addRenderObject(waterSurfaceRender, LR_WATERSURFACE); GridRender *blackRender = new GridRender(OT_BLACK); + blackRender->color = Vector(0, 0, 0); //blackRender->alpha = 0; blackRender->blendEnabled = false; addRenderObject(blackRender, LR_ELEMENTS4); @@ -8515,22 +8591,17 @@ void Game::toggleMiniMapRender(int v) void Game::toggleGridRender() { float t = 0; + float a = 0; if (gridRender->alpha == 0) - { - gridRender->alpha.interpolateTo(0.5, t); - gridRender2->alpha.interpolateTo(0.5, t); - gridRender3->alpha.interpolateTo(0.5, t); - edgeRender->alpha.interpolateTo(0.5, t); - gridRenderEnt->alpha.interpolateTo(0.5, t); - } - else if (gridRender->alpha == 0.5) - { - gridRender->alpha.interpolateTo(0, t); - gridRender2->alpha.interpolateTo(0, t); - gridRender3->alpha.interpolateTo(0, t); - edgeRender->alpha.interpolateTo(0, t); - gridRenderEnt->alpha.interpolateTo(0, t); - } + a = 0.5f; + + gridRender->alpha.interpolateTo(a, t); + gridRender2->alpha.interpolateTo(a, t); + gridRender3->alpha.interpolateTo(a, t); + edgeRender->alpha.interpolateTo(a, t); + gridRenderEnt->alpha.interpolateTo(a, t); + gridRenderUser1->alpha.interpolateTo(a, t); + gridRenderUser2->alpha.interpolateTo(a, t); } Vector Game::getCameraPositionFor(const Vector &pos) @@ -10624,7 +10695,7 @@ void Game::setGrid(ElementTemplate *et, Vector position, float rot360) } TileVector s(t.x+x, t.y+y); //Vector v = Vector(position.x+et->grid[i].x*TILE_SIZE, position.y+et->grid[i].y*TILE_SIZE); - setGrid(s, 1); + setGrid(s, OT_INVISIBLE); } } @@ -10752,6 +10823,12 @@ void Game::removeState() miniMapRender = 0; gridRender = 0; + gridRender2 = 0; + gridRender3 = 0; + edgeRender = 0; + gridRenderEnt = 0; + gridRenderUser1 = 0; + gridRenderUser2 = 0; worldMapRender = 0; //core->sound->stopStreamingOgg(); @@ -10922,44 +10999,6 @@ bool Game::collideCircleWithGrid(const Vector& position, float r) return false; } -bool Game::collideBoxWithGrid(const Vector& position, int hw, int hh) -{ - Vector tile = position; - TileVector t(tile); - tile.x = t.x; - tile.y = t.y; - - float hsz = TILE_SIZE/2; - int xrange=1,yrange=1; - xrange = (hw/TILE_SIZE)+1; - yrange = (hh/TILE_SIZE)+1; - for (int x = tile.x-xrange; x <= tile.x+xrange; x++) - { - for (int y = tile.y-yrange; y <= tile.y+yrange; y++) - { - int v = this->getGrid(TileVector(x, y)); - if (v == 1) - { - if (tile.x == x && tile.y == y) return true; - float rx = (x*TILE_SIZE)+TILE_SIZE/2; - float ry = (y*TILE_SIZE)+TILE_SIZE/2; - - - if (isBoxIn(position, Vector(hw, hh), Vector(rx, ry), Vector(hsz, hsz))) - { - return true; - } - if (isBoxIn(Vector(rx, ry), Vector(hsz, hsz), position, Vector(hw, hh))) - { - return true; - } - } - } - } - return false; -} - - void Game::learnedRecipe(Recipe *r, bool effects) { if (nocasecmp(dsq->getTopStateData()->name,"Game")==0 && !applyingState) diff --git a/Aquaria/Game.h b/Aquaria/Game.h index 5193014..caefa3c 100644 --- a/Aquaria/Game.h +++ b/Aquaria/Game.h @@ -587,6 +587,14 @@ enum ObsType // set by entities OT_INVISIBLEENT = 0x20, + + // mask for all bits that block + OT_BLOCKING = OT_MASK_BLACK | OT_INVISIBLE | OT_INVISIBLEIN | OT_HURT | OT_INVISIBLEENT, + + // free for use, not colliding by default + OT_USER1 = 0x40, + OT_USER2 = 0x80, + OT_USER_MASK = OT_USER1 | OT_USER2, }; struct EntitySaveData @@ -620,12 +628,14 @@ public: std::string getSelectedChoice() { return selectedChoice; } - int getGrid(const TileVector &tile) const; - int getGridRaw(unsigned int x, unsigned int y) const; - const signed char *getGridColumn(int tileX); - void setGrid(const TileVector &tile, int v); - bool isObstructed(const TileVector &tile, int t = -1) const; + ObsType getGrid(const TileVector &tile) const; + ObsType getGridRaw(const TileVector &tile) const; + unsigned char *getGridColumn(int tileX); + void setGrid(const TileVector &tile, ObsType v); + void addGrid(const TileVector &tile, ObsType v); + bool isObstructed(const TileVector &tile, int t = OT_BLOCKING) const; void trimGrid(); + void dilateGrid(unsigned int radius, ObsType test, ObsType set, ObsType allowOverwrite); void clearPointers(); @@ -655,7 +665,6 @@ public: void registerSporeDrop(const Vector &pos, int t); - bool collideBoxWithGrid(const Vector& position, int w, int h); bool collideCircleWithGrid(const Vector& position, float r); bool collideHairVsCircle(Entity *a, int num, const Vector &pos2, float radius, float perc=0, int *colSegment=0); @@ -959,7 +968,7 @@ public: void createGradient(); std::string saveMusic; - GridRender *gridRender, *gridRender2, *gridRender3, *edgeRender, *gridRenderEnt; + GridRender *gridRender, *gridRender2, *gridRender3, *edgeRender, *gridRenderEnt, *gridRenderUser1, *gridRenderUser2; void toggleGridRender(); ElementUpdateList elementUpdateList; ElementUpdateList elementInteractionList; @@ -1174,7 +1183,7 @@ protected: void toggleSceneEditor(); #endif - signed char grid[MAX_GRID][MAX_GRID]; + unsigned char grid[MAX_GRID][MAX_GRID]; Quad *bg, *bg2; @@ -1200,21 +1209,23 @@ extern Game *game; // INLINE FUNCTIONS inline -int Game::getGridRaw(unsigned int x, unsigned int y) const +ObsType Game::getGridRaw(const TileVector &tile) const { - return grid[x][y]; + return (unsigned(tile.x) < unsigned(MAX_GRID) && unsigned(tile.y) < unsigned(MAX_GRID)) + ? ObsType(grid[tile.x][tile.y]) + : OT_INVISIBLE; } inline -int Game::getGrid(const TileVector &tile) const +ObsType Game::getGrid(const TileVector &tile) const { - //if (tile.x < 0 || tile.x >= MAX_GRID || tile.y < 0 || tile.y >= MAX_GRID) return OT_INVISIBLE; - //return grid[tile.x][tile.y]; - return (unsigned(tile.x) < unsigned(MAX_GRID) && unsigned(tile.y) < unsigned(MAX_GRID)) ? grid[tile.x][tile.y] : OT_INVISIBLE; + return (unsigned(tile.x) < unsigned(MAX_GRID) && unsigned(tile.y) < unsigned(MAX_GRID)) + ? ObsType(grid[tile.x][tile.y] & OT_BLOCKING) + : OT_INVISIBLE; } inline -const signed char *Game::getGridColumn(int tileX) +unsigned char *Game::getGridColumn(int tileX) { if (tileX < 0) return grid[0]; @@ -1225,14 +1236,21 @@ const signed char *Game::getGridColumn(int tileX) } inline -void Game::setGrid(const TileVector &tile, int v) +void Game::setGrid(const TileVector &tile, ObsType v) { - if (tile.x < 0 || tile.x >= MAX_GRID || tile.y < 0 || tile.y >= MAX_GRID) return; - grid[tile.x][tile.y] = v; + if (unsigned(tile.x) < unsigned(MAX_GRID) && unsigned(tile.y) < unsigned(MAX_GRID)) + grid[tile.x][tile.y] = v; } inline -bool Game::isObstructed(const TileVector &tile, int t /* = -1 */) const +void Game::addGrid(const TileVector &tile, ObsType v) +{ + if (unsigned(tile.x) < unsigned(MAX_GRID) && unsigned(tile.y) < unsigned(MAX_GRID)) + grid[tile.x][tile.y] |= v; +} + +inline +bool Game::isObstructed(const TileVector &tile, int t /* = OT_BLOCKING */) const { return (getGrid(tile) & t); } diff --git a/Aquaria/GridRender.cpp b/Aquaria/GridRender.cpp index bbfd4a3..fa6c9cd 100644 --- a/Aquaria/GridRender.cpp +++ b/Aquaria/GridRender.cpp @@ -66,30 +66,6 @@ inline static void doRenderGrid(int x, int startCol, int endCol) void GridRender::onRender() { - switch(obsType) - { - case OT_INVISIBLE: - core->setColor(1, 0, 0, alpha.getValue()); - break; - case OT_INVISIBLEIN: - core->setColor(1, 0.5, 0, alpha.getValue()); - break; - case OT_INVISIBLEENT: - core->setColor(0, 1, 0.5, alpha.getValue()); - break; - case OT_BLACK: - core->setColor(0, 0, 0, 1); - break; - case OT_BLACKINVIS: - core->setColor(0.3, 0, 0.6, alpha.getValue()); - break; - case OT_HURT: - core->setColor(1, 1, 0, alpha.getValue()); - break; - default: - break; - } - const signed char obsType = this->obsType; Vector camPos = core->cameraPos; camPos.x -= core->getVirtualOffX() * (core->invGlobalScale); @@ -112,11 +88,11 @@ void GridRender::onRender() return; for (int x = startX; x <= endX; ++x) { - const signed char *gridColumn = dsq->game->getGridColumn(x); + const unsigned char *gridColumn = dsq->game->getGridColumn(x); int startCol = -1, y; // fast-forward to next drawable byte - if(const signed char *next = (const signed char*)memchr(gridColumn + startY, obsType, endY - startY + 1)) // find next byte with correct obs type + if(const unsigned char *next = (const unsigned char*)memchr(gridColumn + startY, obsType, endY - startY + 1)) // find next byte with correct obs type { y = next - gridColumn; // will get incremented right away, which is okay, because we alrady set startCol startCol = y; @@ -131,7 +107,7 @@ void GridRender::onRender() doRenderGrid(x, startCol, y - 1); // fast-forward to next drawable byte - if(const signed char *next = (const signed char*)memchr(gridColumn + y, obsType, endY - y)) // find next byte with correct obs type + if(const unsigned char *next = (const unsigned char*)memchr(gridColumn + y, obsType, endY - y)) // find next byte with correct obs type { y = next - gridColumn; // will get incremented right away, which is okay, because we alrady set startCol startCol = y; diff --git a/Aquaria/PathFinding.cpp b/Aquaria/PathFinding.cpp index f214f88..3a0f69e 100644 --- a/Aquaria/PathFinding.cpp +++ b/Aquaria/PathFinding.cpp @@ -24,16 +24,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "DSQ.h" #include "Game.h" -class SearchGrid +class SearchGridRaw { public: - SearchGrid() : game(dsq->game) {} + SearchGridRaw(ObsType blocking) : game(dsq->game), blockingObsBits(blocking) {} inline bool operator()(unsigned x, unsigned y) const { - return game->getGrid(TileVector(x, y)) == OT_EMPTY; + return (game->getGridRaw(TileVector(x, y)) & blockingObsBits) == OT_EMPTY; } private: + const ObsType blockingObsBits; const Game *game; }; @@ -157,7 +158,7 @@ void PathFinding::generatePath(RenderObject *ro, TileVector start, TileVector go VectorPath& vp = ro->position.data->path; vp.clear(); - SearchGrid grid; + SearchGridRaw grid(OT_BLOCKING); JPS::PathVector path; if(JPS::findPath(path, grid, start.x, start.y, goal.x, goal.y, 1)) { @@ -166,9 +167,12 @@ void PathFinding::generatePath(RenderObject *ro, TileVector start, TileVector go } } -bool PathFinding::generatePathSimple(VectorPath& path, const Vector& start, const Vector& end, unsigned int step /* = 0 */) +bool PathFinding::generatePathSimple(VectorPath& path, const Vector& start, const Vector& end, unsigned int step /* = 0 */, unsigned int obs /* = 0 */) { - SearchGrid grid; + if(obs == OT_EMPTY) + obs = OT_BLOCKING; + + SearchGridRaw grid((ObsType)obs); JPS::PathVector p; TileVector tstart(start); TileVector tend(end); diff --git a/Aquaria/PathFinding.h b/Aquaria/PathFinding.h index c0dc9c2..7920cbb 100644 --- a/Aquaria/PathFinding.h +++ b/Aquaria/PathFinding.h @@ -37,7 +37,7 @@ public: void molestPath(VectorPath &path); void generatePath(RenderObject *go, TileVector g1, TileVector g2, int offx=0, int offy=0); - bool generatePathSimple(VectorPath& path, const Vector& start, const Vector& end, unsigned int step = 0); + bool generatePathSimple(VectorPath& path, const Vector& start, const Vector& end, unsigned int step = 0, unsigned int obs = 0); }; #endif diff --git a/Aquaria/ScriptInterface.cpp b/Aquaria/ScriptInterface.cpp index efe7a40..07e49b8 100644 --- a/Aquaria/ScriptInterface.cpp +++ b/Aquaria/ScriptInterface.cpp @@ -2898,6 +2898,16 @@ luaFunc(reconstructEntityGrid) luaReturnNil(); } +luaFunc(dilateGrid) +{ + unsigned int radius = lua_tointeger(L, 1); + ObsType test = (ObsType)lua_tointeger(L, 2); + ObsType set = (ObsType)lua_tointeger(L, 3); + ObsType allowOverwrite = (ObsType)lua_tointeger(L, 4); + dsq->game->dilateGrid(radius, test, set, allowOverwrite); + luaReturnNil(); +} + luaFunc(entity_setCanLeaveWater) { Entity *e = entity(L); @@ -8347,6 +8357,11 @@ luaFunc(getObstruction) luaReturnInt(dsq->game->getGrid(TileVector(Vector(lua_tonumber(L, 1), lua_tonumber(L, 2))))); } +luaFunc(getGridRaw) +{ + luaReturnInt(dsq->game->getGridRaw(TileVector(Vector(lua_tonumber(L, 1), lua_tonumber(L, 2))))); +} + luaFunc(isObstructedBlock) { float x = lua_tonumber(L, 1); @@ -8568,13 +8583,14 @@ luaFunc(isShuttingDownGameState) luaReturnBool(dsq->game->isShuttingDownGameState()); } -// startx, starty, endx, endy [, step, xtab, ytab] +// startx, starty, endx, endy [, step, xtab, ytab, obsMask] luaFunc(findPath) { VectorPath path; Vector start(lua_tonumber(L, 1), lua_tonumber(L, 2)); Vector end(lua_tonumber(L, 3), lua_tonumber(L, 4)); - if(!dsq->pathFinding.generatePathSimple(path, start, end, lua_tointeger(L, 5))) + ObsType obs = ObsType(lua_tointeger(L, 8)); + if(!dsq->pathFinding.generatePathSimple(path, start, end, lua_tointeger(L, 5), obs)) luaReturnBool(false); const unsigned num = path.getNumPathNodes(); @@ -8964,6 +8980,7 @@ static const struct { luaRegister(reconstructGrid), luaRegister(reconstructEntityGrid), + luaRegister(dilateGrid), luaRegister(ing_hasIET), luaRegister(ing_getIngredientName), @@ -9463,6 +9480,7 @@ static const struct { luaRegister(isObstructed), luaRegister(isObstructedBlock), luaRegister(getObstruction), + luaRegister(getGridRaw), luaRegister(findPath), luaRegister(castLine), luaRegister(getUserInputString), @@ -10597,6 +10615,11 @@ static const struct { luaConstant(OT_INVISIBLEIN), luaConstant(OT_HURT), luaConstant(OT_INVISIBLEENT), + luaConstant(OT_USER1), + luaConstant(OT_USER2), + luaConstant(OT_MASK_BLACK), + luaConstant(OT_BLOCKING), + luaConstant(OT_USER_MASK), luaConstant(SEE_MAP_NEVER), luaConstant(SEE_MAP_DEFAULT),