1 /* Copyright (C) 2013-2014 Michal Brzozowski (rusolis@poczta.fm)
2 
3    This file is part of KeeperRL.
4 
5    KeeperRL is free software; you can redistribute it and/or modify it under the terms of the
6    GNU General Public License as published by the Free Software Foundation; either version 2
7    of the License, or (at your option) any later version.
8 
9    KeeperRL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10    even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License along with this program.
14    If not, see http://www.gnu.org/licenses/ . */
15 
16 #include "stdafx.h"
17 
18 #include "level_maker.h"
19 #include "item_factory.h"
20 #include "square.h"
21 #include "collective_builder.h"
22 #include "collective.h"
23 #include "shortest_path.h"
24 #include "creature.h"
25 #include "level_builder.h"
26 #include "model.h"
27 #include "monster_ai.h"
28 #include "item.h"
29 #include "view_id.h"
30 #include "furniture_type.h"
31 #include "furniture_factory.h"
32 #include "furniture.h"
33 #include "progress.h"
34 #include "file_path.h"
35 #include "movement_set.h"
36 #include "container_range.h"
37 #include "settlement_info.h"
38 #include "task.h"
39 
40 namespace {
41 
failGen()42 void failGen() {
43   throw LevelGenException();
44 }
45 
checkGen(bool b)46 void checkGen(bool b) {
47   if (!b)
48     failGen();
49 }
50 
51 class Predicate {
52   public:
apply(LevelBuilder * builder,Vec2 pos) const53   bool apply(LevelBuilder* builder, Vec2 pos) const {
54     return predFun(builder, pos);
55   }
56 
getRandomPosition(LevelBuilder * builder,Rectangle area)57   Vec2 getRandomPosition(LevelBuilder* builder, Rectangle area) {
58     vector<Vec2> good;
59     for (Vec2 v : area)
60       if (apply(builder, v))
61         good.push_back(v);
62     if (good.empty())
63       failGen();
64     return builder->getRandom().choose(good);
65   }
66 
attrib(SquareAttrib attr)67   static Predicate attrib(SquareAttrib attr) {
68     return Predicate([=] (LevelBuilder* builder, Vec2 pos) { return builder->hasAttrib(pos, attr);});
69   }
70 
operator !() const71   Predicate operator !() const {
72     PredFun self(predFun);
73     return Predicate([self] (LevelBuilder* builder, Vec2 pos) { return !self(builder, pos);});
74   }
75 
operator &&(const Predicate & p1) const76   Predicate operator && (const Predicate& p1) const {
77     PredFun self(predFun);
78     return Predicate([self, p1] (LevelBuilder* builder, Vec2 pos) {
79         return p1.apply(builder, pos) && self(builder, pos);});
80   }
81 
operator ||(const Predicate & p1) const82   Predicate operator || (const Predicate& p1) const {
83     PredFun self(predFun);
84     return Predicate([=] (LevelBuilder* builder, Vec2 pos) {
85         return p1.apply(builder, pos) || self(builder, pos);});
86   }
87 
type(FurnitureType t)88   static Predicate type(FurnitureType t) {
89     return Predicate([=] (LevelBuilder* builder, Vec2 pos) {
90       return builder->isFurnitureType(pos, t);});
91   }
92 
inRectangle(Rectangle r)93   static Predicate inRectangle(Rectangle r) {
94     return Predicate([=] (LevelBuilder* builder, Vec2 pos) {
95       return pos.inRectangle(r);});
96   }
97 
alwaysTrue()98   static Predicate alwaysTrue() {
99     return Predicate([=] (LevelBuilder* builder, Vec2 pos) { return true;});
100   }
101 
alwaysFalse()102   static Predicate alwaysFalse() {
103     return Predicate([=] (LevelBuilder* builder, Vec2 pos) { return false;});
104   }
105 
canEnter(MovementType m)106   static Predicate canEnter(MovementType m) {
107     return Predicate([=] (LevelBuilder* builder, Vec2 pos) { return builder->canNavigate(pos, m);});
108   }
109 
110   private:
111   typedef function<bool(LevelBuilder*, Vec2)> PredFun;
Predicate(PredFun fun)112   Predicate(PredFun fun) : predFun(fun) {}
113   PredFun predFun;
114 };
115 
116 class SquareChange {
117   public:
none()118   static SquareChange none() {
119     return SquareChange([](LevelBuilder*, Vec2) {});
120   }
121 
add(SquareChange added)122   SquareChange& add(SquareChange added) {
123     auto funCopy = changeFun; // copy just the function because storing this leads to a crash
124     changeFun = [added, funCopy] (LevelBuilder* builder, Vec2 pos) {
125         funCopy(builder, pos); added.changeFun(builder, pos); };
126     return *this;
127   }
128 
SquareChange(FurnitureType type,optional<SquareAttrib> attrib=::none)129   SquareChange(FurnitureType type, optional<SquareAttrib> attrib = ::none)
130       : changeFun([=](LevelBuilder* builder, Vec2 pos) {
131     builder->putFurniture(pos, type);
132     if (attrib)
133       builder->addAttrib(pos, *attrib);
134   }) {}
135 
SquareChange(SquareAttrib attrib)136   SquareChange(SquareAttrib attrib)
137       : changeFun([=](LevelBuilder* builder, Vec2 pos) {
138     builder->addAttrib(pos, attrib);
139   }) {}
140 
SquareChange(FurnitureType f1,FurnitureType f2)141   SquareChange(FurnitureType f1, FurnitureType f2)
142       : changeFun([=](LevelBuilder* builder, Vec2 pos) {
143     builder->putFurniture(pos, f1);
144     builder->putFurniture(pos, f2); }) {}
145 
reset(FurnitureType f1)146   static SquareChange reset(FurnitureType f1) {
147     return SquareChange([=](LevelBuilder* builder, Vec2 pos) {
148       builder->resetFurniture(pos, f1);
149     });
150   }
151 
apply(LevelBuilder * builder,Vec2 pos)152   void apply(LevelBuilder* builder, Vec2 pos) {
153     changeFun(builder, pos);
154   }
155 
156   private:
157   typedef function<void(LevelBuilder*, Vec2)> ChangeFun;
SquareChange(ChangeFun fun)158   SquareChange(ChangeFun fun) : changeFun(fun) {}
159   ChangeFun changeFun;
160 
161 };
162 
163 class Empty : public LevelMaker {
164   public:
Empty(SquareChange s)165   Empty(SquareChange s) : square(s) {}
166 
make(LevelBuilder * builder,Rectangle area)167   virtual void make(LevelBuilder* builder, Rectangle area) override {
168     for (Vec2 v : area)
169       square.apply(builder, v);
170   }
171 
172   private:
173   SquareChange square;
174 };
175 
176 class RoomMaker : public LevelMaker {
177   public:
RoomMaker(int _numRooms,int _minSize,int _maxSize,SquareChange wall=SquareChange::none (),optional<FurnitureType> _onType=none,PLevelMaker _roomContents=unique<Empty> (FurnitureType::FLOOR),vector<PLevelMaker> _insideMakers={},bool _diggableCorners=false)178   RoomMaker(int _numRooms,
179             int _minSize, int _maxSize,
180             SquareChange wall = SquareChange::none(),
181             optional<FurnitureType> _onType = none,
182             PLevelMaker _roomContents = unique<Empty>(FurnitureType::FLOOR),
183             vector<PLevelMaker> _insideMakers = {},
184             bool _diggableCorners = false) :
185       numRooms(_numRooms),
186       minSize(_minSize),
187       maxSize(_maxSize),
188       wallChange(wall.add(SquareChange(SquareAttrib::ROOM_WALL))),
189       onType(_onType),
190       roomContents(std::move(_roomContents)),
191       insideMakers(std::move(_insideMakers)),
192       diggableCorners(_diggableCorners) {}
193 
make(LevelBuilder * builder,Rectangle area)194   virtual void make(LevelBuilder* builder, Rectangle area) override {
195     int spaceBetween = 0;
196     Table<int> taken(area.right(), area.bottom());
197     for (Vec2 v : area)
198       taken[v] = onType && !builder->isFurnitureType(v, *onType);
199     for (int i : Range(numRooms)) {
200       Vec2 p, k;
201       bool good;
202       int cnt = 100;
203       do {
204         k = Vec2(builder->getRandom().get(minSize, maxSize), builder->getRandom().get(minSize, maxSize));
205         p = Vec2(area.left() + spaceBetween + builder->getRandom().get(area.width() - k.x - 2 * spaceBetween),
206                  area.top() + spaceBetween + builder->getRandom().get(area.height() - k.y - 2 * spaceBetween));
207         good = true;
208         for (Vec2 v : Rectangle(k.x + 2 * spaceBetween, k.y + 2 * spaceBetween))
209           if (taken[p + v - Vec2(spaceBetween,spaceBetween)]) {
210             good = false;
211             break;
212           }
213       } while (!good && --cnt > 0);
214       if (cnt == 0) {
215         INFO << "Placed only " << i << " rooms out of " << numRooms;
216         break;
217       }
218       for (Vec2 v : Rectangle(k))
219         taken[v + p] = 1;
220       for (Vec2 v : Rectangle(k - Vec2(2, 2)))
221         builder->resetFurniture(p + v + Vec2(1, 1), FurnitureType::FLOOR, SquareAttrib::ROOM);
222       for (int i : Range(p.x, p.x + k.x)) {
223         wallChange.apply(builder, Vec2(i, p.y));
224         wallChange.apply(builder, Vec2(i, p.y + k.y - 1));
225         if ((i == p.x || i == p.x + k.x - 1) && !diggableCorners) {
226           builder->addAttrib(Vec2(i, p.y), SquareAttrib::NO_DIG);
227           builder->addAttrib(Vec2(i, p.y + k.y - 1), SquareAttrib::NO_DIG);
228         }
229       }
230       for (int i : Range(p.y + 1, p.y + k.y - 1)) {
231         wallChange.apply(builder, Vec2(p.x, i));
232         wallChange.apply(builder, Vec2(p.x + k.x - 1, i));
233       }
234       Rectangle inside(p.x + 1, p.y + 1, p.x + k.x - 1, p.y + k.y - 1);
235       roomContents->make(builder, inside);
236       if (i < insideMakers.size())
237         insideMakers[i]->make(builder, inside);
238       else
239         for (Vec2 v : inside)
240           builder->addAttrib(v, SquareAttrib::EMPTY_ROOM);
241     }
242   }
243 
244   private:
245   int numRooms;
246   int minSize;
247   int maxSize;
248   SquareChange wallChange;
249   optional<FurnitureType> onType;
250   PLevelMaker roomContents;
251   vector<PLevelMaker> insideMakers;
252   bool diggableCorners;
253 };
254 
255 class Connector : public LevelMaker {
256   public:
Connector(optional<FurnitureFactory> _door,double _doorProb,double _diggingCost=3,Predicate pred=Predicate::canEnter ({MovementTrait::WALK}),optional<SquareAttrib> setAttr=none)257   Connector(optional<FurnitureFactory> _door, double _doorProb, double _diggingCost = 3,
258         Predicate pred = Predicate::canEnter({MovementTrait::WALK}), optional<SquareAttrib> setAttr = none)
259       : door(_door), doorProb(_doorProb), diggingCost(_diggingCost), connectPred(pred), setAttrib(setAttr) {
260   }
getValue(LevelBuilder * builder,Vec2 pos,Rectangle area)261   double getValue(LevelBuilder* builder, Vec2 pos, Rectangle area) {
262     if (builder->canNavigate(pos, {MovementTrait::WALK}))
263       return 1;
264     if (builder->hasAttrib(pos, SquareAttrib::NO_DIG))
265       return ShortestPath::infinity;
266     if (builder->hasAttrib(pos, SquareAttrib::LAKE))
267       return 15;
268     if (builder->hasAttrib(pos, SquareAttrib::RIVER))
269       return 15;
270     int numCorners = 0;
271     int numTotal = 0;
272     for (Vec2 v : Vec2::directions8())
273       if ((pos + v).inRectangle(area) && builder->canNavigate(pos + v, MovementTrait::WALK)) {
274         if (abs(v.x) == abs(v.y))
275           ++numCorners;
276         ++numTotal;
277       }
278     if (numCorners == 1)
279       return 1000;
280     if (numTotal - numCorners > 1)
281       return diggingCost + 5;
282     return diggingCost;
283   }
284 
connect(LevelBuilder * builder,Vec2 p1,Vec2 p2,Rectangle area)285   void connect(LevelBuilder* builder, Vec2 p1, Vec2 p2, Rectangle area) {
286     ShortestPath path(area,
287         [builder, this, &area](Vec2 pos) { return getValue(builder, pos, area); },
288         [] (Vec2 v) { return v.length4(); },
289         Vec2::directions4(builder->getRandom()), p1 ,p2);
290     for (Vec2 v = p2; v != p1; v = path.getNextMove(v)) {
291       if (!builder->canNavigate(v, {MovementTrait::WALK})) {
292         if (auto furniture = builder->getFurniture(v, FurnitureLayer::MIDDLE)) {
293           bool placeDoor = furniture->isWall() && builder->hasAttrib(v, SquareAttrib::ROOM_WALL);
294           if (!furniture->getMovementSet().canEnter({MovementTrait::WALK}))
295             builder->removeFurniture(v, FurnitureLayer::MIDDLE);
296           if (placeDoor && door && builder->getRandom().chance(doorProb))
297             builder->putFurniture(v, *door);
298         }
299         if (builder->canNavigate(v, {MovementTrait::WALK}))
300           continue;
301         if (builder->getFurniture(v, FurnitureLayer::GROUND)->canBuildBridgeOver())
302           builder->putFurniture(v, FurnitureType::BRIDGE);
303       }
304       if (!path.isReachable(v))
305         failGen();
306     }
307   }
308 
make(LevelBuilder * builder,Rectangle area)309   virtual void make(LevelBuilder* builder, Rectangle area) override {
310     Vec2 p1, p2;
311     vector<Vec2> points = area.getAllSquares().filter([&] (Vec2 v) { return connectPred.apply(builder, v);});
312     if (points.size() < 2)
313       return;
314     for (int i : Range(30)) {
315       p1 = builder->getRandom().choose(points);
316       p2 = builder->getRandom().choose(points);
317       if (p1 != p2)
318         connect(builder, p1, p2, area);
319     }
320     auto dijkstraFun = [&] (Vec2 pos) {
321       if (builder->canNavigate(pos, MovementTrait::WALK))
322         return 1.;
323       else
324         return ShortestPath::infinity;};
325     Table<bool> connected(area, false);
326     while (1) {
327       Dijkstra dijkstra(area, p1, 10000, dijkstraFun);
328       for (Vec2 v : area)
329         if (dijkstra.isReachable(v))
330           connected[v] = true;
331       bool found = false;
332       for (Vec2 v : area)
333         if (connectPred.apply(builder, v) && !connected[v]) {
334           connect(builder, p1, v, area);
335           p1 = v;
336           found = true;
337           break;
338          }
339       if (!found)
340         break;
341     }
342   }
343 
344   private:
345   optional<FurnitureFactory> door;
346   double doorProb;
347   double diggingCost;
348   Predicate connectPred;
349   optional<SquareAttrib> setAttrib;
350 };
351 
352 namespace {
353 class Furnitures : public LevelMaker {
354   public:
Furnitures(Predicate pred,double _density,FurnitureFactory _factory,optional<SquareAttrib> setAttr=none)355   Furnitures(Predicate pred, double _density, FurnitureFactory _factory, optional<SquareAttrib> setAttr = none):
356       factory(_factory), density(_density), predicate(pred), attr(setAttr) {
357   }
358 
make(LevelBuilder * builder,Rectangle area)359   virtual void make(LevelBuilder* builder, Rectangle area) override {
360     vector<Vec2> available;
361     for (Vec2 v : area)
362       if (predicate.apply(builder, v) && builder->canPutFurniture(v, FurnitureLayer::MIDDLE))
363         available.push_back(v);
364     for (int i : Range(available.size() * density)) {
365       Vec2 pos = builder->getRandom().choose(available);
366       builder->putFurniture(pos, factory);
367       if (attr)
368         builder->addAttrib(pos, *attr);
369       available.removeElement(pos);
370     }
371   }
372 
373   private:
374   FurnitureFactory factory;
375   double density;
376   Predicate predicate;
377   optional<SquareAttrib> attr;
378 };
379 }
380 
381 class Inhabitants : public LevelMaker {
382   public:
383 
Inhabitants(InhabitantsInfo inhab,CollectiveBuilder * col,Predicate pred=Predicate::alwaysTrue ())384   Inhabitants(InhabitantsInfo inhab, CollectiveBuilder* col, Predicate pred = Predicate::alwaysTrue()) :
385       inhabitants(inhab), actorFactory(MonsterAIFactory::monster()), onPred(pred), collective(col) {}
386 
make(LevelBuilder * builder,Rectangle area)387   virtual void make(LevelBuilder* builder, Rectangle area) override {
388     if (!actorFactory)
389       actorFactory = MonsterAIFactory::stayInLocation(builder->toGlobalCoordinates(area));
390     Table<char> taken(area.right(), area.bottom());
391     for (auto& minion : inhabitants.generateCreatures(builder->getRandom(), collective->getTribe(), *actorFactory)) {
392       PCreature& creature = minion.first;
393       Vec2 pos;
394       int numTries = 100;
395       do {
396         pos = Vec2(builder->getRandom().get(area.left(), area.right()),
397             builder->getRandom().get(area.top(), area.bottom()));
398       } while (--numTries > 0 && (!builder->canPutCreature(pos, creature.get()) || (!onPred.apply(builder, pos))));
399       checkGen(numTries > 0);
400       if (collective) {
401         collective->addCreature(creature.get(), minion.second);
402         builder->addCollective(collective);
403       }
404       builder->putCreature(pos, std::move(creature));
405       taken[pos] = 1;
406     }
407   }
408 
409   private:
410   InhabitantsInfo inhabitants;
411   optional<MonsterAIFactory> actorFactory;
412   Predicate onPred;
413   CollectiveBuilder* collective = nullptr;
414 };
415 
416 class Creatures : public LevelMaker {
417   public:
Creatures(CreatureFactory f,int num,MonsterAIFactory actorF,Predicate pred=Predicate::alwaysTrue ())418   Creatures(CreatureFactory f, int num, MonsterAIFactory actorF, Predicate pred = Predicate::alwaysTrue()) :
419       creatures(f), numCreatures(num), actorFactory(actorF), onPred(pred) {}
420 
make(LevelBuilder * builder,Rectangle area)421   virtual void make(LevelBuilder* builder, Rectangle area) override {
422     if (!actorFactory)
423       actorFactory = MonsterAIFactory::stayInLocation(builder->toGlobalCoordinates(area));
424     Table<char> taken(area.right(), area.bottom());
425     for (int i : Range(numCreatures)) {
426       PCreature creature = creatures.random(*actorFactory);
427       Vec2 pos;
428       int numTries = 100;
429       do {
430         pos = Vec2(builder->getRandom().get(area.left(), area.right()),
431             builder->getRandom().get(area.top(), area.bottom()));
432       } while (--numTries > 0 && (!builder->canPutCreature(pos, creature.get()) || (!onPred.apply(builder, pos))));
433       checkGen(numTries > 0);
434       builder->putCreature(pos, std::move(creature));
435       taken[pos] = 1;
436     }
437   }
438 
439   private:
440   CreatureFactory creatures;
441   int numCreatures;
442   optional<MonsterAIFactory> actorFactory;
443   Predicate onPred;
444 };
445 
446 class Items : public LevelMaker {
447   public:
Items(ItemFactory _factory,int minc,int maxc,Predicate pred=Predicate::alwaysTrue (),bool _placeOnFurniture=false)448   Items(ItemFactory _factory, int minc, int maxc, Predicate pred = Predicate::alwaysTrue(),
449       bool _placeOnFurniture = false) :
450       factory(_factory), minItem(minc), maxItem(maxc), predicate(pred), placeOnFurniture(_placeOnFurniture) {}
451 
make(LevelBuilder * builder,Rectangle area)452   virtual void make(LevelBuilder* builder, Rectangle area) override {
453     int numItem = builder->getRandom().get(minItem, maxItem);
454     for (int i : Range(numItem)) {
455       Vec2 pos;
456       do {
457         pos = Vec2(builder->getRandom().get(area.left(), area.right()), builder->getRandom().get(area.top(),
458               area.bottom()));
459       } while (!predicate.apply(builder, pos) ||
460            !builder->canNavigate(pos, MovementTrait::WALK) ||
461            (!placeOnFurniture && builder->getFurniture(pos, FurnitureLayer::MIDDLE)));
462       builder->putItems(pos, factory.random());
463     }
464   }
465 
466   private:
467   ItemFactory factory;
468   int minItem;
469   int maxItem;
470   Predicate predicate;
471   bool placeOnFurniture;
472 };
473 
474 class River : public LevelMaker {
475   public:
River(int _width,FurnitureType type)476   River(int _width, FurnitureType type) : width(_width), furnitureType(type){}
477 
make(LevelBuilder * builder,Rectangle area)478   virtual void make(LevelBuilder* builder, Rectangle area) override {
479     int wind = 5;
480     int middle = (area.left() + area.right()) / 2;
481     int px = builder->getRandom().get(middle - wind, middle + width);
482     int kx = px + builder->getRandom().get(-wind, wind); // builder->getRandom().get(area.left(), area.right()) - width;
483     if (kx < 0)
484       kx = 0;
485     if (kx >= area.right() - width)
486       kx = area.right() - width - 1;
487     int tot = 5;
488     for (int h : Range(tot)) {
489       int height = area.top() * (tot - h) / tot + area.bottom() * h / tot;
490       int height2 = area.top() * (tot - h - 1) / tot + area.bottom() * (h + 1) / tot;
491       vector<Vec2> line = straightLine(px, height, kx, (h == tot - 1) ? area.bottom() : height2);
492       for (Vec2 v : line)
493         for (int i : Range(width)) {
494           Vec2 pos = v + Vec2(i, 0);
495           builder->resetFurniture(pos, furnitureType, SquareAttrib::RIVER);
496         }
497       px = kx;
498       kx = px + builder->getRandom().get(-wind, wind);
499       if (kx < 0)
500         kx = 0;
501       if (kx >= area.right() - width)
502         kx = area.right() - width - 1;
503     }
504   }
505 
506   private:
507 
straightLine(int x0,int y0,int x1,int y1)508   vector<Vec2> straightLine(int x0, int y0, int x1, int y1){
509     INFO << "Line " << x1 << " " << y0 << " " << x1 << " " << y1;
510     int dx = x1 - x0;
511     int dy = y1 - y0;
512     vector<Vec2> ret{ Vec2(x0, y0)};
513     if (abs(dx) > abs(dy)) {          // slope < 1
514       double m = (double) dy / (double) dx;      // compute slope
515       double b = y0 - m*x0;
516       dx = (dx < 0) ? -1 : 1;
517       while (x0+dx != x1) {
518         x0 += dx;
519         ret.push_back(Vec2(x0,(int)roundf(m*x0+b)));
520       }
521     } else
522       if (dy != 0) {                              // slope >= 1
523         double m = (double) dx / (double) dy;      // compute slope
524         double b = x0 - m*y0;
525         dy = (dy < 0) ? -1 : 1;
526         while (y0+dy != y1) {
527           y0 += dy;
528           ret.push_back(Vec2((int)round(m*y0+b),y0));
529         }
530       }
531     return ret;
532   }
533 
534   int width;
535   FurnitureType furnitureType;
536 };
537 
538 class MountainRiver : public LevelMaker {
539   public:
MountainRiver(int num,Predicate startPred)540   MountainRiver(int num, Predicate startPred)
541     : number(num), startPredicate(startPred) {}
542 
fillLake(LevelBuilder * builder,set<Vec2> & waterTiles,Rectangle area,Vec2 pos)543   optional<Vec2> fillLake(LevelBuilder* builder, set<Vec2>& waterTiles, Rectangle area, Vec2 pos) {
544     vector<Vec2> ret;
545     double height = builder->getHeightMap(pos);
546     queue<Vec2> q;
547     set<Vec2> visited {pos};
548     map<Vec2, Vec2> predecessor {{ pos, pos}};
549     q.push(pos);
550     while (!q.empty()) {
551       pos = q.front();
552       q.pop();
553       for (Vec2 v : pos.neighbors8(builder->getRandom()))
554         if (v.inRectangle(area) && !visited.count(v)) {
555           visited.insert(v);
556           predecessor[v] = pos;
557           if (fabs(builder->getHeightMap(v) - height) < 0.000001)
558             q.push(v);
559           else
560           if (builder->getHeightMap(v) < height)
561             ret.push_back(v);
562         }
563     }
564     if (builder->getRandom().roll(predecessor.size()) || ret.empty()) {
565       for (auto& elem : predecessor)
566         if (!ret.contains(elem.first))
567           waterTiles.insert(elem.first);
568       if (ret.empty())
569         return none;
570       else
571         return builder->getRandom().choose(ret);
572     } else {
573       Vec2 end = builder->getRandom().choose(ret);
574       for (Vec2 v = predecessor.at(end);; v = predecessor.at(v)) {
575         waterTiles.insert(v);
576         if (v == predecessor.at(v))
577           break;
578       }
579       return end;
580     }
581   }
582 
make(LevelBuilder * builder,Rectangle area)583   virtual void make(LevelBuilder* builder, Rectangle area) override {
584     set<Vec2> allWaterTiles;
585     for (int i : Range(number)) {
586       set<Vec2> waterTiles;
587       Vec2 pos = startPredicate.getRandomPosition(builder, area);
588       int width = builder->getRandom().get(3, 6);
589       while (1) {
590         if (builder->hasAttrib(pos, SquareAttrib::RIVER))
591           break;
592         if (auto next = fillLake(builder, waterTiles, area, pos))
593           pos = *next;
594         else
595           break;
596       }
597       for (Vec2 v : waterTiles)
598         for (Vec2 v2 : Rectangle(v, v + Vec2(width, width)))
599           allWaterTiles.insert(v2);
600     }
601     for (auto layer : Iter(Vec2::calculateLayers(allWaterTiles))) {
602       for (Vec2 v : *layer)
603         if (v.inRectangle(area) && !builder->hasAttrib(v, SquareAttrib::RIVER)) {
604           builder->addAttrib(v, SquareAttrib::RIVER);
605           builder->resetFurniture(v, getWaterType(builder, v, layer.index()));
606         }
607     }
608   }
609 
getWaterType(LevelBuilder * builder,Vec2 pos,int numLayer)610   FurnitureType getWaterType(LevelBuilder* builder, Vec2 pos, int numLayer) {
611     if (builder->hasAttrib(pos, SquareAttrib::MOUNTAIN))
612       return FurnitureFactory::getWaterType(100);
613     else if (numLayer == 0)
614       return FurnitureType::SAND;
615     else
616       return FurnitureFactory::getWaterType(1.1 * (numLayer - 1));
617   }
618 
619   private:
620   int number;
621   Predicate startPredicate;
622 };
623 
624 class Blob : public LevelMaker {
625   public:
Blob(double _insideRatio=0.333)626   Blob(double _insideRatio = 0.333) : insideRatio(_insideRatio) {}
627 
628   virtual void addSquare(LevelBuilder* builder, Vec2 pos, int edgeDist) = 0;
629 
make(LevelBuilder * builder,Rectangle area)630   virtual void make(LevelBuilder* builder, Rectangle area) override {
631     vector<Vec2> squares;
632     Table<char> isInside(area, 0);
633     Vec2 center = area.middle();
634     squares.push_back(center);
635     isInside[center] = 1;
636     for (int i : Range(area.width() * area.height() * insideRatio)) {
637       vector<Vec2> nextPos;
638       for (auto pos : squares)
639         for (Vec2 next : pos.neighbors4())
640           if (next.inRectangle(area) && !squares.contains(next))
641             nextPos.push_back(next);
642       vector<double> probs = nextPos.transform([&](Vec2 v) {
643           double px = std::abs(v.x - center.x);
644           double py = std::abs(v.y - center.y);
645           py *= area.width();
646           py /= area.height();
647           double coeff = -1.0 + 1.0 / (sqrt(px * px + py * py) / sqrt(2 * area.width() * area.width()));
648           CHECK(coeff > 0.0);
649           return coeff;
650         });
651       Vec2 chosen = builder->getRandom().choose(nextPos, probs);
652       isInside[chosen] = 1;
653       squares.push_back(chosen);
654     }
655     queue<Vec2> q;
656     int inf = 10000;
657     Table<int> distance(area, inf);
658     for (Vec2 v : isInside.getBounds())
659       if (!isInside[v]) {
660         distance[v] = 0;
661         q.push(v);
662       }
663     while (!q.empty()) {
664       Vec2 pos = q.front();
665       q.pop();
666       for (Vec2 v : pos.neighbors8())
667         if (v.inRectangle(area) && distance[v] == inf) {
668           distance[v] = distance[pos] + 1;
669           q.push(v);
670           addSquare(builder, v, distance[v]);
671         }
672     }
673   }
674 
675   private:
676   double insideRatio;
677 };
678 
679 class UniformBlob : public Blob {
680   public:
UniformBlob(FurnitureType insideSquare,optional<FurnitureType> borderSquare=none,optional<SquareAttrib> _attrib=none,double insideRatio=0.3333)681   UniformBlob(FurnitureType insideSquare, optional<FurnitureType> borderSquare = none,
682       optional<SquareAttrib> _attrib = none, double insideRatio = 0.3333) : Blob(insideRatio),
683       inside(insideSquare), border(borderSquare), attrib(_attrib) {}
684 
addSquare(LevelBuilder * builder,Vec2 pos,int edgeDist)685   virtual void addSquare(LevelBuilder* builder, Vec2 pos, int edgeDist) override {
686     if (edgeDist == 1 && border)
687       builder->resetFurniture(pos, *border, attrib);
688     else
689       builder->resetFurniture(pos, inside, attrib);
690   }
691 
692   private:
693   FurnitureType inside;
694   optional<FurnitureType> border;
695   optional<SquareAttrib> attrib;
696 };
697 
698 class FurnitureBlob : public Blob {
699   public:
FurnitureBlob(FurnitureFactory in,double insideRatio=0.3333)700   FurnitureBlob(FurnitureFactory in, double insideRatio = 0.3333) : Blob(insideRatio), inside(in) {}
701 
addSquare(LevelBuilder * builder,Vec2 pos,int edgeDist)702   virtual void addSquare(LevelBuilder* builder, Vec2 pos, int edgeDist) override {
703     builder->putFurniture(pos, inside);
704   }
705 
706   private:
707   FurnitureFactory inside;
708 };
709 
710 class Lake : public Blob {
711   public:
Lake(bool s=true)712   Lake(bool s = true) : sand(s) {}
addSquare(LevelBuilder * builder,Vec2 pos,int edgeDist)713   virtual void addSquare(LevelBuilder* builder, Vec2 pos, int edgeDist) override {
714     builder->addAttrib(pos, SquareAttrib::LAKE);
715     if (sand && edgeDist == 1 && !builder->isFurnitureType(pos, FurnitureType::WATER))
716       builder->resetFurniture(pos, FurnitureType::SAND);
717     else
718       builder->resetFurniture(pos, FurnitureFactory::getWaterType(double(edgeDist) / 2));
719   }
720 
721   private:
722   bool sand;
723 };
724 
725 class RemoveFurniture : public LevelMaker {
726   public:
RemoveFurniture(FurnitureLayer l)727   RemoveFurniture(FurnitureLayer l) : layer(l) {
728     CHECK(layer != FurnitureLayer::GROUND);
729   }
730 
make(LevelBuilder * builder,Rectangle area)731   virtual void make(LevelBuilder* builder, Rectangle area) override {
732     for (Vec2 v : area)
733       builder->removeFurniture(v, layer);
734   }
735 
736   private:
737   FurnitureLayer layer;
738 };
739 
740 struct BuildingType {
741   FurnitureType wall;
742   FurnitureType floorInside;
743   FurnitureType floorOutside;
744   optional<FurnitureFactory> door;
745 };
746 
getBuildingInfo(SettlementInfo info)747 static BuildingType getBuildingInfo(SettlementInfo info) {
748   switch (info.buildingId) {
749     case BuildingId::WOOD:
750       return CONSTRUCT(BuildingType,
751           c.wall = FurnitureType::WOOD_WALL;
752           c.floorInside = FurnitureType::FLOOR;
753           c.floorOutside = FurnitureType::GRASS;
754           c.door = FurnitureFactory(info.tribe, FurnitureType::DOOR);
755       );
756     case BuildingId::WOOD_CASTLE:
757       return CONSTRUCT(BuildingType,
758           c.wall = FurnitureType::WOOD_WALL;
759           c.floorInside = FurnitureType::FLOOR;
760           c.floorOutside = FurnitureType::MUD;
761           c.door = FurnitureFactory(info.tribe, FurnitureType::DOOR);
762       );
763     case BuildingId::MUD:
764       return CONSTRUCT(BuildingType,
765           c.wall = FurnitureType::MUD_WALL;
766           c.floorInside = FurnitureType::MUD;
767           c.floorOutside = FurnitureType::MUD;);
768     case BuildingId::BRICK:
769       return CONSTRUCT(BuildingType,
770           c.wall = FurnitureType::CASTLE_WALL;
771           c.floorInside = FurnitureType::FLOOR;
772           c.floorOutside = FurnitureType::MUD;
773           c.door = FurnitureFactory(info.tribe, FurnitureType::DOOR);
774       );
775     case BuildingId::DUNGEON:
776       return CONSTRUCT(BuildingType,
777           c.wall = FurnitureType::MOUNTAIN;
778           c.floorInside = FurnitureType::FLOOR;
779           c.floorOutside = FurnitureType::FLOOR;
780           c.door = FurnitureFactory(info.tribe, FurnitureType::DOOR);
781       );
782     case BuildingId::DUNGEON_SURFACE:
783       return CONSTRUCT(BuildingType,
784           c.wall = FurnitureType::MOUNTAIN;
785           c.floorInside = FurnitureType::FLOOR;
786           c.floorOutside = FurnitureType::HILL;
787           c.door = FurnitureFactory(info.tribe, FurnitureType::DOOR);
788       );
789   }
790 }
791 
792 class Buildings : public LevelMaker {
793   public:
Buildings(int _minBuildings,int _maxBuildings,int _minSize,int _maxSize,BuildingType _building,bool _align,vector<PLevelMaker> _insideMakers,bool _roadConnection=true)794   Buildings(int _minBuildings, int _maxBuildings,
795       int _minSize, int _maxSize,
796       BuildingType _building,
797       bool _align,
798       vector<PLevelMaker> _insideMakers,
799       bool _roadConnection = true) :
800     minBuildings(_minBuildings),
801     maxBuildings(_maxBuildings),
802     minSize(_minSize), maxSize(_maxSize),
803     align(_align),
804     building(_building),
805     insideMakers(std::move(_insideMakers)),
806     roadConnection(_roadConnection) {
807       CHECK(insideMakers.size() <= minBuildings);
808     }
809 
Buildings(int _minBuildings,int _maxBuildings,int _minSize,int _maxSize,BuildingType _building,bool _align,PLevelMaker _insideMaker,bool _roadConnection=true)810   Buildings(int _minBuildings, int _maxBuildings,
811       int _minSize, int _maxSize,
812       BuildingType _building,
813       bool _align,
814       PLevelMaker _insideMaker,
815       bool _roadConnection = true) : Buildings(_minBuildings, _maxBuildings, _minSize, _maxSize, _building, _align,
816         _insideMaker ? makeVec<PLevelMaker>(std::move(_insideMaker)) : vector<PLevelMaker>(), _roadConnection) {}
817 
make(LevelBuilder * builder,Rectangle area)818   virtual void make(LevelBuilder* builder, Rectangle area) override {
819     Table<bool> filled(area);
820     int width = area.width();
821     int height = area.height();
822     for (Vec2 v : area)
823       filled[v] =  0;
824     int sizeVar = 1;
825     int spaceBetween = 1;
826     int alignHeight = 0;
827     if (align) {
828       alignHeight = height / 2 - 2 + builder->getRandom().get(5);
829     }
830     int nextw = -1;
831     int numBuildings = builder->getRandom().get(minBuildings, maxBuildings);
832     for (int i = 0; i < numBuildings; ++i) {
833       bool spaceOk = true;
834       int w, h, px, py;
835       int cnt = 10000;
836       bool buildingRow;
837       do {
838         buildingRow = builder->getRandom().get(2);
839         spaceOk = true;
840         w = builder->getRandom().get(minSize, maxSize);
841         h = builder->getRandom().get(minSize, maxSize);
842         if (nextw > -1 && nextw + w < area.right()) {
843           px = nextw;
844           nextw = -1;
845         } else
846           px = area.left() + builder->getRandom().get(width - w - 2 * spaceBetween + 1) + spaceBetween;
847         if (!align)
848           py = area.top() + builder->getRandom().get(height - h - 2 * spaceBetween + 1) + spaceBetween;
849         else {
850           py = area.top() + (buildingRow == 1 ? alignHeight - h - 1 : alignHeight + 2);
851           if (py + h >= area.bottom() || py < area.top()) {
852             spaceOk = false;
853             continue;
854           }
855         }
856         Vec2 tmp(px - spaceBetween, py - spaceBetween);
857         for (Vec2 v : Rectangle(w + spaceBetween * 2 + 1, h + spaceBetween * 2 + 1))
858           if (!(tmp + v).inRectangle(area) || filled[px + v.x - spaceBetween][py + v.y - spaceBetween]) {
859             spaceOk = false;
860             break;
861           }
862       } while (!spaceOk && --cnt > 0);
863       if (cnt == 0) {
864         if (i < minBuildings)
865           failGen(); // "Failed to add " << minBuildings - i << " buildings out of " << minBuildings;
866         else
867           break;
868       }
869       if (builder->getRandom().roll(1))
870         nextw = px + w;
871       for (Vec2 v : Rectangle(w + 1, h + 1)) {
872         filled[Vec2(px, py) + v] = true;
873         builder->putFurniture(Vec2(px, py) + v, building.wall);
874         builder->setCovered(Vec2(px, py) + v, true);
875       }
876       for (Vec2 v : Rectangle(w - 1, h - 1)) {
877         auto pos = Vec2(px + 1, py + 1) + v;
878         builder->resetFurniture(pos, building.floorInside, SquareAttrib::ROOM);
879       }
880       Vec2 doorLoc = align ?
881           Vec2(px + builder->getRandom().get(1, w),
882                py + (buildingRow * h)) :
883           getRandomExit(Random, Rectangle(px, py, px + w + 1, py + h + 1));
884       builder->resetFurniture(doorLoc, building.floorInside);
885       if (building.door)
886         builder->putFurniture(doorLoc, *building.door);
887       Rectangle inside(px + 1, py + 1, px + w, py + h);
888       if (i < insideMakers.size())
889         insideMakers[i]->make(builder, inside);
890       else
891         for (Vec2 v : inside)
892           builder->addAttrib(v, SquareAttrib::EMPTY_ROOM);
893     }
894     if (align)
895       for (Vec2 v : Rectangle(area.left() + area.width() / 3, area.top() + alignHeight,
896             area.right() - area.width() / 3, area.top() + alignHeight + 2))
897         builder->addAttrib(v, SquareAttrib::BUILDINGS_CENTER);
898     if (roadConnection) {
899       Vec2 pos = Vec2((area.left() + area.right()) / 2, area.top() + alignHeight);
900       builder->removeFurniture(pos, FurnitureLayer::MIDDLE);
901       builder->putFurniture(pos, FurnitureParams{FurnitureType::ROAD, TribeId::getMonster()});
902       builder->addAttrib(pos, SquareAttrib::CONNECT_ROAD);
903     }
904   }
905 
906   private:
907   int minBuildings;
908   int maxBuildings;
909   int minSize;
910   int maxSize;
911   bool align;
912   BuildingType building;
913   vector<PLevelMaker> insideMakers;
914   bool roadConnection;
915 };
916 
917 DEF_UNIQUE_PTR(MakerQueue);
918 
919 class MakerQueue : public LevelMaker {
920   public:
921   MakerQueue() = default;
MakerQueue(vector<PLevelMaker> _makers)922   MakerQueue(vector<PLevelMaker> _makers) : makers(std::move(_makers)) {}
923 
924   template <typename T1, typename T2, typename... Args>
MakerQueue(T1 && t1,T2 && t2,Args &&...args)925   MakerQueue(T1&& t1, T2&& t2, Args&&... args) : MakerQueue(makeVec<PLevelMaker>(std::move(t1), std::move(t2), std::move(args)...)) {}
926 
addMaker(PLevelMaker maker)927   void addMaker(PLevelMaker maker) {
928     makers.push_back(std::move(maker));
929   }
930 
make(LevelBuilder * builder,Rectangle area)931   virtual void make(LevelBuilder* builder, Rectangle area) override {
932     for (auto& maker : makers)
933       maker->make(builder, area);
934   }
935 
936   private:
937   vector<PLevelMaker> makers;
938 };
939 
940 class PredicatePrecalc {
941   public:
PredicatePrecalc(const Predicate & predicate,LevelBuilder * builder,Rectangle area)942   PredicatePrecalc(const Predicate& predicate, LevelBuilder* builder, Rectangle area)
943       : counts(Rectangle(area.topLeft(), area.bottomRight() + Vec2(1, 1))) {
944     int px = counts.getBounds().left();
945     int py = counts.getBounds().top();
946     for (int x : Range(px, counts.getBounds().right()))
947       counts[x][py] = 0;
948     for (int y : Range(py, counts.getBounds().bottom()))
949       counts[px][y] = 0;
950     for (Vec2 v : Rectangle(area.topLeft() + Vec2(1, 1), counts.getBounds().bottomRight()))
951       counts[v] = (predicate.apply(builder, v - Vec2(1, 1)) ? 1 : 0) +
952         counts[v.x - 1][v.y] + counts[v.x][v.y - 1] -counts[v.x - 1][v.y - 1];
953   }
954 
getCount(Rectangle area) const955   int getCount(Rectangle area) const {
956     return counts[area.bottomRight()] + counts[area.topLeft()]
957       -counts[area.bottomLeft()] - counts[area.topRight()];
958   }
959 
960   private:
961   Table<int> counts;
962 };
963 
964 
965 class RandomLocations : public LevelMaker {
966   public:
RandomLocations(vector<PLevelMaker> _insideMakers,const vector<pair<int,int>> & _sizes,Predicate pred,bool _separate=true)967   RandomLocations(vector<PLevelMaker> _insideMakers, const vector<pair<int, int>>& _sizes,
968       Predicate pred, bool _separate = true)
969         : insideMakers(std::move(_insideMakers)), sizes(_sizes), predicate(sizes.size(), pred),
970           separate(_separate) {
971         CHECK(insideMakers.size() == sizes.size());
972         CHECK(predicate.size() == sizes.size());
973       }
974 
RandomLocations(vector<PLevelMaker> _insideMakers,const vector<pair<int,int>> & _sizes,const vector<Predicate> & pred,bool _separate=true)975   RandomLocations(vector<PLevelMaker> _insideMakers, const vector<pair<int, int>>& _sizes,
976       const vector<Predicate>& pred, bool _separate = true)
977         : insideMakers(std::move(_insideMakers)), sizes(_sizes), predicate(pred.begin(), pred.end()),
978           separate(_separate) {
979     CHECK(insideMakers.size() == sizes.size());
980     CHECK(pred.size() == sizes.size());
981   }
982 
983   class LocationPredicate {
984     public:
LocationPredicate(Predicate main,Predicate sec,int minSec,int maxSec)985     LocationPredicate(Predicate main, Predicate sec, int minSec, int maxSec)
986       // main and sec must be mutually exclusive!!!
987         : predicate(main), second(sec), minSecond(minSec), maxSecond(maxSec) {
988     }
989 
LocationPredicate(Predicate p)990     LocationPredicate(Predicate p) : predicate(p) {}
991 
992     class Precomputed {
993       public:
Precomputed(LevelBuilder * builder,Rectangle area,Predicate p1,Predicate p2,int minSec,int maxSec)994       Precomputed(LevelBuilder* builder, Rectangle area, Predicate p1, Predicate p2, int minSec, int maxSec)
995         : pred1(p1, builder, area), pred2(p2, builder, area), minSecond(minSec), maxSecond(maxSec) {
996       }
997 
apply(Rectangle rect) const998       bool apply(Rectangle rect) const {
999         int numFirst = pred1.getCount(rect);
1000         int numSecond = pred2.getCount(rect);
1001         return numSecond >= minSecond && numSecond < maxSecond && numSecond + numFirst == rect.width() * rect.height();
1002       }
1003 
1004       private:
1005       PredicatePrecalc pred1;
1006       PredicatePrecalc pred2;
1007       int minSecond;
1008       int maxSecond;
1009     };
1010 
precompute(LevelBuilder * builder,Rectangle area)1011     Precomputed precompute(LevelBuilder* builder, Rectangle area) {
1012       return Precomputed(builder, area, predicate, second, minSecond, maxSecond);
1013     }
1014 
1015     private:
1016     Predicate predicate;
1017     Predicate second = Predicate::alwaysFalse();
1018     int minSecond = 0;
1019     int maxSecond = 1;
1020   };
1021 
RandomLocations(bool _separate=true)1022   RandomLocations(bool _separate = true) : separate(_separate) {}
1023 
add(PLevelMaker maker,Vec2 size,LocationPredicate pred)1024   void add(PLevelMaker maker, Vec2 size, LocationPredicate pred) {
1025     insideMakers.push_back(std::move(maker));
1026     sizes.push_back({size.x, size.y});
1027     predicate.push_back(pred);
1028   }
1029 
setMinDistance(LevelMaker * m1,LevelMaker * m2,double dist)1030   void setMinDistance(LevelMaker* m1, LevelMaker* m2, double dist) {
1031     minDistance[{m1, m2}] = dist;
1032     minDistance[{m2, m1}] = dist;
1033   }
1034 
setMaxDistance(LevelMaker * m1,LevelMaker * m2,double dist)1035   void setMaxDistance(LevelMaker* m1, LevelMaker* m2, double dist) {
1036     maxDistance[{m1, m2}] = dist;
1037     maxDistance[{m2, m1}] = dist;
1038   }
1039 
setMinMargin(LevelMaker * m1,int margin)1040   void setMinMargin(LevelMaker *m1, int margin) {
1041     minMargin[m1] = margin;
1042   }
1043 
setMinDistanceLast(LevelMaker * m,double dist)1044   void setMinDistanceLast(LevelMaker* m, double dist) {
1045     minDistance[{m, insideMakers.back().get()}]  = dist;
1046     minDistance[{insideMakers.back().get(), m}]  = dist;
1047   }
1048 
setMaxDistanceLast(LevelMaker * m,double dist)1049   void setMaxDistanceLast(LevelMaker* m, double dist) {
1050     maxDistance[{m, insideMakers.back().get()}] = dist;
1051     maxDistance[{insideMakers.back().get(), m}] = dist;
1052   }
1053 
make(LevelBuilder * builder,Rectangle area)1054   virtual void make(LevelBuilder* builder, Rectangle area) override {
1055     vector<LocationPredicate::Precomputed> precomputed;
1056     for (int i : All(insideMakers))
1057       precomputed.push_back(predicate[i].precompute(builder, area));
1058     for (int i : Range(3000))
1059       if (tryMake(builder, precomputed, area))
1060         return;
1061     failGen(); // "Failed to find free space for " << (int)sizes.size() << " areas";
1062   }
1063 
tryMake(LevelBuilder * builder,const vector<LocationPredicate::Precomputed> & precomputed,Rectangle area)1064   bool tryMake(LevelBuilder* builder, const vector<LocationPredicate::Precomputed>& precomputed, Rectangle area) {
1065     vector<Rectangle> occupied;
1066     vector<Rectangle> makerBounds;
1067     vector<LevelBuilder::Rot> maps;
1068     for (int i : All(insideMakers))
1069       maps.push_back(builder->getRandom().choose(
1070             LevelBuilder::CW0, LevelBuilder::CW1, LevelBuilder::CW2, LevelBuilder::CW3));
1071     for (int i : All(insideMakers)) {
1072       auto maker = insideMakers[i].get();
1073       int width = sizes[i].first;
1074       int height = sizes[i].second;
1075       if (contains({LevelBuilder::CW1, LevelBuilder::CW3}, maps[i]))
1076         std::swap(width, height);
1077       CHECK(width <= area.width() && height <= area.height());
1078       int px;
1079       int py;
1080       int cnt = 1000;
1081       bool ok;
1082       do {
1083         Progress::checkIfInterrupted();
1084         ok = true;
1085         int margin = minMargin.count(maker) ? minMargin.at(maker) : 0;
1086         CHECK(width + 2 * margin < area.width()) << "Couldn't fit maker width inside area.";
1087         CHECK(height + 2 * margin < area.height())  << "Couldn't fit maker height inside area.";
1088         px = area.left() + margin + builder->getRandom().get(area.width() - width - 2 * margin);
1089         py = area.top() + margin + builder->getRandom().get(area.height() - height - 2 * margin);
1090         Rectangle area(px, py, px + width, py + height);
1091         for (int j : Range(i))
1092           if ((maxDistance.count({insideMakers[j].get(), maker}) &&
1093                 maxDistance[{insideMakers[j].get(), maker}] < area.middle().dist8(occupied[j].middle())) ||
1094               minDistance[{insideMakers[j].get(), maker}] > area.middle().dist8(occupied[j].middle())) {
1095             ok = false;
1096             break;
1097           }
1098         if (!precomputed[i].apply(area))
1099           ok = false;
1100         else
1101           if (separate)
1102             for (Rectangle r : occupied)
1103               if (r.intersects(area)) {
1104                 ok = false;
1105                 break;
1106               }
1107       } while (!ok && --cnt > 0);
1108       if (cnt == 0)
1109         return false;
1110       occupied.push_back(Rectangle(px, py, px + width, py + height));
1111       makerBounds.push_back(Rectangle(px, py, px + sizes[i].first, py + sizes[i].second));
1112     }
1113     CHECK(insideMakers.size() == occupied.size());
1114     for (int i : All(insideMakers)) {
1115       builder->pushMap(makerBounds[i], maps[i]);
1116       insideMakers[i]->make(builder, makerBounds[i]);
1117       builder->popMap();
1118     }
1119     return true;
1120   }
1121 
1122   private:
1123   vector<PLevelMaker> insideMakers;
1124   vector<pair<int, int>> sizes;
1125   vector<LocationPredicate> predicate;
1126   bool separate;
1127   map<pair<LevelMaker*, LevelMaker*>, double> minDistance;
1128   map<pair<LevelMaker*, LevelMaker*>, double> maxDistance;
1129   map<LevelMaker*, int> minMargin;
1130 };
1131 
1132 class Margin : public LevelMaker {
1133   public:
Margin(int s,PLevelMaker in)1134   Margin(int s, PLevelMaker in) : left(s), top(s), right(s), bottom(s), inside(std::move(in)) {}
Margin(int _left,int _top,int _right,int _bottom,PLevelMaker in)1135   Margin(int _left, int _top, int _right, int _bottom, PLevelMaker in)
1136       :left(_left) ,top(_top), right(_right), bottom(_bottom), inside(std::move(in)) {}
1137 
make(LevelBuilder * builder,Rectangle area)1138   virtual void make(LevelBuilder* builder, Rectangle area) override {
1139     CHECK(area.width() > left + right && area.height() > top + bottom);
1140     inside->make(builder, Rectangle(
1141           area.left() + left,
1142           area.top() + top,
1143           area.right() - right,
1144           area.bottom() - bottom));
1145   }
1146 
1147   private:
1148   int left, top, right, bottom;
1149   PLevelMaker inside;
1150 };
1151 
addAvg(int x,int y,const Table<double> & wys,double & avg,int & num)1152 void addAvg(int x, int y, const Table<double>& wys, double& avg, int& num) {
1153   Vec2 pos(x, y);
1154   if (pos.inRectangle(wys.getBounds())) {
1155     avg += wys[pos];
1156     ++num;
1157   }
1158 }
1159 
1160 struct NoiseInit {
1161   int topLeft;
1162   int topRight;
1163   int bottomRight;
1164   int bottomLeft;
1165   int middle;
1166 };
1167 
genNoiseMap(RandomGen & random,Rectangle area,NoiseInit init,double varianceMult)1168 Table<double> genNoiseMap(RandomGen& random, Rectangle area, NoiseInit init, double varianceMult) {
1169   int width = 1;
1170   while (width < area.width() - 1 || width < area.height() - 1)
1171     width *= 2;
1172   width /= 2;
1173   ++width;
1174   Table<double> wys(width, width);
1175   wys[0][0] = init.topLeft;
1176   wys[width - 1][0] = init.topRight;
1177   wys[width - 1][width - 1] = init.bottomRight;
1178   wys[0][width - 1] = init.bottomLeft;
1179   wys[(width - 1) / 2][(width - 1) / 2] = init.middle;
1180 
1181   double variance = 0.5;
1182   double heightDiff = 0.1;
1183   for (int a = width - 1; a >= 2; a /= 2) {
1184     if (a < width - 1)
1185       for (Vec2 pos1 : Rectangle((width - 1) / a, (width - 1) / a)) {
1186         Vec2 pos = pos1 * a;
1187         double avg = (wys[pos] + wys[pos.x + a][pos.y] + wys[pos.x][pos.y + a] + wys[pos.x + a][pos.y + a]) / 4;
1188         wys[pos.x + a / 2][pos.y + a / 2] =
1189             avg + variance * (random.getDouble() * 2 - 1);
1190       }
1191     for (Vec2 pos1 : Rectangle((width - 1) / a, (width - 1) / a + 1)) {
1192       Vec2 pos = pos1 * a;
1193       double avg = 0;
1194       int num = 0;
1195       addAvg(pos.x + a / 2, pos.y - a / 2, wys, avg, num);
1196       addAvg(pos.x, pos.y, wys, avg, num);
1197       addAvg(pos.x + a, pos.y, wys, avg, num);
1198       addAvg(pos.x + a / 2, pos.y + a / 2, wys, avg, num);
1199       wys[pos.x + a / 2][pos.y] =
1200           avg / num + variance * (random.getDouble() * 2 - 1);
1201     }
1202     for (Vec2 pos1 : Rectangle((width - 1) / a + 1, (width - 1) / a)) {
1203       Vec2 pos = pos1 * a;
1204       double avg = 0;
1205       int num = 0;
1206       addAvg(pos.x - a / 2, pos.y + a / 2, wys, avg, num);
1207       addAvg(pos.x, pos.y, wys, avg, num);
1208       addAvg(pos.x, pos.y + a , wys, avg, num);
1209       addAvg(pos.x + a / 2, pos.y + a / 2, wys, avg, num);
1210       wys[pos.x][pos.y + a / 2] =
1211           avg / num + variance * (random.getDouble() * 2 - 1);
1212     }
1213     variance *= varianceMult;
1214   }
1215   Table<double> ret(area);
1216   Vec2 offset(area.left(), area.top());
1217   for (Vec2 v : area) {
1218     Vec2 lv((v.x - offset.x) * width / area.width(), (v.y - offset.y) * width / area.height());
1219     ret[v] = wys[lv];
1220   }
1221   return ret;
1222 }
1223 
raiseLocalMinima(Table<double> & t)1224 void raiseLocalMinima(Table<double>& t) {
1225   Vec2 minPos = t.getBounds().topLeft();
1226   for (Vec2 v : t.getBounds())
1227     if (t[v] < t[minPos])
1228       minPos = v;
1229   Table<bool> visited(t.getBounds(), false);
1230   auto comparator = [&](const Vec2& v1, const Vec2& v2) { return t[v1] > t[v2];};
1231   priority_queue<Vec2, vector<Vec2>, decltype(comparator)> q(comparator);
1232   q.push(minPos);
1233   visited[minPos] = true;
1234   while (!q.empty()) {
1235     Vec2 pos = q.top();
1236     q.pop();
1237     for (Vec2 v : pos.neighbors4())
1238       if (v.inRectangle(t.getBounds()) && !visited[v]) {
1239         if (t[v] < t[pos])
1240           t[v] = t[pos];
1241         q.push(v);
1242         visited[v] = true;
1243       }
1244   }
1245 }
1246 
sortedValues(const Table<double> & t)1247 vector<double> sortedValues(const Table<double>& t) {
1248   vector<double> values;
1249   for (Vec2 v : t.getBounds()) {
1250     values.push_back(t[v]);
1251   }
1252   std::sort(values.begin(), values.end());
1253   return values;
1254 }
1255 
1256 class SetSunlight : public LevelMaker {
1257   public:
SetSunlight(double a,Predicate p)1258   SetSunlight(double a, Predicate p) : amount(a), pred(p) {}
1259 
make(LevelBuilder * builder,Rectangle area)1260   virtual void make(LevelBuilder* builder, Rectangle area) override {
1261     for (Vec2 v : area)
1262       if (pred.apply(builder, v))
1263         builder->setSunlight(v, amount);
1264   }
1265 
1266   private:
1267   double amount;
1268   Predicate pred;
1269 };
1270 
1271 class Mountains : public LevelMaker {
1272   public:
1273   static constexpr double varianceM = 0.45;
Mountains(double lowland,double hill,NoiseInit init)1274   Mountains(double lowland, double hill, NoiseInit init)
1275       : ratioLowland(lowland), ratioHill(hill), noiseInit(init), varianceMult(varianceM) {
1276   }
1277 
make(LevelBuilder * builder,Rectangle area)1278   virtual void make(LevelBuilder* builder, Rectangle area) override {
1279     Table<double> wys = genNoiseMap(builder->getRandom(), area, noiseInit, varianceMult);
1280     raiseLocalMinima(wys);
1281     vector<double> values = sortedValues(wys);
1282     double cutOffLowland = values[(int)(ratioLowland * double(values.size() - 1))];
1283     double cutOffHill = values[(int)((ratioHill + ratioLowland) * double(values.size() - 1))];
1284     double cutOffDarkness = values[(int)((ratioHill + ratioLowland + 1.0) * 0.5 * double(values.size() - 1))];
1285     int dCnt = 0, mCnt = 0, hCnt = 0, lCnt = 0;
1286     for (Vec2 v : area) {
1287       builder->setHeightMap(v, wys[v]);
1288       if (wys[v] >= cutOffHill) {
1289         builder->putFurniture(v, FurnitureType::FLOOR);
1290         builder->putFurniture(v, {FurnitureType::MOUNTAIN, TribeId::getKeeper()}, SquareAttrib::MOUNTAIN);
1291         builder->setSunlight(v, max(0.0, 1. - (wys[v] - cutOffHill) / (cutOffDarkness - cutOffHill)));
1292         builder->setCovered(v, true);
1293         ++mCnt;
1294       }
1295       else if (wys[v] >= cutOffLowland) {
1296         builder->putFurniture(v, FurnitureType::HILL, SquareAttrib::HILL);
1297         ++hCnt;
1298       }
1299       else {
1300         builder->putFurniture(v, FurnitureType::GRASS, SquareAttrib::LOWLAND);
1301         ++lCnt;
1302       }
1303     }
1304     INFO << "Terrain distribution " << dCnt << " darkness, " << mCnt << " mountain, " << hCnt << " hill, " << lCnt << " lowland";
1305   }
1306 
1307   private:
1308   double ratioLowland;
1309   double ratioHill;
1310   NoiseInit noiseInit;
1311   double varianceMult;
1312 };
1313 
1314 class Roads : public LevelMaker {
1315   public:
Roads()1316   Roads() {}
1317 
makeBridge(LevelBuilder * builder,Vec2 pos)1318   bool makeBridge(LevelBuilder* builder, Vec2 pos) {
1319     return !builder->canNavigate(pos, {MovementTrait::WALK}) && builder->canNavigate(pos, {MovementTrait::SWIM});
1320   }
1321 
getValue(LevelBuilder * builder,Vec2 pos)1322   double getValue(LevelBuilder* builder, Vec2 pos) {
1323     if ((!builder->canNavigate(pos, MovementType({MovementTrait::WALK, MovementTrait::SWIM})) &&
1324          !builder->hasAttrib(pos, SquareAttrib::ROAD_CUT_THRU)) ||
1325         builder->hasAttrib(pos, SquareAttrib::NO_ROAD))
1326       return ShortestPath::infinity;
1327     if (makeBridge(builder, pos))
1328       return 10;
1329     if (builder->isFurnitureType(pos, FurnitureType::ROAD) || builder->isFurnitureType(pos, FurnitureType::BRIDGE))
1330       return 1;
1331     return 1 + pow(1 + builder->getHeightMap(pos), 2);
1332   }
1333 
getRoadType(LevelBuilder * builder,Vec2 pos)1334   FurnitureType getRoadType(LevelBuilder* builder, Vec2 pos) {
1335     if (makeBridge(builder, pos))
1336       return FurnitureType::BRIDGE;
1337     else
1338       return FurnitureType::ROAD;
1339   }
1340 
make(LevelBuilder * builder,Rectangle area)1341   virtual void make(LevelBuilder* builder, Rectangle area) override {
1342     vector<Vec2> points;
1343     for (Vec2 v : area)
1344       if (builder->hasAttrib(v, SquareAttrib::CONNECT_ROAD)) {
1345         points.push_back(v);
1346         INFO << "Connecting point " << v;
1347       }
1348     for (int ind : Range(1, points.size())) {
1349       Vec2 p1 = points[ind];
1350       Vec2 p2 = points[ind - 1];
1351       ShortestPath path(area,
1352           [=](Vec2 pos) { return (pos == p1 || pos == p2) ? 1 : getValue(builder, pos); },
1353           [] (Vec2 v) { return v.length4(); },
1354           Vec2::directions4(builder->getRandom()), p1, p2);
1355       for (Vec2 v = p2; v != p1; v = path.getNextMove(v)) {
1356         if (!path.isReachable(v))
1357           failGen();
1358         auto roadType = getRoadType(builder, v);
1359         if (v != p2 && v != p1 && !builder->isFurnitureType(v, roadType))
1360           builder->putFurniture(v, roadType);
1361       }
1362     }
1363   }
1364 };
1365 
1366 class StartingPos : public LevelMaker {
1367   public:
1368 
StartingPos(Predicate pred,StairKey key)1369   StartingPos(Predicate pred, StairKey key) : predicate(pred), stairKey(key) {}
1370 
make(LevelBuilder * builder,Rectangle area)1371   virtual void make(LevelBuilder* builder, Rectangle area) override {
1372     for (Vec2 pos : area)
1373       if (predicate.apply(builder, pos))
1374         builder->modSquare(pos)->setLandingLink(stairKey);
1375   }
1376 
1377   private:
1378   Predicate predicate;
1379   StairKey stairKey;
1380 };
1381 
1382 class TransferPos : public LevelMaker {
1383   public:
1384 
TransferPos(Predicate pred,StairKey key,int w)1385   TransferPos(Predicate pred, StairKey key, int w) : predicate(pred), stairKey(key), width(w) {}
1386 
make(LevelBuilder * builder,Rectangle area)1387   virtual void make(LevelBuilder* builder, Rectangle area) override {
1388     bool found = false;
1389     for (Vec2 pos : area)
1390       if (((pos.x - area.left() < width) || (pos.y - area.top() < width) ||
1391           (area.right() - pos.x <= width) || (area.bottom() - pos.y <= width)) &&
1392           predicate.apply(builder, pos)) {
1393         builder->modSquare(pos)->setLandingLink(stairKey);
1394         found = true;
1395       }
1396     checkGen(found);
1397   }
1398 
1399   private:
1400   Predicate predicate;
1401   StairKey stairKey;
1402   int width;
1403 };
1404 
1405 class Forrest : public LevelMaker {
1406   public:
Forrest(double _ratio,double _density,FurnitureType _onType,FurnitureFactory _factory)1407   Forrest(double _ratio, double _density, FurnitureType _onType, FurnitureFactory _factory)
1408       : ratio(_ratio), density(_density), factory(_factory), onType(_onType) {}
1409 
make(LevelBuilder * builder,Rectangle area)1410   virtual void make(LevelBuilder* builder, Rectangle area) override {
1411     Table<double> wys = genNoiseMap(builder->getRandom(), area, {0, 0, 0, 0, 0}, 0.65);
1412     vector<double> values = sortedValues(wys);
1413     double cutoff = values[values.size() * ratio];
1414     for (Vec2 v : area)
1415       if (builder->isFurnitureType(v, onType) && builder->canNavigate(v, {MovementTrait::WALK}) && wys[v] < cutoff) {
1416         if (builder->getRandom().getDouble() <= density)
1417           builder->putFurniture(v, factory);
1418         builder->addAttrib(v, SquareAttrib::FORREST);
1419       }
1420   }
1421 
1422   private:
1423   double ratio;
1424   double density;
1425   FurnitureFactory factory;
1426   FurnitureType onType;
1427 };
1428 
1429 class PlaceCollective : public LevelMaker {
1430   public:
PlaceCollective(CollectiveBuilder * c,Predicate pred=Predicate::alwaysTrue ())1431   PlaceCollective(CollectiveBuilder* c, Predicate pred = Predicate::alwaysTrue())
1432       : collective(NOTNULL(c)), predicate(pred) {}
1433 
make(LevelBuilder * builder,Rectangle area)1434   virtual void make(LevelBuilder* builder, Rectangle area) override {
1435     if (!collective->hasCentralPoint())
1436       collective->setCentralPoint(builder->toGlobalCoordinates(area).middle());
1437     collective->addArea(builder->toGlobalCoordinates(area.getAllSquares()
1438         .filter([&](Vec2 pos) { return predicate.apply(builder, pos); })));
1439     builder->addCollective(collective);
1440   }
1441 
1442   private:
1443   CollectiveBuilder* collective;
1444   Predicate predicate;
1445 };
1446 
1447 class ForEachSquare : public LevelMaker {
1448   public:
ForEachSquare(function<void (LevelBuilder *,Vec2 pos)> f,Predicate _onPred=Predicate::alwaysTrue ())1449   ForEachSquare(function<void(LevelBuilder*, Vec2 pos)> f, Predicate _onPred = Predicate::alwaysTrue())
1450     : fun(f), onPred(_onPred) {}
1451 
make(LevelBuilder * builder,Rectangle area)1452   virtual void make(LevelBuilder* builder, Rectangle area) override {
1453     for (Vec2 v : area)
1454       if (onPred.apply(builder, v))
1455         fun(builder, v);
1456   }
1457 
1458   protected:
1459   function<void(LevelBuilder*, Vec2 pos)> fun;
1460   Predicate onPred;
1461 };
1462 
1463 class AddAttrib : public ForEachSquare {
1464   public:
AddAttrib(SquareAttrib attr,Predicate onPred=Predicate::alwaysTrue ())1465   AddAttrib(SquareAttrib attr, Predicate onPred = Predicate::alwaysTrue())
1466       : ForEachSquare([attr](LevelBuilder* b, Vec2 pos) { b->addAttrib(pos, attr); }, onPred) {}
1467 };
1468 
1469 class RemoveAttrib : public ForEachSquare {
1470   public:
RemoveAttrib(SquareAttrib attr,Predicate onPred=Predicate::alwaysTrue ())1471   RemoveAttrib(SquareAttrib attr, Predicate onPred = Predicate::alwaysTrue())
1472     : ForEachSquare([attr](LevelBuilder* b, Vec2 pos) { b->removeAttrib(pos, attr); }, onPred) {}
1473 };
1474 
1475 enum class StairDirection {
1476   UP, DOWN
1477 };
1478 
1479 class Stairs : public LevelMaker {
1480   public:
Stairs(StairDirection dir,StairKey k,Predicate onPred,optional<SquareAttrib> _setAttr=none)1481   Stairs(StairDirection dir, StairKey k, Predicate onPred, optional<SquareAttrib> _setAttr = none)
1482     : direction(dir), key(k), onPredicate(onPred), setAttr(_setAttr) {}
1483 
make(LevelBuilder * builder,Rectangle area)1484   virtual void make(LevelBuilder* builder, Rectangle area) override {
1485     auto type = direction == StairDirection::DOWN ? FurnitureType::DOWN_STAIRS : FurnitureType::UP_STAIRS;
1486     vector<Vec2> allPos;
1487     for (Vec2 v : area)
1488       if (onPredicate.apply(builder, v) && builder->canPutFurniture(v, Furniture::getLayer(type)))
1489         allPos.push_back(v);
1490     checkGen(allPos.size() > 0);
1491     Vec2 pos = allPos[builder->getRandom().get(allPos.size())];
1492     builder->putFurniture(pos, FurnitureParams{type, TribeId::getHostile()});
1493     builder->setLandingLink(pos, key);
1494   }
1495 
1496   private:
1497   StairDirection direction;
1498   StairKey key;
1499   Predicate onPredicate;
1500   optional<SquareAttrib> setAttr;
1501 };
1502 
1503 class ShopMaker : public LevelMaker {
1504   public:
ShopMaker(ItemFactory _factory,TribeId _tribe,int _numItems,BuildingType _building)1505   ShopMaker(ItemFactory _factory, TribeId _tribe, int _numItems, BuildingType _building)
1506       : factory(_factory), tribe(_tribe), numItems(_numItems), building(_building) {}
1507 
make(LevelBuilder * builder,Rectangle area)1508   virtual void make(LevelBuilder* builder, Rectangle area) override {
1509     PCreature shopkeeper = CreatureFactory::getShopkeeper(builder->toGlobalCoordinates(area), tribe);
1510     vector<Vec2> pos;
1511     for (Vec2 v : area)
1512       if (builder->canNavigate(v, MovementTrait::WALK) && builder->isFurnitureType(v, building.floorInside))
1513         pos.push_back(v);
1514     builder->putCreature(pos[builder->getRandom().get(pos.size())], std::move(shopkeeper));
1515     builder->putFurniture(pos[builder->getRandom().get(pos.size())], FurnitureParams{FurnitureType::GROUND_TORCH, tribe});
1516     for (int i : Range(numItems)) {
1517       Vec2 v = pos[builder->getRandom().get(pos.size())];
1518       builder->putItems(v, factory.random());
1519     }
1520   }
1521 
1522   private:
1523   ItemFactory factory;
1524   TribeId tribe;
1525   int numItems;
1526   BuildingType building;
1527 };
1528 
1529 class LevelExit : public LevelMaker {
1530   public:
LevelExit(FurnitureFactory e,int _minCornerDist=1)1531   LevelExit(FurnitureFactory e, int _minCornerDist = 1)
1532       : exit(e), minCornerDist(_minCornerDist) {}
1533 
make(LevelBuilder * builder,Rectangle area)1534   virtual void make(LevelBuilder* builder, Rectangle area) override {
1535     Vec2 pos = getRandomExit(builder->getRandom(), area, minCornerDist);
1536     builder->putFurniture(pos, exit);
1537   }
1538 
1539   private:
1540   FurnitureFactory exit;
1541   optional<SquareAttrib> attrib;
1542   int minCornerDist;
1543 };
1544 
1545 class Division : public LevelMaker {
1546   public:
Division(double _vRatio,double _hRatio,PLevelMaker _upperLeft,PLevelMaker _upperRight,PLevelMaker _lowerLeft,PLevelMaker _lowerRight,optional<SquareChange> _wall=none)1547   Division(double _vRatio, double _hRatio,
1548       PLevelMaker _upperLeft, PLevelMaker _upperRight, PLevelMaker _lowerLeft, PLevelMaker _lowerRight,
1549       optional<SquareChange> _wall = none) : vRatio(_vRatio), hRatio(_hRatio),
1550       upperLeft(std::move(_upperLeft)), upperRight(std::move(_upperRight)), lowerLeft(std::move(_lowerLeft)),
1551       lowerRight(std::move(_lowerRight)), wall(_wall) {}
1552 
Division(double _hRatio,PLevelMaker _left,PLevelMaker _right,optional<SquareChange> _wall=none)1553   Division(double _hRatio, PLevelMaker _left, PLevelMaker _right, optional<SquareChange> _wall = none)
1554       : vRatio(-1), hRatio(_hRatio), upperLeft(std::move(_left)), upperRight(std::move(_right)), wall(_wall) {}
1555 
Division(bool,double _vRatio,PLevelMaker _top,PLevelMaker _bottom,optional<SquareChange> _wall=none)1556   Division(bool, double _vRatio, PLevelMaker _top, PLevelMaker _bottom, optional<SquareChange> _wall = none)
1557       : vRatio(_vRatio), hRatio(-1), upperLeft(std::move(_top)), lowerLeft(std::move(_bottom)), wall(_wall) {}
1558 
makeHorizDiv(LevelBuilder * builder,Rectangle area)1559   void makeHorizDiv(LevelBuilder* builder, Rectangle area) {
1560     int hDiv = area.left() + min(area.width() - 1, max(1, (int) (hRatio * area.width())));
1561     if (upperLeft)
1562       upperLeft->make(builder, Rectangle(area.left(), area.top(), hDiv, area.bottom()));
1563     if (upperRight)
1564       upperRight->make(builder, Rectangle(hDiv + (wall ? 1 : 0), area.top(), area.right(), area.bottom()));
1565     if (wall)
1566       for (int i : Range(area.top(), area.bottom()))
1567         wall->apply(builder, Vec2(hDiv, i));
1568   }
1569 
makeVertDiv(LevelBuilder * builder,Rectangle area)1570   void makeVertDiv(LevelBuilder* builder, Rectangle area) {
1571     int vDiv = area.top() + min(area.height() - 1, max(1, (int) (vRatio * area.height())));
1572     if (upperLeft)
1573       upperLeft->make(builder, Rectangle(area.left(), area.top(), area.right(), vDiv));
1574     if (lowerLeft)
1575       lowerLeft->make(builder, Rectangle(area.left(), vDiv + (wall ? 1 : 0), area.right(), area.bottom()));
1576     if (wall)
1577       for (int i : Range(area.left(), area.right()))
1578         wall->apply(builder, Vec2(i, vDiv));
1579   }
1580 
makeDiv(LevelBuilder * builder,Rectangle area)1581   void makeDiv(LevelBuilder* builder, Rectangle area) {
1582     int vDiv = area.top() + min(area.height() - 1, max(1, (int) (vRatio * area.height())));
1583     int hDiv = area.left() + min(area.width() - 1, max(1, (int) (hRatio * area.width())));
1584     int wallSpace = wall ? 1 : 0;
1585     if (upperLeft)
1586       upperLeft->make(builder, Rectangle(area.left(), area.top(), hDiv, vDiv));
1587     if (upperRight)
1588       upperRight->make(builder, Rectangle(hDiv + wallSpace, area.top(), area.right(), vDiv));
1589     if (lowerLeft)
1590       lowerLeft->make(builder, Rectangle(area.left(), vDiv + wallSpace, hDiv, area.bottom()));
1591     if (lowerRight)
1592       lowerRight->make(builder, Rectangle(hDiv + wallSpace, vDiv + wallSpace, area.right(), area.bottom()));
1593     if (wall) {
1594       for (int i : Range(area.top(), area.bottom()))
1595         wall->apply(builder, Vec2(hDiv, i));
1596       for (int i : Range(area.left(), area.right()))
1597         wall->apply(builder, Vec2(i, vDiv));
1598     }
1599   }
1600 
make(LevelBuilder * builder,Rectangle area)1601   virtual void make(LevelBuilder* builder, Rectangle area) override {
1602     if (vRatio < 0)
1603       makeHorizDiv(builder, area);
1604     else if (hRatio < 0)
1605       makeVertDiv(builder, area);
1606     else
1607       makeDiv(builder, area);
1608   }
1609 
1610   private:
1611   double vRatio, hRatio;
1612   PLevelMaker upperLeft;
1613   PLevelMaker upperRight;
1614   PLevelMaker lowerLeft;
1615   PLevelMaker lowerRight;
1616   optional<SquareChange> wall;
1617 };
1618 
1619 class AreaCorners : public LevelMaker {
1620   public:
AreaCorners(PLevelMaker _maker,Vec2 _size,vector<PLevelMaker> _insideMakers)1621   AreaCorners(PLevelMaker _maker, Vec2 _size, vector<PLevelMaker> _insideMakers)
1622       : maker(std::move(_maker)), size(_size), insideMakers(std::move(_insideMakers)) {}
1623 
getCorners(Rectangle area)1624   vector<Rectangle> getCorners(Rectangle area) {
1625     return {
1626       Rectangle(area.topLeft(), area.topLeft() + size),
1627       Rectangle(area.topRight() - Vec2(size.x, 0), area.topRight() + Vec2(0, size.y)),
1628       Rectangle(area.bottomLeft() - Vec2(0, size.y), area.bottomLeft() + Vec2(size.x, 0)),
1629       Rectangle(area.bottomRight() - size, area.bottomRight())};
1630   }
1631 
make(LevelBuilder * builder,Rectangle area)1632   virtual void make(LevelBuilder* builder, Rectangle area) override {
1633     vector<Rectangle> corners = builder->getRandom().permutation(getCorners(area));
1634     for (int i : All(corners)) {
1635       maker->make(builder, corners[i]);
1636       if (i < insideMakers.size())
1637         insideMakers[i]->make(builder, corners[i]);
1638     }
1639   }
1640 
1641   private:
1642   PLevelMaker maker;
1643   Vec2 size;
1644   vector<PLevelMaker> insideMakers;
1645 };
1646 
1647 class CastleExit : public LevelMaker {
1648   public:
CastleExit(TribeId _guardTribe,BuildingType _building,CreatureId _guardId)1649   CastleExit(TribeId _guardTribe, BuildingType _building, CreatureId _guardId)
1650     : guardTribe(_guardTribe), building(_building), guardId(_guardId) {}
1651 
make(LevelBuilder * builder,Rectangle area)1652   virtual void make(LevelBuilder* builder, Rectangle area) override {
1653     Vec2 loc(area.right() - 1, area.middle().y);
1654     builder->resetFurniture(loc + Vec2(2, 0), building.floorInside);
1655     if (building.door)
1656       builder->putFurniture(loc + Vec2(2, 0), *building.door);
1657     builder->addAttrib(loc + Vec2(2, 0), SquareAttrib::CONNECT_ROAD);
1658     vector<Vec2> walls { Vec2(1, -2), Vec2(2, -2), Vec2(2, -1), Vec2(2, 1), Vec2(2, 2), Vec2(1, 2)};
1659     for (Vec2 v : walls)
1660       builder->putFurniture(loc + v, building.wall);
1661     vector<Vec2> floor { Vec2(1, -1), Vec2(1, 0), Vec2(1, 1), Vec2(0, -1), Vec2(0, 0), Vec2(0, 1) };
1662     for (Vec2 v : floor)
1663       builder->resetFurniture(loc + v, building.floorInside);
1664     vector<Vec2> guardPos { Vec2(1, 1), Vec2(1, -1) };
1665     for (Vec2 pos : guardPos) {
1666       builder->putCreature(loc + pos, CreatureFactory::fromId(guardId, guardTribe,
1667           MonsterAIFactory::stayInLocation(
1668               builder->toGlobalCoordinates(Rectangle(loc + pos, loc + pos + Vec2(1, 1))), false)));
1669     }
1670   }
1671 
1672   private:
1673   TribeId guardTribe;
1674   BuildingType building;
1675   CreatureId guardId;
1676 };
1677 
1678 class AddMapBorder : public LevelMaker {
1679   public:
AddMapBorder(int w)1680   AddMapBorder(int w) : width(w) {}
1681 
make(LevelBuilder * builder,Rectangle area)1682   virtual void make(LevelBuilder* builder, Rectangle area) override {
1683     for (Vec2 v : area)
1684       if (!v.inRectangle(area.minusMargin(width)))
1685         builder->setUnavailable(v);
1686   }
1687 
1688   private:
1689   int width;
1690 };
1691 
1692 class BorderGuard : public LevelMaker {
1693   public:
1694 
BorderGuard(PLevelMaker inside,SquareChange c)1695   BorderGuard(PLevelMaker inside, SquareChange c)
1696       : change(c), insideMaker(std::move(inside)) {}
1697 
make(LevelBuilder * builder,Rectangle area)1698   virtual void make(LevelBuilder* builder, Rectangle area) override {
1699     for (int i : Range(area.left(), area.right())) {
1700       change.apply(builder, Vec2(i, area.top()));
1701       change.apply(builder, Vec2(i, area.bottom() - 1));
1702     }
1703     for (int i : Range(area.top(), area.bottom())) {
1704       change.apply(builder, Vec2(area.left(), i));
1705       change.apply(builder, Vec2(area.right() - 1, i));
1706     }
1707     insideMaker->make(builder, Rectangle(area.left() + 1, area.top() + 1, area.right() - 1, area.bottom() - 1));
1708   }
1709 
1710   private:
1711   SquareChange change;
1712   PLevelMaker insideMaker;
1713 
1714 };
1715 }
1716 
1717 
1718 
stockpileMaker(StockpileInfo info)1719 static PMakerQueue stockpileMaker(StockpileInfo info) {
1720   auto floor = FurnitureType::FLOOR_STONE1;
1721   ItemFactory items;
1722   optional<FurnitureType> furniture;
1723   switch (info.type) {
1724     case StockpileInfo::GOLD:
1725       furniture = FurnitureType::TREASURE_CHEST;
1726       items = ItemFactory::singleType(ItemType::GoldPiece{});
1727       break;
1728     case StockpileInfo::MINERALS:
1729       items = ItemFactory::minerals();
1730       break;
1731   }
1732   auto queue = unique<MakerQueue>();
1733   queue->addMaker(unique<Empty>(floor));
1734   if (furniture)
1735     queue->addMaker(unique<Empty>(SquareChange(*furniture)));
1736   queue->addMaker(unique<Items>(items, info.number, info.number + 1, Predicate::alwaysTrue(), !!furniture));
1737   return queue;
1738 }
1739 
cryptLevel(RandomGen & random,SettlementInfo info)1740 PLevelMaker LevelMaker::cryptLevel(RandomGen& random, SettlementInfo info) {
1741   auto queue = unique<MakerQueue>();
1742   BuildingType building = getBuildingInfo(info);
1743   queue->addMaker(unique<Empty>(SquareChange(FurnitureType::FLOOR, FurnitureType::MOUNTAIN)));
1744   queue->addMaker(unique<PlaceCollective>(info.collective));
1745   queue->addMaker(unique<RoomMaker>(random.get(8, 15), 3, 5));
1746   queue->addMaker(unique<Connector>(building.door, 0));
1747   if (info.furniture)
1748     queue->addMaker(unique<Furnitures>(Predicate::attrib(SquareAttrib::EMPTY_ROOM), 0.3, *info.furniture));
1749   for (StairKey key : info.downStairs)
1750     queue->addMaker(unique<Stairs>(StairDirection::DOWN, key, Predicate::type(FurnitureType::FLOOR)));
1751   for (StairKey key : info.upStairs)
1752     queue->addMaker(unique<Stairs>(StairDirection::UP, key, Predicate::type(FurnitureType::FLOOR)));
1753   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective));
1754   queue->addMaker(unique<Items>(ItemFactory::dungeon(), 5, 10));
1755   return unique<BorderGuard>(std::move(queue), SquareChange(FurnitureType::FLOOR, FurnitureType::MOUNTAIN));
1756 }
1757 
mazeLevel(RandomGen & random,SettlementInfo info)1758 PLevelMaker LevelMaker::mazeLevel(RandomGen& random, SettlementInfo info) {
1759   auto queue = unique<MakerQueue>();
1760   BuildingType building = getBuildingInfo(info);
1761   queue->addMaker(unique<Empty>(SquareChange(FurnitureType::FLOOR, FurnitureType::MOUNTAIN)));
1762   queue->addMaker(unique<RoomMaker>(random.get(8, 15), 3, 5));
1763   queue->addMaker(unique<Connector>(building.door, 0.75));
1764   if (info.furniture)
1765     queue->addMaker(unique<Furnitures>(Predicate::attrib(SquareAttrib::EMPTY_ROOM), 0.3, *info.furniture));
1766   for (StairKey key : info.downStairs)
1767     queue->addMaker(unique<Stairs>(StairDirection::DOWN, key, Predicate::type(FurnitureType::FLOOR)));
1768   for (StairKey key : info.upStairs)
1769     queue->addMaker(unique<Stairs>(StairDirection::UP, key, Predicate::type(FurnitureType::FLOOR)));
1770   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective));
1771   queue->addMaker(unique<Items>(ItemFactory::dungeon(), 5, 10));
1772   return unique<BorderGuard>(std::move(queue), SquareChange(FurnitureType::FLOOR, FurnitureType::MOUNTAIN));
1773 }
1774 
getElderRoom(SettlementInfo info)1775 static PMakerQueue getElderRoom(SettlementInfo info) {
1776   BuildingType building = getBuildingInfo(info);
1777   PMakerQueue elderRoom = unique<MakerQueue>();
1778   if (info.elderLoot)
1779     elderRoom->addMaker(unique<Items>(ItemFactory::singleType(*info.elderLoot), 1, 2));
1780   return elderRoom;
1781 }
1782 
village2(RandomGen & random,SettlementInfo info)1783 static PMakerQueue village2(RandomGen& random, SettlementInfo info) {
1784   BuildingType building = getBuildingInfo(info);
1785   auto queue = unique<MakerQueue>();
1786   queue->addMaker(unique<PlaceCollective>(info.collective));
1787   vector<PLevelMaker> insideMakers = makeVec<PLevelMaker>(getElderRoom(info));
1788   for (auto& elem : info.stockpiles)
1789     insideMakers.push_back(stockpileMaker(elem));
1790   if (info.shopFactory)
1791     insideMakers.push_back(unique<ShopMaker>(*info.shopFactory, info.tribe, random.get(8, 16), building));
1792   queue->addMaker(unique<Buildings>(6, 10, 3, 4, building, false, std::move(insideMakers)));
1793   if (info.furniture)
1794     queue->addMaker(unique<Furnitures>(Predicate::attrib(SquareAttrib::EMPTY_ROOM), 0.3, *info.furniture));
1795   if (info.outsideFeatures)
1796     queue->addMaker(unique<Furnitures>(Predicate::type(building.floorOutside), 0.01, *info.outsideFeatures));
1797   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective, Predicate::type(building.floorOutside)));
1798   return queue;
1799 }
1800 
village(RandomGen & random,SettlementInfo info,int minRooms,int maxRooms)1801 static PMakerQueue village(RandomGen& random, SettlementInfo info, int minRooms, int maxRooms) {
1802   BuildingType building = getBuildingInfo(info);
1803   auto queue = unique<MakerQueue>();
1804   queue->addMaker(unique<PlaceCollective>(info.collective));
1805   queue->addMaker(unique<UniformBlob>(building.floorOutside, none, none, 0.6));
1806   vector<PLevelMaker> insideMakers = makeVec<PLevelMaker>(
1807  //     hatchery(CreatureFactory::singleType(info.tribe, CreatureId::PIG), random.get(2, 5)),
1808       getElderRoom(info));
1809   if (info.shopFactory)
1810     insideMakers.push_back(unique<ShopMaker>(*info.shopFactory, info.tribe, random.get(8, 16), building));
1811   for (auto& elem : info.stockpiles)
1812     insideMakers.push_back(stockpileMaker(elem));
1813   queue->addMaker(unique<Buildings>(minRooms, maxRooms, 3, 7, building, true, std::move(insideMakers)));
1814   if (info.furniture)
1815     queue->addMaker(unique<Furnitures>(Predicate::attrib(SquareAttrib::EMPTY_ROOM), 0.3, *info.furniture));
1816   if (info.outsideFeatures)
1817     queue->addMaker(unique<Furnitures>(
1818         Predicate::type(building.floorOutside) &&
1819         Predicate::attrib(SquareAttrib::BUILDINGS_CENTER), 0.2, *info.outsideFeatures, SquareAttrib::NO_ROAD));
1820   for (StairKey key : info.downStairs)
1821     queue->addMaker(unique<Stairs>(StairDirection::DOWN, key, Predicate::attrib(SquareAttrib::EMPTY_ROOM)));
1822   for (StairKey key : info.upStairs)
1823     queue->addMaker(unique<Stairs>(StairDirection::UP, key, Predicate::attrib(SquareAttrib::EMPTY_ROOM)));
1824   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective, Predicate::type(building.floorOutside)));
1825   return queue;
1826 }
1827 
cottage(SettlementInfo info)1828 static PMakerQueue cottage(SettlementInfo info) {
1829   BuildingType building = getBuildingInfo(info);
1830   auto queue = unique<MakerQueue>();
1831   queue->addMaker(unique<Empty>(building.floorOutside));
1832   auto room = getElderRoom(info);
1833   for (StairKey key : info.upStairs)
1834     room->addMaker(unique<Stairs>(StairDirection::UP, key, Predicate::type(building.floorInside), none));
1835   for (StairKey key : info.downStairs)
1836     room->addMaker(unique<Stairs>(StairDirection::DOWN, key, Predicate::type(building.floorInside), none));
1837   if (info.furniture)
1838     room->addMaker(unique<Furnitures>(Predicate::type(building.floorInside), 0.3, *info.furniture));
1839   if (info.outsideFeatures)
1840     room->addMaker(unique<Furnitures>(Predicate::type(building.floorOutside), 0.1, *info.outsideFeatures));
1841   queue->addMaker(unique<Buildings>(1, 2, 5, 7, building, false, std::move(room), false));
1842   queue->addMaker(unique<PlaceCollective>(info.collective));
1843   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective, Predicate::type(building.floorOutside)));
1844   return queue;
1845 }
1846 
forrestCottage(SettlementInfo info)1847 static PMakerQueue forrestCottage(SettlementInfo info) {
1848   BuildingType building = getBuildingInfo(info);
1849   auto queue = unique<MakerQueue>();
1850   auto room = getElderRoom(info);
1851   for (StairKey key : info.upStairs)
1852     room->addMaker(unique<Stairs>(StairDirection::UP, key, Predicate::type(building.floorInside), none));
1853   for (StairKey key : info.downStairs)
1854     room->addMaker(unique<Stairs>(StairDirection::DOWN, key, Predicate::type(building.floorInside), none));
1855   if (info.furniture)
1856     room->addMaker(unique<Furnitures>(Predicate::type(building.floorInside), 0.3, *info.furniture));
1857   if (info.outsideFeatures)
1858     room->addMaker(unique<Furnitures>(Predicate::type(building.floorOutside), 0.1, *info.outsideFeatures));
1859   queue->addMaker(unique<Buildings>(1, 3, 3, 4, building, false, std::move(room), false));
1860   queue->addMaker(unique<PlaceCollective>(info.collective));
1861   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective, Predicate::type(building.floorOutside)));
1862   return queue;
1863 }
1864 
castle(RandomGen & random,SettlementInfo info)1865 static PMakerQueue castle(RandomGen& random, SettlementInfo info) {
1866   BuildingType building = getBuildingInfo(info);
1867   auto castleRoom = [&] { return unique<BorderGuard>(unique<Empty>(SquareChange::reset(building.floorInside).add(SquareAttrib::EMPTY_ROOM)),
1868       SquareChange(building.wall, SquareAttrib::ROOM_WALL)); };
1869   auto leftSide = unique<MakerQueue>();
1870   leftSide->addMaker(unique<Division>(true, random.getDouble(0.5, 0.5),
1871       unique<Margin>(1, -1, -1, 1, castleRoom()), unique<Margin>(1, 1, -1, -1, castleRoom())));
1872   leftSide->addMaker(getElderRoom(info));
1873   auto inside = unique<MakerQueue>();
1874   vector<PLevelMaker> insideMakers;
1875   if (info.shopFactory)
1876     insideMakers.push_back(unique<ShopMaker>(*info.shopFactory, info.tribe, random.get(8, 16), building));
1877   inside->addMaker(unique<Division>(random.getDouble(0.25, 0.4), std::move(leftSide),
1878         unique<Buildings>(1, 3, 3, 6, building, false, std::move(insideMakers), false),
1879             SquareChange(building.wall, SquareAttrib::ROOM_WALL)));
1880   auto insidePlusWall = unique<MakerQueue>();
1881   if (info.outsideFeatures)
1882     inside->addMaker(unique<Furnitures>(Predicate::type(building.floorOutside), 0.03, *info.outsideFeatures));
1883   if (info.furniture)
1884     inside->addMaker(unique<Furnitures>(Predicate::attrib(SquareAttrib::EMPTY_ROOM), 0.35, *info.furniture));
1885   insidePlusWall->addMaker(unique<Empty>(SquareChange::reset(building.floorOutside)));
1886   insidePlusWall->addMaker(unique<BorderGuard>(std::move(inside), building.wall));
1887   auto queue = unique<MakerQueue>();
1888   int insideMargin = 2;
1889   queue->addMaker(unique<Margin>(insideMargin, unique<PlaceCollective>(info.collective)));
1890   queue->addMaker(unique<Margin>(insideMargin, std::move(insidePlusWall)));
1891   vector<PLevelMaker> cornerMakers;
1892   for (auto& elem : info.stockpiles)
1893     cornerMakers.push_back(unique<Margin>(1, stockpileMaker(elem)));
1894   queue->addMaker(unique<AreaCorners>(
1895       unique<BorderGuard>(unique<Empty>(SquareChange::reset(building.floorInside).add(SquareAttrib::CASTLE_CORNER)),
1896           SquareChange(building.wall, SquareAttrib::ROOM_WALL)),
1897       Vec2(5, 5),
1898       std::move(cornerMakers)));
1899   queue->addMaker(unique<Margin>(insideMargin, unique<Connector>(building.door, 1, 18)));
1900   queue->addMaker(unique<Margin>(insideMargin, unique<CastleExit>(info.tribe, building, *info.guardId)));
1901   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective, Predicate::type(building.floorOutside)));
1902   for (StairKey key : info.downStairs)
1903     queue->addMaker(unique<Stairs>(StairDirection::DOWN, key,
1904           Predicate::attrib(SquareAttrib::CASTLE_CORNER) &&
1905           Predicate::type(building.floorInside), none));
1906   queue->addMaker(unique<StartingPos>(Predicate::type(FurnitureType::MUD), StairKey::heroSpawn()));
1907   queue->addMaker(unique<AddAttrib>(SquareAttrib::NO_DIG, Predicate::type(building.wall)));
1908   return queue;
1909 }
1910 
castle2(RandomGen & random,SettlementInfo info)1911 static PMakerQueue castle2(RandomGen& random, SettlementInfo info) {
1912   BuildingType building = getBuildingInfo(info);
1913   auto inside = unique<MakerQueue>();
1914   auto insideMaker = unique<MakerQueue>(
1915       getElderRoom(info),
1916       stockpileMaker(info.stockpiles.getOnlyElement()));
1917   inside->addMaker(unique<Buildings>(1, 2, 3, 4, building, false, std::move(insideMaker), false));
1918   auto insidePlusWall = unique<MakerQueue>();
1919   insidePlusWall->addMaker(unique<Empty>(building.floorOutside));
1920   insidePlusWall->addMaker(unique<BorderGuard>(std::move(inside), building.wall));
1921   auto queue = unique<MakerQueue>();
1922   queue->addMaker(unique<PlaceCollective>(info.collective));
1923   queue->addMaker(std::move(insidePlusWall));
1924   queue->addMaker(unique<Connector>(building.door, 1, 18));
1925   queue->addMaker(unique<CastleExit>(info.tribe, building, *info.guardId));
1926   if (info.outsideFeatures)
1927     queue->addMaker(unique<Furnitures>(Predicate::type(building.floorOutside), 0.05, *info.outsideFeatures));
1928   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective, Predicate::type(building.floorOutside)));
1929   queue->addMaker(unique<AddAttrib>(SquareAttrib::NO_DIG, Predicate::type(building.wall)));
1930   return queue;
1931 }
1932 
tower(RandomGen & random,SettlementInfo info,bool withExit)1933 static PLevelMaker tower(RandomGen& random, SettlementInfo info, bool withExit) {
1934   BuildingType building = getBuildingInfo(info);
1935   auto queue = unique<MakerQueue>();
1936   queue->addMaker(unique<Empty>(SquareChange(FurnitureType::FLOOR, building.wall)));
1937   if (withExit)
1938     queue->addMaker(unique<LevelExit>(*building.door, 2));
1939   queue->addMaker(unique<Margin>(1, unique<Empty>(SquareChange::reset(building.floorInside))));
1940   queue->addMaker(unique<Margin>(1, unique<AddAttrib>(SquareAttrib::ROOM)));
1941   queue->addMaker(unique<RemoveAttrib>(SquareAttrib::ROAD_CUT_THRU));
1942   if (info.collective)
1943     queue->addMaker(unique<PlaceCollective>(info.collective));
1944   PLevelMaker downStairs;
1945   for (StairKey key : info.downStairs)
1946     downStairs = unique<Stairs>(StairDirection::DOWN, key, Predicate::type(building.floorInside));
1947   PLevelMaker upStairs;
1948   for (StairKey key : info.upStairs)
1949     upStairs = unique<Stairs>(StairDirection::UP, key, Predicate::type(building.floorInside));
1950   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective, Predicate::type(building.floorInside)));
1951   queue->addMaker(unique<Division>(0.5, 0.5, std::move(upStairs), nullptr, nullptr, std::move(downStairs)));
1952   if (info.furniture)
1953     queue->addMaker(unique<Furnitures>(Predicate::type(building.floorInside), 0.5, *info.furniture));
1954   return std::move(queue);
1955 }
1956 
towerLevel(RandomGen & random,SettlementInfo info)1957 PLevelMaker LevelMaker::towerLevel(RandomGen& random, SettlementInfo info) {
1958   return PLevelMaker(tower(random, info, false));
1959 }
1960 
getSize(RandomGen & random,SettlementType type)1961 Vec2 getSize(RandomGen& random, SettlementType type) {
1962   switch (type) {
1963     case SettlementType::WITCH_HOUSE:
1964     case SettlementType::CEMETERY:
1965     case SettlementType::MOUNTAIN_LAKE:
1966     case SettlementType::SMALL_VILLAGE:
1967     case SettlementType::SWAMP: return {random.get(12, 16), random.get(12, 16)};
1968     case SettlementType::COTTAGE: return {random.get(8, 10), random.get(8, 10)};
1969     case SettlementType::FORREST_COTTAGE: return {15, 15};
1970     case SettlementType::FOREST: return {18, 13};
1971     case SettlementType::FORREST_VILLAGE: return {20, 20};
1972     case SettlementType::VILLAGE:
1973     case SettlementType::ANT_NEST:
1974     case SettlementType::CASTLE: return {30, 20};
1975     case SettlementType::CASTLE2: return {13, 13};
1976     case SettlementType::MINETOWN: return {30, 20};
1977     case SettlementType::SMALL_MINETOWN: return {15, 15};
1978     case SettlementType::CAVE: return {12, 12};
1979     case SettlementType::SPIDER_CAVE: return {12, 12};
1980     case SettlementType::VAULT: return {10, 10};
1981     case SettlementType::TOWER: return {5, 5};
1982     case SettlementType::ISLAND_VAULT_DOOR:
1983     case SettlementType::ISLAND_VAULT: return {6, 6};
1984   }
1985 }
1986 
getSettlementPredicate(SettlementType type)1987 RandomLocations::LocationPredicate getSettlementPredicate(SettlementType type) {
1988   switch (type) {
1989     case SettlementType::FOREST:
1990     case SettlementType::FORREST_COTTAGE:
1991     case SettlementType::FORREST_VILLAGE:
1992       return !Predicate::attrib(SquareAttrib::RIVER) && Predicate::attrib(SquareAttrib::FORREST);
1993     case SettlementType::CAVE:
1994       return RandomLocations::LocationPredicate(
1995           Predicate::type(FurnitureType::MOUNTAIN), Predicate::attrib(SquareAttrib::HILL), 5, 15);
1996     case SettlementType::VAULT:
1997     case SettlementType::ANT_NEST:
1998     case SettlementType::SMALL_MINETOWN:
1999     case SettlementType::MINETOWN:
2000       return Predicate::type(FurnitureType::MOUNTAIN);
2001     case SettlementType::SPIDER_CAVE:
2002       return RandomLocations::LocationPredicate(
2003           Predicate::type(FurnitureType::MOUNTAIN),
2004           Predicate::attrib(SquareAttrib::CONNECTOR), 1, 2);
2005     case SettlementType::MOUNTAIN_LAKE:
2006     case SettlementType::ISLAND_VAULT:
2007       return Predicate::attrib(SquareAttrib::MOUNTAIN);
2008     case SettlementType::ISLAND_VAULT_DOOR:
2009       return RandomLocations::LocationPredicate(
2010             Predicate::attrib(SquareAttrib::MOUNTAIN) && !Predicate::attrib(SquareAttrib::RIVER),
2011             Predicate::attrib(SquareAttrib::RIVER), 10, 30);
2012     default:
2013       return Predicate::attrib(SquareAttrib::LOWLAND) &&
2014           !Predicate::attrib(SquareAttrib::RIVER);
2015   }
2016 }
2017 
genericMineTownMaker(RandomGen & random,SettlementInfo info,int numCavern,int maxCavernSize,int numRooms,int minRoomSize,int maxRoomSize,bool connect)2018 static PMakerQueue genericMineTownMaker(RandomGen& random, SettlementInfo info, int numCavern, int maxCavernSize,
2019     int numRooms, int minRoomSize, int maxRoomSize, bool connect) {
2020   BuildingType building = getBuildingInfo(info);
2021   auto queue = unique<MakerQueue>();
2022   vector<PLevelMaker> vCavern;
2023   vector<pair<int, int>> sizes;
2024   for (int i : Range(numCavern)) {
2025     sizes.push_back(make_pair(random.get(5, maxCavernSize), random.get(5, maxCavernSize)));
2026     vCavern.push_back(unique<UniformBlob>(building.floorInside));
2027   }
2028   queue->addMaker(unique<RandomLocations>(std::move(vCavern), sizes, Predicate::alwaysTrue(), false));
2029   vector<PLevelMaker> roomInsides;
2030   if (info.shopFactory)
2031     roomInsides.push_back(unique<ShopMaker>(*info.shopFactory, info.tribe, random.get(8, 16), building));
2032   for (auto& elem : info.stockpiles)
2033     roomInsides.push_back(stockpileMaker(elem));
2034   queue->addMaker(unique<RoomMaker>(numRooms, minRoomSize, maxRoomSize, building.wall, none,
2035       unique<Empty>(SquareChange(building.floorInside, ifTrue(connect, SquareAttrib::CONNECT_CORRIDOR))),
2036       std::move(roomInsides), true));
2037   queue->addMaker(unique<Connector>(none, 0));
2038   Predicate featurePred = Predicate::attrib(SquareAttrib::EMPTY_ROOM) && Predicate::type(building.floorInside);
2039   for (StairKey key : info.downStairs)
2040     queue->addMaker(unique<Stairs>(StairDirection::DOWN, key, featurePred));
2041   for (StairKey key : info.upStairs)
2042     queue->addMaker(unique<Stairs>(StairDirection::UP, key, featurePred));
2043   if (info.furniture)
2044     queue->addMaker(unique<Furnitures>(featurePred, 0.3, *info.furniture));
2045   if (info.outsideFeatures)
2046     queue->addMaker(unique<Furnitures>(Predicate::type(building.floorInside), 0.09, *info.outsideFeatures));
2047   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective));
2048   queue->addMaker(unique<PlaceCollective>(info.collective));
2049   return queue;
2050 }
2051 
mineTownMaker(RandomGen & random,SettlementInfo info)2052 static PMakerQueue mineTownMaker(RandomGen& random, SettlementInfo info) {
2053   return genericMineTownMaker(random, info, 10, 12, random.get(5, 7), 6, 8, true);
2054 }
2055 
antNestMaker(RandomGen & random,SettlementInfo info)2056 static PMakerQueue antNestMaker(RandomGen& random, SettlementInfo info) {
2057   auto ret = genericMineTownMaker(random, info, 4, 6, random.get(5, 7), 3, 4, false);
2058   ret->addMaker(unique<AddAttrib>(SquareAttrib::NO_DIG));
2059   return ret;
2060 }
2061 
smallMineTownMaker(RandomGen & random,SettlementInfo info)2062 static PMakerQueue smallMineTownMaker(RandomGen& random, SettlementInfo info) {
2063   return genericMineTownMaker(random, info, 2, 7, random.get(3, 5), 5, 7, true);
2064 }
2065 
vaultMaker(SettlementInfo info,bool connection)2066 static PMakerQueue vaultMaker(SettlementInfo info, bool connection) {
2067   auto queue = unique<MakerQueue>();
2068   BuildingType building = getBuildingInfo(info);
2069   if (connection)
2070     queue->addMaker(unique<UniformBlob>(building.floorOutside, none, SquareAttrib::CONNECT_CORRIDOR));
2071   else
2072     queue->addMaker(unique<UniformBlob>(building.floorOutside));
2073   auto insidePredicate = Predicate::type(building.floorOutside) && Predicate::canEnter(MovementTrait::WALK);
2074   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective, insidePredicate));
2075   if (info.shopFactory)
2076     queue->addMaker(unique<Items>(*info.shopFactory, 16, 20, insidePredicate));
2077   queue->addMaker(unique<PlaceCollective>(info.collective, insidePredicate));
2078   return queue;
2079 }
2080 
spiderCaveMaker(SettlementInfo info)2081 static PMakerQueue spiderCaveMaker(SettlementInfo info) {
2082   auto queue = unique<MakerQueue>();
2083   BuildingType building = getBuildingInfo(info);
2084   auto inside = unique<MakerQueue>();
2085   inside->addMaker(unique<UniformBlob>(building.floorOutside, none, SquareAttrib::CONNECT_CORRIDOR));
2086   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective));
2087   if (info.shopFactory)
2088     inside->addMaker(unique<Items>(*info.shopFactory, 5, 10));
2089   queue->addMaker(unique<Margin>(3, std::move(inside)));
2090   queue->addMaker(unique<PlaceCollective>(info.collective));
2091   queue->addMaker(unique<Connector>(none, 0));
2092   return queue;
2093 }
2094 
islandVaultMaker(RandomGen & random,SettlementInfo info,bool door)2095 static PLevelMaker islandVaultMaker(RandomGen& random, SettlementInfo info, bool door) {
2096   BuildingType building = getBuildingInfo(info);
2097   auto inside = unique<MakerQueue>();
2098   inside->addMaker(unique<PlaceCollective>(info.collective));
2099   Predicate featurePred = Predicate::type(building.floorInside);
2100   if (!info.stockpiles.empty())
2101     inside->addMaker(stockpileMaker(info.stockpiles.getOnlyElement()));
2102   else
2103     inside->addMaker(unique<Empty>(SquareChange::reset(building.floorInside)));
2104   for (StairKey key : info.downStairs)
2105     inside->addMaker(unique<Stairs>(StairDirection::DOWN, key, featurePred));
2106   for (StairKey key : info.upStairs)
2107     inside->addMaker(unique<Stairs>(StairDirection::UP, key, featurePred));
2108   auto buildingMaker = unique<MakerQueue>(
2109       unique<Empty>(SquareChange(building.wall)),
2110       unique<AddAttrib>(SquareAttrib::NO_DIG),
2111       unique<RemoveAttrib>(SquareAttrib::CONNECT_CORRIDOR),
2112       unique<Margin>(1, std::move(inside))
2113       );
2114   if (door)
2115     buildingMaker->addMaker(unique<LevelExit>(FurnitureFactory(TribeId::getMonster(), FurnitureType::DOOR)));
2116   return unique<MakerQueue>(
2117         unique<Empty>(SquareChange::reset(FurnitureType::WATER)),
2118         unique<Margin>(1, std::move(buildingMaker)));
2119 }
2120 
dragonCaveMaker(SettlementInfo info)2121 static PMakerQueue dragonCaveMaker(SettlementInfo info) {
2122   auto queue = vaultMaker(info, true);
2123 /*  queue->addMaker(unique<RandomLocations>({unique<CreatureAltarMaker>(info.collective)}, {{1, 1}},
2124       {Predicate::type(FurnitureType::HILL)}));*/
2125   return queue;
2126 }
2127 
mineTownLevel(RandomGen & random,SettlementInfo info)2128 PLevelMaker LevelMaker::mineTownLevel(RandomGen& random, SettlementInfo info) {
2129   auto queue = unique<MakerQueue>();
2130   queue->addMaker(unique<Empty>(SquareChange(FurnitureType::FLOOR, FurnitureType::MOUNTAIN)));
2131   queue->addMaker(mineTownMaker(random, info));
2132   return unique<BorderGuard>(std::move(queue), SquareChange(FurnitureType::FLOOR, FurnitureType::MOUNTAIN));
2133 }
2134 
cemetery(SettlementInfo info)2135 static PMakerQueue cemetery(SettlementInfo info) {
2136   BuildingType building = getBuildingInfo(info);
2137   auto queue = unique<MakerQueue>(
2138           unique<PlaceCollective>(info.collective),
2139           unique<Margin>(1, unique<Buildings>(1, 2, 2, 3, building, false, nullptr, false)),
2140           unique<Furnitures>(Predicate::type(FurnitureType::GRASS), 0.15,
2141               FurnitureFactory(info.tribe, FurnitureType::GRAVE)));
2142   for (StairKey key : info.downStairs)
2143     queue->addMaker(unique<Stairs>(StairDirection::DOWN, key, Predicate::type(building.floorInside)));
2144   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective));
2145   return queue;
2146 }
2147 
emptyCollective(SettlementInfo info)2148 static PLevelMaker emptyCollective(SettlementInfo info) {
2149   return unique<MakerQueue>(
2150       unique<PlaceCollective>(info.collective),
2151       unique<Inhabitants>(info.inhabitants, info.collective));
2152 }
2153 
swamp(SettlementInfo info)2154 static PMakerQueue swamp(SettlementInfo info) {
2155   auto queue = unique<MakerQueue>(
2156       unique<Lake>(false),
2157       unique<PlaceCollective>(info.collective)
2158   );
2159   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective));
2160   return queue;
2161 }
2162 
mountainLake(SettlementInfo info)2163 static PMakerQueue mountainLake(SettlementInfo info) {
2164   auto queue = unique<MakerQueue>(
2165       unique<UniformBlob>(FurnitureType::WATER, none, SquareAttrib::LAKE),
2166       unique<PlaceCollective>(info.collective)
2167   );
2168   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective));
2169   return queue;
2170 }
2171 
getMountains(BiomeId id)2172 static PLevelMaker getMountains(BiomeId id) {
2173   switch (id) {
2174     case BiomeId::GRASSLAND:
2175     case BiomeId::FORREST:
2176       return unique<Mountains>(0.68, 0.06, NoiseInit{0, 1, 0, 0, 0});
2177     case BiomeId::MOUNTAIN:
2178       return unique<Mountains>(0.25, 0.1, NoiseInit{0, 1, 0, 0, 0});
2179   }
2180 }
2181 
getForrest(BiomeId id)2182 static PLevelMaker getForrest(BiomeId id) {
2183   FurnitureFactory vegetationLow(TribeId::getHostile(),
2184       {{FurnitureType::CANIF_TREE, 2}, {FurnitureType::BUSH, 1 }});
2185   FurnitureFactory vegetationHigh(TribeId::getHostile(),
2186       {{FurnitureType::DECID_TREE, 2}, {FurnitureType::BUSH, 1 }});
2187   switch (id) {
2188     case BiomeId::MOUNTAIN:
2189       return unique<MakerQueue>(
2190           unique<Forrest>(0.2, 0.5, FurnitureType::GRASS, vegetationLow),
2191           unique<Forrest>(0.8, 0.5, FurnitureType::HILL, vegetationHigh));
2192     case BiomeId::GRASSLAND:
2193       return unique<MakerQueue>(
2194           unique<Forrest>(0.3, 0.25, FurnitureType::GRASS, vegetationLow),
2195           unique<Forrest>(0.8, 0.25, FurnitureType::HILL, vegetationHigh));
2196     case BiomeId::FORREST:
2197       return unique<MakerQueue>(
2198           unique<Forrest>(0.8, 0.5, FurnitureType::GRASS, vegetationLow),
2199           unique<Forrest>(0.8, 0.5, FurnitureType::HILL, vegetationHigh));
2200   }
2201 }
2202 
getForrestCreatures(CreatureFactory factory,int levelWidth,BiomeId biome)2203 static PLevelMaker getForrestCreatures(CreatureFactory factory, int levelWidth, BiomeId biome) {
2204   int div;
2205   switch (biome) {
2206     case BiomeId::FORREST: div = 2000; break;
2207     case BiomeId::GRASSLAND:
2208     case BiomeId::MOUNTAIN: div = 7000; break;
2209   }
2210   return unique<Creatures>(factory, levelWidth * levelWidth / div, MonsterAIFactory::wildlifeNonPredator());
2211 }
2212 
topLevel(RandomGen & random,optional<CreatureFactory> forrestCreatures,vector<SettlementInfo> settlements,int width,bool keeperSpawn,BiomeId biomeId)2213 PLevelMaker LevelMaker::topLevel(RandomGen& random, optional<CreatureFactory> forrestCreatures,
2214     vector<SettlementInfo> settlements, int width, bool keeperSpawn, BiomeId biomeId) {
2215   auto queue = unique<MakerQueue>();
2216   auto locations = unique<RandomLocations>();
2217   auto locations2 = unique<RandomLocations>();
2218   LevelMaker* startingPos = nullptr;
2219   int locationMargin = 10;
2220   if (keeperSpawn) {
2221     auto startingPosMaker = unique<StartingPos>(Predicate::alwaysTrue(), StairKey::keeperSpawn());
2222     startingPos = startingPosMaker.get();
2223     locations->add(std::move(startingPosMaker), Vec2(4, 4), RandomLocations::LocationPredicate(
2224         Predicate::attrib(SquareAttrib::HILL) && Predicate::canEnter({MovementTrait::WALK}),
2225         Predicate::attrib(SquareAttrib::MOUNTAIN), 1, 8));
2226     int minMargin = 50;
2227     locations->setMinMargin(startingPos, minMargin - locationMargin);
2228   }
2229   struct CottageInfo {
2230     LevelMaker* maker;
2231     CollectiveBuilder* collective;
2232     TribeId tribe;
2233     int maxDistance;
2234   };
2235   vector<CottageInfo> cottages;
2236   for (SettlementInfo settlement : settlements) {
2237     PLevelMaker queue;
2238     switch (settlement.type) {
2239       case SettlementType::SMALL_VILLAGE:
2240         queue = village(random, settlement, 3, 4);
2241         cottages.push_back({queue.get(), settlement.collective, settlement.tribe, 16});
2242         break;
2243       case SettlementType::VILLAGE:
2244         queue = village(random, settlement, 4, 8);
2245         break;
2246       case SettlementType::FORREST_VILLAGE:
2247         queue = village2(random, settlement);
2248         break;
2249       case SettlementType::CASTLE:
2250         queue = castle(random, settlement);
2251         break;
2252       case SettlementType::CASTLE2:
2253         queue = castle2(random, settlement);
2254         break;
2255       case SettlementType::COTTAGE:
2256         queue = cottage(settlement);
2257         cottages.push_back({queue.get(), settlement.collective, settlement.tribe, 13});
2258         break;
2259       case SettlementType::FORREST_COTTAGE:
2260         queue = forrestCottage(settlement);
2261         break;
2262       case SettlementType::TOWER:
2263         queue = tower(random, settlement, true);
2264         break;
2265       case SettlementType::WITCH_HOUSE:
2266         queue = cottage(settlement);
2267         break;
2268       case SettlementType::FOREST:
2269         queue = emptyCollective(settlement);
2270         break;
2271       case SettlementType::MINETOWN:
2272         queue = mineTownMaker(random, settlement);
2273         break;
2274       case SettlementType::ANT_NEST:
2275         queue = antNestMaker(random, settlement);
2276         break;
2277       case SettlementType::SMALL_MINETOWN:
2278         queue = smallMineTownMaker(random, settlement);
2279         break;
2280       case SettlementType::VAULT:
2281         queue = vaultMaker(settlement, false);
2282         if (keeperSpawn)
2283           locations->setMaxDistance(startingPos, queue.get(), width / 3);
2284         break;
2285       case SettlementType::ISLAND_VAULT:
2286         queue = islandVaultMaker(random, settlement, false);
2287         break;
2288       case SettlementType::ISLAND_VAULT_DOOR:
2289         queue = islandVaultMaker(random, settlement, true);
2290         break;
2291       case SettlementType::CAVE:
2292         queue = dragonCaveMaker(settlement);
2293         break;
2294       case SettlementType::SPIDER_CAVE:
2295         queue = spiderCaveMaker(settlement);
2296         break;
2297       case SettlementType::CEMETERY:
2298         queue = cemetery(settlement);
2299         break;
2300       case SettlementType::MOUNTAIN_LAKE:
2301         queue = mountainLake(settlement);
2302         break;
2303       case SettlementType::SWAMP:
2304         queue = swamp(settlement);
2305         break;
2306     }
2307     if (settlement.type == SettlementType::SPIDER_CAVE)
2308       locations2->add(std::move(queue), getSize(random, settlement.type), getSettlementPredicate(settlement.type));
2309     else {
2310       if (keeperSpawn) {
2311         if (settlement.closeToPlayer) {
2312           locations->setMinDistance(startingPos, queue.get(), 25);
2313           locations->setMaxDistance(startingPos, queue.get(), 60);
2314         } else
2315           locations->setMinDistance(startingPos, queue.get(), 70);
2316       }
2317       locations->add(std::move(queue), getSize(random, settlement.type), getSettlementPredicate(settlement.type));
2318     }
2319   }
2320   Predicate lowlandPred = Predicate::attrib(SquareAttrib::LOWLAND) && !Predicate::attrib(SquareAttrib::RIVER);
2321   for (auto& cottage : cottages)
2322     for (int i : Range(random.get(1, 3))) {
2323       locations->add(unique<MakerQueue>(
2324             unique<RemoveFurniture>(FurnitureLayer::MIDDLE),
2325             unique<FurnitureBlob>(FurnitureFactory(cottage.tribe, FurnitureType::CROPS)),
2326             unique<PlaceCollective>(cottage.collective)),
2327           {random.get(7, 12), random.get(7, 12)},
2328           lowlandPred);
2329       locations->setMaxDistanceLast(cottage.maker, cottage.maxDistance);
2330     }
2331   if (biomeId == BiomeId::GRASSLAND || biomeId == BiomeId::FORREST)
2332     for (int i : Range(random.get(0, 3)))
2333       locations->add(unique<Lake>(), {random.get(20, 30), random.get(20, 30)}, Predicate::attrib(SquareAttrib::LOWLAND));
2334   if (biomeId == BiomeId::MOUNTAIN)
2335     for (int i : Range(random.get(3, 6))) {
2336       locations->add(unique<UniformBlob>(FurnitureType::WATER, none, SquareAttrib::LAKE),
2337           {random.get(10, 30), random.get(10, 30)}, Predicate::type(FurnitureType::MOUNTAIN));
2338   //  locations->setMaxDistanceLast(startingPos, i == 0 ? 25 : 60);
2339   }
2340 /*  for (int i : Range(random.get(3, 5))) {
2341     locations->add(unique<UniformBlob>(FurnitureType::FLOOR, none),
2342         {random.get(5, 12), random.get(5, 12)}, Predicate::type(SquareId::MOUNTAIN));
2343  //   locations->setMaxDistanceLast(startingPos, i == 0 ? 25 : 40);
2344   }*/
2345   int mapBorder = 30;
2346   queue->addMaker(unique<Empty>(FurnitureType::WATER));
2347   queue->addMaker(getMountains(biomeId));
2348   queue->addMaker(unique<MountainRiver>(1, Predicate::type(FurnitureType::MOUNTAIN)));
2349   queue->addMaker(unique<AddAttrib>(SquareAttrib::CONNECT_CORRIDOR, Predicate::attrib(SquareAttrib::LOWLAND)));
2350   queue->addMaker(unique<AddAttrib>(SquareAttrib::CONNECT_CORRIDOR, Predicate::attrib(SquareAttrib::HILL)));
2351   queue->addMaker(getForrest(biomeId));
2352   queue->addMaker(unique<Margin>(mapBorder + locationMargin, std::move(locations)));
2353   queue->addMaker(unique<Margin>(mapBorder, unique<Roads>()));
2354   queue->addMaker(unique<Margin>(mapBorder,
2355         unique<TransferPos>(Predicate::canEnter(MovementTrait::WALK), StairKey::transferLanding(), 2)));
2356   queue->addMaker(unique<Margin>(mapBorder, unique<Connector>(none, 0, 5,
2357           Predicate::canEnter({MovementTrait::WALK}) &&
2358           Predicate::attrib(SquareAttrib::CONNECT_CORRIDOR),
2359       SquareAttrib::CONNECTOR)));
2360   queue->addMaker(unique<Margin>(mapBorder + locationMargin, std::move(locations2)));
2361   queue->addMaker(unique<Items>(ItemFactory::mushrooms(), width / 10, width / 5));
2362   queue->addMaker(unique<AddMapBorder>(mapBorder));
2363   if (forrestCreatures)
2364     queue->addMaker(unique<Margin>(mapBorder, getForrestCreatures(*forrestCreatures, width - 2 * mapBorder, biomeId)));
2365   return std::move(queue);
2366 }
2367 
getRandomExit(RandomGen & random,Rectangle rect,int minCornerDist)2368 Vec2 LevelMaker::getRandomExit(RandomGen& random, Rectangle rect, int minCornerDist) {
2369   CHECK(rect.width() > 2 * minCornerDist && rect.height() > 2 * minCornerDist);
2370   int w1 = random.get(2);
2371   int w2 = random.get(2);
2372   int d1 = random.get(minCornerDist, rect.width() - minCornerDist);
2373   int d2 = random.get(minCornerDist, rect.height() - minCornerDist);
2374   return Vec2(
2375         rect.left() + d1 * w1 + (1 - w1) * w2 * (rect.width() - 1),
2376         rect.top() + d2 * (1 - w1) + w1 * w2 * (rect.height() - 1));
2377 }
2378 
2379 class SpecificArea : public LevelMaker {
2380   public:
SpecificArea(Rectangle a,PLevelMaker m)2381   SpecificArea(Rectangle a, PLevelMaker m) : area(a), maker(std::move(m)) {}
2382 
make(LevelBuilder * builder,Rectangle)2383   virtual void make(LevelBuilder* builder, Rectangle) override {
2384     maker->make(builder, area);
2385   }
2386 
2387   private:
2388   Rectangle area;
2389   PLevelMaker maker;
2390 };
2391 
splashLevel(CreatureFactory heroLeader,CreatureFactory heroes,CreatureFactory monsters,CreatureFactory imps,const FilePath & splashPath)2392 PLevelMaker LevelMaker::splashLevel(CreatureFactory heroLeader, CreatureFactory heroes, CreatureFactory monsters,
2393     CreatureFactory imps, const FilePath& splashPath) {
2394   auto queue = unique<MakerQueue>();
2395   queue->addMaker(unique<Empty>(FurnitureType::BLACK_FLOOR));
2396   Rectangle leaderSpawn(
2397           Level::getSplashVisibleBounds().right() + 1, Level::getSplashVisibleBounds().middle().y,
2398           Level::getSplashVisibleBounds().right() + 2, Level::getSplashVisibleBounds().middle().y + 1);
2399   Rectangle heroSpawn(
2400           Level::getSplashVisibleBounds().right() + 2, Level::getSplashVisibleBounds().middle().y - 1,
2401           Level::getSplashBounds().right(), Level::getSplashVisibleBounds().middle().y + 2);
2402   Rectangle monsterSpawn1(
2403           Level::getSplashVisibleBounds().left(), 0,
2404           Level::getSplashVisibleBounds().right(), Level::getSplashVisibleBounds().top() - 1);
2405   Rectangle monsterSpawn2(
2406           Level::getSplashVisibleBounds().left(), Level::getSplashVisibleBounds().bottom() + 2,
2407           Level::getSplashVisibleBounds().right(), Level::getSplashBounds().bottom());
2408   queue->addMaker(unique<SpecificArea>(leaderSpawn, unique<Creatures>(heroLeader, 1,MonsterAIFactory::splashHeroes(true))));
2409   queue->addMaker(unique<SpecificArea>(heroSpawn, unique<Creatures>(heroes, 22, MonsterAIFactory::splashHeroes(false))));
2410   queue->addMaker(unique<SpecificArea>(monsterSpawn1, unique<Creatures>(monsters, 17, MonsterAIFactory::splashMonsters())));
2411   queue->addMaker(unique<SpecificArea>(monsterSpawn2, unique<Creatures>(monsters, 17, MonsterAIFactory::splashMonsters())));
2412   queue->addMaker(unique<SpecificArea>(monsterSpawn1, unique<Creatures>(imps, 15,
2413           MonsterAIFactory::splashImps(splashPath))));
2414   queue->addMaker(unique<SpecificArea>(monsterSpawn2, unique<Creatures>(imps, 15,
2415           MonsterAIFactory::splashImps(splashPath))));
2416   queue->addMaker(unique<SetSunlight>(0.0, !Predicate::inRectangle(Level::getSplashVisibleBounds())));
2417   return std::move(queue);
2418 }
2419 
2420 
underground(RandomGen & random,CreatureFactory waterFactory,CreatureFactory lavaFactory)2421 static PLevelMaker underground(RandomGen& random, CreatureFactory waterFactory, CreatureFactory lavaFactory) {
2422   auto queue = unique<MakerQueue>();
2423   if (random.roll(1)) {
2424     vector<PLevelMaker> vCavern;
2425     vector<pair<int, int>> sizes;
2426     int minSize = random.get(5, 15);
2427     int maxSize = minSize + random.get(3, 10);
2428     for (int i : Range(sqrt(random.get(4, 100)))) {
2429       int size = random.get(minSize, maxSize);
2430       sizes.push_back(make_pair(size, size));
2431    /*   if (random.roll(4))
2432         queue->addMaker(unique<Items>(ItemFactory::mushrooms(), SquareId::PATH, 2, 5));*/
2433       vCavern.push_back(unique<UniformBlob>(FurnitureType::FLOOR));
2434     }
2435     queue->addMaker(unique<RandomLocations>(std::move(vCavern), sizes, Predicate::alwaysTrue(), false));
2436   }
2437   switch (random.get(1, 3)) {
2438     case 1: queue->addMaker(unique<River>(3, random.choose(FurnitureType::WATER, FurnitureType::MAGMA)));
2439             break;
2440     case 2:{
2441           int numLakes = sqrt(random.get(1, 100));
2442           auto lakeType = random.choose(FurnitureType::WATER, FurnitureType::MAGMA);
2443           vector<pair<int, int>> sizes;
2444           vector<PLevelMaker> makers;
2445           for (int i : Range(numLakes)) {
2446             int size = random.get(6, 20);
2447             sizes.emplace_back(size, size);
2448             makers.push_back(unique<UniformBlob>(lakeType, none, SquareAttrib::LAKE));
2449           }
2450           queue->addMaker(unique<RandomLocations>(std::move(makers), sizes, Predicate::alwaysTrue(), false));
2451           if (lakeType == FurnitureType::WATER) {
2452             queue->addMaker(unique<Creatures>(waterFactory, 1, MonsterAIFactory::monster(),
2453                   Predicate::type(FurnitureType::WATER)));
2454           }
2455           if (lakeType == FurnitureType::MAGMA) {
2456             queue->addMaker(unique<Creatures>(lavaFactory, random.get(1, 4),
2457                   MonsterAIFactory::monster(), Predicate::type(FurnitureType::MAGMA)));
2458           }
2459            break;
2460       }
2461     default: break;
2462   }
2463   return std::move(queue);
2464 }
2465 
roomLevel(RandomGen & random,CreatureFactory roomFactory,CreatureFactory waterFactory,CreatureFactory lavaFactory,vector<StairKey> up,vector<StairKey> down,FurnitureFactory furniture)2466 PLevelMaker LevelMaker::roomLevel(RandomGen& random, CreatureFactory roomFactory, CreatureFactory waterFactory,
2467     CreatureFactory lavaFactory, vector<StairKey> up, vector<StairKey> down, FurnitureFactory furniture) {
2468   auto queue = unique<MakerQueue>();
2469   queue->addMaker(unique<Empty>(SquareChange(FurnitureType::FLOOR, FurnitureType::MOUNTAIN)));
2470   queue->addMaker(underground(random, waterFactory, lavaFactory));
2471   queue->addMaker(unique<RoomMaker>(random.get(8, 15), 4, 7, SquareChange::none(),
2472         FurnitureType::MOUNTAIN, unique<Empty>(FurnitureType::FLOOR)));
2473   queue->addMaker(unique<Connector>(FurnitureFactory(TribeId::getHostile(), FurnitureType::DOOR), 0.5));
2474   queue->addMaker(unique<Furnitures>(Predicate::attrib(SquareAttrib::EMPTY_ROOM), 0.05, furniture));
2475   for (StairKey key : down)
2476     queue->addMaker(unique<Stairs>(StairDirection::DOWN, key, Predicate::type(FurnitureType::FLOOR)));
2477   for (StairKey key : up)
2478     queue->addMaker(unique<Stairs>(StairDirection::UP, key, Predicate::type(FurnitureType::FLOOR)));
2479   queue->addMaker(unique<Creatures>(roomFactory, random.get(10, 15), MonsterAIFactory::monster()));
2480   queue->addMaker(unique<Items>(ItemFactory::dungeon(), 5, 10));
2481   return unique<BorderGuard>(std::move(queue), SquareChange(FurnitureType::FLOOR, FurnitureType::MOUNTAIN));
2482 }
2483 
2484 namespace {
2485 
2486 class SokobanFromFile : public LevelMaker {
2487   public:
SokobanFromFile(Table<char> f,StairKey hole)2488   SokobanFromFile(Table<char> f, StairKey hole) : file(f), holeKey(hole) {}
2489 
make(LevelBuilder * builder,Rectangle area)2490   virtual void make(LevelBuilder* builder, Rectangle area) override {
2491     CHECK(area == file.getBounds()) << "Bad size of sokoban input.";
2492     builder->setNoDiagonalPassing();
2493     for (Vec2 v : area) {
2494       builder->resetFurniture(v, FurnitureType::FLOOR);
2495       switch (file[v]) {
2496         case '.':
2497           break;
2498         case '#':
2499           builder->putFurniture(v, FurnitureType::DUNGEON_WALL);
2500           break;
2501         case '^':
2502           builder->putFurniture(v, FurnitureType::SOKOBAN_HOLE);
2503           break;
2504         case '$':
2505           builder->addAttrib(v, SquareAttrib::SOKOBAN_PRIZE);
2506           break;
2507         case '@':
2508           builder->addAttrib(v, SquareAttrib::SOKOBAN_ENTRY);
2509           break;
2510         case '+':
2511           builder->putFurniture(v, FurnitureParams{FurnitureType::DOOR, TribeId::getHostile()});
2512           break;
2513         case '0':
2514           builder->putCreature(v, CreatureFactory::fromId(CreatureId::SOKOBAN_BOULDER, TribeId::getPeaceful()));
2515           break;
2516         default: FATAL << "Unknown symbol in sokoban data: " << file[v];
2517       }
2518     }
2519   }
2520 
2521   Table<char> file;
2522   StairKey holeKey;
2523 };
2524 
2525 }
2526 
sokobanFromFile(RandomGen & random,SettlementInfo info,Table<char> file)2527 PLevelMaker LevelMaker::sokobanFromFile(RandomGen& random, SettlementInfo info, Table<char> file) {
2528   auto queue = unique<MakerQueue>();
2529   queue->addMaker(unique<SokobanFromFile>(file, info.downStairs.getOnlyElement()));
2530   queue->addMaker(unique<Stairs>(StairDirection::DOWN, info.downStairs.getOnlyElement(),
2531         Predicate::attrib(SquareAttrib::SOKOBAN_ENTRY)));
2532   //queue->addMaker(unique<PlaceCollective>(info.collective));
2533   queue->addMaker(unique<Inhabitants>(info.inhabitants, info.collective, Predicate::attrib(SquareAttrib::SOKOBAN_PRIZE)));
2534   return std::move(queue);
2535 }
2536 
2537 namespace {
2538 
2539 class BattleFromFile : public LevelMaker {
2540   public:
BattleFromFile(Table<char> f,CreatureList a,CreatureList e)2541   BattleFromFile(Table<char> f, CreatureList a, CreatureList e)
2542       : level(f), allies(a), enemies(e) {}
2543 
make(LevelBuilder * builder,Rectangle area)2544   virtual void make(LevelBuilder* builder, Rectangle area) override {
2545     CHECK(area == level.getBounds()) << "Bad size of battle level input.";
2546     auto alliesList = allies.generate(builder->getRandom(), TribeId::getKeeper(), MonsterAIFactory::guard());
2547     int allyIndex = 0;
2548     auto enemyList = enemies.generate(builder->getRandom(), TribeId::getHuman(),
2549         MonsterAIFactory::singleTask(Task::attackCreatures(getWeakPointers(alliesList))));
2550     int enemyIndex = 0;
2551     for (Vec2 v : area) {
2552       builder->resetFurniture(v, FurnitureType::FLOOR);
2553       switch (level[v]) {
2554         case '.':
2555           break;
2556         case '#':
2557           builder->putFurniture(v, FurnitureType::MOUNTAIN);
2558           break;
2559         case 'a':
2560           if (allyIndex < alliesList.size()) {
2561             builder->putCreature(v, std::move(alliesList[allyIndex]));
2562             ++allyIndex;
2563           }
2564           break;
2565         case 'e':
2566           if (enemyIndex < enemyList.size()) {
2567             builder->putCreature(v, std::move(enemyList[enemyIndex]));
2568             ++enemyIndex;
2569           }
2570           break;
2571         default: FATAL << "Unknown symbol in battle test data: " << level[v];
2572       }
2573     }
2574   }
2575 
2576   Table<char> level;
2577   CreatureList allies;
2578   CreatureList enemies;
2579 };
2580 
2581 }
2582 
battleLevel(Table<char> level,CreatureList allies,CreatureList enemies)2583 PLevelMaker LevelMaker::battleLevel(Table<char> level, CreatureList allies, CreatureList enemies) {
2584   return unique<BattleFromFile>(level, allies, enemies);
2585 }
2586 
emptyLevel(RandomGen &)2587 PLevelMaker LevelMaker::emptyLevel(RandomGen&) {
2588   auto queue = unique<MakerQueue>();
2589   queue->addMaker(unique<Empty>(FurnitureType::GRASS));
2590   return std::move(queue);
2591 }
2592