1 #include "stdafx.h"
2 #include "util.h"
3 #include "creature.h"
4 #include "collective_config.h"
5 #include "tribe.h"
6 #include "game.h"
7 #include "technology.h"
8 #include "collective_warning.h"
9 #include "item_type.h"
10 #include "resource_id.h"
11 #include "inventory.h"
12 #include "workshops.h"
13 #include "lasting_effect.h"
14 #include "item.h"
15 #include "view_id.h"
16 #include "furniture_type.h"
17 #include "spawn_type.h"
18 #include "minion_task.h"
19 #include "furniture_usage.h"
20 #include "creature_attributes.h"
21 #include "collective.h"
22 #include "zones.h"
23 #include "construction_map.h"
24 #include "item_class.h"
25 #include "villain_type.h"
26 #include "furniture.h"
27 #include "immigrant_info.h"
28 #include "tutorial_highlight.h"
29 #include "trap_type.h"
30 #include "spell_id.h"
31 #include "spell.h"
32 #include "creature_factory.h"
33 #include "resource_info.h"
34 #include "workshop_item.h"
35
36
37 template <class Archive>
serialize(Archive & ar,const unsigned int version)38 void CollectiveConfig::serialize(Archive& ar, const unsigned int version) {
39 ar(immigrantInterval, maxPopulation, populationIncreases, immigrantInfo);
40 ar(type, leaderAsFighter, spawnGhosts, ghostProb, guardianInfo, regenerateMana);
41 }
42
43 SERIALIZABLE(CollectiveConfig);
44 SERIALIZATION_CONSTRUCTOR_IMPL(CollectiveConfig);
45
46 template <class Archive>
serialize(Archive & ar,const unsigned int version)47 void AttractionInfo::serialize(Archive& ar, const unsigned int version) {
48 ar(types, amountClaimed);
49 }
50
51 SERIALIZABLE(AttractionInfo);
52 SERIALIZATION_CONSTRUCTOR_IMPL(AttractionInfo);
53
54 template <class Archive>
serialize(Archive & ar,const unsigned int version)55 void PopulationIncrease::serialize(Archive& ar, const unsigned int version) {
56 ar(type, increasePerSquare, maxIncrease);
57 }
58
59 SERIALIZABLE(PopulationIncrease);
60
61 template <class Archive>
serialize(Archive & ar,const unsigned int version)62 void GuardianInfo::serialize(Archive& ar, const unsigned int version) {
63 ar(creature, probability, minEnemies, minVictims);
64 }
65
66 SERIALIZABLE(GuardianInfo);
67
addBedRequirementToImmigrants()68 void CollectiveConfig::addBedRequirementToImmigrants() {
69 for (auto& info : immigrantInfo) {
70 PCreature c = CreatureFactory::fromId(info.getId(0), TribeId::getKeeper());
71 if (auto spawnType = c->getAttributes().getSpawnType()) {
72 AttractionType bedType = getDormInfo()[*spawnType].bedType;
73 bool hasBed = false;
74 info.visitRequirements(makeVisitor(
75 [&](const AttractionInfo& attraction) -> void {
76 for (auto& type : attraction.types)
77 if (type == bedType)
78 hasBed = true;
79 },
80 [&](const auto&) {}
81 ));
82 if (!hasBed)
83 info.addRequirement(AttractionInfo(1, bedType));
84 }
85 }
86 }
87
CollectiveConfig(int interval,const vector<ImmigrantInfo> & im,CollectiveType t,int maxPop,vector<PopulationIncrease> popInc)88 CollectiveConfig::CollectiveConfig(int interval, const vector<ImmigrantInfo>& im,
89 CollectiveType t, int maxPop, vector<PopulationIncrease> popInc)
90 : immigrantInterval(interval),
91 maxPopulation(maxPop), populationIncreases(popInc), immigrantInfo(im), type(t) {
92 if (type == KEEPER)
93 addBedRequirementToImmigrants();
94 }
95
keeper(int immigrantInterval,int maxPopulation,bool regenerateMana,vector<PopulationIncrease> increases,const vector<ImmigrantInfo> & im)96 CollectiveConfig CollectiveConfig::keeper(int immigrantInterval, int maxPopulation, bool regenerateMana,
97 vector<PopulationIncrease> increases, const vector<ImmigrantInfo>& im) {
98 auto ret = CollectiveConfig(immigrantInterval, im, KEEPER, maxPopulation, increases);
99 ret.regenerateMana = regenerateMana;
100 return ret;
101 }
102
withImmigrants(int interval,int maxPopulation,const vector<ImmigrantInfo> & im)103 CollectiveConfig CollectiveConfig::withImmigrants(int interval, int maxPopulation, const vector<ImmigrantInfo>& im) {
104 return CollectiveConfig(interval, im, VILLAGE, maxPopulation, {});
105 }
106
noImmigrants()107 CollectiveConfig CollectiveConfig::noImmigrants() {
108 return CollectiveConfig(0, {}, VILLAGE, 10000, {});
109 }
110
setLeaderAsFighter()111 CollectiveConfig& CollectiveConfig::setLeaderAsFighter() {
112 leaderAsFighter = true;
113 return *this;
114 }
115
setGhostSpawns(double prob,int num)116 CollectiveConfig& CollectiveConfig::setGhostSpawns(double prob, int num) {
117 ghostProb = prob;
118 spawnGhosts = num;
119 return *this;
120 }
121
getNumGhostSpawns() const122 int CollectiveConfig::getNumGhostSpawns() const {
123 return spawnGhosts;
124 }
125
getImmigrantTimeout() const126 int CollectiveConfig::getImmigrantTimeout() const {
127 return 500;
128 }
129
getGhostProb() const130 double CollectiveConfig::getGhostProb() const {
131 return ghostProb;
132 }
133
isLeaderFighter() const134 bool CollectiveConfig::isLeaderFighter() const {
135 return leaderAsFighter;
136 }
137
getManageEquipment() const138 bool CollectiveConfig::getManageEquipment() const {
139 return type == KEEPER;
140 }
141
getFollowLeaderIfNoTerritory() const142 bool CollectiveConfig::getFollowLeaderIfNoTerritory() const {
143 return type == KEEPER;
144 }
145
hasVillainSleepingTask() const146 bool CollectiveConfig::hasVillainSleepingTask() const {
147 return type != KEEPER;
148 }
149
getRegenerateMana() const150 bool CollectiveConfig::getRegenerateMana() const {
151 return regenerateMana;
152 }
153
hasImmigrantion(bool currentlyActiveModel) const154 bool CollectiveConfig::hasImmigrantion(bool currentlyActiveModel) const {
155 return type != KEEPER || currentlyActiveModel;
156 }
157
getImmigrantInterval() const158 int CollectiveConfig::getImmigrantInterval() const {
159 return immigrantInterval;
160 }
161
getStripSpawns() const162 bool CollectiveConfig::getStripSpawns() const {
163 return type == KEEPER;
164 }
165
getFetchItems() const166 bool CollectiveConfig::getFetchItems() const {
167 return type == KEEPER;
168 }
169
getEnemyPositions() const170 bool CollectiveConfig::getEnemyPositions() const {
171 return type == KEEPER;
172 }
173
getWarnings() const174 bool CollectiveConfig::getWarnings() const {
175 return type == KEEPER;
176 }
177
getConstructions() const178 bool CollectiveConfig::getConstructions() const {
179 return type == KEEPER;
180 }
181
bedsLimitImmigration() const182 bool CollectiveConfig::bedsLimitImmigration() const {
183 return type == KEEPER;
184 }
185
getMaxPopulation() const186 int CollectiveConfig::getMaxPopulation() const {
187 return maxPopulation;
188 }
189
getImmigrantInfo() const190 const vector<ImmigrantInfo>& CollectiveConfig::getImmigrantInfo() const {
191 return immigrantInfo;
192 }
193
getPopulationIncreases() const194 const vector<PopulationIncrease>& CollectiveConfig::getPopulationIncreases() const {
195 return populationIncreases;
196 }
197
setGuardian(GuardianInfo info)198 CollectiveConfig& CollectiveConfig::setGuardian(GuardianInfo info) {
199 guardianInfo = info;
200 return *this;
201 }
202
getGuardianInfo() const203 const optional<GuardianInfo>& CollectiveConfig::getGuardianInfo() const {
204 return guardianInfo;
205 }
206
getDormInfo() const207 const EnumMap<SpawnType, DormInfo>& CollectiveConfig::getDormInfo() const {
208 static EnumMap<SpawnType, DormInfo> dormInfo ([](SpawnType type) -> DormInfo {
209 switch (type) {
210 case SpawnType::HUMANOID: return {FurnitureType::BED, CollectiveWarning::BEDS};
211 case SpawnType::UNDEAD: return {FurnitureType::GRAVE};
212 case SpawnType::BEAST: return {FurnitureType::BEAST_CAGE};
213 case SpawnType::DEMON: return {FurnitureType::DEMON_SHRINE};
214 }
215 });
216 return dormInfo;
217 }
218
getRoomsNeedingLight() const219 const vector<FurnitureType>& CollectiveConfig::getRoomsNeedingLight() const {
220 static vector<FurnitureType> ret {
221 FurnitureType::WORKSHOP,
222 FurnitureType::FORGE,
223 FurnitureType::LABORATORY,
224 FurnitureType::JEWELER,
225 FurnitureType::STEEL_FURNACE,
226 FurnitureType::TRAINING_WOOD,
227 FurnitureType::TRAINING_IRON,
228 FurnitureType::TRAINING_STEEL,
229 FurnitureType::BOOKCASE_WOOD,
230 FurnitureType::BOOKCASE_IRON,
231 FurnitureType::BOOKCASE_GOLD,
232 };
233 return ret;
234 };
235
getFloors()236 const vector<FloorInfo>& CollectiveConfig::getFloors() {
237 static vector<FloorInfo> ret = {
238 {FurnitureType::FLOOR_WOOD1, {CollectiveResourceId::WOOD, 2}, "Wooden", 0.02},
239 {FurnitureType::FLOOR_WOOD2, {CollectiveResourceId::WOOD, 2}, "Wooden", 0.02},
240 {FurnitureType::FLOOR_STONE1, {CollectiveResourceId::STONE, 2}, "Stone", 0.04},
241 {FurnitureType::FLOOR_STONE2, {CollectiveResourceId::STONE, 2}, "Stone", 0.04},
242 {FurnitureType::FLOOR_CARPET1, {CollectiveResourceId::GOLD, 2}, "Carpet", 0.06},
243 {FurnitureType::FLOOR_CARPET2, {CollectiveResourceId::GOLD, 2}, "Carpet", 0.06},
244 };
245 return ret;
246 }
247
getEfficiencyBonus(FurnitureType type)248 double CollectiveConfig::getEfficiencyBonus(FurnitureType type) {
249 for (auto& info : getFloors())
250 if (info.type == type)
251 return info.efficiencyBonus;
252 switch (type) {
253 case FurnitureType::DUNGEON_WALL:
254 return 0.04;
255 default:
256 return 0;
257 }
258 }
259
canBuildOutsideTerritory(FurnitureType type)260 bool CollectiveConfig::canBuildOutsideTerritory(FurnitureType type) {
261 switch (type) {
262 case FurnitureType::EYEBALL:
263 case FurnitureType::KEEPER_BOARD:
264 case FurnitureType::DUNGEON_WALL:
265 case FurnitureType::TORCH_N:
266 case FurnitureType::TORCH_E:
267 case FurnitureType::TORCH_S:
268 case FurnitureType::TORCH_W:
269 case FurnitureType::TUTORIAL_ENTRANCE:
270 case FurnitureType::BRIDGE: return true;
271 default: return false;
272 }
273 }
274
getFurnitureStorage(FurnitureType t)275 static StorageDestinationFun getFurnitureStorage(FurnitureType t) {
276 return [t](WConstCollective col)->const set<Position>& { return col->getConstructions().getBuiltPositions(t); };
277 }
278
getZoneStorage(ZoneId zone)279 static StorageDestinationFun getZoneStorage(ZoneId zone) {
280 return [zone](WConstCollective col)->const set<Position>& { return col->getZones().getPositions(zone); };
281 }
282
getResourceInfo(CollectiveResourceId id)283 const ResourceInfo& CollectiveConfig::getResourceInfo(CollectiveResourceId id) {
284 static EnumMap<CollectiveResourceId, ResourceInfo> resourceInfo([](CollectiveResourceId id)->ResourceInfo {
285 switch (id) {
286 case CollectiveResourceId::MANA:
287 return { nullptr, none, ItemType::GoldPiece{}, "mana", ViewId::MANA};
288 case CollectiveResourceId::PRISONER_HEAD:
289 return { nullptr, none, ItemType::GoldPiece{}, "", ViewId::IMPALED_HEAD, true};
290 case CollectiveResourceId::GOLD:
291 return {getFurnitureStorage(FurnitureType::TREASURE_CHEST), ItemIndex::GOLD, ItemType::GoldPiece{}, "gold", ViewId::GOLD};
292 case CollectiveResourceId::WOOD:
293 return { getZoneStorage(ZoneId::STORAGE_RESOURCES), ItemIndex::WOOD, ItemType::WoodPlank{}, "wood", ViewId::WOOD_PLANK,
294 false, TutorialHighlight::WOOD_RESOURCE};
295 case CollectiveResourceId::IRON:
296 return { getZoneStorage(ZoneId::STORAGE_RESOURCES), ItemIndex::IRON, ItemType::IronOre{}, "iron", ViewId::IRON_ROCK};
297 case CollectiveResourceId::STEEL:
298 return { getZoneStorage(ZoneId::STORAGE_RESOURCES), ItemIndex::STEEL, ItemType::SteelIngot{}, "steel", ViewId::STEEL_INGOT};
299 case CollectiveResourceId::STONE:
300 return { getZoneStorage(ZoneId::STORAGE_RESOURCES), ItemIndex::STONE, ItemType::Rock{}, "granite", ViewId::ROCK};
301 case CollectiveResourceId::CORPSE:
302 return { getFurnitureStorage(FurnitureType::GRAVE), ItemIndex::REVIVABLE_CORPSE, ItemType::GoldPiece{}, "corpses", ViewId::BODY_PART, true};
303 }
304 });
305 return resourceInfo[id];
306 }
307
unMarkedItems()308 static CollectiveItemPredicate unMarkedItems() {
309 return [](WConstCollective col, WConstItem it) { return !col->isItemMarked(it); };
310 }
311
312
getFetchInfo()313 const vector<ItemFetchInfo>& CollectiveConfig::getFetchInfo() {
314 static vector<ItemFetchInfo> ret {
315 {ItemIndex::CORPSE, unMarkedItems(), getFurnitureStorage(FurnitureType::GRAVE), true, CollectiveWarning::GRAVES},
316 {ItemIndex::GOLD, unMarkedItems(), getFurnitureStorage(FurnitureType::TREASURE_CHEST), false,
317 CollectiveWarning::CHESTS},
318 {ItemIndex::MINION_EQUIPMENT, [](WConstCollective col, WConstItem it)
319 { return it->getClass() != ItemClass::GOLD && !col->isItemMarked(it);},
320 getZoneStorage(ZoneId::STORAGE_EQUIPMENT), false, CollectiveWarning::EQUIPMENT_STORAGE},
321 {ItemIndex::WOOD, unMarkedItems(), getZoneStorage(ZoneId::STORAGE_RESOURCES), false,
322 CollectiveWarning::RESOURCE_STORAGE},
323 {ItemIndex::IRON, unMarkedItems(), getZoneStorage(ZoneId::STORAGE_RESOURCES), false,
324 CollectiveWarning::RESOURCE_STORAGE},
325 {ItemIndex::STEEL, unMarkedItems(), getZoneStorage(ZoneId::STORAGE_RESOURCES), false,
326 CollectiveWarning::RESOURCE_STORAGE},
327 {ItemIndex::STONE, unMarkedItems(), getZoneStorage(ZoneId::STORAGE_RESOURCES), false,
328 CollectiveWarning::RESOURCE_STORAGE},
329 };
330 return ret;
331 }
332
MinionTaskInfo(Type t,const string & desc,optional<CollectiveWarning> w)333 MinionTaskInfo::MinionTaskInfo(Type t, const string& desc, optional<CollectiveWarning> w)
334 : type(t), description(desc), warning(w) {
335 CHECK(type != FURNITURE);
336 }
337
MinionTaskInfo()338 MinionTaskInfo::MinionTaskInfo() {}
339
MinionTaskInfo(FurnitureType type,const string & desc)340 MinionTaskInfo::MinionTaskInfo(FurnitureType type, const string& desc) : type(FURNITURE),
341 furniturePredicate([type](WConstCollective, WConstCreature, FurnitureType t) { return t == type;}),
342 description(desc) {
343 }
344
MinionTaskInfo(UsagePredicate pred,const string & desc)345 MinionTaskInfo::MinionTaskInfo(UsagePredicate pred, const string& desc) : type(FURNITURE),
346 furniturePredicate(pred), description(desc) {
347 }
348
MinionTaskInfo(UsagePredicate usagePred,ActivePredicate activePred,const string & desc)349 MinionTaskInfo::MinionTaskInfo(UsagePredicate usagePred, ActivePredicate activePred, const string& desc) :
350 type(FURNITURE), furniturePredicate(usagePred), activePredicate(activePred), description(desc) {
351 }
352
__anonad4a5b400a02(WorkshopType type)353 static EnumMap<WorkshopType, WorkshopInfo> workshops([](WorkshopType type)->WorkshopInfo {
354 switch (type) {
355 case WorkshopType::WORKSHOP: return {FurnitureType::WORKSHOP, "workshop", SkillId::WORKSHOP};
356 case WorkshopType::FORGE: return {FurnitureType::FORGE, "forge", SkillId::FORGE};
357 case WorkshopType::LABORATORY: return {FurnitureType::LABORATORY, "laboratory", SkillId::LABORATORY};
358 case WorkshopType::JEWELER: return {FurnitureType::JEWELER, "jeweler", SkillId::JEWELER};
359 case WorkshopType::STEEL_FURNACE: return {FurnitureType::STEEL_FURNACE, "steel furnace", SkillId::FURNACE};
360 }});
361
getWorkshopType(FurnitureType furniture)362 optional<WorkshopType> CollectiveConfig::getWorkshopType(FurnitureType furniture) {
363 static optional<EnumMap<FurnitureType, optional<WorkshopType>>> map;
364 if (!map) {
365 map.emplace();
366 for (auto type : ENUM_ALL(WorkshopType))
367 (*map)[workshops[type].furniture] = type;
368 }
369 return (*map)[furniture];
370 }
371
getStartingResource() const372 map<CollectiveResourceId, int> CollectiveConfig::getStartingResource() const {
373 return map<CollectiveResourceId, int>{};
374 }
375
getTrainingFurniture(ExperienceType type)376 const vector<FurnitureType>& CollectiveConfig::getTrainingFurniture(ExperienceType type) {
377 static EnumMap<ExperienceType, vector<FurnitureType>> ret(
378 [](ExperienceType expType) {
379 vector<FurnitureType> furniture;
380 for (auto type : ENUM_ALL(FurnitureType))
381 if (!!getTrainingMaxLevel(expType, type))
382 furniture.push_back(type);
383 return furniture;
384 });
385 return ret[type];
386 }
387
getTrainingMaxLevel(ExperienceType experienceType,FurnitureType type)388 optional<int> CollectiveConfig::getTrainingMaxLevel(ExperienceType experienceType, FurnitureType type) {
389 switch (experienceType) {
390 case ExperienceType::MELEE:
391 switch (type) {
392 case FurnitureType::TRAINING_WOOD:
393 return 3;
394 case FurnitureType::TRAINING_IRON:
395 return 7;
396 case FurnitureType::TRAINING_STEEL:
397 return 12;
398 default:
399 return none;
400 }
401 break;
402 case ExperienceType::SPELL:
403 switch (type) {
404 case FurnitureType::BOOKCASE_WOOD:
405 return 3;
406 case FurnitureType::BOOKCASE_IRON:
407 return 7;
408 case FurnitureType::BOOKCASE_GOLD:
409 return 12;
410 default:
411 return none;
412 }
413 break;
414 default:
415 return none;
416 }
417 }
418
getManaForConquering(const optional<VillainType> & type)419 int CollectiveConfig::getManaForConquering(const optional<VillainType>& type) {
420 if (type)
421 switch (*type) {
422 case VillainType::MAIN:
423 return 200;
424 case VillainType::LESSER:
425 return 100;
426 default:
427 break;;
428 }
429 return 50;
430 }
431
432 CollectiveConfig::CollectiveConfig(const CollectiveConfig&) = default;
433
~CollectiveConfig()434 CollectiveConfig::~CollectiveConfig() {
435 }
436
getTrainingPredicate(ExperienceType experienceType)437 static auto getTrainingPredicate(ExperienceType experienceType) {
438 return [experienceType] (WConstCollective, WConstCreature c, FurnitureType t) {
439 if (auto maxIncrease = CollectiveConfig::getTrainingMaxLevel(experienceType, t))
440 return !c || (c->getAttributes().getExpLevel(experienceType) < *maxIncrease &&
441 !c->getAttributes().isTrainingMaxedOut(experienceType));
442 else
443 return false;
444 };
445 }
446
447 template <typename Pred>
addManaGenerationPredicate(Pred p)448 static auto addManaGenerationPredicate(Pred p) {
449 return [p] (WConstCollective col, WConstCreature c, FurnitureType t) {
450 return (!!CollectiveConfig::getTrainingMaxLevel(ExperienceType::SPELL, t) &&
451 (!col || col->getConfig().getRegenerateMana()))
452 || p(col, c, t);
453 };
454 }
455
getTaskInfo(MinionTask task)456 const MinionTaskInfo& CollectiveConfig::getTaskInfo(MinionTask task) {
457 static EnumMap<MinionTask, MinionTaskInfo> map([](MinionTask task) -> MinionTaskInfo {
458 switch (task) {
459 case MinionTask::WORKER: return {MinionTaskInfo::WORKER, "working"};
460 case MinionTask::TRAIN: return {getTrainingPredicate(ExperienceType::MELEE), "training"};
461 case MinionTask::SLEEP: return {FurnitureType::BED, "sleeping"};
462 case MinionTask::EAT: return {MinionTaskInfo::EAT, "eating"};
463 case MinionTask::GRAVE: return {FurnitureType::GRAVE, "sleeping"};
464 case MinionTask::LAIR: return {FurnitureType::BEAST_CAGE, "sleeping"};
465 case MinionTask::THRONE: return {FurnitureType::THRONE, "throne"};
466 case MinionTask::STUDY: return {addManaGenerationPredicate(getTrainingPredicate(ExperienceType::SPELL)),
467 "studying"};
468 case MinionTask::PRISON: return {FurnitureType::PRISON, "prison"};
469 case MinionTask::CROPS: return {FurnitureType::CROPS, "crops"};
470 case MinionTask::RITUAL: return {FurnitureType::DEMON_SHRINE, "rituals"};
471 case MinionTask::ARCHERY: return {MinionTaskInfo::ARCHERY, "archery range"};
472 case MinionTask::COPULATE: return {MinionTaskInfo::COPULATE, "copulation"};
473 case MinionTask::EXPLORE: return {MinionTaskInfo::EXPLORE, "spying"};
474 case MinionTask::SPIDER: return {MinionTaskInfo::SPIDER, "spider"};
475 case MinionTask::EXPLORE_NOCTURNAL: return {MinionTaskInfo::EXPLORE, "spying"};
476 case MinionTask::EXPLORE_CAVES: return {MinionTaskInfo::EXPLORE, "spying"};
477 case MinionTask::BE_WHIPPED: return {FurnitureType::WHIPPING_POST, "being whipped"};
478 case MinionTask::BE_TORTURED: return {FurnitureType::TORTURE_TABLE, "being tortured"};
479 case MinionTask::BE_EXECUTED: return {FurnitureType::GALLOWS, "being executed"};
480 case MinionTask::CRAFT: return {[](WConstCollective, WConstCreature c, FurnitureType t) {
481 if (auto type = getWorkshopType(t))
482 return !c || c->getAttributes().getSkills().getValue(getWorkshopInfo(*type).skill) > 0;
483 else
484 return false;
485 },
486 [](WConstCollective collective, FurnitureType t) {
487 if (auto type = getWorkshopType(t))
488 return !collective->getWorkshops().get(*type).isIdle();
489 else
490 return false;
491 },
492 "crafting"};
493 }
494 });
495 return map[task];
496 }
497
getWorkshopInfo(WorkshopType type)498 const WorkshopInfo& CollectiveConfig::getWorkshopInfo(WorkshopType type) {
499 return workshops[type];
500 }
501
502
getWorkshops() const503 unique_ptr<Workshops> CollectiveConfig::getWorkshops() const {
504 return unique_ptr<Workshops>(new Workshops({
505 {WorkshopType::WORKSHOP, {
506 Workshops::Item::fromType(ItemType::LeatherArmor{}, 6, {CollectiveResourceId::WOOD, 20}),
507 Workshops::Item::fromType(ItemType::LeatherHelm{}, 1, {CollectiveResourceId::WOOD, 6}),
508 Workshops::Item::fromType(ItemType::LeatherBoots{}, 2, {CollectiveResourceId::WOOD, 10}),
509 Workshops::Item::fromType(ItemType::LeatherGloves{}, 1, {CollectiveResourceId::WOOD, 2}),
510 Workshops::Item::fromType(ItemType::Club{}, 3, {CollectiveResourceId::WOOD, 10})
511 .setTutorialHighlight(TutorialHighlight::SCHEDULE_CLUB),
512 Workshops::Item::fromType(ItemType::HeavyClub{}, 5, {CollectiveResourceId::WOOD, 20})
513 .setTechId(TechId::TWO_H_WEAP),
514 Workshops::Item::fromType(ItemType::Bow{}, 13, {CollectiveResourceId::WOOD, 20}).setTechId(TechId::ARCHERY),
515 Workshops::Item::fromType(ItemType::WoodenStaff{}, 13, {CollectiveResourceId::WOOD, 20})
516 .setTechId(TechId::MAGICAL_WEAPONS),
517 Workshops::Item::fromType(ItemType::TrapItem{TrapType::BOULDER}, 20, {CollectiveResourceId::STONE, 50})
518 .setTechId(TechId::TRAPS),
519 Workshops::Item::fromType(ItemType::TrapItem{TrapType::POISON_GAS}, 10, {CollectiveResourceId::WOOD, 20})
520 .setTechId(TechId::TRAPS),
521 Workshops::Item::fromType(ItemType::TrapItem{TrapType::ALARM}, 8, {CollectiveResourceId::WOOD, 20})
522 .setTechId(TechId::TRAPS),
523 Workshops::Item::fromType(ItemType::TrapItem{TrapType::WEB}, 8, {CollectiveResourceId::WOOD, 20})
524 .setTechId(TechId::TRAPS),
525 Workshops::Item::fromType(ItemType::TrapItem{TrapType::SURPRISE}, 8, {CollectiveResourceId::WOOD, 20})
526 .setTechId(TechId::TRAPS),
527 Workshops::Item::fromType(ItemType::TrapItem{TrapType::TERROR}, 8, {CollectiveResourceId::WOOD, 20})
528 .setTechId(TechId::TRAPS),
529 }},
530 {WorkshopType::FORGE, {
531 Workshops::Item::fromType(ItemType::Sword{}, 10, {CollectiveResourceId::IRON, 20}),
532 Workshops::Item::fromType(ItemType::SteelSword{}, 20, {CollectiveResourceId::STEEL, 20})
533 .setTechId(TechId::STEEL_MAKING),
534 Workshops::Item::fromType(ItemType::ChainArmor{}, 30, {CollectiveResourceId::IRON, 40}),
535 Workshops::Item::fromType(ItemType::SteelArmor{}, 30, {CollectiveResourceId::STEEL, 40})
536 .setTechId(TechId::STEEL_MAKING),
537 Workshops::Item::fromType(ItemType::IronHelm{}, 8, {CollectiveResourceId::IRON, 16}),
538 Workshops::Item::fromType(ItemType::IronBoots{}, 12, {CollectiveResourceId::IRON, 24}),
539 Workshops::Item::fromType(ItemType::WarHammer{}, 16, {CollectiveResourceId::IRON, 40})
540 .setTechId(TechId::TWO_H_WEAP),
541 Workshops::Item::fromType(ItemType::BattleAxe{}, 22, {CollectiveResourceId::IRON, 50})
542 .setTechId(TechId::TWO_H_WEAP),
543 Workshops::Item::fromType(ItemType::SteelBattleAxe{}, 22, {CollectiveResourceId::STEEL, 50})
544 .setTechId(TechId::STEEL_MAKING),
545 Workshops::Item::fromType(ItemType::IronStaff{}, 20, {CollectiveResourceId::IRON, 40})
546 .setTechId(TechId::MAGICAL_WEAPONS),
547 }},
548 {WorkshopType::LABORATORY, {
549 Workshops::Item::fromType(ItemType::Potion{Effect::Lasting{LastingEffect::SLOWED}}, 2,
550 {CollectiveResourceId::GOLD, 2}),
551 Workshops::Item::fromType(ItemType::Potion{Effect::Lasting{LastingEffect::SLEEP}}, 2,
552 {CollectiveResourceId::GOLD, 2}),
553 Workshops::Item::fromType(ItemType::Potion{
554 Effect::Lasting{LastingEffect::POISON_RESISTANT}}, 4, {CollectiveResourceId::GOLD, 6}),
555 Workshops::Item::fromType(ItemType::Potion{
556 Effect::Lasting{LastingEffect::SPEED}}, 4, {CollectiveResourceId::GOLD, 6}),
557 Workshops::Item::fromType(ItemType::Potion{
558 Effect::Lasting{LastingEffect::TELEPATHY}}, 4, {CollectiveResourceId::GOLD, 6}),
559 Workshops::Item::fromType(ItemType::Potion{
560 Effect::Lasting{LastingEffect::REGENERATION}}, 4, {CollectiveResourceId::GOLD, 8}),
561 Workshops::Item::fromType(ItemType::Potion{
562 Effect::Lasting{LastingEffect::POISON}}, 4, {CollectiveResourceId::GOLD, 8}),
563 Workshops::Item::fromType(ItemType::Potion{
564 Effect::Lasting{LastingEffect::FLYING}}, 4, {CollectiveResourceId::GOLD, 8}),
565 Workshops::Item::fromType(ItemType::Potion{Effect::Heal{}}, 4, {CollectiveResourceId::GOLD, 10})
566 .setTechId(TechId::ALCHEMY_ADV),
567 Workshops::Item::fromType(ItemType::Potion{
568 Effect::Lasting{LastingEffect::BLIND}}, 4, {CollectiveResourceId::GOLD, 15})
569 .setTechId(TechId::ALCHEMY_ADV),
570 Workshops::Item::fromType(ItemType::Potion{
571 Effect::Lasting{LastingEffect::MELEE_RESISTANCE}}, 6, {CollectiveResourceId::GOLD, 20})
572 .setTechId(TechId::ALCHEMY_ADV),
573 Workshops::Item::fromType(ItemType::Potion{
574 Effect::Lasting{LastingEffect::INVISIBLE}}, 6, {CollectiveResourceId::GOLD, 20})
575 .setTechId(TechId::ALCHEMY_ADV),
576 //Alchemical conversion to and from gold
577 Workshops::Item::fromType(ItemType::GoldPiece{}, 5, {CollectiveResourceId::IRON, 30})
578 .setTechId(TechId::ALCHEMY_CONV).setBatchSize(10),
579 Workshops::Item::fromType(ItemType::WoodPlank{}, 5, {CollectiveResourceId::GOLD, 10})
580 .setTechId(TechId::ALCHEMY_CONV).setBatchSize(10),
581 Workshops::Item::fromType(ItemType::IronOre{}, 5, {CollectiveResourceId::GOLD, 10})
582 .setTechId(TechId::ALCHEMY_CONV).setBatchSize(10),
583 Workshops::Item::fromType(ItemType::Rock{}, 5, {CollectiveResourceId::GOLD, 10})
584 .setTechId(TechId::ALCHEMY_CONV).setBatchSize(10),
585 }},
586 {WorkshopType::JEWELER, {
587 Workshops::Item::fromType(ItemType::Ring{LastingEffect::POISON_RESISTANT}, 10,
588 {CollectiveResourceId::GOLD, 20}),
589 Workshops::Item::fromType(ItemType::Ring{LastingEffect::FIRE_RESISTANT}, 10,
590 {CollectiveResourceId::GOLD, 30}),
591 Workshops::Item::fromType(ItemType::Ring{LastingEffect::MAGIC_RESISTANCE}, 10,
592 {CollectiveResourceId::GOLD, 30}),
593 Workshops::Item::fromType(ItemType::Ring{LastingEffect::RESTED}, 10, {CollectiveResourceId::GOLD, 30}),
594 Workshops::Item::fromType(ItemType::Ring{LastingEffect::SATIATED}, 10, {CollectiveResourceId::GOLD, 30}),
595 Workshops::Item::fromType(ItemType::Amulet{LastingEffect::NIGHT_VISION}, 10, {CollectiveResourceId::GOLD, 20}),
596 Workshops::Item::fromType(ItemType::Amulet{LastingEffect::ELF_VISION}, 10, {CollectiveResourceId::GOLD, 20}),
597 Workshops::Item::fromType(ItemType::Amulet{LastingEffect::WARNING}, 10, {CollectiveResourceId::GOLD, 30}),
598 Workshops::Item::fromType(ItemType::DefenseAmulet{}, 10, {CollectiveResourceId::GOLD, 40}),
599 Workshops::Item::fromType(ItemType::Amulet{LastingEffect::REGENERATION}, 10, {CollectiveResourceId::GOLD, 60}),
600 }},
601 {WorkshopType::STEEL_FURNACE, {
602 Workshops::Item::fromType(ItemType::SteelIngot{}, 25, {CollectiveResourceId::IRON, 30}).setBatchSize(10),
603 }},
604 }));
605 }
606
getInitialTech() const607 vector<Technology*> CollectiveConfig::getInitialTech() const {
608 if (type == KEEPER)
609 return {
610 Technology::get(TechId::GEOLOGY1),
611 Technology::get(TechId::SPELLS),
612 };
613 else
614 return {};
615 }
616