Browse Source

Clean up RndLocOk

dun-data2
Anders Jenbo 4 years ago
parent
commit
1af53e5754
  1. 2
      Source/drlg_l1.cpp
  2. 2
      Source/drlg_l2.cpp
  3. 2
      Source/drlg_l3.cpp
  4. 2
      Source/drlg_l4.cpp
  5. 11
      Source/items.cpp
  6. 255
      Source/monster.cpp
  7. 426
      Source/objects.cpp
  8. 2
      Source/objects.h

2
Source/drlg_l1.cpp

@ -2195,7 +2195,7 @@ void LoadL1Dungeon(const char *path, int vx, int vy)
InitDungeonPieces();
SetMapMonsters(dunData.get(), Point(0, 0).megaToWorld());
SetMapObjects(dunData.get(), 0, 0);
SetMapObjects(dunData.get(), Point(0, 0).megaToWorld());
}
void LoadPreL1Dungeon(const char *path)

2
Source/drlg_l2.cpp

@ -2926,7 +2926,7 @@ void LoadL2Dungeon(const char *path, int vx, int vy)
ViewPosition = { vx, vy };
SetMapMonsters(dunData.get(), Point(0, 0).megaToWorld());
SetMapObjects(dunData.get(), 0, 0);
SetMapObjects(dunData.get(), Point(0, 0).megaToWorld());
}
void LoadPreL2Dungeon(const char *path)

2
Source/drlg_l3.cpp

