1 #include "UndergroundSectorModel.h"
2 
3 #include "JsonUtility.h"
4 #include "Random.h"
5 
UndergroundSectorModel(uint8_t sectorId_,uint8_t sectorZ_,uint8_t adjacentSectors_,std::array<uint8_t,NUM_DIF_LEVELS> numTroops_,std::array<uint8_t,NUM_DIF_LEVELS> numElites_,std::array<uint8_t,NUM_DIF_LEVELS> numCreatures_,std::array<uint8_t,NUM_DIF_LEVELS> numTroopsVariance_,std::array<uint8_t,NUM_DIF_LEVELS> numElitesVariance_,std::array<uint8_t,NUM_DIF_LEVELS> numCreaturesVariance_)6 UndergroundSectorModel::UndergroundSectorModel(uint8_t sectorId_, uint8_t sectorZ_, uint8_t adjacentSectors_,
7 	std::array<uint8_t, NUM_DIF_LEVELS> numTroops_, std::array<uint8_t, NUM_DIF_LEVELS> numElites_, std::array<uint8_t, NUM_DIF_LEVELS> numCreatures_,
8 	std::array<uint8_t, NUM_DIF_LEVELS> numTroopsVariance_, std::array<uint8_t, NUM_DIF_LEVELS> numElitesVariance_, std::array<uint8_t, NUM_DIF_LEVELS> numCreaturesVariance_)
9 		: sectorId(sectorId_), sectorZ(sectorZ_), adjacentSectors(adjacentSectors_),
10 		numTroops(numTroops_), numElites(numElites_), numCreatures(numCreatures_),
11 		numTroopsVariance(numTroopsVariance_), numElitesVariance(numElitesVariance_), numCreaturesVariance(numCreaturesVariance_) {}
12 
createUndergroundSectorInfo(uint8_t difficultyLevel) const13 UNDERGROUND_SECTORINFO* UndergroundSectorModel::createUndergroundSectorInfo(uint8_t difficultyLevel) const
14 {
15 	UNDERGROUND_SECTORINFO* const u = new UNDERGROUND_SECTORINFO{};
16 
17 	u->ubSectorX = SECTORX(sectorId);
18 	u->ubSectorY = SECTORY(sectorId);
19 	u->ubSectorZ = sectorZ;
20 	u->ubAdjacentSectors = adjacentSectors;
21 
22 	u->ubNumTroops    = numTroops[difficultyLevel - 1]    + Random(numTroopsVariance[difficultyLevel - 1]   );
23 	u->ubNumElites    = numElites[difficultyLevel - 1]    + Random(numElitesVariance[difficultyLevel - 1]   );
24 	u->ubNumCreatures = numCreatures[difficultyLevel - 1] + Random(numCreaturesVariance[difficultyLevel - 1]);
25 
26 	return u;
27 }
28 
deserialize(const rapidjson::Value & obj)29 UndergroundSectorModel* UndergroundSectorModel::deserialize(const rapidjson::Value& obj)
30 {
31 	uint8_t sectorId = JsonUtility::parseSectorID(obj["sector"].GetString());
32 	uint8_t sectorZ = obj["sectorLevel"].GetUint();
33 	if (sectorZ == 0 || sectorZ > 3)
34 	{
35 		ST::string err = "Sector level must be between 1 and 3";
36 		throw std::runtime_error(err.to_std_string());
37 	}
38 
39 	uint8_t adjacencyFlag = NO_ADJACENT_SECTOR;
40 	if (obj.HasMember("adjacentSectors") && obj["adjacentSectors"].IsArray())
41 	{
42 		auto adjacencies = obj["adjacentSectors"].GetArray();
43 		for (auto& el : adjacencies)
44 		{
45 			ST::string adj = el.GetString();
46 			if (adj.size() != 1)
47 			{
48 				ST::string err = ST::format("'{}' is not a valid adjacency direction.", adj);
49 				throw std::runtime_error(err.to_std_string());
50 			}
51 			switch (adj[0])
52 			{
53 			case DIRECTION_NORTH:
54 				adjacencyFlag |= NORTH_ADJACENT_SECTOR;
55 				break;
56 			case DIRECTION_EAST:
57 				adjacencyFlag |= EAST_ADJACENT_SECTOR;
58 				break;
59 			case DIRECTION_SOUTH:
60 				adjacencyFlag |= SOUTH_ADJACENT_SECTOR;
61 				break;
62 			case DIRECTION_WEST:
63 				adjacencyFlag |= WEST_ADJACENT_SECTOR;
64 				break;
65 			default:
66 				ST::string err = ST::format("{} is not a valid direction.", adj[0]);
67 				throw std::runtime_error(err.to_std_string());
68 			}
69 		}
70 	}
71 
72 	return new UndergroundSectorModel(
73 		sectorId, sectorZ, adjacencyFlag,
74 		JsonUtility::readIntArrayByDiff(obj, "numTroops"),
75 		JsonUtility::readIntArrayByDiff(obj, "numElites"),
76 		JsonUtility::readIntArrayByDiff(obj, "numCreatures"),
77 		JsonUtility::readIntArrayByDiff(obj, "numTroopsVariance"),
78 		JsonUtility::readIntArrayByDiff(obj, "numElitesVariance"),
79 		JsonUtility::readIntArrayByDiff(obj, "numCreaturesVariance")
80 	);
81 }
82 
validateData(const std::vector<const UndergroundSectorModel * > & ugSectors)83 void UndergroundSectorModel::validateData(const std::vector<const UndergroundSectorModel*>& ugSectors)
84 {
85 	// check for existence of hard-coded references
86 	// the list below is based on the occurrences of FindUnderGroundSector in codebase
87 	std::array<uint8_t, 3> basementSectors[] = {
88 		{ 13, 5,  1 },  // Draassen mine
89 		{ 9,  8,  1 },  // Cambria mine
90 		{ 14, 10, 1 },  // Alma mine
91 		{ 4,  8,  2 }   // Grumm mine
92 	};
93 	for (auto basementLoc : basementSectors)
94 	{
95 		uint8_t sectorId = SECTOR(basementLoc[0], basementLoc[1]);
96 		uint8_t sectorZ = basementLoc[2];
97 		auto iter = std::find_if(ugSectors.begin(), ugSectors.end(), [sectorId, sectorZ](const UndergroundSectorModel* s) { return (s->sectorId == sectorId && s->sectorZ == sectorZ); });
98 		if (iter == ugSectors.end())
99 		{
100 			ST::string err = ST::format("An underground sector is expected at ({},{},{}), but is not defined.", basementLoc[0], basementLoc[1], basementLoc[2]);
101 			throw std::runtime_error(err.to_std_string());
102 		}
103 	}
104 }