1 #include "stdafx.h"
2 #include "level_builder.h"
3 #include "progress_meter.h"
4 #include "square.h"
5 #include "creature.h"
6 #include "level_maker.h"
7 #include "collective_builder.h"
8 #include "view_object.h"
9 #include "item.h"
10 #include "furniture.h"
11 #include "furniture_factory.h"
12 #include "position.h"
13 #include "movement_set.h"
14
LevelBuilder(ProgressMeter * meter,RandomGen & r,int width,int height,const string & n,bool allCovered,optional<double> defaultLight)15 LevelBuilder::LevelBuilder(ProgressMeter* meter, RandomGen& r, int width, int height, const string& n, bool allCovered,
16 optional<double> defaultLight)
17 : squares(Rectangle(width, height)), unavailable(width, height, false),
18 heightMap(width, height, 0), covered(width, height, allCovered),
19 sunlight(width, height, defaultLight ? *defaultLight : (allCovered ? 0.0 : 1.0)),
20 attrib(width, height), items(width, height), furniture(Rectangle(width, height)),
21 name(n), progressMeter(meter), random(r) {
22 for (Vec2 v : squares.getBounds())
23 squares.putElem(v, {});
24 }
25
LevelBuilder(RandomGen & r,int width,int height,const string & n,bool covered)26 LevelBuilder::LevelBuilder(RandomGen& r, int width, int height, const string& n, bool covered)
27 : LevelBuilder(nullptr, r, width, height, n, covered) {
28 }
29
~LevelBuilder()30 LevelBuilder::~LevelBuilder() {}
31
32 LevelBuilder::LevelBuilder(LevelBuilder&&) = default;
33
getRandom()34 RandomGen& LevelBuilder::getRandom() {
35 return random;
36 }
37
hasAttrib(Vec2 posT,SquareAttrib attr)38 bool LevelBuilder::hasAttrib(Vec2 posT, SquareAttrib attr) {
39 Vec2 pos = transform(posT);
40 return attrib[pos].contains(attr);
41 }
42
addAttrib(Vec2 pos,SquareAttrib attr)43 void LevelBuilder::addAttrib(Vec2 pos, SquareAttrib attr) {
44 attrib[transform(pos)].insert(attr);
45 }
46
removeAttrib(Vec2 pos,SquareAttrib attr)47 void LevelBuilder::removeAttrib(Vec2 pos, SquareAttrib attr) {
48 attrib[transform(pos)].erase(attr);
49 }
50
modSquare(Vec2 pos)51 WSquare LevelBuilder::modSquare(Vec2 pos) {
52 return squares.getWritable(transform(pos));
53 }
54
toGlobalCoordinates(Rectangle area)55 Rectangle LevelBuilder::toGlobalCoordinates(Rectangle area) {
56 return area.apply([this](Vec2 v) { return transform(v); });
57 }
58
toGlobalCoordinates(vector<Vec2> v)59 vector<Vec2> LevelBuilder::toGlobalCoordinates(vector<Vec2> v) {
60 return v.transform([this](Vec2 v) { return transform(v); });
61 }
62
addCollective(CollectiveBuilder * col)63 void LevelBuilder::addCollective(CollectiveBuilder* col) {
64 if (!collectives.contains(col))
65 collectives.push_back(col);
66 }
67
setHeightMap(Vec2 pos,double h)68 void LevelBuilder::setHeightMap(Vec2 pos, double h) {
69 heightMap[transform(pos)] = h;
70 }
71
getHeightMap(Vec2 pos)72 double LevelBuilder::getHeightMap(Vec2 pos) {
73 return heightMap[transform(pos)];
74 }
75
putCreature(Vec2 pos,PCreature creature)76 void LevelBuilder::putCreature(Vec2 pos, PCreature creature) {
77 creatures.emplace_back(std::move(creature), transform(pos));
78 }
79
putItems(Vec2 posT,vector<PItem> it)80 void LevelBuilder::putItems(Vec2 posT, vector<PItem> it) {
81 CHECK(canNavigate(posT, {MovementTrait::WALK}));
82 Vec2 pos = transform(posT);
83 append(items[pos], std::move(it));
84 }
85
putFurniture(Vec2 posT,FurnitureFactory & f,optional<SquareAttrib> attrib)86 void LevelBuilder::putFurniture(Vec2 posT, FurnitureFactory& f, optional<SquareAttrib> attrib) {
87 putFurniture(posT, f.getRandom(getRandom()), attrib);
88 }
89
putFurniture(Vec2 posT,FurnitureParams f,optional<SquareAttrib> attrib)90 void LevelBuilder::putFurniture(Vec2 posT, FurnitureParams f, optional<SquareAttrib> attrib) {
91 auto layer = Furniture::getLayer(f.type);
92 if (getFurniture(posT, layer))
93 removeFurniture(posT, layer);
94 furniture.getBuilt(layer).putElem(transform(posT), f);
95 if (attrib)
96 addAttrib(posT, *attrib);
97 }
98
putFurniture(Vec2 pos,FurnitureType type,optional<SquareAttrib> attrib)99 void LevelBuilder::putFurniture(Vec2 pos, FurnitureType type, optional<SquareAttrib> attrib) {
100 putFurniture(pos, {type, TribeId::getHostile()}, attrib);
101 }
102
resetFurniture(Vec2 posT,FurnitureType type,optional<SquareAttrib> attrib)103 void LevelBuilder::resetFurniture(Vec2 posT, FurnitureType type, optional<SquareAttrib> attrib) {
104 CHECK(Furniture::getLayer(type) == FurnitureLayer::GROUND);
105 removeAllFurniture(posT);
106 putFurniture(posT, type, attrib);
107 }
108
canPutFurniture(Vec2 posT,FurnitureLayer layer)109 bool LevelBuilder::canPutFurniture(Vec2 posT, FurnitureLayer layer) {
110 return !getFurniture(posT, layer);
111 }
112
removeFurniture(Vec2 pos,FurnitureLayer layer)113 void LevelBuilder::removeFurniture(Vec2 pos, FurnitureLayer layer) {
114 furniture.getBuilt(layer).clearElem(transform(pos));
115 }
116
removeAllFurniture(Vec2 pos)117 void LevelBuilder::removeAllFurniture(Vec2 pos) {
118 for (auto layer : ENUM_ALL(FurnitureLayer))
119 removeFurniture(pos, layer);
120 }
121
getFurnitureType(Vec2 posT,FurnitureLayer layer)122 optional<FurnitureType> LevelBuilder::getFurnitureType(Vec2 posT, FurnitureLayer layer) {
123 if (auto f = getFurniture(posT, layer))
124 return f->getType();
125 else
126 return none;
127 }
128
isFurnitureType(Vec2 pos,FurnitureType type)129 bool LevelBuilder::isFurnitureType(Vec2 pos, FurnitureType type) {
130 return getFurnitureType(pos, Furniture::getLayer(type)) == type;
131 }
132
getFurniture(Vec2 posT,FurnitureLayer layer)133 WConstFurniture LevelBuilder::getFurniture(Vec2 posT, FurnitureLayer layer) {
134 return furniture.getBuilt(layer).getReadonly(transform(posT));
135 }
136
setLandingLink(Vec2 posT,StairKey key)137 void LevelBuilder::setLandingLink(Vec2 posT, StairKey key) {
138 Vec2 pos = transform(posT);
139 squares.getWritable(pos)->setLandingLink(key);
140 }
141
canPutCreature(Vec2 posT,WCreature c)142 bool LevelBuilder::canPutCreature(Vec2 posT, WCreature c) {
143 Vec2 pos = transform(posT);
144 if (!canNavigate(posT, c->getMovementType()))
145 return false;
146 for (pair<PCreature, Vec2>& c : creatures) {
147 if (c.second == pos)
148 return false;
149 }
150 return true;
151 }
152
setNoDiagonalPassing()153 void LevelBuilder::setNoDiagonalPassing() {
154 noDiagonalPassing = true;
155 }
156
build(WModel m,LevelMaker * maker,LevelId levelId)157 PLevel LevelBuilder::build(WModel m, LevelMaker* maker, LevelId levelId) {
158 CHECK(!!m);
159 CHECK(mapStack.empty());
160 maker->make(this, squares.getBounds());
161 for (Vec2 v : squares.getBounds())
162 if (!items[v].empty())
163 squares.getWritable(v)->dropItemsLevelGen(std::move(items[v]));
164 auto l = Level::create(std::move(squares), std::move(furniture), m, name, sunlight, levelId, covered);
165 l->unavailable = unavailable;
166 for (pair<PCreature, Vec2>& c : creatures)
167 Position(c.second, l.get()).addCreature(std::move(c.first));
168 for (CollectiveBuilder* c : collectives)
169 c->setLevel(l.get());
170 l->noDiagonalPassing = noDiagonalPassing;
171 return l;
172 }
173
identity()174 static Vec2::LinearMap identity() {
175 return [](Vec2 v) { return v; };
176 }
177
deg90(Rectangle bounds)178 static Vec2::LinearMap deg90(Rectangle bounds) {
179 return [bounds](Vec2 v) {
180 v -= bounds.topLeft();
181 return bounds.topLeft() + Vec2(v.y, v.x);
182 };
183 }
184
deg180(Rectangle bounds)185 static Vec2::LinearMap deg180(Rectangle bounds) {
186 return [bounds](Vec2 v) {
187 return bounds.topLeft() - v + bounds.bottomRight() - Vec2(1, 1);
188 };
189 }
190
deg270(Rectangle bounds)191 static Vec2::LinearMap deg270(Rectangle bounds) {
192 return [bounds](Vec2 v) {
193 v -= bounds.topRight() - Vec2(1, 0);
194 return bounds.topLeft() + Vec2(v.y, -v.x);
195 };
196 }
197
pushMap(Rectangle bounds,Rot rot)198 void LevelBuilder::pushMap(Rectangle bounds, Rot rot) {
199 switch (rot) {
200 case CW0: mapStack.push_back(identity()); break;
201 case CW1: mapStack.push_back(deg90(bounds)); break;
202 case CW2: mapStack.push_back(deg180(bounds)); break;
203 case CW3: mapStack.push_back(deg270(bounds)); break;
204 }
205 }
206
popMap()207 void LevelBuilder::popMap() {
208 mapStack.pop_back();
209 }
210
transform(Vec2 v)211 Vec2 LevelBuilder::transform(Vec2 v) {
212 for (auto m : mapStack.reverse()) {
213 v = m(v);
214 }
215 return v;
216 }
217
setCovered(Vec2 posT,bool state)218 void LevelBuilder::setCovered(Vec2 posT, bool state) {
219 covered[transform(posT)] = state;
220 }
221
setSunlight(Vec2 pos,double s)222 void LevelBuilder::setSunlight(Vec2 pos, double s) {
223 sunlight[pos] = s;
224 }
225
setUnavailable(Vec2 pos)226 void LevelBuilder::setUnavailable(Vec2 pos) {
227 unavailable[transform(pos)] = true;
228 }
229
canNavigate(Vec2 posT,const MovementType & movement)230 bool LevelBuilder::canNavigate(Vec2 posT, const MovementType& movement) {
231 Vec2 pos = transform(posT);
232 if (unavailable[pos])
233 return false;
234 bool result = true;
235 for (auto layer : ENUM_ALL(FurnitureLayer))
236 if (auto f = furniture.getBuilt(layer).getReadonly(pos)) {
237 bool canEnter = f->getMovementSet().canEnter(movement, covered[pos], false, none);
238 if (f->overridesMovement())
239 return canEnter;
240 else
241 result &= canEnter;
242 }
243 return result;
244
245 }
246