OpenGTA/navdata.cpp

230 lines
6.6 KiB
C++
Raw Normal View History

2015-12-03 00:37:02 +00:00
/************************************************************************
2015-12-03 00:37:37 +00:00
* Copyright (c) 2005-2007 tok@openlinux.org.uk *
2015-12-03 00:37:02 +00:00
* *
* This file contains code derived from information copyrighted by *
* DMA Design. It may not be used in a commercial product. *
* *
* See license.txt for details. *
* *
* This notice may not be removed or altered. *
************************************************************************/
#include <cassert>
#include <iostream>
#include <sstream>
2015-12-03 00:37:37 +00:00
#include <iomanip>
2015-12-03 00:37:02 +00:00
#include "navdata.h"
#include "log.h"
2015-12-03 00:37:37 +00:00
#include "dataholder.h"
2015-12-03 00:37:02 +00:00
#include "m_exceptions.h"
namespace OpenGTA {
Rect2D::Rect2D() {
x = y = w = h = 0;
}
Rect2D::Rect2D(PHYSFS_uint8 a, PHYSFS_uint8 b, PHYSFS_uint8 c, PHYSFS_uint8 d) {
x = a;
y = b;
w = c;
h = d;
}
bool Rect2D::isInside(PHYSFS_uint8 _x, PHYSFS_uint8 _y) {
if ((_x >= x ) && (_y >= y) &&
(PHYSFS_uint16(_x) <= PHYSFS_uint16(x) + w) &&
(PHYSFS_uint16(_y) <= PHYSFS_uint16(y) + h)) {
lastSubLocation = subLocation(_x, _y);
return true;
}
return false;
}
PHYSFS_uint16 Rect2D::getSize() {
PHYSFS_uint16 res = w;
res *= h;
return res;
}
// 0 = central, 1 = north, 2 = south, 4 = east, 8 = west
PHYSFS_uint8 Rect2D::subLocation(PHYSFS_uint8 _x, PHYSFS_uint8 _y) {
PHYSFS_uint8 in_x = _x - x; // offset in rect; assume: x <= _x
PHYSFS_uint8 in_y = _y - y;
float rel_x = float(in_x)/w;
float rel_y = float(in_y)/h;
PHYSFS_uint8 res = 0;
#define ONE_THIRD 1.0f/3.0f
#define TWO_THIRDS 2.0f/3.0f
if (rel_x <= ONE_THIRD)
// INFO << "west" << std::endl;
res |= 8;
else if (rel_x >= TWO_THIRDS)
//INFO << "east" << std::endl;
res |= 4;
if (rel_y <= ONE_THIRD)
res |= 1;
//INFO << "north" << std::endl;
else if (rel_y >= TWO_THIRDS)
res |= 2;
//INFO << "south" << std::endl;
return res;
}
2015-12-03 00:37:37 +00:00
NavData::Sector::Sector(PHYSFS_file* fd) : Rect2D(), sam(0), name("") {
2015-12-03 00:37:02 +00:00
sam = 0;
isADummy = 0;
assert(fd);
2015-12-03 00:37:37 +00:00
//memset(name2, 0, 30);
2015-12-03 00:37:02 +00:00
PHYSFS_read(fd, static_cast<void*>(&x), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&y), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&w), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&h), 1, 1);
PHYSFS_read(fd, static_cast<void*>(&sam), 1, 1);
2015-12-03 00:37:37 +00:00
// seek over the name embedded in the mapfile; use sample-num to
// lookup in msg-db
//PHYSFS_read(fd, static_cast<void*>(&name2), 30, 1);
PHYSFS_seek(fd, PHYSFS_tell(fd) + 30);
2015-12-03 00:37:02 +00:00
}
2015-12-03 00:37:37 +00:00
NavData::Sector::Sector() : Rect2D(), sam(0), name("") {
2015-12-03 00:37:02 +00:00
x = 0;
y = 0;
w = 255;
h = 255;
sam = 0;
isADummy = 1;
2015-12-03 00:37:37 +00:00
//memset(name2, 0, 30);
2015-12-03 00:37:02 +00:00
}
const char* NavData::Sector::getFullName() {
if (isADummy)
return "";
std::string n;
if (lastSubLocation == 0)
2015-12-03 00:38:22 +00:00
//n.append("Central ");
n.append(_c);
2015-12-03 00:37:02 +00:00
else if (lastSubLocation == 1)
2015-12-03 00:38:22 +00:00
//n.append("North ");
n.append(_n);
2015-12-03 00:37:02 +00:00
else if (lastSubLocation == 2)
2015-12-03 00:38:22 +00:00
n.append(_s);
//n.append("South ");
2015-12-03 00:37:02 +00:00
else if (lastSubLocation == 4)
2015-12-03 00:38:22 +00:00
n.append(_e);
//n.append("East ");
2015-12-03 00:37:02 +00:00
else if (lastSubLocation == 8)
2015-12-03 00:38:22 +00:00
n.append(_w);
//n.append("West ");
2015-12-03 00:37:02 +00:00
else if (lastSubLocation == 9)
2015-12-03 00:38:22 +00:00
n.append(_nw);
//n.append("Northwest ");
2015-12-03 00:37:02 +00:00
else if (lastSubLocation == 10)
2015-12-03 00:38:22 +00:00
n.append(_sw);
//n.append("Southwest ");
2015-12-03 00:37:02 +00:00
else if (lastSubLocation == 5)
2015-12-03 00:38:22 +00:00
n.append(_ne);
//n.append("Northeast ");
2015-12-03 00:37:02 +00:00
else if (lastSubLocation == 6)
2015-12-03 00:38:22 +00:00
n.append(_se);
//n.append("Southeast ");
n.append(" ");
2015-12-03 00:37:02 +00:00
n.append(name);
return n.c_str();
}
2015-12-03 00:38:22 +00:00
std::string NavData::_c;
std::string NavData::_n;
std::string NavData::_s;
std::string NavData::_w;
std::string NavData::_e;
std::string NavData::_nw;
std::string NavData::_ne;
std::string NavData::_sw;
std::string NavData::_se;
2015-12-03 00:37:37 +00:00
NavData::NavData(PHYSFS_uint32 size, PHYSFS_file *fd, const size_t level_num) {
2015-12-03 00:37:02 +00:00
if (size % 35) {
std::ostringstream o;
o << "Navdata size: " << size << " % 35 != 0";
throw E_INVALIDFORMAT(o.str());
//throw std::string("Invalid NavData size in mapfile");
}
PHYSFS_uint32 c = size / 35;
assert(fd);
2015-12-03 00:37:37 +00:00
MessageDB & msg = MainMsgHolder::Instance().get();
2015-12-03 00:38:22 +00:00
_c =msg.getText("c");
_n = msg.getText("n");
_s = msg.getText("s");
_w = msg.getText("w");
_e = msg.getText("e");
_nw = msg.getText("nw");
_ne = msg.getText("ne");
_sw = msg.getText("sw");
_se = msg.getText("se");
2015-12-03 00:37:02 +00:00
for (PHYSFS_uint32 i = 0; i < c; ++i) {
Sector *sec = new Sector(fd);
if (sec->getSize() == 0) { // workaround for 'NYC.CMP' (empty sectors)
delete sec;
WARN << "skipping zero size sector" << std::endl;
continue;
}
2015-12-03 00:37:37 +00:00
else {
std::ostringstream os;
os << std::setfill('0') << std::setw(3) << level_num << "area" << std::setfill('0') <<
std::setw(3) << int(sec->sam);
//INFO << i << " " << sec->name2 << std::endl << os.str() << " : " << msg.getText(os.str()) << std::endl;
sec->name = msg.getText(os.str());
2015-12-03 00:37:02 +00:00
areas.insert(std::pair<PHYSFS_uint16, Sector*>(sec->getSize(), sec));
2015-12-03 00:37:37 +00:00
}
2015-12-03 00:37:02 +00:00
}
// dummy catch-all sector for gta london maps
areas.insert(std::pair<PHYSFS_uint16, Sector*>(255*255, new Sector()));
2015-12-03 00:37:37 +00:00
2015-12-03 00:37:02 +00:00
/*
std::cout << "map areas (by size)" << std::endl;
SectorMapType::iterator i = areas.begin();
while (i != areas.end()) {
2015-12-03 00:37:37 +00:00
std::cout << " " << i->first << " : " << i->second->name2 << " @ " <<
2015-12-03 00:37:02 +00:00
int(i->second->x) << "," << int(i->second->y) << " " << int(i->second->w) << "x" <<
int(i->second->h) << " sample " << int(i->second->sam) << std::endl;
++i;
}
*/
}
NavData::~NavData() {
clear();
}
NavData::Sector* NavData::getSectorAt(PHYSFS_uint8 x, PHYSFS_uint8 y) {
SectorMapType::iterator it = areas.begin();
while (it != areas.end()) {
if (it->second->isInside(x, y))
return it->second;
++it;
}
std::ostringstream o;
o << "Querying invalid sector at " << int(x) << ", " << int(y);
throw E_OUTOFRANGE(o.str());
return NULL;
}
void NavData::clear() {
SectorMapType::iterator it = areas.begin();
while (it != areas.end()) {
delete it->second;
++it;
}
areas.clear();
}
}
#if 0
int main(int argc, char* argv[]) {
OpenGTA::Rect2D a(3, 4, 10, 20);
a.subLocation(atoi(argv[1]), atoi(argv[2]));
}
#endif