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 "unit.h"
00037 #include "unittype.h"
00038 #include "unit_cache.h"
00039 #include "map.h"
00040 #include "player.h"
00041
00042
00043
00044
00045
00055 CBuildRestrictionOnTop *OnTopDetails(const CUnit *unit, const CUnitType *parent)
00056 {
00057 CBuildRestrictionAnd *andb;
00058 CBuildRestrictionOnTop *ontopb;
00059
00060 for (std::vector<CBuildRestriction *>::iterator i = unit->Type->BuildingRules.begin();
00061 i != unit->Type->BuildingRules.end(); ++i) {
00062 if ((ontopb = dynamic_cast<CBuildRestrictionOnTop *>(*i))) {
00063 if (!parent) {
00064
00065 return ontopb;
00066 }
00067 if (parent == ontopb->Parent) {
00068 return ontopb;
00069 }
00070 } else if ((andb = dynamic_cast<CBuildRestrictionAnd *>(*i))) {
00071 for (std::vector<CBuildRestriction *>::iterator i = andb->_or_list.begin();
00072 i != andb->_or_list.end(); ++i) {
00073 if ((ontopb = dynamic_cast<CBuildRestrictionOnTop *>(*i))) {
00074 if (!parent) {
00075
00076 return ontopb;
00077 }
00078 if (parent == ontopb->Parent) {
00079 return ontopb;
00080 }
00081 }
00082 }
00083 }
00084 }
00085 return NULL;
00086 }
00087
00091 bool CBuildRestrictionAnd::Check(const CUnitType *type, int x, int y, CUnit *&ontoptarget) const
00092 {
00093 for (std::vector<CBuildRestriction*>::const_iterator i = _or_list.begin();
00094 i != _or_list.end(); ++i) {
00095 if (!(*i)->Check(type, x, y, ontoptarget)) {
00096 return false;
00097 }
00098 }
00099 return true;
00100 }
00101
00105 bool CBuildRestrictionDistance::Check(const CUnitType *type, int x, int y, CUnit *&ontoptarget) const
00106 {
00107 CUnit *table[UnitMax];
00108 int n;
00109 int x1 = 0;
00110 int x2 = 0;
00111 int y1 = 0;
00112 int y2 = 0;
00113 int distance = 0;
00114
00115 if (this->DistanceType == LessThanEqual ||
00116 this->DistanceType == GreaterThan ||
00117 this->DistanceType == Equal ||
00118 this->DistanceType == NotEqual) {
00119 x1 = std::max(x - this->Distance, 0);
00120 y1 = std::max(y - this->Distance, 0);
00121 x2 = std::min(x + type->TileWidth + this->Distance, Map.Info.MapWidth);
00122 y2 = std::min(y + type->TileHeight + this->Distance, Map.Info.MapHeight);
00123 distance = this->Distance;
00124 } else if (this->DistanceType == LessThan ||
00125 this->DistanceType == GreaterThanEqual) {
00126 x1 = std::max(x - this->Distance - 1, 0);
00127 y1 = std::max(y - this->Distance - 1, 0);
00128 x2 = std::min(x + type->TileWidth + this->Distance + 1, Map.Info.MapWidth);
00129 y2 = std::min(y + type->TileHeight + this->Distance + 1, Map.Info.MapHeight);
00130 distance = this->Distance - 1;
00131 }
00132 n = UnitCache.Select(x1, y1, x2, y2, table, UnitMax);
00133
00134 switch (this->DistanceType) {
00135 case GreaterThan :
00136 case GreaterThanEqual :
00137 for (int i = 0; i < n; ++i) {
00138 if (this->RestrictType == table[i]->Type &&
00139 MapDistanceBetweenTypes(type, x, y, table[i]->Type, table[i]->X, table[i]->Y) <= distance) {
00140 return false;
00141 }
00142 }
00143 return true;
00144 case LessThan :
00145 case LessThanEqual :
00146 for (int i = 0; i < n; ++i) {
00147 if (this->RestrictType == table[i]->Type &&
00148 MapDistanceBetweenTypes(type, x, y, table[i]->Type, table[i]->X, table[i]->Y) <= distance) {
00149 return true;
00150 }
00151 }
00152 return false;
00153 case Equal :
00154 for (int i = 0; i < n; ++i) {
00155 if (this->RestrictType == table[i]->Type &&
00156 MapDistanceBetweenTypes(type, x, y, table[i]->Type, table[i]->X, table[i]->Y) == distance) {
00157 return true;
00158 }
00159 }
00160 return false;
00161 case NotEqual :
00162 for (int i = 0; i < n; ++i) {
00163 if (this->RestrictType == table[i]->Type &&
00164 MapDistanceBetweenTypes(type, x, y, table[i]->Type, table[i]->X, table[i]->Y) == distance) {
00165 return false;
00166 }
00167 }
00168 return true;
00169 }
00170 return false;
00171 }
00172
00176 bool CBuildRestrictionAddOn::Check(const CUnitType *type, int x, int y, CUnit *&ontoptarget) const
00177 {
00178 CUnit *table[UnitMax];
00179 int n;
00180 int i;
00181 int x1;
00182 int y1;
00183
00184 x1 = x - this->OffsetX < 0 ? -1 : x - this->OffsetX;
00185 x1 = x1 >= Map.Info.MapWidth ? -1 : x1;
00186 y1 = y - this->OffsetY < 0 ? -1 : y - this->OffsetY;
00187 y1 = y1 >= Map.Info.MapHeight ? -1 : y1;
00188 if (!(x1 == -1 || y1 == -1)) {
00189 n = UnitCache.Select(x1, y1, table, UnitMax);
00190 for (i = 0; i < n; ++i) {
00191 if (table[i]->Type == this->Parent &&
00192 table[i]->X == x1 && table[i]->Y == y1) {
00193 return true;
00194 }
00195 }
00196 }
00197 return false;
00198 }
00199
00203 bool CBuildRestrictionOnTop::Check(const CUnitType *type, int x, int y, CUnit *&ontoptarget) const
00204 {
00205 CUnit *table[UnitMax];
00206 int n;
00207 int i;
00208
00209 ontoptarget = NULL;
00210 n = UnitCache.Select(x, y, table, UnitMax);
00211 for (i = 0; i < n; ++i) {
00212 if (table[i]->X == x && table[i]->Y == y && !table[i]->Destroyed &&
00213 table[i]->Orders[0]->Action != UnitActionDie) {
00214 if (table[i]->Type == this->Parent &&
00215 table[i]->Orders[0]->Action != UnitActionBuilt) {
00216
00217 ontoptarget = table[i];
00218 } else {
00219
00220 ontoptarget = NULL;
00221 return false;
00222 }
00223 }
00224 }
00225 return ontoptarget != NULL;
00226 }
00227
00228
00239 CUnit *CanBuildHere(const CUnit *unit, const CUnitType *type, int x, int y)
00240 {
00241 CUnit *ontoptarget;
00242
00243
00244
00245
00246 if (x + type->TileWidth > Map.Info.MapWidth) {
00247 return NULL;
00248 }
00249 if (y + type->TileHeight > Map.Info.MapHeight) {
00250 return NULL;
00251 }
00252
00253
00254 if (type->ShoreBuilding) {
00255 bool success = false;
00256
00257
00258 for (int h = type->TileHeight; h--;) {
00259 for (int w = type->TileWidth; w--;) {
00260 if (Map.Field(x + w, y + h)->Flags & MapFieldCoastAllowed) {
00261 h = w = 0;
00262 success = true;
00263 break;
00264 }
00265 }
00266 }
00267 if (!success) {
00268 return NULL;
00269 }
00270 }
00271
00272 if (type->BuildingRules.empty()) {
00273 return (unit == NULL) ? (CUnit *)1 : const_cast<CUnit *>(unit);
00274 }
00275
00276 ontoptarget = NULL;
00277 for (std::vector<CBuildRestriction *>::const_iterator ib = type->BuildingRules.begin();
00278 ib != type->BuildingRules.end(); ++ib) {
00279
00280 if ((*ib)->Check(type, x, y, ontoptarget)) {
00281
00282 if (unit == NULL) {
00283 return ontoptarget ? ontoptarget : (CUnit *)1;
00284 } else {
00285 return ontoptarget ? ontoptarget : (CUnit *)unit;
00286 }
00287 }
00288 }
00289 return NULL;
00290 }
00291
00301 bool CanBuildOn(int x, int y, int mask)
00302 {
00303 if (x < 0 || y < 0 || x >= Map.Info.MapWidth || y >= Map.Info.MapHeight) {
00304 return false;
00305 }
00306 return (Map.Field(x, y)->Flags & mask) ? false : true;
00307 }
00308
00320 CUnit *CanBuildUnitType(const CUnit *unit, const CUnitType *type, int x, int y, int real)
00321 {
00322 int j;
00323 int testmask;
00324 CPlayer *player;
00325 CUnit *ontop;
00326
00327
00328 ontop = CanBuildHere(unit, type, x, y);
00329 if (ontop == NULL) {
00330 return NULL;
00331 }
00332 if (ontop != (CUnit *)1 && ontop != unit) {
00333 return ontop;
00334 }
00335
00336
00337
00338
00339 j = 0;
00340 if (unit) {
00341 UnmarkUnitFieldFlags(unit);
00342 }
00343
00344 player = NULL;
00345
00346 if (unit && unit->Player->Type == PlayerPerson) {
00347 player = unit->Player;
00348 }
00349
00350 for (int h = type->TileHeight; h--;) {
00351 for (int w = type->TileWidth; w--;) {
00352 if (player && !real) {
00353 testmask = MapFogFilterFlags(player, x + w, y + h, type->MovementMask);
00354 } else {
00355 testmask = type->MovementMask;
00356 }
00357 if (!CanBuildOn(x + w, y + h, testmask)) {
00358 if (unit) {
00359 MarkUnitFieldFlags(unit);
00360 }
00361 return NULL;
00362 }
00363 if (player && !Map.IsFieldExplored(player, x + w, y + h)) {
00364 if (unit) {
00365 MarkUnitFieldFlags(unit);
00366 }
00367 return NULL;
00368 }
00369 }
00370 }
00371 if (unit) {
00372 MarkUnitFieldFlags(unit);
00373 }
00374
00375
00376
00377
00378 return ontop;
00379 }
00380