Skip to content

Commit

Permalink
generalized flags for skills; keys; bosses; summons
Browse files Browse the repository at this point in the history
  • Loading branch information
malytomas committed Jul 31, 2023
1 parent 6ac3c3c commit 1738f4e
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 94 deletions.
14 changes: 6 additions & 8 deletions sources/dnt.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,7 @@ struct Skill : private Noncopyable
AttributesValueMapping range, radius, duration, damageAmount;
DamageTypeEnum damageType = DamageTypeEnum::None;
SkillAttributesEffects casterAttributes, targetAttributes;
bool movesCaster = false; // moves the caster to the target position
bool movesTarget = false; // moves targeted entity to position of the caster
bool knockback = false; // moves targeted entity one tile away from the caster
bool stun = false; // prevents the target from any actions for one tick, and grants stun immunity for the following tick
bool requiresLineOfSight = true; // the target position must be visible from the caster position
bool requiresCasterIsAlone = false; // no other characters may be visible (line of sight check) anywhere from the caster position
bool createsGroundEffect = false;
std::vector<std::string> casterFlags, targetFlags; // available flags: lineOfSight, alone, moves, stun, knockback, groundEffect
ThingPower power;
};

Expand All @@ -102,6 +96,7 @@ struct Item : private Noncopyable
AttributesValueMapping requirements;
AttributesValueMapping attributes;
std::vector<Skill> skills;
std::vector<std::string> flags;
ThingPower power;
};

Expand Down Expand Up @@ -206,7 +201,7 @@ Skill generateSkill(uint32 level, SlotEnum slot);
std::string skillJson(const Skill &skill);
Item generateItem(uint32 level, SlotEnum slot);
std::string itemJson(const Item &item);
Monster generateMonster(uint32 level, uint32 difficulty);
Monster generateMonster(uint32 level, sint32 difficultyOffset);
std::string monsterJson(const Monster &monster);

const char *tileName(TileEnum tile);
Expand All @@ -217,3 +212,6 @@ uint32 bossIndexToLevel(uint32 index);
Floor generateFloor(uint32 level);
FloorExport exportFloor(const Floor &floor);
void exportDungeon(PointerRange<const Floor> floors);

