tibia-rme/source/basemap.cpp
2023-01-29 23:32:19 -03:00

338 lines
8.1 KiB
C++

//////////////////////////////////////////////////////////////////////
// This file is part of Remere's Map Editor
//////////////////////////////////////////////////////////////////////
// Remere's Map Editor 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.
//
// Remere's Map Editor 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 "main.h"
#include "tile.h"
#include "basemap.h"
BaseMap::BaseMap() :
allocator(),
tilecount(0),
root(*this)
{
////
}
BaseMap::~BaseMap()
{
////
}
void BaseMap::clear(bool del)
{
PositionVector pos_vec;
for(MapIterator map_iter = begin(); map_iter != end(); ++map_iter) {
Tile* t = (*map_iter)->get();
pos_vec.push_back(t->getPosition());
}
for(PositionVector::iterator pos_iter = pos_vec.begin(); pos_iter != pos_vec.end(); ++pos_iter) {
setTile(*pos_iter, nullptr, del);
}
}
void BaseMap::clearVisible(uint32_t mask)
{
root.clearVisible(mask);
}
Tile* BaseMap::createTile(int x, int y, int z)
{
ASSERT(z < rme::MapLayers);
QTreeNode* leaf = root.getLeafForce(x, y);
TileLocation* loc = leaf->createTile(x, y, z);
if(loc->get())
return loc->get();
Tile* t = allocator(loc);
leaf->setTile(x, y, z, t);
return t;
}
TileLocation* BaseMap::getTileL(int x, int y, int z)
{
ASSERT(z < rme::MapLayers);
QTreeNode* leaf = root.getLeaf(x, y);
if(leaf) {
Floor* floor = leaf->getFloor(z);
if(floor)
return &floor->locs[(x & 3)*4 + (y & 3)];
}
return nullptr;
}
const TileLocation* BaseMap::getTileL(int x, int y, int z) const
{
// Don't create static const maps!
BaseMap* self = const_cast<BaseMap*>(this);
return self->getTileL(x, y, z);
}
TileLocation* BaseMap::getTileL(const Position& pos)
{
return getTileL(pos.x, pos.y, pos.z);
}
const TileLocation* BaseMap::getTileL(const Position& pos) const
{
return getTileL(pos.x, pos.y, pos.z);
}
TileLocation* BaseMap::createTileL(int x, int y, int z)
{
ASSERT(z < rme::MapLayers);
QTreeNode* leaf = root.getLeafForce(x, y);
Floor* floor = leaf->createFloor(x, y, z);
uint32_t offsetX = x & 3;
uint32_t offsetY = y & 3;
return &floor->locs[offsetX*4+offsetY];
}
TileLocation* BaseMap::createTileL(const Position& pos)
{
return createTileL(pos.x, pos.y, pos.z);
}
void BaseMap::setTile(int x, int y, int z, Tile* new_tile, bool remove)
{
ASSERT(!new_tile || new_tile->getX() == x);
ASSERT(!new_tile || new_tile->getY() == y);
ASSERT(!new_tile || new_tile->getZ() == z);
QTreeNode* leaf = root.getLeafForce(x, y);
Tile* old_tile = leaf->setTile(x, y, z, new_tile);
if ((remove && old_tile) || new_tile)
updateUniqueIds(remove ? old_tile : nullptr, new_tile);
if (remove) {
delete old_tile;
}
}
void BaseMap::setTile(const Position& position, Tile* new_tile, bool remove)
{
setTile(position.x, position.y, position.z, new_tile, remove);
}
void BaseMap::setTile(Tile* new_tile, bool remove)
{
ASSERT(new_tile);
const Position& position = new_tile->getPosition();
setTile(position.x, position.y, position.z, new_tile, remove);
}
Tile* BaseMap::swapTile(int x, int y, int z, Tile* new_tile)
{
ASSERT(z < rme::MapLayers);
ASSERT(!new_tile || new_tile->getX() == x);
ASSERT(!new_tile || new_tile->getY() == y);
ASSERT(!new_tile || new_tile->getZ() == z);
QTreeNode* leaf = root.getLeafForce(x, y);
Tile* old_tile = leaf->setTile(x, y, z, new_tile);
if (old_tile || new_tile)
updateUniqueIds(old_tile, new_tile);
return old_tile;
}
Tile* BaseMap::swapTile(const Position& position, Tile* new_tile)
{
return swapTile(position.x, position.y, position.z, new_tile);
}
// Iterators
MapIterator::MapIterator(BaseMap* _map) :
local_i(0),
local_z(0),
current_tile(nullptr),
map(_map)
{
////
}
MapIterator::~MapIterator()
{
////
}
MapIterator::MapIterator(const MapIterator& other)
{
for(std::vector<MapIterator::NodeIndex>::const_iterator it = other.nodestack.begin(); it != other.nodestack.end(); it++) {
nodestack.push_back(MapIterator::NodeIndex(*it));
}
local_i = other.local_i;
local_z = other.local_z;
map = other.map;
current_tile = other.current_tile;
}
MapIterator BaseMap::begin()
{
MapIterator it(this);
it.nodestack.push_back(MapIterator::NodeIndex(&root));
while(true) {
MapIterator::NodeIndex& current = it.nodestack.back();
QTreeNode* node = current.node;
int& index = current.index;
//printf("Contemplating %p of %p (stack size %d)\n", node, this, it.nodestack.size());
bool unwind = false;
for(; index < 16; ++index) {
//printf("\tChecking index %d of %p\n", index, node);
if(QTreeNode* child = node->child[index]) {
if(child->isLeaf) {
QTreeNode* leaf = child;
//printf("\t%p is leaf\n", child);
for(it.local_z = 0; it.local_z < rme::MapLayers; ++it.local_z) {
if(Floor* floor = leaf->array[it.local_z]) {
for(it.local_i = 0; it.local_i < 16; ++it.local_i) {
//printf("\tit(%d;%d;%d)\n", it.local_x, it.local_y, it.local_z);
TileLocation& t = floor->locs[it.local_i];
if(t.get()) {
//printf("return it\n");
it.current_tile = &t;
return it;
}
}
}
}
} else {
//printf("\tAdding %p\n", child);
++index;
it.nodestack.push_back(MapIterator::NodeIndex(child));
unwind = true;
break;
}
}
}
if(unwind)
continue;
//printf("Discarding dead node %p\n", node);
it.nodestack.pop_back();
if(it.nodestack.empty())
break;
}
return end();
}
MapIterator BaseMap::end()
{
MapIterator it(this);
it.local_i = -1;
it.local_z = -1;
return it;
}
TileLocation* MapIterator::operator*()
{
return current_tile;
}
TileLocation* MapIterator::operator->()
{
return current_tile;
}
MapIterator& MapIterator::operator++()
{
//printf("MapIterator::operator++");
bool increased = false;
bool first = true;
while(true) {
MapIterator::NodeIndex& current = nodestack.back();
QTreeNode* node = current.node;
int& index = current.index;
//printf("Contemplating %p (stack size %d)\n", node, nodestack.size());
bool unwind = false;
for(; index < rme::MapLayers; ++index) {
//printf("\tChecking index %d of %p\n", index, node);
if(QTreeNode* child = node->child[index]) {
if(child->isLeaf) {
QTreeNode* leaf = child;
//printf("\t%p is leaf\n", child);
for(; local_z < rme::MapLayers; ++local_z) {
//printf("\t\tIterating over Z:%d of %p", local_z, child);
if(Floor* floor = leaf->array[local_z]) {
//printf("\n");
for(; local_i < rme::MapLayers; ++local_i) {
//printf("\t\tIterating over Y:%d of %p\n", local_y, child);
TileLocation& t = floor->locs[local_i];
if(t.get()) {
if(increased) {
//printf("Modified %p to %p\n", current_tile, t);
current_tile = &t;
return *this;
} else {
increased = true;
}
} else if(first) {
increased = true;
first = false;
}
}
if(local_i > rme::MapMaxLayer) {
//printf("\t\tReset local_x\n");
local_i = 0;
}
} else {
//printf(":dead floor\n");
}
} if(local_z == rme::MapLayers) {
//printf("\t\tReset local_z\n");
local_z = 0;
}
} else {
//printf("\tAdding %p\n", child);
++index;
nodestack.push_back(MapIterator::NodeIndex(child));
unwind = true;
break;
}
}
}
if(unwind)
continue;
//printf("Discarding dead node %p\n", node);
nodestack.pop_back();
if(nodestack.size() == 0) {
// Set all values to "end"
//printf("END\n");
local_z = -1;
local_i = -1;
return *this;
}
}
return *this;
}
MapIterator MapIterator::operator++(int)
{
MapIterator i(*this);
++*this;
return i;
}