-
Notifications
You must be signed in to change notification settings - Fork 6
/
navdata.cpp
229 lines (211 loc) · 6.64 KB
/
navdata.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/************************************************************************
* Copyright (c) 2005-2007 [email protected] *
* *
* 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>
#include <iomanip>
#include "navdata.h"
#include "log.h"
#include "dataholder.h"
#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;
}
NavData::Sector::Sector(PHYSFS_file* fd) : Rect2D(), sam(0), name("") {
sam = 0;
isADummy = 0;
assert(fd);
//memset(name2, 0, 30);
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);
// 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);
}
NavData::Sector::Sector() : Rect2D(), sam(0), name("") {
x = 0;
y = 0;
w = 255;
h = 255;
sam = 0;
isADummy = 1;
//memset(name2, 0, 30);
}
const char* NavData::Sector::getFullName() {
if (isADummy)
return "";
std::string n;
if (lastSubLocation == 0)
//n.append("Central ");
n.append(_c);
else if (lastSubLocation == 1)
//n.append("North ");
n.append(_n);
else if (lastSubLocation == 2)
n.append(_s);
//n.append("South ");
else if (lastSubLocation == 4)
n.append(_e);
//n.append("East ");
else if (lastSubLocation == 8)
n.append(_w);
//n.append("West ");
else if (lastSubLocation == 9)
n.append(_nw);
//n.append("Northwest ");
else if (lastSubLocation == 10)
n.append(_sw);
//n.append("Southwest ");
else if (lastSubLocation == 5)
n.append(_ne);
//n.append("Northeast ");
else if (lastSubLocation == 6)
n.append(_se);
//n.append("Southeast ");
n.append(" ");
n.append(name);
return n.c_str();
}
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;
NavData::NavData(PHYSFS_uint32 size, PHYSFS_file *fd, const size_t level_num) {
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);
MessageDB & msg = MainMsgHolder::Instance().get();
_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");
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;
}
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());
areas.insert(std::pair<PHYSFS_uint16, Sector*>(sec->getSize(), sec));
}
}
// dummy catch-all sector for gta london maps
areas.insert(std::pair<PHYSFS_uint16, Sector*>(255*255, new Sector()));
/*
std::cout << "map areas (by size)" << std::endl;
SectorMapType::iterator i = areas.begin();
while (i != areas.end()) {
std::cout << " " << i->first << " : " << i->second->name2 << " @ " <<
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