template<class... T>
constexpr bool always_false = false;
14 changes: 6 additions & 8 deletions sources/export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace
switch (neighbors)
{
case 0:
return uni(u8"\u2588");
return "X";
case 1:
return uni(u8"\u2500");
case 2:
Expand Down Expand Up @@ -61,13 +61,14 @@ namespace
switch (f.tile(x, y))
{
case TileEnum::Empty:
case TileEnum::Outside:
res += " ";
break;
case TileEnum::Decoration:
res += uni(u8"\u2591");
break;
case TileEnum::Spawn:
res += "+";
res += "S";
break;
case TileEnum::Waypoint:
res += "O";
Expand All @@ -79,7 +80,7 @@ namespace
res += "H";
break;
case TileEnum::Chest:
res += "X";
res += "$";
break;
case TileEnum::Monster:
res += "@";
Expand All @@ -98,9 +99,6 @@ namespace
res += connectedWall(neighbors);
break;
}
case TileEnum::Outside:
res += uni(u8"\u2588");
break;
default:
res += "?";
break;
Expand Down Expand Up @@ -137,7 +135,7 @@ namespace
else if constexpr (std::is_same_v<T, std::unique_ptr<Monster>>)
json += "\"data\":" + monsterJson(*arg) + ",\n";
else
static_assert(false, "non-exhaustive visitor!");
static_assert(always_false<T>, "non-exhaustive visitor!");
},
extra);
removeLastComma(json);
Expand Down Expand Up @@ -168,7 +166,7 @@ FloorExport exportFloor(const Floor &floor)
{
for (uint32 x = 0; x < floor.width; x++)
{
if (floor.tile(x, y) == TileEnum::Empty)
if (floor.tile(x, y) == TileEnum::Empty || floor.tile(x, y) == TileEnum::Outside)
continue;
result.json += tileJson(Vec2i(x, y), floor.tile(x, y), floor.extra(x, y));
result.json += ",\n";
Expand Down
161 changes: 105 additions & 56 deletions sources/floor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,59 @@ namespace
CAGE_ASSERT(isConnected(f));
}

void cutoutFloor(Floor &f)
{
const auto &rowOutside = [&](uint32 y) -> bool
{
for (uint32 x = 0; x < f.width; x++)
if (f.tile(x, y) != TileEnum::Outside)
return false;
return true;
};
const auto &cutRow = [&](uint32 y)
{
for (; y < f.height - 1; y++)
{
for (uint32 x = 0; x < f.width; x++)
{
f.tile(x, y) = f.tile(x, y + 1);
f.extra(x, y) = std::move(f.extra(x, y + 1));
}
}
f.height--;
f.tiles.resize(f.width * f.height);
f.extras.resize(f.width * f.height);
};
const auto &transpose = [&]
{
Floor g;
g.tiles.resize(f.tiles.size());
g.extras.resize(f.extras.size());
g.width = f.height;
g.height = f.width;
for (uint32 y = 0; y < f.height; y++)
{
for (uint32 x = 0; x < f.width; x++)
{
g.tile(y, x) = f.tile(x, y);
g.extra(y, x) = std::move(f.extra(x, y));
}
}
std::swap(f.width, f.height);
std::swap(f.tiles, g.tiles);
std::swap(f.extras, g.extras);
};

for (uint32 i = 0; i < 2; i++)
{
while (rowOutside(0))
cutRow(0);
while (rowOutside(f.height - 1))
cutRow(f.height - 1);
transpose();
}
}

void generateShopFloor(Floor &f)
{
static constexpr uint32 w = 17, h = 9;
Expand All @@ -200,12 +253,49 @@ namespace
f.tile(2 * w / 3, h / 2) = TileEnum::Waypoint;
}

Item generateKeyToAllDoors(const Floor &f)
{
Item item;
item.name = "Key";

std::vector<Vec2i> doors;
const uint32 cnt = f.width * f.height;
for (uint32 i = 0; i < cnt; i++)
if (f.tiles[i] == TileEnum::Door)
doors.push_back(Vec2i(i % f.width, i / f.width));
std::string json;
json += "{\n";
json += "\"class\":\"key\",\n";
json += "\"doors\":[\n";
for (const Vec2i &door : doors)
{
json += "{\n";
json += (Stringizer() + "\"x\":" + door[0] + ",\n").value.c_str();
json += (Stringizer() + "\"y\":" + door[1] + "\n").value.c_str();
json += "},"; // /door
}
removeLastComma(json);
json += "]\n"; // /doors
json += "}"; // /root
item.flags.push_back(std::move(json));

return item;
}

Monster generateBossMonster(const Floor &f)
{
Monster mr = generateMonster(f.level, levelToBossIndex(f.level));
mr.name = Stringizer() + "Guardian of " + f.level + "th floor";
mr.onDeath.push_back(std::make_unique<Item>(generateKeyToAllDoors(f)));
return mr;
}

void generateBossFloor(Floor &f)
{
CAGE_ASSERT(isLevelBoss(f.level));
const uint32 bossIndex = levelToBossIndex(f.level);
const uint32 r = bossIndex * 2 + randomRange(5, 10);
const uint32 w = r * 2 + 7;
uint32 w = r * 2 + 7;
floorResize(f, Vec2i(w));

// generate circular room
Expand Down Expand Up @@ -270,9 +360,11 @@ namespace
f.tile(w - 4, w / 2) = TileEnum::Door;

findOutlineWalls(f);
cutoutFloor(f); // make sure that all coordinates stored in extra jsons are correct
w = f.width;

f.tile(w / 2, w / 2) = TileEnum::Monster; // the boss
f.extra(w / 2, w / 2) = std::make_unique<Monster>(generateMonster(f.level, f.level + bossIndex));
f.extra(w / 2, w / 2) = std::make_unique<Monster>(generateBossMonster(f));

{ // additional monsters
const uint32 cnt = bossIndex * 2;
Expand Down Expand Up @@ -405,68 +497,25 @@ namespace
}
}

void cutoutFloor(Floor &f)
void fillExtras(Floor &f)
{
const auto &rowOutside = [&](uint32 y) -> bool
{
for (uint32 x = 0; x < f.width; x++)
if (f.tile(x, y) != TileEnum::Outside)
return false;
return true;
};
const auto &cutRow = [&](uint32 y)
const uint32 cnt = f.width * f.height;
for (uint32 i = 0; i < cnt; i++)
{
for (; y < f.height - 1; y++)
switch (f.tiles[i])
{
for (uint32 x = 0; x < f.width; x++)
case TileEnum::Monster:
{
f.tile(x, y) = f.tile(x, y + 1);
f.extra(x, y) = std::move(f.extra(x, y + 1));
if (f.extras[i] == TileExtra())
f.extras[i] = std::make_unique<Monster>(generateMonster(f.level, 0));
break;
}
}
f.height--;
f.tiles.resize(f.width * f.height);
f.extras.resize(f.width * f.height);
};
const auto &transpose = [&]
{
Floor g;
g.tiles.resize(f.tiles.size());
g.extras.resize(f.extras.size());
g.width = f.height;
g.height = f.width;
for (uint32 y = 0; y < f.height; y++)
{
for (uint32 x = 0; x < f.width; x++)
case TileEnum::Chest:
{
g.tile(y, x) = f.tile(x, y);
g.extra(y, x) = std::move(f.extra(x, y));
// todo
break;
}
}
std::swap(f.width, f.height);
std::swap(f.tiles, g.tiles);
std::swap(f.extras, g.extras);
};

for (uint32 i = 0; i < 2; i++)
{
while (rowOutside(0))
cutRow(0);
while (rowOutside(f.height - 1))
cutRow(f.height - 1);
transpose();
}
}

void fillExtras(Floor &f)
{
const uint32 cnt = f.width * f.height;
for (uint32 i = 0; i < cnt; i++)
{
if (f.tiles[i] == TileEnum::Monster && f.extras[i] == TileExtra())
{
f.extras[i] = std::make_unique<Monster>(generateMonster(f.level, 0));
}
}
}
}
Expand Down
10 changes: 9 additions & 1 deletion sources/item.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ std::string itemJson(const Item &item)
{
std::string json;
json += "{\n";
json += "\"class\":\"item\",\n";
json += std::string() + "\"name\":\"" + item.name.c_str() + "\",\n";
json += std::string() + "\"slot\":\"" + slotName(item.slot) + "\",\n";
json += "\"requirements\":" + attributesValueMappingJson(item.requirements) + ",\n";
Expand All @@ -48,8 +49,15 @@ std::string itemJson(const Item &item)
for (const Skill &skill : item.skills)
json += skillJson(skill) + ",\n";
removeLastComma(json);
json += "]\n"; // /skills
json += "],\n"; // /skills

json += "\"flags\":[\n";
for (const std::string &flag : item.flags)
json += flag + ",\n";
removeLastComma(json);
json += "],\n"; // /casterFlags

removeLastComma(json);
json += "}"; // /root
return json;
}
2 changes: 1 addition & 1 deletion sources/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ int main(int argc, const char *args[])
if (argc <= 1)
{
std::vector<Floor> floors;
for (uint32 l = 0; l < 4; l++)
for (uint32 l = 0; l < 10; l++)
floors.push_back(generateFloor(l));
exportDungeon(floors);
}
Expand Down
14 changes: 8 additions & 6 deletions sources/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ namespace
}
}

