00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00030
00031
00032
00033
00034
00035 #include "stratagus.h"
00036 #include "patch_manager.h"
00037 #include "patch_type.h"
00038 #include "patch.h"
00039 #include "iolib.h"
00040 #include "map.h"
00041
00042 #include <algorithm>
00043 #include <sstream>
00044 #include <iomanip>
00045
00046
00047
00048
00049
00050
00051 CPatchManager::CPatchManager() :
00052 loadedAll(false)
00053 {
00054 }
00055
00056
00057 CPatchManager::~CPatchManager()
00058 {
00059 std::map<std::string, CPatchType *>::iterator i;
00060
00061 for (i = this->patchTypesMap.begin(); i != this->patchTypesMap.end(); ++i) {
00062 delete i->second;
00063 }
00064 }
00065
00066
00067 void
00068 CPatchManager::updateMapFlags(int x1, int y1, int x2, int y2)
00069 {
00070 x1 = std::max(x1, 0);
00071 y1 = std::max(y1, 0);
00072 x2 = std::min(x2, Map.Info.MapWidth - 1);
00073 y2 = std::min(y2, Map.Info.MapHeight - 1);
00074
00075 for (int j = y1; j <= y2; ++j) {
00076 for (int i = x1; i <= x2; ++i) {
00077 int offsetX, offsetY;
00078 CPatch *patch = this->getPatch(i, j, &offsetX, &offsetY);
00079 if (patch) {
00080 unsigned short flags = patch->getType()->getFlag(offsetX, offsetY);
00081 Map.Field(i, j)->Flags = flags;
00082 Map.Field(i, j)->Cost = 1 << (flags & MapFieldSpeedMask);
00083 }
00084 }
00085 }
00086 }
00087
00088 CPatch *
00089 CPatchManager::add(const std::string &typeName, int x, int y)
00090 {
00091 CPatchType *type = this->patchTypesMap[typeName];
00092 Assert(type);
00093 if (!type) {
00094 fprintf(stderr, "Patch not found: %s\n", typeName.c_str());
00095 return NULL;
00096 }
00097
00098 CPatch *patch = new CPatch(type, x, y);
00099 this->patches.push_back(patch);
00100
00101 updateMapFlags(x, y, x + type->getTileWidth() - 1, y + type->getTileHeight() - 1);
00102
00103 return patch;
00104 }
00105
00106 void
00107 CPatchManager::remove(CPatch *patch)
00108 {
00109 this->patches.remove(patch);
00110 this->removedPatches.push_back(patch);
00111
00112 updateMapFlags(patch->getX(), patch->getY(),
00113 patch->getX() + patch->getType()->getTileWidth(),
00114 patch->getY() + patch->getType()->getTileHeight());
00115 }
00116
00117 void
00118 CPatchManager::move(CPatch *patch, int x, int y)
00119 {
00120 if (x != patch->getX() || y != patch->getY()) {
00121 int x1, y1, x2, y2;
00122
00123 if (x < patch->getX()) {
00124 x1 = x;
00125 x2 = patch->getX() + patch->getType()->getTileWidth() - 1;
00126 } else {
00127 x1 = patch->getX();
00128 x2 = x + patch->getType()->getTileWidth() - 1;
00129 }
00130 if (y < patch->getY()) {
00131 y1 = y;
00132 y2 = patch->getY() + patch->getType()->getTileHeight() - 1;
00133 } else {
00134 y1 = patch->getY();
00135 y2 = y + patch->getType()->getTileHeight() - 1;
00136 }
00137
00138 patch->setPos(x, y);
00139
00140 updateMapFlags(x1, y1, x2, y2);
00141 }
00142 }
00143
00144 void
00145 CPatchManager::moveToTop(CPatch *patch)
00146 {
00147 this->patches.remove(patch);
00148 this->patches.push_back(patch);
00149
00150 updateMapFlags(patch->getX(), patch->getY(),
00151 patch->getX() + patch->getType()->getTileWidth() - 1,
00152 patch->getY() + patch->getType()->getTileHeight() - 1);
00153 }
00154
00155
00156 void
00157 CPatchManager::moveToBottom(CPatch *patch)
00158 {
00159 this->patches.remove(patch);
00160 this->patches.push_front(patch);
00161
00162 updateMapFlags(patch->getX(), patch->getY(),
00163 patch->getX() + patch->getType()->getTileWidth() - 1,
00164 patch->getY() + patch->getType()->getTileHeight() - 1);
00165 }
00166
00167
00168 CPatch *
00169 CPatchManager::getPatch(int x, int y, int *xOffset, int *yOffset) const
00170 {
00171 std::list<CPatch *>::const_reverse_iterator i;
00172 std::list<CPatch *>::const_reverse_iterator rend;
00173
00174
00175 rend = this->patches.rend();
00176 for (i = this->patches.rbegin(); i != rend; ++i) {
00177 int patchX = (*i)->getX();
00178 int patchY = (*i)->getY();
00179 CPatchType *patchType = (*i)->getType();
00180
00181
00182 if (patchX <= x && x < patchX + patchType->getTileWidth() &&
00183 patchY <= y && y < patchY + patchType->getTileHeight()) {
00184 int xPatchOffset = x - patchX;
00185 int yPatchOffset = y - patchY;
00186 unsigned short flag = patchType->getFlag(xPatchOffset, yPatchOffset);
00187
00188
00189 if (!(flag & MapFieldTransparent)) {
00190 if (xOffset != NULL && yOffset != NULL) {
00191 *xOffset = xPatchOffset;
00192 *yOffset = yPatchOffset;
00193 }
00194
00195 return *i;
00196 }
00197 }
00198 }
00199 return NULL;
00200 }
00201
00202 std::list<CPatch *>
00203 CPatchManager::getPatches() const
00204 {
00205 return this->patches;
00206 }
00207
00208 std::vector<std::string>
00209 CPatchManager::getPatchTypeNames() const
00210 {
00211 std::vector<std::string> names;
00212 std::map<std::string, CPatchType *>::const_iterator i;
00213
00214 for (i = this->patchTypesMap.begin(); i != this->patchTypesMap.end(); ++i) {
00215 names.push_back(i->second->getName());
00216 }
00217
00218 return names;
00219 }
00220
00221
00222 void
00223 CPatchManager::load()
00224 {
00225 std::list<CPatch *>::iterator i;
00226 for (i = this->patches.begin(); i != this->patches.end(); ++i) {
00227 (*i)->getType()->load();
00228 }
00229 }
00230
00231 void
00232 CPatchManager::loadAll()
00233 {
00234 std::map<std::string, CPatchType *>::const_iterator i;
00235
00236 for (i = this->patchTypesMap.begin(); i != this->patchTypesMap.end(); ++i) {
00237 i->second->load();
00238 }
00239
00240 loadedAll = true;
00241 }
00242
00243 static void clearPatches(std::list<CPatch *> &patches)
00244 {
00245 std::list<CPatch *>::iterator i;
00246 for (i = patches.begin(); i != patches.end(); ++i) {
00247 (*i)->getType()->clean();
00248 delete *i;
00249 }
00250 patches.clear();
00251 }
00252
00253 void
00254 CPatchManager::clear()
00255 {
00256 clearPatches(this->patches);
00257 clearPatches(this->removedPatches);
00258
00259 if (loadedAll) {
00260 std::map<std::string, CPatchType *>::const_iterator i;
00261
00262 for (i = this->patchTypesMap.begin(); i != this->patchTypesMap.end(); ++i) {
00263 i->second->clean();
00264 }
00265 loadedAll = false;
00266 }
00267 }
00268
00269
00270
00271 CPatchType *
00272 CPatchManager::newPatchType(const std::string &name, const std::string &file,
00273 int tileWidth, int tileHeight, int *flags)
00274 {
00275 unsigned short *newFlags = new unsigned short[tileWidth * tileHeight];
00276 for (int i = 0; i < tileWidth * tileHeight; ++i) {
00277 newFlags[i] = flags[i];
00278 }
00279
00280 CPatchType *patchType = newPatchType(name, file, tileWidth, tileHeight, newFlags);
00281
00282 delete[] newFlags;
00283 return patchType;
00284 }
00285
00286 CPatchType *
00287 CPatchManager::newPatchType(const std::string &name, const std::string &file,
00288 int tileWidth, int tileHeight, unsigned short *flags)
00289 {
00290
00291 if (this->patchTypesMap[name] != NULL) {
00292 return this->patchTypesMap[name];
00293 }
00294
00295 CPatchType *patchType = new CPatchType(name, file, tileWidth, tileHeight, flags);
00296 this->patchTypesMap[name] = patchType;
00297
00298 return patchType;
00299 }
00300
00301 CPatchType *
00302 CPatchManager::getPatchType(const std::string &name)
00303 {
00304 return this->patchTypesMap[name];
00305 }
00306
00307 std::string
00308 CPatchManager::savePatches(bool patchesOnly) const
00309 {
00310 std::map<std::string, bool> patchTypeSaved;
00311 std::list<CPatch *>::const_iterator i;
00312 std::ostringstream ostr;
00313
00314 for (i = this->patches.begin(); i != this->patches.end(); ++i) {
00315 const std::string &name = (*i)->getType()->getName();
00316
00317 if (!patchesOnly && !patchTypeSaved[name]) {
00318 ostr << this->savePatchType((*i)->getType());
00319 patchTypeSaved[name] = true;
00320 }
00321
00322 ostr << "patch(\"" << name << "\", "
00323 << (*i)->getX() << ", " << (*i)->getY() << ")\n";
00324 }
00325
00326 return ostr.str();
00327 }
00328
00329 std::string
00330 CPatchManager::savePatchType(CPatchType *patchType) const
00331 {
00332 std::ostringstream ostr;
00333
00334 ostr << "patchType(\"" << patchType->getName() << "\", \""
00335 << patchType->getGraphic()->File << "\", "
00336 << patchType->getTileWidth() << ", "
00337 << patchType->getTileHeight() << ", {\n";
00338
00339 for (int j = 0; j < patchType->getTileHeight(); ++j) {
00340 for (int i = 0; i < patchType->getTileWidth(); ++i) {
00341 std::ostringstream flag;
00342 flag << " 0x"
00343 << std::hex << std::setw(4) << std::setfill('0')
00344 << patchType->getFlag(i, j);
00345 ostr << flag.str() << ",";
00346 }
00347 ostr << "\n";
00348 }
00349
00350 ostr << "})\n";
00351
00352 return ostr.str();
00353 }
00354