-
Total de itens
1153 -
Registro em
-
Última visita
-
Dias Ganhos
3
Tudo que AlexandreKG postou
-
Bom,gente eu nao sei se fis algo,errado mas eu botei nas sources do meu esrver assim, //////////////////////////////////////////////////////////////////////// // OpenTibia - an opensource roleplaying game //////////////////////////////////////////////////////////////////////// // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. //////////////////////////////////////////////////////////////////////// #include "otpch.h" #include <iomanip> #include <boost/config.hpp> #include <boost/bind.hpp> #include "iomap.h" #include "map.h" #include "tile.h" #include "creature.h" #include "player.h" #include "combat.h" #include "iomapserialize.h" #include "items.h" #include "game.h" extern Game g_game; Map::Map() { mapWidth = 0; mapHeight = 0; } bool Map::loadMap(const std::string& identifier) { int64_t start = OTSYS_TIME(); IOMap* loader = new IOMap(); if(!loader->loadMap(this, identifier)) /*{ std::cout << "> FATAL: OTBM Loader - " << loader->getLastErrorString() << std::endl; return false; } std::cout << "> Map loading time: " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl; start = OTSYS_TIME(); if(!loader->loadSpawns(this)) std::cout << "> WARNING: Could not load spawn data." << std::endl; if(!loader->loadHouses(this)) std::cout << "> WARNING: Could not load house data." << std::endl; }*/ delete loader; std::cout << "> Data parsing time: " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl; start = OTSYS_TIME(); IOMapSerialize::getInstance()->updateHouses(); IOMapSerialize::getInstance()->updateAuctions(); std::cout << "> Houses synchronization time: " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl; start = OTSYS_TIME(); IOMapSerialize::getInstance()->loadHouses(); IOMapSerialize::getInstance()->loadMap(this); std::cout << "> Content unserialization time: " << (OTSYS_TIME() - start) / (1000.) << " seconds." << std::endl; return true; } bool Map::saveMap() { IOMapSerialize* IOLoader = IOMapSerialize::getInstance(); bool saved = false; for(uint32_t tries = 0; tries < 3; ++tries) { if(!IOLoader->saveHouses()) continue; saved = true; break; } if(!saved) return false; saved = false; for(uint32_t tries = 0; tries < 3; ++tries) { if(!IOLoader->saveMap(this)) continue; saved = true; break; } return saved; } Tile* Map::getTile(int32_t x, int32_t y, int32_t z) { if(x < 0 || x > 0xFFFF || y < 0 || y > 0xFFFF || z < 0 || z >= MAP_MAX_LAYERS) return NULL; QTreeLeafNode* leaf = QTreeNode::getLeafStatic(&root, x, y); if(!leaf) return NULL; Floor* floor = leaf->getFloor(z); if(!floor) return NULL; return floor->tiles[x & FLOOR_MASK][y & FLOOR_MASK]; } void Map::setTile(uint16_t x, uint16_t y, uint16_t z, Tile* newTile) { if(z >= MAP_MAX_LAYERS) { std::cout << "[Error - Map::setTile]: Attempt to set tile on invalid Z coordinate - " << z << "!" << std::endl; return; } QTreeLeafNode::newLeaf = false; QTreeLeafNode* leaf = root.createLeaf(x, y, 15); if(QTreeLeafNode::newLeaf) { //update north QTreeLeafNode* northLeaf = root.getLeaf(x, y - FLOOR_SIZE); if(northLeaf) northLeaf->m_leafS = leaf; //update west leaf QTreeLeafNode* westLeaf = root.getLeaf(x - FLOOR_SIZE, y); if(westLeaf) westLeaf->m_leafE = leaf; //update south QTreeLeafNode* southLeaf = root.getLeaf(x, y + FLOOR_SIZE); if(southLeaf) leaf->m_leafS = southLeaf; //update east QTreeLeafNode* eastLeaf = root.getLeaf(x + FLOOR_SIZE, y); if(eastLeaf) leaf->m_leafE = eastLeaf; } uint32_t offsetX = x & FLOOR_MASK, offsetY = y & FLOOR_MASK; Floor* floor = leaf->createFloor(z); if(!floor->tiles[offsetX][offsetY]) { floor->tiles[offsetX][offsetY] = newTile; newTile->qt_node = leaf; } else std::cout << "[Error - Map::setTile] Tile already exists - pos " << offsetX << "/" << offsetY << "/" << z << std::endl; if(newTile->hasFlag(TILESTATE_REFRESH)) { RefreshBlock_t rb; if(TileItemVector* tileItems = newTile->getItemList()) { for(ItemVector::iterator it = tileItems->getBeginDownItem(); it != tileItems->getEndDownItem(); ++it) rb.list.push_back((*it)->clone()); } rb.lastRefresh = OTSYS_TIME(); g_game.addRefreshTile(newTile, rb); } } bool Map::placeCreature(const Position& centerPos, Creature* creature, bool extendedPos /*= false*/, bool forced /*= false*/) { bool foundTile = false, placeInPz = false; Tile* tile = getTile(centerPos); if(tile) { placeInPz = tile->hasFlag(TILESTATE_PROTECTIONZONE); uint32_t flags = FLAG_IGNOREBLOCKITEM; if(creature->isAccountManager()) flags |= FLAG_IGNOREBLOCKCREATURE; ReturnValue ret = tile->__queryAdd(0, creature, 1, flags); if(forced || ret == RET_NOERROR || ret == RET_PLAYERISNOTINVITED) foundTile = true; } size_t shufflePos = 0; PairVector relList; if(extendedPos) { shufflePos = 8; relList.push_back(PositionPair(-2, 0)); relList.push_back(PositionPair(0, -2)); relList.push_back(PositionPair(0, 2)); relList.push_back(PositionPair(2, 0)); std::random_shuffle(relList.begin(), relList.end()); } relList.push_back(PositionPair(-1, -1)); relList.push_back(PositionPair(-1, 0)); relList.push_back(PositionPair(-1, 1)); relList.push_back(PositionPair(0, -1)); relList.push_back(PositionPair(0, 1)); relList.push_back(PositionPair(1, -1)); relList.push_back(PositionPair(1, 0)); relList.push_back(PositionPair(1, 1)); std::random_shuffle(relList.begin() + shufflePos, relList.end()); uint32_t radius = 1; Position tryPos; for(uint32_t n = 1; n <= radius && !foundTile; ++n) { for(PairVector::iterator it = relList.begin(); it != relList.end() && !foundTile; ++it) { int32_t dx = it->first * n, dy = it->second * n; tryPos = centerPos; tryPos.x = tryPos.x + dx; tryPos.y = tryPos.y + dy; if(!(tile = getTile(tryPos)) || (placeInPz && !tile->hasFlag(TILESTATE_PROTECTIONZONE))) continue; if(tile->__queryAdd(0, creature, 1, 0) == RET_NOERROR) { if(!extendedPos) { foundTile = true; break; } if(isSightClear(centerPos, tryPos, false)) { foundTile = true; break; } } } } if(!foundTile) return false; int32_t index = 0; uint32_t flags = 0; Item* toItem = NULL; if(Cylinder* toCylinder = tile->__queryDestination(index, creature, &toItem, flags)) { toCylinder->__internalAddThing(creature); if(Tile* toTile = toCylinder->getTile()) toTile->qt_node->addCreature(creature); } return true; } bool Map::removeCreature(Creature* creature) { Tile* tile = creature->getTile(); if(!tile) return false; tile->qt_node->removeCreature(creature); tile->__removeThing(creature, 0); return true; } void Map::getSpectatorsInternal(SpectatorVec& list, const Position& centerPos, bool checkForDuplicate, int32_t minRangeX, int32_t maxRangeX, int32_t minRangeY, int32_t maxRangeY, int32_t minRangeZ, int32_t maxRangeZ) { int32_t minoffset = centerPos.z - maxRangeZ, maxoffset = centerPos.z - minRangeZ, x1 = std::min((int32_t)0xFFFF, std::max((int32_t)0, (centerPos.x + minRangeX + minoffset))), y1 = std::min((int32_t)0xFFFF, std::max((int32_t)0, (centerPos.y + minRangeY + minoffset))), x2 = std::min((int32_t)0xFFFF, std::max((int32_t)0, (centerPos.x + maxRangeX + maxoffset))), y2 = std::min((int32_t)0xFFFF, std::max((int32_t)0, (centerPos.y + maxRangeY + maxoffset))), startx1 = x1 - (x1 % FLOOR_SIZE), starty1 = y1 - (y1 % FLOOR_SIZE), endx2 = x2 - (x2 % FLOOR_SIZE), endy2 = y2 - (y2 % FLOOR_SIZE); QTreeLeafNode* startLeaf = getLeaf(startx1, starty1); QTreeLeafNode* leafS = startLeaf; QTreeLeafNode* leafE; for(int32_t ny = starty1; ny <= endy2; ny += FLOOR_SIZE) { leafE = leafS; for(int32_t nx = startx1; nx <= endx2; nx += FLOOR_SIZE) { if(leafE) { CreatureVector& nodeList = leafE->creatureList; CreatureVector::const_iterator it = nodeList.begin(); if(it != nodeList.end()) { do { Creature* creature = (*it); const Position& pos = creature->getPosition(); int32_t offsetZ = centerPos.z - pos.z; if(pos.z < minRangeZ || pos.z > maxRangeZ) continue; if(pos.y < (centerPos.y + minRangeY + offsetZ) || pos.y > (centerPos.y + maxRangeY + offsetZ)) continue; if(pos.x < (centerPos.x + minRangeX + offsetZ) || pos.x > (centerPos.x + maxRangeX + offsetZ)) continue; if(!checkForDuplicate || std::find(list.begin(), list.end(), creature) == list.end()) list.push_back(creature); } while(++it != nodeList.end()); } leafE = leafE->stepEast(); } else leafE = getLeaf(nx + FLOOR_SIZE, ny); } if(leafS) leafS = leafS->stepSouth(); else leafS = getLeaf(startx1, ny + FLOOR_SIZE); } } void Map::getSpectators(SpectatorVec& list, const Position& centerPos, bool checkforduplicate /*= false*/, bool multifloor /*= false*/, int32_t minRangeX /*= 0*/, int32_t maxRangeX /*= 0*/, int32_t minRangeY /*= 0*/, int32_t maxRangeY /*= 0*/) { if(centerPos.z >= MAP_MAX_LAYERS) return; bool foundCache = false, cacheResult = false; if(!minRangeX && !maxRangeX && !minRangeY && !maxRangeY && multifloor && !checkforduplicate) { SpectatorCache::iterator it = spectatorCache.find(centerPos); if(it != spectatorCache.end()) { list = *it->second; foundCache = true; } else cacheResult = true; } if(!foundCache) { minRangeX = (!minRangeX ? -maxViewportX : -minRangeX); maxRangeX = (!maxRangeX ? maxViewportX : maxRangeX); minRangeY = (!minRangeY ? -maxViewportY : -minRangeY); maxRangeY = (!maxRangeY ? maxViewportY : maxRangeY); int32_t minRangeZ, maxRangeZ; if(multifloor) { if(centerPos.z > 7) { //underground, 8->15 minRangeZ = std::max(centerPos.z - 2, 0); maxRangeZ = std::min(centerPos.z + 2, MAP_MAX_LAYERS - 1); } //above ground else if(centerPos.z == 6) { minRangeZ = 0; maxRangeZ = 8; } else if(centerPos.z == 7) { minRangeZ = 0; maxRangeZ = 9; } else { minRangeZ = 0; maxRangeZ = 7; } } else { minRangeZ = centerPos.z; maxRangeZ = centerPos.z; } getSpectatorsInternal(list, centerPos, true, minRangeX, maxRangeX, minRangeY, maxRangeY, minRangeZ, maxRangeZ); if(cacheResult) spectatorCache[centerPos].reset(new SpectatorVec(list)); } } const SpectatorVec& Map::getSpectators(const Position& centerPos) { if(centerPos.z >= MAP_MAX_LAYERS) { boost::shared_ptr<SpectatorVec> p(new SpectatorVec()); SpectatorVec& list = *p; return list; } SpectatorCache::iterator it = spectatorCache.find(centerPos); if(it != spectatorCache.end()) return *it->second; boost::shared_ptr<SpectatorVec> p(new SpectatorVec()); spectatorCache[centerPos] = p; SpectatorVec& list = *p; int32_t minRangeX = -maxViewportX, maxRangeX = maxViewportX, minRangeY = -maxViewportY, maxRangeY = maxViewportY, minRangeZ, maxRangeZ; if(centerPos.z > 7) { //underground, 8->15 minRangeZ = std::max(centerPos.z - 2, 0); maxRangeZ = std::min(centerPos.z + 2, MAP_MAX_LAYERS - 1); } //above ground else if(centerPos.z == 6) { minRangeZ = 0; maxRangeZ = 8; } else if(centerPos.z == 7) { minRangeZ = 0; maxRangeZ = 9; } else { minRangeZ = 0; maxRangeZ = 7; } getSpectatorsInternal(list, centerPos, false, minRangeX, maxRangeX, minRangeY, maxRangeY, minRangeZ, maxRangeZ); return list; } bool Map::canThrowObjectTo(const Position& fromPos, const Position& toPos, bool checkLineOfSight /*= true*/, int32_t rangex /*= Map::maxClientViewportX*/, int32_t rangey /*= Map::maxClientViewportY*/) { //z checks //underground 8->15 //ground level and above 7->0 if((fromPos.z >= 8 && toPos.z < 8) || (toPos.z >= 8 && fromPos.z < 8) || fromPos.z - fromPos.z > 2) return false; int32_t deltax = std::abs(fromPos.x - toPos.x), deltay = std::abs( fromPos.y - toPos.y), deltaz = std::abs(fromPos.z - toPos.z); if(deltax - deltaz > rangex || deltay - deltaz > rangey) return false; if(!checkLineOfSight) return true; return isSightClear(fromPos, toPos, false); } bool Map::checkSightLine(const Position& fromPos, const Position& toPos) const { Position start = fromPos; Position end = toPos; int32_t x, y, z, dx = std::abs(start.x - end.x), dy = std::abs(start.y - end.y), dz = std::abs(start.z - end.z), sx, sy, sz, ey, ez, max = dx, dir = 0; if(dy > max) { max = dy; dir = 1; } if(dz > max) { max = dz; dir = 2; } switch(dir) { case 1: //x -> y //y -> x //z -> z std::swap(start.x, start.y); std::swap(end.x, end.y); std::swap(dx, dy); break; case 2: //x -> z //y -> y //z -> x std::swap(start.x, start.z); std::swap(end.x, end.z); std::swap(dx, dz); break; default: //x -> x //y -> y //z -> z break; } sx = ((start.x < end.x) ? 1 : -1); sy = ((start.y < end.y) ? 1 : -1); sz = ((start.z < end.z) ? 1 : -1); ey = ez = 0; x = start.x; y = start.y; z = start.z; int32_t lastrx = 0, lastry = 0, lastrz = 0; for(; x != end.x + sx; x += sx) { int32_t rx, ry, rz; switch(dir) { case 1: rx = y; ry = x; rz = z; break; case 2: rx = z; ry = y; rz = x; break; default: rx = x; ry = y; rz = z; break; } if(!lastrx && !lastry && !lastrz) { lastrx = rx; lastry = ry; lastrz = rz; } if(lastrz != rz || ((toPos.x != rx || toPos.y != ry || toPos.z != rz) && (fromPos.x != rx || fromPos.y != ry || fromPos.z != rz))) { if(lastrz != rz && const_cast<Map*>(this)->getTile(lastrx, lastry, std::min(lastrz, rz))) return false; lastrx = rx; lastry = ry; lastrz = rz; const Tile* tile = const_cast<Map*>(this)->getTile(rx, ry, rz); if(tile && tile->hasProperty(BLOCKPROJECTILE)) return false; } ey += dy; ez += dz; if(2 * ey >= dx) { y += sy; ey -= dx; } if(2 * ez >= dx) { z += sz; ez -= dx; } } return true; } bool Map::isSightClear(const Position& fromPos, const Position& toPos, bool floorCheck) const { if(floorCheck && fromPos.z != toPos.z) return false; // Cast two converging rays and see if either yields a result. return checkSightLine(fromPos, toPos) || checkSightLine(toPos, fromPos); } const Tile* Map::canWalkTo(const Creature* creature, const Position& pos) { switch(creature->getWalkCache(pos)) { case 0: return NULL; case 1: return getTile(pos); default: break; } //used for none-cached tiles Tile* tile = getTile(pos); if(creature->getTile() != tile && (!tile || tile->__queryAdd(0, creature, 1, FLAG_PATHFINDING | FLAG_IGNOREFIELDDAMAGE) != RET_NOERROR)) return NULL; return tile; } bool Map::getPathTo(const Creature* creature, const Position& destPos, std::list<Direction>& listDir, int32_t maxSearchDist /*= -1*/) { if(!canWalkTo(creature, destPos)) return false; Position startPos = destPos; Position endPos = creature->getPosition(); listDir.clear(); if(startPos.z != endPos.z) return false; AStarNodes nodes; AStarNode* startNode = nodes.createOpenNode(); startNode->x = startPos.x; startNode->y = startPos.y; startNode->g = 0; startNode->h = nodes.getEstimatedDistance(startPos.x, startPos.y, endPos.x, endPos.y); startNode->f = startNode->g + startNode->h; startNode->parent = NULL; Position pos; pos.z = startPos.z; static int32_t neighbourOrderList[8][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1}, //diagonal {-1, -1}, {1, -1}, {1, 1}, {-1, 1}, }; AStarNode* found = NULL; AStarNode* n = NULL; const Tile* tile = NULL; while(maxSearchDist != -1 || nodes.countClosedNodes() < 100) { if(!(n = nodes.getBestNode())) { listDir.clear(); return false; //no path found } if(n->x == endPos.x && n->y == endPos.y) { found = n; break; } for(uint8_t i = 0; i < 8; ++i) { pos.x = n->x + neighbourOrderList[i][0]; pos.y = n->y + neighbourOrderList[i][1]; bool outOfRange = false; if(maxSearchDist != -1 && (std::abs(endPos.x - pos.x) > maxSearchDist || std::abs(endPos.y - pos.y) > maxSearchDist)) outOfRange = true; if(!outOfRange && (tile = canWalkTo(creature, pos))) { //The cost (g) for this neighbour int32_t cost = nodes.getMapWalkCost(creature, n, tile, pos), extraCost = nodes.getTileWalkCost(creature, tile), newg = n->g + cost + extraCost; //Check if the node is already in the closed/open list //If it exists and the nodes already on them has a lower cost (g) then we can ignore this neighbour node AStarNode* neighbourNode = nodes.getNodeInList(pos.x, pos.y); if(neighbourNode) { if(neighbourNode->g <= newg) //The node on the closed/open list is cheaper than this one continue; nodes.openNode(neighbourNode); } else if(!(neighbourNode = nodes.createOpenNode())) //Does not exist in the open/closed list, create a new node { //seems we ran out of nodes listDir.clear(); return false; } //This node is the best node so far with this state neighbourNode->x = pos.x; neighbourNode->y = pos.y; neighbourNode->g = newg; neighbourNode->h = nodes.getEstimatedDistance(neighbourNode->x, neighbourNode->y, endPos.x, endPos.y); neighbourNode->f = neighbourNode->g + neighbourNode->h; neighbourNode->parent = n; } } nodes.closeNode(n); } int32_t prevx = endPos.x, prevy = endPos.y, dx, dy; while(found) { pos.x = found->x; pos.y = found->y; dx = pos.x - prevx; dy = pos.y - prevy; prevx = pos.x; prevy = pos.y; found = found->parent; if(dx == -1 && dy == -1) listDir.push_back(NORTHWEST); else if(dx == 1 && dy == -1) listDir.push_back(NORTHEAST); else if(dx == -1 && dy == 1) listDir.push_back(SOUTHWEST); else if(dx == 1 && dy == 1) listDir.push_back(SOUTHEAST); else if(dx == -1) listDir.push_back(WEST); else if(dx == 1) listDir.push_back(EAST); else if(dy == -1) listDir.push_back(NORTH); else if(dy == 1) listDir.push_back(SOUTH); } return !listDir.empty(); } bool Map::getPathMatching(const Creature* creature, std::list<Direction>& dirList, const FrozenPathingConditionCall& pathCondition, const FindPathParams& fpp) { Position startPos = creature->getPosition(); Position endPos; AStarNodes nodes; AStarNode* startNode = nodes.createOpenNode(); startNode->x = startPos.x; startNode->y = startPos.y; startNode->f = 0; startNode->parent = NULL; dirList.clear(); int32_t bestMatch = 0; Position pos; pos.z = startPos.z; static int32_t neighbourOrderList[8][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1}, //diagonal {-1, -1}, {1, -1}, {1, 1}, {-1, 1}, }; AStarNode* found = NULL; AStarNode* n = NULL; const Tile* tile = NULL; while(fpp.maxSearchDist != -1 || nodes.countClosedNodes() < 100) { if(!(n = nodes.getBestNode())) { if(found) //not quite what we want, but we found something break; dirList.clear(); return false; //no path found } if(pathCondition(startPos, Position(n->x, n->y, startPos.z), fpp, bestMatch)) { found = n; endPos = Position(n->x, n->y, startPos.z); if(!bestMatch) break; } int32_t dirCount = (fpp.allowDiagonal ? 8 : 4); for(int32_t i = 0; i < dirCount; ++i) { pos.x = n->x + neighbourOrderList[i][0]; pos.y = n->y + neighbourOrderList[i][1]; bool inRange = true; if(fpp.maxSearchDist != -1 && (std::abs(startPos.x - pos.x) > fpp.maxSearchDist || std::abs(startPos.y - pos.y) > fpp.maxSearchDist)) inRange = false; if(fpp.keepDistance) { if(!pathCondition.isInRange(startPos, pos, fpp)) inRange = false; } if(inRange && (tile = canWalkTo(creature, pos))) { //The cost (g) for this neighbour int32_t cost = nodes.getMapWalkCost(creature, n, tile, pos), extraCost = nodes.getTileWalkCost(creature, tile), newf = n->f + cost + extraCost; //Check if the node is already in the closed/open list //If it exists and the nodes already on them has a lower cost (g) then we can ignore this neighbour node AStarNode* neighbourNode = nodes.getNodeInList(pos.x, pos.y); if(neighbourNode) { if(neighbourNode->f <= newf) //The node on the closed/open list is cheaper than this one continue; nodes.openNode(neighbourNode); } else if(!(neighbourNode = nodes.createOpenNode())) //Does not exist in the open/closed list, create a new node { if(found) //not quite what we want, but we found something break; //seems we ran out of nodes dirList.clear(); return false; } //This node is the best node so far with this state neighbourNode->x = pos.x; neighbourNode->y = pos.y; neighbourNode->parent = n; neighbourNode->f = newf; } } nodes.closeNode(n); } if(!found) return false; int32_t prevx = endPos.x, prevy = endPos.y, dx, dy; found = found->parent; while(found) { pos.x = found->x; pos.y = found->y; dx = pos.x - prevx; dy = pos.y - prevy; prevx = pos.x; prevy = pos.y; found = found->parent; if(dx == 1 && dy == 1) dirList.push_front(NORTHWEST); else if(dx == -1 && dy == 1) dirList.push_front(NORTHEAST); else if(dx == 1 && dy == -1) dirList.push_front(SOUTHWEST); else if(dx == -1 && dy == -1) dirList.push_front(SOUTHEAST); else if(dx == 1) dirList.push_front(WEST); else if(dx == -1) dirList.push_front(EAST); else if(dy == 1) dirList.push_front(NORTH); else if(dy == -1) dirList.push_front(SOUTH); } return true; } //*********** AStarNodes ************* AStarNodes::AStarNodes() { curNode = 0; openNodes.reset(); } AStarNode* AStarNodes::createOpenNode() { if(curNode >= MAX_NODES) return NULL; uint32_t retNode = curNode; curNode++; openNodes[retNode] = 1; return &nodes[retNode]; } AStarNode* AStarNodes::getBestNode() { if(!curNode) return NULL; int32_t bestNodeF = 100000; uint32_t bestNode = 0; bool found = false; for(uint32_t i = 0; i < curNode; i++) { if(nodes[i].f < bestNodeF && openNodes[i] == 1) { found = true; bestNodeF = nodes[i].f; bestNode = i; } } if(found) return &nodes[bestNode]; return NULL; } void AStarNodes::closeNode(AStarNode* node) { uint32_t pos = GET_NODE_INDEX(node); if(pos < MAX_NODES) { openNodes[pos] = 0; return; } assert(pos >= MAX_NODES); std::cout << "AStarNodes. trying to close node out of range" << std::endl; return; } void AStarNodes::openNode(AStarNode* node) { uint32_t pos = GET_NODE_INDEX(node); if(pos < MAX_NODES) { openNodes[pos] = 1; return; } assert(pos >= MAX_NODES); std::cout << "AStarNodes. trying to open node out of range" << std::endl; return; } uint32_t AStarNodes::countClosedNodes() { uint32_t counter = 0; for(uint32_t i = 0; i < curNode; i++) { if(!openNodes[i]) counter++; } return counter; } uint32_t AStarNodes::countOpenNodes() { uint32_t counter = 0; for(uint32_t i = 0; i < curNode; i++) { if(openNodes[i] == 1) counter++; } return counter; } bool AStarNodes::isInList(uint16_t x, uint16_t y) { for(uint32_t i = 0; i < curNode; i++) { if(nodes[i].x == x && nodes[i].y == y) return true; } return false; } AStarNode* AStarNodes::getNodeInList(uint16_t x, uint16_t y) { for(uint32_t i = 0; i < curNode; i++) { if(nodes[i].x == x && nodes[i].y == y) return &nodes[i]; } return NULL; } int32_t AStarNodes::getMapWalkCost(const Creature* creature, AStarNode* node, const Tile* neighbourTile, const Position& neighbourPos) { if(std::abs(node->x - neighbourPos.x) == std::abs(node->y - neighbourPos.y)) //diagonal movement extra cost return MAP_DIAGONALWALKCOST; return MAP_NORMALWALKCOST; } int32_t AStarNodes::getTileWalkCost(const Creature* creature, const Tile* tile) { int32_t cost = 0; if(tile->getTopVisibleCreature(creature)) //destroy creature cost cost += MAP_NORMALWALKCOST * 3; if(const MagicField* field = tile->getFieldItem()) { if(!creature->isImmune(field->getCombatType())) cost += MAP_NORMALWALKCOST * 3; } return cost; } int32_t AStarNodes::getEstimatedDistance(uint16_t x, uint16_t y, uint16_t xGoal, uint16_t yGoal) { int32_t diagonal = std::min(std::abs(x - xGoal), std::abs(y - yGoal)); return (MAP_DIAGONALWALKCOST * diagonal) + (MAP_NORMALWALKCOST * ((std::abs( x - xGoal) + std::abs(y - yGoal)) - (2 * diagonal))); } //*********** Floor constructor ************** Floor::Floor() { for(int32_t i = 0; i < FLOOR_SIZE; ++i) { for(int32_t j = 0; j < FLOOR_SIZE; ++j) tiles[i][j] = 0; } } //**************** QTreeNode ********************** QTreeNode::QTreeNode() { m_isLeaf = false; for(int32_t i = 0; i < 4; ++i) m_child[i] = NULL; } QTreeNode::~QTreeNode() { for(int32_t i = 0; i < 4; ++i) delete m_child[i]; } QTreeLeafNode* QTreeNode::getLeaf(uint16_t x, uint16_t y) { if(isLeaf()) return static_cast<QTreeLeafNode*>(this); uint32_t index = ((x & 0x8000) >> 15) | ((y & 0x8000) >> 14); if(m_child[index]) return m_child[index]->getLeaf(x * 2, y * 2); return NULL; } QTreeLeafNode* QTreeNode::getLeafStatic(QTreeNode* root, uint16_t x, uint16_t y) { QTreeNode* currentNode = root; uint32_t currentX = x, currentY = y; while(currentNode) { if(currentNode->isLeaf()) return static_cast<QTreeLeafNode*>(currentNode); uint32_t index = ((currentX & 0x8000) >> 15) | ((currentY & 0x8000) >> 14); if(!currentNode->m_child[index]) return NULL; currentNode = currentNode->m_child[index]; currentX = currentX * 2; currentY = currentY * 2; } return NULL; } QTreeLeafNode* QTreeNode::createLeaf(uint16_t x, uint16_t y, uint16_t level) { if(!isLeaf()) { uint32_t index = ((x & 0x8000) >> 15) | ((y & 0x8000) >> 14); if(!m_child[index]) { if(level != FLOOR_BITS) m_child[index] = new QTreeNode(); else { m_child[index] = new QTreeLeafNode(); QTreeLeafNode::newLeaf = true; } } return m_child[index]->createLeaf(x * 2, y * 2, level - 1); } return static_cast<QTreeLeafNode*>(this); } //************ LeafNode ************************ bool QTreeLeafNode::newLeaf = false; QTreeLeafNode::QTreeLeafNode() { for(int32_t i = 0; i < MAP_MAX_LAYERS; ++i) m_array[i] = NULL; m_isLeaf = true; m_leafS = NULL; m_leafE = NULL; } QTreeLeafNode::~QTreeLeafNode() { for(int32_t i = 0; i < MAP_MAX_LAYERS; ++i) delete m_array[i]; } Floor* QTreeLeafNode::createFloor(uint16_t z) { if(!m_array[z]) m_array[z] = new Floor(); return m_array[z]; } Para o server nao verificar a versao do mapa,e eu poder entrar no server,usando mapa de uma versao mais antiga,por exemplo meu serv é 8.6,queria usar o mapa de 8.0. Ta eu compilei deu tudo certin,so que quando vou entrar no server,dis que a posição esta íncorreta.Nao da nenhum erro no distro,nao sei oque pode ser. Notem,que eu botei o */ e /* para nao verificar a versao do mapa.Pode ser que esteje no local errado.
- 16 respostas
-
- [erro] posição incorreta
- tibia
- (e 1 mais)
-
dúvida [Encerrado] Erro ao iniciar distro compilado 8.6
tópico respondeu ao AlexandreKG de AlexandreKG em Tópicos Sem Resposta
vlw funciono so que agr esta dando erro no items.otbm,sendo que eu baixei otro server 8.6 botei la e mesmo assim o erro persiste. -
Os melhores webservers em suas melhores verções!
tópico respondeu ao Piabeta Kun de AlexandreKG em Websites & Layouts
Bom,este topico tem muita utilidade pois muitos membros ,sempre tem duvida de que webserver escolher. E fes muito bem em por o xampp 1.7.3 na lista ^^ -
dúvida [Encerrado] Erro ao iniciar distro compilado 8.6
um tópico no fórum postou AlexandreKG Tópicos Sem Resposta
Fala galerinha,sempre tem que dar um erro comigo.Eu estava com o erro na hora de compilar mais ja consegui so que agora quando vou abri ele fica assim. Sendo que esta tudo certo no config.lua Eu queria saber,se teria como compilar por console,que dai da pra dar reload e talz. -
ASDAHUSUDA
-
dúvida [Encerrado] Erro No Distro
tópico respondeu ao JulioNakanishi de AlexandreKG em Tópicos Sem Resposta
Tente usar outro server,este pode estar com algum arquivo bugado. -
[Encerrado] Player Morre E Positions Zeram
tópico respondeu ao Surfadao de AlexandreKG em Tópicos Sem Resposta
accountManager = "no" namelockManager = "yes" newPlayerChooseVoc = "yes" newPlayerSpawnPosX = 155 newPlayerSpawnPosY = 52 newPlayerSpawnPosZ = 7 newPlayerTownId = 2 newPlayerLevel = 8 newPlayerMagicLevel = 0 generateAccountNumber = "no" Esses "no" e "yes",funcionam em lua assim? Tente trocar: no - false yes - true Assim,deverá funcionar. -
[Encerrado] Duvida com a Posição do Templo
tópico respondeu ao Maristella de AlexandreKG em Tópicos Sem Resposta
Não adianta,voce arrumar no config.lua . Depois que voce criou um char,isso nao vai mudar em nada.Então para arrumar voce precisa do SQL Studio,voce abre sua database,entra na tabela players,procure seu char e edita posição. -
dúvida [Encerrado] Sv.exe Coisas Dentro
tópico respondeu ao jhonatanp de AlexandreKG em Tópicos Sem Resposta
Amigo,wodbo.com era do Jacolos,Crash e Hajbos. Quem são eles? Eles sao os criadores de dbztibia,eles tiverem a ideia de criar o famoso wodbo (World of Dragon Ball Online),o problema é que nesse mundo de wodbo,os paises tem rivalidade,os chilenos nao gostam dos brasileiros.Poloneses que são onde esses 3 especialistas vivem,tambem nao gostam dos brasileiros,bom pelo menos antigamente.Agora as coisas estão mudando e os paises,tao se convivendo junto. Por isso os criadores do wodbo.com,tinham as sources,e só para avisar quando você compila uma source é impossivel descompilar-la.Os criadores do wodbo.com(J&C&H) ,compilaram a source em GUI.Por isso abre como o CMD.Eu nunca tentei,mas eu estava até pensando em criar um 8.0,sem esses bugs que tem nos wodbo hoje em dia.Eu iria criar um 8.0,mas sem o bug do level 631.Bom mas isso nao vem ao caso talves eu crie talves nao. Então isso so escrevi para lhe explicar,que o que voce pode fazer é deletar as vocações e refaze-las,por script. Espero ter ajudado.. Obrigado,Mozark001. -
dúvida [Encerrado] como criar narutibia via hamachi
tópico respondeu ao gokusin de AlexandreKG em Tópicos Sem Resposta
Bom dia,amigo. Bom em primeiro caso,eu achei este video que provavelmente irá servir como ajuda a você então decidi colocar aqui,so seguir ele abaixo,para nao precisar ir ate o youtube e carregar e talz ....Bom ele é para criar um server de tibia,mas é quase mesma coisa,voce vai seguindo o tutorial passo -a passo. Espero ter ajudado...- 6 respostas
-
- narutibia hamahci compartilha
- resolvido
- (e 2 mais)
-
Procure o script em seu server,abra-o com bloco de notas e veja o ID do storage.
-
Bom,boa noite XTibia,estou com uma duvida,quero montar um servidor inovador,de wodbo 9.6,so que eu queria saber como faço para mudar a versao dos arquivos .dat e .spr de 8.54,para 9.6. Quem puder ajudar,valeu ai.
- 5 respostas
-
- como mudar versao de .dat spr
- otserv
- (e 1 mais)
-
mais eu nao tenho seu msn ='( queria te ver =/ Gato, nao sei com qntos paus se faz uma canoa... ...mais seu pai com apenas 1 fez um avião! Eu ouvi isso na minha escola 3 mes atras kkk
-
Como Usar O Dat Editor
tópico respondeu ao PostadorHunter de AlexandreKG em Tutoriais de Programação
Boa noite amigo,eu hospedei o meu Dat Editor,aqui nao pego virus nem nada. http://speedy.sh/hus56/Dat-Editor.rar -
Bom,primeiramente. Boa noite,amigo.Gostaria de ir explicando uma coisa extremamente,importante,voce nao irá ser scripter da noite pro dia,entao recomendo voce a ter amigo,ou companheiro para lhe ajudar,nao fique so lendo as aulas,treine as funçoes também.A sessão abaixo tem varios tutoriais interessantes,basta dar uma olhada. Tutoriais de Scripting Espero ter ajudado...
-
Duvida com Diretório 8.60 Alissow Ots 4.11
pergunta respondeu ao guilol123 de AlexandreKG em Websites
Olá amigo,bom primeiramente,baixe esta versao dos arquivos. xampp 1.7.3 Gesior 10.1.6 Concerteza nao terá mais erros.Eu uso esses documentos e aprovo. Espero ter ajudado... -
[GesiorACC] Colocando pagina House.php TFS 0.3+
um tópico no fórum postou AlexandreKG Tutoriais de Websites
Fala galerinha do Ékz,estou mais uma ves postando um tutorial,desta ves como adicionar a pagina house.php no GesiorACC para servers 0.3+. Começando: Vá na pasta xampp/htdocs Procure o houses.php " caso não tenha abra o bloco de notas copie e cole o codigo e no nome coloque houses.php, salve dentro da pasta htdocs" Apague tudo e ponha isso: <?PHP $main_content .= '<form method="post" action=""><table>'; if(count($config['site']['worlds']) > 1) { if(isset($_POST['world']) and is_numeric($_POST['world'])) { $wid = (int) $_POST['world']; $wid = '<option value='.$wid.'>'.$config['site']['worlds'][$wid].'</option>'; } $select_w .= '<tr><td>Select World:</td><td><select name="world" onchange="submit()">'.$wid.''; $i=1; foreach($config['site']['worlds'] as $id => $world_n) { if($_POST['world'] != $id) { $worlds[$i] .= '<option value="'.$id.'">'.$world_n.'</option>'; } if($id == (int) $_POST['world']) { $world_id = $id; $world_name = $world_n; } $i++; } $main_content .= ''.$select_w.''; for($i=0;$i <= count($config['site']['worlds']); $i++) { $main_content .= ''.$worlds[$i].''; } $main_content .= '</td></tr></select>'; } if(!isset($world_id)) { $world_id = 0; $world_name = $config['server']['serverName']; } if(count($towns_list) > 1) { if(isset($_POST['town']) and is_numeric($_POST['town'])) { $pid = (int) $_POST['town']; $pid = '<option value='.$pid.'>'.$towns_list[$world_id][$pid].'</option>'; } else { $pid = '<option value="all">[ALL]</option>'; $all=true; } $select .= '<tr><td>Select City:</td><td><select name="town" onchange="submit()">'.$pid.''; $i=1; foreach($towns_list[$world_id] as $id => $town_n) { if($_POST['town'] != $id) { $towns[$i] .= '<option value="'.$id.'">'.$town_n.'</option>'; } if($id == (int) $_POST['town']) { $town_id = $id; $town_name = $town_n; } $i++; } $main_content .= ''.$select.''; for($i=1;$i <= count($towns_list[$world_id]); $i++) { $main_content .= ''.$towns[$i].''; } if(!$all) $main_content .= '<option value="all">[ALL]</option>'; $main_content .= '</td></tr></select>'; } if(isset($town_id)) { $a_status = array(1 => "Empty", "Rented", "[ALL]"); if(isset($_POST['status']) and is_numeric($_POST['status'])) { $sid = (int) $_POST['status']; $sid = '<option value='.$sid.'>'.$a_status[$sid].'</option>'; if($_POST['status'] == 1) $s[1] = true; elseif($_POST['status'] == 2) $s[2] = true; elseif($_POST['status'] == 3) $s[3] = true; } $main_content .= '<tr><td>Select by status:</td><td><select name="status" onchange="submit()">'.$sid.''; if(!$s[3]) $main_content .= '<option value="3">[ALL]</opyion>'; if(!$s[2]) $main_content .= '<option value="2">Rented</option>'; if(!$s[1]) $main_content .= '<option value="1">Empty</option>'; $main_content .= '</td></tr></select>'; } $main_content .= '</table></form>'; if(isset($_POST['status'])) { if($_POST['status'] == 1) $stat = "and `owner` = ''"; elseif($_POST['status'] == 2) $stat = "and `owner` > 0"; } if(!isset($town_id)) { $houses_info = $SQL->query("SELECT * FROM `houses` WHERE `world_id` = ".$world_id." ORDER BY `town` , `name`"); $towns_all = true; } $main_content .= '<h2>Houses on '.$config['site']['worlds'][(int) $_GET['world']].'</h2>'; $main_content .= '<table><tr bgcolor="'.$config['site']['vdarkborder'].'"><td><font color="white"><b>Address</b></font></td><td><font color="white"><b>Size</b></font></td><td><font color="white"><b>Price</b></font></td><td><font color="white"><b>City</b></font></td><td><font color="white"><b>Status</b></font></td></tr>'; $number_of_rows = 1; if(!$towns_all) $houses_info = $SQL->query("SELECT * FROM `houses` WHERE `world_id` = ".$world_id." and `town` = ".$town_id." ".$stat." ORDER BY `name`"); $players_info = $SQL->query("SELECT `houses`.`id` AS `houseid` , `players`.`name` AS `ownername` , `accounts`.`premdays` AS `premdays` , `accounts`.`lastday` AS `lastlogin` FROM `houses` , `players` , `accounts` WHERE `players`.`id` = `houses`.`owner` AND `accounts`.`id` = `players`.`account_id`"); $players = array(); foreach($players_info->fetchAll() as $player) $players[$player['houseid']] = array('name' => $player['ownername'], 'days' => $player['premdays'], 'last' => $player['lastlogin']); foreach($houses_info->fetchAll() as $house) { $owner = $players[$house['id']]; if(is_int($number_of_rows / 2)) { $bgcolor = $config['site']['darkborder']; } else { $bgcolor = $config['site']['lightborder']; } $number_of_rows++; $main_content .= '<tr bgcolor="'.$bgcolor.'"><td>'.$house['name'].'</td><td align="right" width="35">'.$house['size'].'</td><td align="right" width="65">'.($house['price'] / 1000).'k gp</td><td>'.$towns_list[(int) $house['world_id']][(int) $house['town']].'</td><td>'; if(!empty($owner['name'])) { if($owner['deleted'] > 0) $status='<font color=red><b>[DELETED]</b></font>'; if(isPremium($owner['days'], $owner['last'])) { $main_content .= 'Rented by <a href="?subtopic=characters&name='.urlencode($owner['name']).'">'.$owner['name'].'</a>'.$status.''; } else { $main_content .= 'Rented by <a href="?subtopic=characters&name='.urlencode($owner['name']).'">'.$owner['name'].'</a>'.$status.' (FACC)'; } } else { $main_content .= 'Empty'; } $main_content .= '</td></tr>'; } $main_content .= '</TABLE>'; ?> Vá em xampp/htdocs e abra o index.php e adicione case "houses"; $topic = "houses"; $subtopic = "houses"; include("houses.php"); break; Vá em xampp/htdocs/layout/"pasta do seu layout" Abra o layout.php aperte control+F e procure por guild em seguida adicione o: <li><a href="?subtopic=houses"> » Houses</a></li> Créditos: Mozark001 Paulinho -
Amigo,tente expressar mais sua energia em tibia,pois aqui é uma comunidade de tibia,e nao de jogos derivados.Mas está bom sua entrada parabéns.
-
Bom,pessoal vou encinar agora,alguns comandos basicos porem muito uteis,no seu phpmyadmin.Voce pode estar com alguma duvida,de como colocar,entao algum desses pode ser a sua solução. Não sabe onde adicionar esses comandos? Muito simples abra seu phpmyadmin,e entra na database de seu servidor.Logo após clique na aba SQL,la encima.E pronto vai usando os codigos ali. -------------------------------------------------------------------------------------- Lista: Remover Premium ACC de todos. Não funciona com VIP System . UPDATE account SET premdays=0; -------------------------------------------------------------------------------------- Dar 7 Dias de premium para todos os players da acc.. Não funciona com VIP System. UPDATE accounts SET premdays = premdays + 7 -------------------------------------------------------------------------------------- Colocar todos os players em posição definida UPDATE players SET posx = X, posy = Y, posz = Z; -------------------------------------------------------------------------------------- Colocar todos os players com acesso 1-Player. UPDATE groups SET flags=0,name="Player" WHERE id=1; UPDATE players SET group_id=1; DELETE FROM groups WHERE id<>1; -------------------------------------------------------------------------------------- Criar Account Manager. (Original em forgottenserver.sql) INSERT INTO `players` VALUES (1, 'Account Manager', 1, 1, 1, 0, 150, 150, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 50, 50, 7, '', 400, 0, 0, 0, 0, 0, 0, 0, '', 0, 0, 0, 0, 10, 10, 10, 0, 0); -------------------------------------------------------------------------------------- Remover Red Skull e frags de todos. UPDATE `players` SET `redskulltime`=0; -------------------------------------------------------------------------------------- Dar Todas as Blesses aos players. UPDATE `players` SET `blessings`=31; -------------------------------------------------------------------------------------- Deletar todos os itens de um único player .Onde 1234 é o ID do player. DELETE FROM `player_depotitems` , `player_items` WHERE `player_id` = '1234' -------------------------------------------------------------------------------------- Agora,vou postar uma query que á solução de um erro em Gesior que é aquele erro que da quando voce loga acc no char e da erro OTS_AccountBans.php Algo assim. [/center] CREATE TABLE `bans` ( `id` INT UNSIGNED NOT NULL auto_increment, `type` TINYINT(1) NOT NULL COMMENT '1 - ip banishment, 2 - namelock, 3 - account banishment, 4 - notation, 5 - deletion', `value` INT UNSIGNED NOT NULL COMMENT 'ip address (integer), player guid or account number', `param` INT UNSIGNED NOT NULL DEFAULT 4294967295 COMMENT 'used only for ip banishment mask (integer)', `active` TINYINT(1) NOT NULL DEFAULT TRUE, `expires` INT NOT NULL, `added` INT UNSIGNED NOT NULL, `admin_id` INT UNSIGNED NOT NULL DEFAULT 0, `comment` TEXT NOT NULL, `reason` INT UNSIGNED NOT NULL DEFAULT 0, `action` INT UNSIGNED NOT NULL DEFAULT 0, `statement` VARCHAR(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`), KEY `type` (`type`, `value`), KEY `active` (`active`) ) ENGINE = InnoDB; Bom é isso galera,tomara que gostem. Créditos: Mozark001. Matheus. Kimoszin Irei atualizar o topico sempre que eu achar query novas.
-
Porque nao usa esse Gesior? http://www.4shared.com/rar/0BjGRCeJ/Website_1016.html? Ele funciona em todas versoes de OTServ.
- 4 respostas
-
- erro - website
- tibia
-
(e 1 mais)
Tags:
-
Nao esqueça que tem que liberar as portas 7171 e 7172 tambem.
-
Download xampp 1.7.3 >> http://clickdownloads.uol.com.br/download/xampp-173.html Tomara que tenha ajudado...
-
Amigo,eu sei por que da isso,comigo tambem da. Pois isso é problema no Word,verifique se no seu phpmyadmin,do personagem está 0,voce muda para 1. Espero ter ajudado...
-
dúvida Erro Ao Clicar Em Myaccount No Site
pergunta respondeu ao bernardweger de AlexandreKG em Websites
Execute isso na sua database: CREATE TABLE `bans` ( `id` INT UNSIGNED NOT NULL auto_increment, `type` TINYINT(1) NOT NULL COMMENT '1 - ip banishment, 2 - namelock, 3 - account banishment, 4 - notation, 5 - deletion', `value` INT UNSIGNED NOT NULL COMMENT 'ip address (integer), player guid or account number', `param` INT UNSIGNED NOT NULL DEFAULT 4294967295 COMMENT 'used only for ip banishment mask (integer)', `active` TINYINT(1) NOT NULL DEFAULT TRUE, `expires` INT NOT NULL, `added` INT UNSIGNED NOT NULL, `admin_id` INT UNSIGNED NOT NULL DEFAULT 0, `comment` TEXT NOT NULL, `reason` INT UNSIGNED NOT NULL DEFAULT 0, `action` INT UNSIGNED NOT NULL DEFAULT 0, `statement` VARCHAR(255) NOT NULL DEFAULT '', PRIMARY KEY (`id`), KEY `type` (`type`, `value`), KEY `active` (`active`) ) ENGINE = InnoDB; -
Olá amigo,se voce quer o template existe um aqui no forum.Só que é para wodbo. http://www.xtibia.com/forum/topic/194916-modernacc-wodbo-template-v1-by-mrcatra/ Espero ter ajudado...
- 5 respostas
-
- pedido de ajuda!
- tibia
-
(e 1 mais)
Tags:
-
Quem Está Navegando 0 membros estão online
- Nenhum usuário registrado visualizando esta página.