Monster generateMonster(uint32 level, uint32 difficulty)
Monster generateMonster(uint32 level, sint32 difficultyOffset)
{
Monster mr;

Expand Down Expand Up @@ -58,6 +58,7 @@ std::string monsterJson(const Monster &monster)
{
std::string json;
json += "{\n";
json += "\"class\":\"monster\",\n";
json += std::string() + "\"name\":\"" + monster.name.c_str() + "\",\n";
json += "\"attributes\":" + attributesValueMappingJson(monster.attributes) + ",\n";

Expand All @@ -75,19 +76,20 @@ std::string monsterJson(const Monster &monster)
{
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, std::unique_ptr<Skill>>)
json += "{\n\"type\":\"skill\",\n\"data\":" + skillJson(*arg) + "},\n";
json += skillJson(*arg) + ",\n";
else if constexpr (std::is_same_v<T, std::unique_ptr<Item>>)
json += "{\n\"type\":\"item\",\n\"data\":" + itemJson(*arg) + "},\n";
json += itemJson(*arg) + ",\n";
else if constexpr (std::is_same_v<T, std::unique_ptr<Monster>>)
json += "{\n\"type\":\"monster\",\n\"data\":" + monsterJson(*arg) + "},\n";
json += monsterJson(*arg) + ",\n";
else
static_assert(false, "non-exhaustive visitor!");
static_assert(always_false<T>, "non-exhaustive visitor!");
},
it);
}
removeLastComma(json);
json += "]\n"; // /onDeath
json += "],\n"; // /onDeath

removeLastComma(json);
json += "}"; // /root
return json;
}
Loading

0 comments on commit 1738f4e

Please sign in to comment.