@ -2268,7 +2268,7 @@ void LoadL3Dungeon(const char *path, int vx, int vy)
ViewPosition = { vx, vy };
SetMapMonsters(dunData.get(), Point(0, 0).megaToWorld());
SetMapObjects(dunData.get(), 0, 0);
SetMapObjects(dunData.get(), Point(0, 0).megaToWorld());
for (int j = 0; j < MAXDUNY; j++) {
for (int i = 0; i < MAXDUNX; i++) {

2
Source/drlg_l4.cpp

@ -1334,7 +1334,7 @@ void LoadL4Dungeon(const char *path, int vx, int vy)
DRLG_Init_Globals();
SetMapMonsters(dunData.get(), Point(0, 0).megaToWorld());
SetMapObjects(dunData.get(), 0, 0);
SetMapObjects(dunData.get(), Point(0, 0).megaToWorld());
}
void LoadPreL4Dungeon(const char *path)

11
Source/items.cpp

@ -412,12 +412,13 @@ bool ItemPlace(Point position)
Point GetRandomAvailableItemPosition()
{
Point position = {};
do {
position = Point { GenerateRnd(80), GenerateRnd(80) } + Displacement { 16, 16 };
} while (!ItemPlace(position));
while (true) {
Point position = Point { GenerateRnd(80), GenerateRnd(80) } + Displacement { 16, 16 };
if (ItemPlace(position))
return position;
}
return position;
return {};
}
void AddInitItems()

255
Source/monster.cpp

@ -186,15 +186,15 @@ void InitMonsterTRN(CMonster &monst)
}
}
void InitMonster(Monster &monster, Direction rd, int mtype, Point position)
void InitMonster(Monster &monster, Direction rd, int monsterTypeIndex, Point position)
{
monster._mdir = rd;
monster.position.tile = position;
monster.position.future = position;
monster.position.old = position;
monster._mMTidx = mtype;
monster._mMTidx = monsterTypeIndex;
monster._mmode = MonsterMode::Stand;
monster.MType = &LevelMonsterTypes[mtype];
monster.MType = &LevelMonsterTypes[monsterTypeIndex];
monster.MData = monster.MType->MData;
monster.mName = pgettext("monster", monster.MData->mName).c_str();
monster.AnimInfo = {};
@ -295,11 +295,11 @@ bool CanPlaceMonster(Point position)
&& !IsTileOccupied(position);
}
void PlaceMonster(int i, int mtype, Point position)
void PlaceMonster(int i, int monsterTypeIndex, Point position)
{
if (LevelMonsterTypes[mtype].mtype == MT_NAKRUL) {
if (LevelMonsterTypes[monsterTypeIndex].mtype == MT_NAKRUL) {
for (int j = 0; j < ActiveMonsterCount; j++) {
if (Monsters[j]._mMTidx == mtype) {
if (Monsters[j]._mMTidx == monsterTypeIndex) {
return;
}
if (Monsters[j].MType->mtype == MT_NAKRUL) {
@ -310,118 +310,127 @@ void PlaceMonster(int i, int mtype, Point position)
dMonster[position.x][position.y] = i + 1;
auto rd = static_cast<Direction>(GenerateRnd(8));
InitMonster(Monsters[i], rd, mtype, position);
InitMonster(Monsters[i], rd, monsterTypeIndex, position);
}
void PlaceGroup(int mtype, int num, UniqueMonsterPack uniqueMonsterPack, int leaderId)
/**
* @brief Walk in a random direction untill the given position is a valid for spawning a monster
*/
std::optional<Point> GetNextSpawnPosition(Point position, int roomId, Rectangle area)
{
int placed = 0;
for (int try2 = 0; try2 < 100; try2++, position += static_cast<Direction>(GenerateRnd(8))) {
if (!CanPlaceMonster(position))
continue;
if (dTransVal[position.x][position.y] != roomId)
continue;
if (!area.Contains(position))
continue;
return position;
}
auto &leader = Monsters[leaderId];
return {};
}
for (int try1 = 0; try1 < 10; try1++) {
while (placed != 0) {
ActiveMonsterCount--;
placed--;
const auto &position = Monsters[ActiveMonsterCount].position.tile;
dMonster[position.x][position.y] = 0;
}
bool PlaceGroup(std::optional<Point> startPosition, int monsterTypeIndex, int num, Rectangle area)
{
num = std::min(num, totalmonsters - ActiveMonsterCount);
int xp;
int yp;
if (uniqueMonsterPack != UniqueMonsterPack::None) {
int offset = GenerateRnd(8);
auto position = leader.position.tile + static_cast<Direction>(offset);
xp = position.x;
yp = position.y;
for (int attempts = 0; attempts < 10; attempts++) {
Point position;
if (startPosition) {
position = *startPosition;
} else {
do {
xp = GenerateRnd(80) + 16;
yp = GenerateRnd(80) + 16;
} while (!CanPlaceMonster({ xp, yp }));
position = Point { GenerateRnd(80), GenerateRnd(80) } + Displacement { 16, 16 };
} while (!CanPlaceMonster(position));
}
int x1 = xp;
int y1 = yp;
if (num + ActiveMonsterCount > totalmonsters) {
num = totalmonsters - ActiveMonsterCount;
}
int j = 0;
for (int try2 = 0; j < num && try2 < 100; xp += Displacement(static_cast<Direction>(GenerateRnd(8))).deltaX, yp += Displacement(static_cast<Direction>(GenerateRnd(8))).deltaX) { /// BUGFIX: `yp += Point.y`
if (!CanPlaceMonster({ xp, yp })
|| (dTransVal[xp][yp] != dTransVal[x1][y1])
|| (uniqueMonsterPack == UniqueMonsterPack::Leashed && (abs(xp - x1) >= 4 || abs(yp - y1) >= 4))) {
try2++;
continue;
}
int roomId = dTransVal[position.x][position.y];
PlaceMonster(ActiveMonsterCount, mtype, { xp, yp });
if (uniqueMonsterPack != UniqueMonsterPack::None) {
auto &minion = Monsters[ActiveMonsterCount];
minion._mmaxhp *= 2;
minion._mhitpoints = minion._mmaxhp;
minion._mint = leader._mint;
if (uniqueMonsterPack == UniqueMonsterPack::Leashed) {
minion.leader = leaderId;
minion.leaderRelation = LeaderRelation::Leashed;
minion._mAi = leader._mAi;
}
int placed = 0;
while (true) {
std::optional<Point> nextPosition = GetNextSpawnPosition(position, roomId, area);
if (!nextPosition)
break;
if (minion._mAi != AI_GARG) {
minion.ChangeAnimationData(MonsterGraphic::Stand);
minion.AnimInfo.CurrentFrame = GenerateRnd(minion.AnimInfo.NumberOfFrames - 1);
minion._mFlags &= ~MFLAG_ALLOW_SPECIAL;
minion._mmode = MonsterMode::Stand;
}
}
position = *nextPosition;
PlaceMonster(ActiveMonsterCount, monsterTypeIndex, position);
ActiveMonsterCount++;
placed++;
j++;
if (placed == num)
return true;
position += static_cast<Direction>(GenerateRnd(8));
}
if (placed >= num) {
break;
for (int i = 0; i < placed; i++) {
ActiveMonsterCount--;
Point position = Monsters[ActiveMonsterCount].position.tile;
dMonster[position.x][position.y] = 0;
}
}
return false;
}
void PlaceMinions(int monsterTypeIndex, int packSize, UniqueMonsterPack uniqueMonsterPack, int leaderId)
{
Monster &leader = Monsters[leaderId];
if (!PlaceGroup(leader.position.tile, monsterTypeIndex, packSize, Rectangle { leader.position.tile, 3 }))
return;
for (int i = ActiveMonsterCount - packSize - 1; i < ActiveMonsterCount; i++) {
Monster &minion = Monsters[i];
minion._mmaxhp *= 2;
minion._mhitpoints = minion._mmaxhp;
minion._mint = leader._mint;
if (uniqueMonsterPack == UniqueMonsterPack::Leashed) {
minion.leader = leaderId;
minion.leaderRelation = LeaderRelation::Leashed;
minion._mAi = leader._mAi;
}
if (minion._mAi != AI_GARG) {
minion.ChangeAnimationData(MonsterGraphic::Stand);
minion.AnimInfo.CurrentFrame = GenerateRnd(minion.AnimInfo.NumberOfFrames - 1);
minion._mFlags &= ~MFLAG_ALLOW_SPECIAL;
minion._mmode = MonsterMode::Stand;
}
}
if (uniqueMonsterPack == UniqueMonsterPack::Leashed) {
leader.packsize = placed;
leader.packsize = packSize;
}
}
void PlaceUniqueMonst(int uniqindex, int miniontype, int bosspacksize)
void PlaceUniqueMonst(int uniqindex, int minionIndex, int bosspacksize)
{
auto &monster = Monsters[ActiveMonsterCount];
const auto &uniqueMonsterData = UniqueMonstersData[uniqindex];
int uniqtype;
for (uniqtype = 0; uniqtype < LevelMonsterTypeCount; uniqtype++) {
if (LevelMonsterTypes[uniqtype].mtype == uniqueMonsterData.mtype) {
int monsterTypeIndex;
for (monsterTypeIndex = 0; monsterTypeIndex < LevelMonsterTypeCount; monsterTypeIndex++) {
if (LevelMonsterTypes[monsterTypeIndex].mtype == uniqueMonsterData.mtype) {
break;
}
}
int count = 0;
Point position;
while (true) {
position = Point { GenerateRnd(80), GenerateRnd(80) } + Displacement { 16, 16 };
int count2 = 0;
for (int x = position.x - 3; x < position.x + 3; x++) {
for (int y = position.y - 3; y < position.y + 3; y++) {
if (InDungeonBounds({ x, y }) && CanPlaceMonster({ x, y })) {
count2++;
}
}
}
for (int tries = 0;; tries++) {
if (tries > 997)
return;
if (count2 < 9) {
count++;
if (count < 1000) {
continue;
position = Point { GenerateRnd(80), GenerateRnd(80) } + Displacement { 16, 16 };
int freeSpots = 0;
for (Point testPosition : PointsInRectangleRange(Rectangle { position, 3 })) {
if (CanPlaceMonster(testPosition)) {
freeSpots++;
}
}
if (freeSpots < 9)
continue;
if (CanPlaceMonster(position)) {
break;
@ -478,8 +487,8 @@ void PlaceUniqueMonst(int uniqindex, int miniontype, int bosspacksize)
position = { UberRow - 2, UberCol };
UberDiabloMonsterIndex = ActiveMonsterCount;
}
PlaceMonster(ActiveMonsterCount, uniqtype, position);
PrepareUniqueMonst(monster, uniqindex, miniontype, bosspacksize, uniqueMonsterData);
PlaceMonster(ActiveMonsterCount, monsterTypeIndex, position);
PrepareUniqueMonst(monster, uniqindex, minionIndex, bosspacksize, uniqueMonsterData);
}
int AddMonsterType(_monster_id type, placeflag placeflag)
@ -539,28 +548,25 @@ void ClrAllMonsters()
void PlaceUniqueMonsters()
{
for (int u = 0; UniqueMonstersData[u].mtype != -1; u++) {
for (int u = 0; UniqueMonstersData[u].mtype != MT_INVALID; u++) {
if (UniqueMonstersData[u].mlevel != currlevel)
continue;
bool done = false;
int mt;
for (mt = 0; mt < LevelMonsterTypeCount; mt++) {
done = (LevelMonsterTypes[mt].mtype == UniqueMonstersData[u].mtype);
if (done)
break;
}
if (u == UMT_GARBUD && Quests[Q_GARBUD]._qactive == QUEST_NOTAVAIL)
done = false;
continue;
if (u == UMT_ZHAR && Quests[Q_ZHAR]._qactive == QUEST_NOTAVAIL)
done = false;
continue;
if (u == UMT_SNOTSPIL && Quests[Q_LTBANNER]._qactive == QUEST_NOTAVAIL)
done = false;
continue;
if (u == UMT_LACHDAN && Quests[Q_VEIL]._qactive == QUEST_NOTAVAIL)
done = false;
continue;
if (u == UMT_WARLORD && Quests[Q_WARLORD]._qactive == QUEST_NOTAVAIL)
done = false;
if (done)
PlaceUniqueMonst(u, mt, 8);
continue;
for (int minionIndex = 0; minionIndex < LevelMonsterTypeCount; minionIndex++) {
if (LevelMonsterTypes[minionIndex].mtype == UniqueMonstersData[u].mtype) {
PlaceUniqueMonst(u, minionIndex, 8);
break;
}
}
}
}
@ -568,7 +574,7 @@ void PlaceQuestMonsters()
{
if (!setlevel) {
if (Quests[Q_BUTCHER].IsAvailable()) {
PlaceUniqueMonst(UMT_BUTCHER, 0, 0);
PlaceUniqueMonst(UMT_BUTCHER, -1, 0);
}
if (currlevel == Quests[Q_SKELKING]._qlevel && gbIsMultiplayer) {
@ -611,9 +617,9 @@ void PlaceQuestMonsters()
if (currlevel == Quests[Q_BETRAYER]._qlevel && gbIsMultiplayer) {
AddMonsterType(UniqueMonstersData[UMT_LAZARUS].mtype, PLACE_UNIQUE);
AddMonsterType(UniqueMonstersData[UMT_RED_VEX].mtype, PLACE_UNIQUE);
PlaceUniqueMonst(UMT_LAZARUS, 0, 0);
PlaceUniqueMonst(UMT_RED_VEX, 0, 0);
PlaceUniqueMonst(UMT_BLACKJADE, 0, 0);
PlaceUniqueMonst(UMT_LAZARUS, -1, 0);
PlaceUniqueMonst(UMT_RED_VEX, -1, 0);
PlaceUniqueMonst(UMT_BLACKJADE, -1, 0);
auto dunData = LoadFileInMem<uint16_t>("Levels\\L4Data\\Vile1.DUN");
SetMapMonsters(dunData.get(), SetPiece.position.megaToWorld());
}
@ -636,10 +642,10 @@ void PlaceQuestMonsters()
}
}
if (UberDiabloMonsterIndex == -1)
PlaceUniqueMonst(UMT_NAKRUL, 0, 0);
PlaceUniqueMonst(UMT_NAKRUL, -1, 0);
}
} else if (setlvlnum == SL_SKELKING) {
PlaceUniqueMonst(UMT_SKELKING, 0, 0);
PlaceUniqueMonst(UMT_SKELKING, -1, 0);
}
}
@ -3453,7 +3459,7 @@ void InitTRNForUniqueMonster(Monster &monster)
monster.uniqueTRN = LoadFileInMem<uint8_t>(filestr);
}
void PrepareUniqueMonst(Monster &monster, int uniqindex, int miniontype, int bosspacksize, const UniqueMonsterData &uniqueMonsterData)
void PrepareUniqueMonst(Monster &monster, int uniqindex, int minionIndex, int bosspacksize, const UniqueMonsterData &uniqueMonsterData)
{
monster._uniqtype = uniqindex + 1;
@ -3551,8 +3557,8 @@ void PrepareUniqueMonst(Monster &monster, int uniqindex, int miniontype, int bos
ActiveMonsterCount++;
if (uniqueMonsterData.monsterPack != UniqueMonsterPack::None) {
PlaceGroup(miniontype, bosspacksize, uniqueMonsterData.monsterPack, ActiveMonsterCount - 1);
if (minionIndex != -1 && bosspacksize != 0 && uniqueMonsterData.monsterPack != UniqueMonsterPack::None) {
PlaceMinions(minionIndex, bosspacksize, uniqueMonsterData.monsterPack, ActiveMonsterCount - 1);
}
if (monster._mAi != AI_GARG) {
@ -3801,14 +3807,14 @@ void InitMonsters()
if (!setlevel) {
if (!gbIsSpawn)
PlaceUniqueMonsters();
int na = 0;
int monsterCount = 0;
for (int s = 16; s < 96; s++) {
for (int t = 16; t < 96; t++) {
if (!IsTileSolid({ s, t }))
na++;
monsterCount++;
}
}
int numplacemonsters = na / 30;
int numplacemonsters = monsterCount / 30;
if (gbIsMultiplayer)
numplacemonsters += numplacemonsters / 2;
if (ActiveMonsterCount + numplacemonsters > MAXMONSTERS - 10)
@ -3823,14 +3829,15 @@ void InitMonsters()
}
}
while (ActiveMonsterCount < totalmonsters) {
int mtype = scattertypes[GenerateRnd(numscattypes)];
int monsterTypeIndex = scattertypes[GenerateRnd(numscattypes)];
int groupSize = 1;
if (currlevel == 1 || GenerateRnd(2) == 0)
na = 1;
groupSize = 1;
else if (currlevel == 2 || leveltype == DTYPE_CRYPT)
na = GenerateRnd(2) + 2;
groupSize = GenerateRnd(2) + 2;
else
na = GenerateRnd(3) + 3;
PlaceGroup(mtype, na, UniqueMonsterPack::None, 0);
groupSize = GenerateRnd(3) + 3;
PlaceGroup({}, monsterTypeIndex, groupSize, { { 16, 16 }, { 80, 80 } });
}
}
for (int i = 0; i < nt; i++) {
@ -3852,9 +3859,9 @@ void SetMapMonsters(const uint16_t *dunData, Point startPosition)
AddMonsterType(UniqueMonstersData[UMT_LAZARUS].mtype, PLACE_UNIQUE);
AddMonsterType(UniqueMonstersData[UMT_RED_VEX].mtype, PLACE_UNIQUE);
AddMonsterType(UniqueMonstersData[UMT_BLACKJADE].mtype, PLACE_UNIQUE);
PlaceUniqueMonst(UMT_LAZARUS, 0, 0);
PlaceUniqueMonst(UMT_RED_VEX, 0, 0);
PlaceUniqueMonst(UMT_BLACKJADE, 0, 0);
PlaceUniqueMonst(UMT_LAZARUS, -1, 0);
PlaceUniqueMonst(UMT_RED_VEX, -1, 0);
PlaceUniqueMonst(UMT_BLACKJADE, -1, 0);
}
int width = SDL_SwapLE16(dunData[0]);
@ -3872,20 +3879,20 @@ void SetMapMonsters(const uint16_t *dunData, Point startPosition)
for (int i = 0; i < width; i++) {
auto monsterId = static_cast<uint8_t>(SDL_SwapLE16(monsterLayer[j * width + i]));
if (monsterId != 0) {
int mtype = AddMonsterType(MonstConvTbl[monsterId - 1], PLACE_SPECIAL);
PlaceMonster(ActiveMonsterCount++, mtype, startPosition + Displacement { i, j });
int monsterTypeIndex = AddMonsterType(MonstConvTbl[monsterId - 1], PLACE_SPECIAL);
PlaceMonster(ActiveMonsterCount++, monsterTypeIndex, startPosition + Displacement { i, j });
}
}
}
}
int AddMonster(Point position, Direction dir, int mtype, bool inMap)
int AddMonster(Point position, Direction dir, int monsterTypeIndex, bool inMap)
{
if (ActiveMonsterCount < MAXMONSTERS) {
int i = ActiveMonsters[ActiveMonsterCount++];
if (inMap)
dMonster[position.x][position.y] = i + 1;
InitMonster(Monsters[i], dir, mtype, position);
InitMonster(Monsters[i], dir, monsterTypeIndex, position);
return i;
}

426
Source/objects.cpp

@ -96,10 +96,6 @@ int numobjfiles;
/** Tracks progress through the tome sequence that spawns Na-Krul (see OperateNakrulBook()) */
int NaKrulTomeSequence;
/** Specifies the X-coordinate delta between barrels. */
int bxadd[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };
/** Specifies the Y-coordinate delta between barrels. */
int byadd[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
/** Maps from shrine_id to shrine name. */
const char *const ShrineNames[] = {
// TRANSLATORS: Shrine Name Block
@ -291,19 +287,36 @@ _speech_id StoryText[3][3] = {
{ TEXT_BOOK31, TEXT_BOOK32, TEXT_BOOK33 }
};
bool RndLocOk(int xp, int yp)
bool IsAvailableObjectPosition(Point position)
{
if (dMonster[xp][yp] != 0)
return false;
if (dPlayer[xp][yp] != 0)
return false;
if (IsObjectAtPosition({ xp, yp }))
return false;
if (TileContainsSetPiece({ xp, yp }))
return false;
if (nSolidTable[dPiece[xp][yp]])
return false;
return IsNoneOf(leveltype, DTYPE_CATHEDRAL, DTYPE_CRYPT) || dPiece[xp][yp] <= 126 || dPiece[xp][yp] >= 144;
return dMonster[position.x][position.y] == 0
&& dPlayer[position.x][position.y] == 0
&& !IsObjectAtPosition(position)
&& !TileContainsSetPiece(position)
&& !nSolidTable[dPiece[position.x][position.y]]
&& (IsNoneOf(leveltype, DTYPE_CATHEDRAL, DTYPE_CRYPT) || dPiece[position.x][position.y] <= 126 || dPiece[position.x][position.y] >= 144);
}
bool IsAvailableObjectPosition(Rectangle area)
{
for (Point testPosition : PointsInRectangleRange(area)) {
if (!IsAvailableObjectPosition(testPosition)) {
return false;
}
}
return true;
}
Point GetRandomAvailableObjectPosition()
{
while (true) {
Point position = Point { GenerateRnd(80), GenerateRnd(80) } + Displacement { 16, 16 };
if (IsAvailableObjectPosition(position))
return position;
}
return {};
}
bool CanPlaceWallTrap(int xp, int yp)
@ -316,24 +329,15 @@ bool CanPlaceWallTrap(int xp, int yp)
return nTrapTable[dPiece[xp][yp]];
}
void InitRndLocObj(int min, int max, _object_id objtype)
void InitRndLocObj(int min, int max, _object_id objtype, int range = 1)
{
int numobjs = GenerateRnd(max - min) + min;
for (int i = 0; i < numobjs; i++) {
while (true) {
int xp = GenerateRnd(80) + 16;
int yp = GenerateRnd(80) + 16;
if (RndLocOk(xp - 1, yp - 1)
&& RndLocOk(xp, yp - 1)
&& RndLocOk(xp + 1, yp - 1)
&& RndLocOk(xp - 1, yp)
&& RndLocOk(xp, yp)
&& RndLocOk(xp + 1, yp)
&& RndLocOk(xp - 1, yp + 1)
&& RndLocOk(xp, yp + 1)
&& RndLocOk(xp + 1, yp + 1)) {
AddObject(objtype, { xp, yp });
Point position = GetRandomAvailableObjectPosition();
if (IsAvailableObjectPosition(Rectangle { position, range })) {
AddObject(objtype, position);
break;
}
}
@ -343,57 +347,19 @@ void InitRndLocObj(int min, int max, _object_id objtype)
void InitRndLocBigObj(int min, int max, _object_id objtype)
{
int numobjs = GenerateRnd(max - min) + min;
for (int i = 0; i < numobjs; i++) {
while (true) {
int xp = GenerateRnd(80) + 16;
int yp = GenerateRnd(80) + 16;
if (RndLocOk(xp - 1, yp - 2)
&& RndLocOk(xp, yp - 2)
&& RndLocOk(xp + 1, yp - 2)
&& RndLocOk(xp - 1, yp - 1)
&& RndLocOk(xp, yp - 1)
&& RndLocOk(xp + 1, yp - 1)
&& RndLocOk(xp - 1, yp)
&& RndLocOk(xp, yp)
&& RndLocOk(xp + 1, yp)
&& RndLocOk(xp - 1, yp + 1)
&& RndLocOk(xp, yp + 1)
&& RndLocOk(xp + 1, yp + 1)) {
AddObject(objtype, { xp, yp });
Point position = GetRandomAvailableObjectPosition();
if (IsAvailableObjectPosition(Rectangle { position + Displacement { 0, -2 }, { 2, 1 } })
&& IsAvailableObjectPosition(Rectangle { position, 1 })) {
AddObject(objtype, position);
break;
}
}
}
}
void InitRndLocObj5x5(int min, int max, _object_id objtype)
{
int numobjs = min + GenerateRnd(max - min);
for (int i = 0; i < numobjs; i++) {
int xp;
int yp;
int cnt = 0;
bool exit = false;
while (!exit) {
exit = true;
xp = GenerateRnd(80) + 16;
yp = GenerateRnd(80) + 16;
for (int n = -2; n <= 2; n++) {
for (int m = -2; m <= 2; m++) {
if (!RndLocOk(xp + m, yp + n))
exit = false;
}
}
if (!exit) {
cnt++;
if (cnt > 20000)
return;
}
}
AddObject(objtype, { xp, yp });
}
}
void ClrAllObjects()
{
memset(Objects, 0, sizeof(Objects));
@ -450,87 +416,47 @@ void AddCandles()
*/
void AddBookLever(Rectangle affectedArea, _speech_id msg)
{
int cnt = 0;
Point position;
bool exit = false;
while (!exit) {
exit = true;
position = Point { GenerateRnd(80), GenerateRnd(80) } + Displacement { 16, 16 };
for (int n = -2; n <= 2; n++) {
for (int m = -2; m <= 2; m++) {
if (!RndLocOk(position.x + m, position.y + n))
exit = false;
for (int tries = 0; tries < 19999; tries++) {
Point position = Point { GenerateRnd(80), GenerateRnd(80) } + Displacement { 16, 16 };
if (IsAvailableObjectPosition(Rectangle { position, 2 })) {
if (Quests[Q_BLIND].IsAvailable())
AddObject(OBJ_BLINDBOOK, position);
else if (Quests[Q_WARLORD].IsAvailable())
AddObject(OBJ_STEELTOME, position);
else if (Quests[Q_BLOOD].IsAvailable()) {
position = SetPiece.position.megaToWorld() + Displacement { 9, 24 };
AddObject(OBJ_BLOODBOOK, position);
}
}
if (!exit) {
cnt++;
if (cnt > 20000)
return;
ObjectAtPosition(position)->InitializeQuestBook(affectedArea, leverid, msg);
leverid++;
break;
}
}
if (Quests[Q_BLIND].IsAvailable())
AddObject(OBJ_BLINDBOOK, position);
if (Quests[Q_WARLORD].IsAvailable())
AddObject(OBJ_STEELTOME, position);
if (Quests[Q_BLOOD].IsAvailable()) {
position = SetPiece.position.megaToWorld() + Displacement { 9, 24 };
AddObject(OBJ_BLOODBOOK, position);
}
ObjectAtPosition(position)->InitializeQuestBook(affectedArea, leverid, msg);
leverid++;
}
void InitRndBarrels()
void InitRndBarrels(_object_id barrelId = OBJ_BARREL, _object_id explosiveBarrelId = OBJ_BARRELEX)
{
_object_id barrelId = OBJ_BARREL;
_object_id explosiveBarrelId = OBJ_BARRELEX;
if (leveltype == DTYPE_NEST) {
barrelId = OBJ_POD;
explosiveBarrelId = OBJ_PODEX;
} else if (leveltype == DTYPE_CRYPT) {
barrelId = OBJ_URN;
explosiveBarrelId = OBJ_URNEX;
}
/** number of groups of barrels to generate */
int numobjs = GenerateRnd(5) + 3;
for (int i = 0; i < numobjs; i++) {
int xp;
int yp;
int groups = GenerateRnd(5) + 3;
for (int i = 0; i < groups; i++) {
Point position = GetRandomAvailableObjectPosition();
AddObject(GenerateRnd(4) != 0 ? barrelId : explosiveBarrelId, position);
int barrelsInGroup = 1;
do {
xp = GenerateRnd(80) + 16;
yp = GenerateRnd(80) + 16;
} while (!RndLocOk(xp, yp));
_object_id o = (GenerateRnd(4) != 0) ? barrelId : explosiveBarrelId;
AddObject(o, { xp, yp });
bool found = true;
/** regulates chance to stop placing barrels in current group */
int p = 0;
/** number of barrels in current group */
int c = 1;
while (GenerateRnd(p) == 0 && found) {
/** number of tries of placing next barrel in current group */
int t = 0;
found = false;
while (true) {
if (t >= 3)
break;
int dir = GenerateRnd(8);
xp += bxadd[dir];
yp += byadd[dir];
found = RndLocOk(xp, yp);
t++;
if (found)
for (int tries = 0;; tries++) {
if (tries >= 3)
return;
position += static_cast<Direction>(GenerateRnd(8));
if (IsAvailableObjectPosition(position)) {
AddObject(GenerateRnd(5) != 0 ? barrelId : explosiveBarrelId, position);
barrelsInGroup++;
break;
}
}
if (found) {
o = (GenerateRnd(5) != 0) ? barrelId : explosiveBarrelId;
AddObject(o, { xp, yp });
c++;
}
p = c / 2;
}
} while (GenerateRnd(barrelsInGroup / 2) == 0);
}
}
@ -804,7 +730,7 @@ void SetupObject(Object &object, Point position, _object_id ot)
object._oDoorFlag = false;
}
void AddCryptBook(_object_id ot, int v2, int ox, int oy)
void AddCryptBook(_object_id ot, int v2, Point position)
{
if (ActiveObjectCount >= MAXOBJECTS)
return;
@ -812,47 +738,41 @@ void AddCryptBook(_object_id ot, int v2, int ox, int oy)
int oi = AvailableObjects[0];
AvailableObjects[0] = AvailableObjects[MAXOBJECTS - 1 - ActiveObjectCount];
ActiveObjects[ActiveObjectCount] = oi;
dObject[ox][oy] = oi + 1;
dObject[position.x][position.y] = oi + 1;
Object &object = Objects[oi];
SetupObject(object, { ox, oy }, ot);
SetupObject(object, position, ot);
AddCryptObject(object, v2);
ActiveObjectCount++;
}
void AddCryptStoryBook(int s)
Point FindPositionForStoryBook()
{
int cnt = 0;
int xp;
int yp;
bool exit = false;
while (!exit) {
exit = true;
xp = GenerateRnd(80) + 16;
yp = GenerateRnd(80) + 16;
for (int n = -2; n <= 2; n++) {
for (int m = -3; m <= 3; m++) {
if (!RndLocOk(xp + m, yp + n))
exit = false;
}
}
if (!exit) {
cnt++;
if (cnt > 20000)
return;
}
Point position;
for (int tries = 0; tries < 19999; tries++) {
position = Point { GenerateRnd(80), GenerateRnd(80) } + Displacement { 16, 16 };
if (IsAvailableObjectPosition({ position + Displacement { -3, -2 }, { 7, 5 } }))
break;
}
AddCryptBook(OBJ_L5BOOKS, s, xp, yp);
AddObject(OBJ_L5CANDLE, { xp - 2, yp + 1 });
AddObject(OBJ_L5CANDLE, { xp - 2, yp });
AddObject(OBJ_L5CANDLE, { xp - 1, yp - 1 });
AddObject(OBJ_L5CANDLE, { xp + 1, yp - 1 });
AddObject(OBJ_L5CANDLE, { xp + 2, yp });
AddObject(OBJ_L5CANDLE, { xp + 2, yp + 1 });
return position;
}
void AddCryptStoryBook(int s)
{
Point position = FindPositionForStoryBook();
AddCryptBook(OBJ_L5BOOKS, s, position);
AddObject(OBJ_L5CANDLE, position + Displacement { -2, 1 });
AddObject(OBJ_L5CANDLE, position + Displacement { -2, 0 });
AddObject(OBJ_L5CANDLE, position + Displacement { -1, -1 });
AddObject(OBJ_L5CANDLE, position + Displacement { 1, -1 });
AddObject(OBJ_L5CANDLE, position + Displacement { 2, 0 });
AddObject(OBJ_L5CANDLE, position + Displacement { 2, 1 });
}
void AddNakrulBook(int a1, int a2, int a3)
{
AddCryptBook(OBJ_L5BOOKS, a1, a2, a3);
AddCryptBook(OBJ_L5BOOKS, a1, { a2, a3 });
}
void AddNakrulGate()
@ -894,33 +814,15 @@ void AddNakrulGate()
void AddStoryBooks()
{
int cnt = 0;
int xp;
int yp;
bool done = false;
while (!done) {
done = true;
xp = GenerateRnd(80) + 16;
yp = GenerateRnd(80) + 16;
for (int yy = -2; yy <= 2; yy++) {
for (int xx = -3; xx <= 3; xx++) {
if (!RndLocOk(xx + xp, yy + yp))
done = false;
}
}
if (!done) {
cnt++;
if (cnt > 20000)
return;
}
}
AddObject(OBJ_STORYBOOK, { xp, yp });
AddObject(OBJ_STORYCANDLE, { xp - 2, yp + 1 });
AddObject(OBJ_STORYCANDLE, { xp - 2, yp });
AddObject(OBJ_STORYCANDLE, { xp - 1, yp - 1 });
AddObject(OBJ_STORYCANDLE, { xp + 1, yp - 1 });
AddObject(OBJ_STORYCANDLE, { xp + 2, yp });
AddObject(OBJ_STORYCANDLE, { xp + 2, yp + 1 });
Point position = FindPositionForStoryBook();
AddObject(OBJ_STORYBOOK, position);
AddObject(OBJ_STORYCANDLE, position + Displacement { -2, 1 });
AddObject(OBJ_STORYCANDLE, position + Displacement { -2, 0 });
AddObject(OBJ_STORYCANDLE, position + Displacement { -1, -1 });
AddObject(OBJ_STORYCANDLE, position + Displacement { 1, -1 });
AddObject(OBJ_STORYCANDLE, position + Displacement { 2, 0 });
AddObject(OBJ_STORYCANDLE, position + Displacement { 2, 1 });
}
void AddHookedBodies(int freq)
@ -979,38 +881,27 @@ void AddL4Goodies()
void AddLazStand()
{
int cnt = 0;
int xp;
int yp;
bool found = false;
while (!found) {
found = true;
xp = GenerateRnd(80) + 16;
yp = GenerateRnd(80) + 16;
for (int yy = -3; yy <= 3; yy++) {
for (int xx = -2; xx <= 3; xx++) {
if (!RndLocOk(xp + xx, yp + yy))
found = false;
}
}
if (!found) {
cnt++;
if (cnt > 10000) {
InitRndLocObj(1, 1, OBJ_LAZSTAND);
return;
}
Point position;
for (int tries = 0;; tries++) {
if (tries >= 9999) {
AddObject(OBJ_LAZSTAND, { 1, 1 });
return;
}
position = Point { GenerateRnd(80), GenerateRnd(80) } + Displacement { 16, 16 };
if (IsAvailableObjectPosition({ position + Displacement { -3, -2 }, { 7, 6 } }))
break;
}
AddObject(OBJ_LAZSTAND, { xp, yp });
AddObject(OBJ_TNUDEM2, { xp, yp + 2 });
AddObject(OBJ_STORYCANDLE, { xp + 1, yp + 2 });
AddObject(OBJ_TNUDEM3, { xp + 2, yp + 2 });
AddObject(OBJ_TNUDEW1, { xp, yp - 2 });
AddObject(OBJ_STORYCANDLE, { xp + 1, yp - 2 });
AddObject(OBJ_TNUDEW2, { xp + 2, yp - 2 });
AddObject(OBJ_STORYCANDLE, { xp - 1, yp - 1 });
AddObject(OBJ_TNUDEW3, { xp - 1, yp });
AddObject(OBJ_STORYCANDLE, { xp - 1, yp + 1 });
AddObject(OBJ_LAZSTAND, position);
AddObject(OBJ_TNUDEM2, position + Displacement { 0, 2 });
AddObject(OBJ_STORYCANDLE, position + Displacement { 1, 2 });
AddObject(OBJ_TNUDEM3, position + Displacement { 2, 2 });
AddObject(OBJ_TNUDEW1, position + Displacement { 0, -2 });
AddObject(OBJ_STORYCANDLE, position + Displacement { 1, -2 });
AddObject(OBJ_TNUDEW2, position + Displacement { 2, -2 });
AddObject(OBJ_STORYCANDLE, position + Displacement { -1, -1 });
AddObject(OBJ_TNUDEW3, position + Displacement { -1, 0 });
AddObject(OBJ_STORYCANDLE, position + Displacement { -1, 1 });
}
void DeleteObject(int oi, int i)
@ -1341,41 +1232,33 @@ void AddTorturedBody(int i)
Objects[i]._oPreFlag = true;
}
void GetRndObjLoc(int randarea, int *xx, int *yy)
/**
* @brief Make 999 attempts at randmly finding a area of the requested size, try a single time more for each size smaller then requested
* @return Found location
*/
Point GetRndObjLoc(int randarea)
{
if (randarea == 0)
return;
int tries = 0;
while (true) {
tries++;
if (tries > 1000 && randarea > 1)
Point position;
for (int tries = 0;; tries++) {
if (tries > 999 && randarea > 1)
randarea--;
*xx = GenerateRnd(MAXDUNX);
*yy = GenerateRnd(MAXDUNY);
bool failed = false;
for (int i = 0; i < randarea && !failed; i++) {
for (int j = 0; j < randarea && !failed; j++) {
failed = !RndLocOk(i + *xx, j + *yy);
}
}
if (!failed)
position = Point { GenerateRnd(MAXDUNX), GenerateRnd(MAXDUNY) };
if (IsAvailableObjectPosition({ position, { randarea, randarea } }))
break;
}
return position;
}
void AddMushPatch()
{
int y;
int x;
if (ActiveObjectCount < MAXOBJECTS) {
int i = AvailableObjects[0];
GetRndObjLoc(5, &x, &y);
dObject[x + 1][y + 1] = -(i + 1);
dObject[x + 2][y + 1] = -(i + 1);
dObject[x + 1][y + 2] = -(i + 1);
AddObject(OBJ_MUSHPATCH, { x + 2, y + 2 });
Point position = GetRndObjLoc(5);
dObject[position.x + 1][position.y + 1] = -(i + 1);
dObject[position.x + 2][position.y + 1] = -(i + 1);
dObject[position.x + 1][position.y + 2] = -(i + 1);
AddObject(OBJ_MUSHPATCH, position + Displacement { 2, 2 });
}
}
@ -4492,11 +4375,7 @@ void AddCryptObjects(int x1, int y1, int x2, int y2)
void AddSlainHero()
{
int x;
int y;
GetRndObjLoc(5, &x, &y);
AddObject(OBJ_SLAINHERO, { x + 2, y + 2 });
AddObject(OBJ_SLAINHERO, GetRndObjLoc(5) + Displacement { 2, 2 });
}
void InitObjects()
@ -4540,9 +4419,9 @@ void InitObjects()
}
if (leveltype == DTYPE_CATACOMBS) {
if (Quests[Q_ROCK].IsAvailable())
InitRndLocObj5x5(1, 1, OBJ_STAND);
InitRndLocObj(1, 1, OBJ_STAND, 2);
if (Quests[Q_SCHAMB].IsAvailable())
InitRndLocObj5x5(1, 1, OBJ_BOOK2R);
InitRndLocObj(1, 1, OBJ_BOOK2R, 2);
AddL2Objs(0, 0, MAXDUNX, MAXDUNY);
AddL2Torches();
if (Quests[Q_BLIND].IsAvailable()) {
@ -4636,12 +4515,12 @@ void InitObjects()
AddL4Goodies();
}
if (leveltype == DTYPE_NEST) {
InitRndBarrels();
InitRndBarrels(OBJ_POD, OBJ_PODEX);
}
if (leveltype == DTYPE_CRYPT) {
InitRndLocBigObj(10, 15, OBJ_L5SARC);
AddCryptObjects(0, 0, MAXDUNX, MAXDUNY);
InitRndBarrels();
InitRndBarrels(OBJ_URN, OBJ_URNEX);
}
InitRndLocObj(5, 10, OBJ_CHEST1);
InitRndLocObj(3, 6, OBJ_CHEST2);
@ -4654,7 +4533,7 @@ void InitObjects()
}
}
void SetMapObjects(const uint16_t *dunData, int startx, int starty)
void SetMapObjects(const uint16_t *dunData, Point start)
{
bool filesLoaded[65] = {};
@ -4672,9 +4551,9 @@ void SetMapObjects(const uint16_t *dunData, int startx, int starty)
const uint16_t *objectLayer = &dunData[layer2Offset + width * height * 2];
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
auto objectId = static_cast<uint8_t>(SDL_SwapLE16(objectLayer[j * width + i]));
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
auto objectId = static_cast<uint8_t>(SDL_SwapLE16(objectLayer[x + y * width]));
if (objectId != 0) {
filesLoaded[AllObjects[ObjTypeConv[objectId]].ofindex] = true;
}
@ -4683,11 +4562,12 @@ void SetMapObjects(const uint16_t *dunData, int startx, int starty)
LoadLevelObjects(filesLoaded);
for (int j = 0; j < height; j++) {
for (int i = 0; i < width; i++) {
auto objectId = static_cast<uint8_t>(SDL_SwapLE16(objectLayer[j * width + i]));
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
auto objectId = static_cast<uint8_t>(SDL_SwapLE16(objectLayer[x + y * width]));
if (objectId != 0) {
AddObject(ObjTypeConv[objectId], { startx + 16 + i, starty + 16 + j });
AddObject(ObjTypeConv[objectId], start + Displacement { x, y });
SDL_Log("Object at %dx%d", start.x + x, start.y + y);
}
}
}

2
Source/objects.h

@ -291,7 +291,7 @@ void AddL2Objs(int x1, int y1, int x2, int y2);
void AddL3Objs(int x1, int y1, int x2, int y2);
void AddCryptObjects(int x1, int y1, int x2, int y2);
void InitObjects();
void SetMapObjects(const uint16_t *dunData, int startx, int starty);
void SetMapObjects(const uint16_t *dunData, Point start);
/**
* @brief Spawns an object of the given type at the map coordinates provided
* @param objType Type specifier

Loading…
Cancel
Save