/** * @file trigs.cpp * * Implementation of functionality for triggering events when the player enters an area. */ #include "levels/trigs.h" #include #include #include "control.h" #include "controls/plrctrls.h" #include "cursor.h" #include "error.h" #include "init.h" #include "utils/language.h" #include "utils/utf8.hpp" namespace devilution { bool trigflag; int numtrigs; TriggerStruct trigs[MAXTRIGGERS]; int TWarpFrom; namespace { /** Specifies the dungeon piece IDs which constitute stairways leading down to the cathedral from town. */ const uint16_t TownDownList[] = { 715, 714, 718, 719, 720, 722, 723, 724, 725, 726 }; /** Specifies the dungeon piece IDs which constitute stairways leading down to the catacombs from town. */ const uint16_t TownWarp1List[] = { 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177, 1178, 1180, 1182, 1184 }; const uint16_t TownCryptList[] = { 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337 }; const uint16_t TownHiveList[] = { 1306, 1307, 1308, 1309 }; /** Specifies the dungeon piece IDs which constitute stairways leading up from the cathedral. */ const uint16_t L1UpList[] = { 126, 128, 129, 130, 131, 132, 134, 136, 137, 138, 139 }; /** Specifies the dungeon piece IDs which constitute stairways leading down from the cathedral. */ const uint16_t L1DownList[] = { 105, 106, 107, 108, 109, 111, 113, 114, 117 }; /** Specifies the dungeon piece IDs which constitute stairways leading up from the catacombs. */ const uint16_t L2UpList[] = { 265, 266 }; /** Specifies the dungeon piece IDs which constitute stairways leading down from the catacombs. */ const uint16_t L2DownList[] = { 268, 269, 270, 271 }; /** Specifies the dungeon piece IDs which constitute stairways leading up to town from the catacombs. */ const uint16_t L2TWarpUpList[] = { 557, 558 }; /** Specifies the dungeon piece IDs which constitute stairways leading up from the caves. */ const uint16_t L3UpList[] = { 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182 }; /** Specifies the dungeon piece IDs which constitute stairways leading down from the caves. */ const uint16_t L3DownList[] = { 161, 162, 163, 164, 165, 166, 167, 168 }; /** Specifies the dungeon piece IDs which constitute stairways leading up to town from the caves. */ const uint16_t L3TWarpUpList[] = { 181, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, 558, 559 }; /** Specifies the dungeon piece IDs which constitute stairways leading up from hell. */ const uint16_t L4UpList[] = { 81, 82, 89 }; /** Specifies the dungeon piece IDs which constitute stairways leading down from hell. */ const uint16_t L4DownList[] = { 119, 129, 130, 131, 132 }; /** Specifies the dungeon piece IDs which constitute stairways leading up to town from hell. */ const uint16_t L4TWarpUpList[] = { 420, 421, 428 }; /** Specifies the dungeon piece IDs which constitute stairways leading down to Diablo from hell. */ const uint16_t L4PentaList[] = { 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383 }; const uint16_t L5TWarpUpList[] = { 171, 172, 173, 174, 175, 176, 177, 178, 183 }; const uint16_t L5UpList[] = { 148, 149, 150, 151, 152, 153, 154, 156, 157, 158 }; const uint16_t L5DownList[] = { 124, 125, 128, 130, 131, 134, 135, 139, 141 }; const uint16_t L6TWarpUpList[] = { 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91 }; const uint16_t L6UpList[] = { 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77 }; const uint16_t L6DownList[] = { 56, 57, 58, 59, 60, 61, 62, 63 }; } // namespace void InitNoTriggers() { numtrigs = 0; trigflag = false; } bool IsWarpOpen(dungeon_type type) { if (gbIsSpawn) return false; if (gbIsMultiplayer && type != DTYPE_NEST) // Opening the nest is part of in town quest return true; Player &myPlayer = *MyPlayer; if (type == DTYPE_CATACOMBS && (myPlayer.pTownWarps & 1) != 0) return true; if (type == DTYPE_CAVES && (myPlayer.pTownWarps & 2) != 0) return true; if (type == DTYPE_HELL && (myPlayer.pTownWarps & 4) != 0) return true; if (gbIsHellfire) { if (type == DTYPE_CATACOMBS && myPlayer._pLevel >= 10) return true; if (type == DTYPE_CAVES && myPlayer._pLevel >= 15) return true; if (type == DTYPE_HELL && myPlayer._pLevel >= 20) return true; if (type == DTYPE_NEST && IsAnyOf(Quests[Q_FARMER]._qactive, QUEST_DONE, QUEST_HIVE_DONE)) return true; if (type == DTYPE_CRYPT && Quests[Q_GRAVE]._qactive == QUEST_DONE) return true; } return false; } void InitTownTriggers() { numtrigs = 0; // Cathedral trigs[numtrigs].position = { 25, 29 }; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; if (IsWarpOpen(DTYPE_CATACOMBS)) { trigs[numtrigs].position = { 49, 21 }; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 5; numtrigs++; } if (IsWarpOpen(DTYPE_CAVES)) { trigs[numtrigs].position = { 17, 69 }; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 9; numtrigs++; } if (IsWarpOpen(DTYPE_HELL)) { trigs[numtrigs].position = { 41, 80 }; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 13; numtrigs++; } if (IsWarpOpen(DTYPE_NEST)) { trigs[numtrigs].position = { 80, 62 }; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 17; numtrigs++; } if (IsWarpOpen(DTYPE_CRYPT)) { trigs[numtrigs].position = { 36, 24 }; trigs[numtrigs]._tmsg = WM_DIABTOWNWARP; trigs[numtrigs]._tlvl = 21; numtrigs++; } trigflag = false; } void InitL1Triggers() { numtrigs = 0; for (WorldTileCoord j = 0; j < MAXDUNY; j++) { for (WorldTileCoord i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 128) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 114) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } trigflag = false; } void InitL2Triggers() { numtrigs = 0; for (WorldTileCoord j = 0; j < MAXDUNY; j++) { for (WorldTileCoord i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 266 && (!Quests[Q_SCHAMB].IsAvailable() || i != Quests[Q_SCHAMB].position.x || j != Quests[Q_SCHAMB].position.y)) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 558) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABTWARPUP; trigs[numtrigs]._tlvl = 0; numtrigs++; } if (dPiece[i][j] == 270) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } trigflag = false; } void InitL3Triggers() { numtrigs = 0; for (WorldTileCoord j = 0; j < MAXDUNY; j++) { for (WorldTileCoord i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 170) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 167) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } if (dPiece[i][j] == 548) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABTWARPUP; numtrigs++; } } } trigflag = false; } void InitL4Triggers() { numtrigs = 0; for (WorldTileCoord j = 0; j < MAXDUNY; j++) { for (WorldTileCoord i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 82) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 421) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABTWARPUP; trigs[numtrigs]._tlvl = 0; numtrigs++; } if (dPiece[i][j] == 119) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } for (WorldTileCoord j = 0; j < MAXDUNY; j++) { for (WorldTileCoord i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 369 && Quests[Q_BETRAYER]._qactive == QUEST_DONE) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } trigflag = false; } void InitHiveTriggers() { numtrigs = 0; for (WorldTileCoord j = 0; j < MAXDUNY; j++) { for (WorldTileCoord i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 65) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 62) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } if (dPiece[i][j] == 79) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABTWARPUP; numtrigs++; } } } trigflag = false; } void InitCryptTriggers() { numtrigs = 0; for (WorldTileCoord j = 0; j < MAXDUNY; j++) { for (WorldTileCoord i = 0; i < MAXDUNX; i++) { if (dPiece[i][j] == 183) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABTWARPUP; trigs[numtrigs]._tlvl = 0; numtrigs++; } if (dPiece[i][j] == 157) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABPREVLVL; numtrigs++; } if (dPiece[i][j] == 125) { trigs[numtrigs].position = { i, j }; trigs[numtrigs]._tmsg = WM_DIABNEXTLVL; numtrigs++; } } } trigflag = false; } void InitSKingTriggers() { trigflag = false; numtrigs = 1; trigs[0].position = { 82, 42 }; trigs[0]._tmsg = WM_DIABRTNLVL; } void InitSChambTriggers() { trigflag = false; numtrigs = 1; trigs[0].position = { 70, 39 }; trigs[0]._tmsg = WM_DIABRTNLVL; } void InitPWaterTriggers() { trigflag = false; numtrigs = 1; trigs[0].position = { 30, 83 }; trigs[0]._tmsg = WM_DIABRTNLVL; } void InitVPTriggers() { trigflag = false; numtrigs = 1; trigs[0].position = { 35, 32 }; trigs[0]._tmsg = WM_DIABRTNLVL; } bool ForceTownTrig() { for (const uint16_t tileId : TownDownList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = _("Down to dungeon"); cursPosition = { 25, 29 }; return true; } } if (IsWarpOpen(DTYPE_CATACOMBS)) { for (const uint16_t tileId : TownWarp1List) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = _("Down to catacombs"); cursPosition = { 49, 21 }; return true; } } } if (IsWarpOpen(DTYPE_CAVES)) { for (uint16_t i = 1198; i <= 1219; ++i) { if (dPiece[cursPosition.x][cursPosition.y] == i) { InfoString = _("Down to caves"); cursPosition = { 17, 69 }; return true; } } } if (IsWarpOpen(DTYPE_HELL)) { for (uint16_t i = 1239; i <= 1254; ++i) { if (dPiece[cursPosition.x][cursPosition.y] == i) { InfoString = _("Down to hell"); cursPosition = { 41, 80 }; return true; } } } if (IsWarpOpen(DTYPE_NEST)) { for (const uint16_t tileId : TownHiveList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = _("Down to Hive"); cursPosition = { 80, 62 }; return true; } } } if (IsWarpOpen(DTYPE_CRYPT)) { for (const uint16_t tileId : TownCryptList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = _("Down to Crypt"); cursPosition = { 36, 24 }; return true; } } } return false; } bool ForceL1Trig() { for (const uint16_t tileId : L1UpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { if (currlevel > 1) InfoString = fmt::format(fmt::runtime(_("Up to level {:d}")), currlevel - 1); else InfoString = _("Up to town"); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { cursPosition = trigs[j].position; return true; } } } } for (const uint16_t tileId : L1DownList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Down to level {:d}")), currlevel + 1); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursPosition = trigs[j].position; return true; } } } } return false; } bool ForceL2Trig() { for (const uint16_t tileId : L2UpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { InfoString = fmt::format(fmt::runtime(_("Up to level {:d}")), currlevel - 1); cursPosition = trigs[j].position; return true; } } } } } for (const uint16_t tileId : L2DownList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Down to level {:d}")), currlevel + 1); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursPosition = trigs[j].position; return true; } } } } if (currlevel == 5) { for (const uint16_t tileId : L2TWarpUpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABTWARPUP) { int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { InfoString = _("Up to town"); cursPosition = trigs[j].position; return true; } } } } } } return false; } bool ForceL3Trig() { for (const uint16_t tileId : L3UpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Up to level {:d}")), currlevel - 1); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { cursPosition = trigs[j].position; return true; } } } } } for (const uint16_t tileId : L3DownList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId || dPiece[cursPosition.x + 1][cursPosition.y] == tileId || dPiece[cursPosition.x + 2][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Down to level {:d}")), currlevel + 1); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursPosition = trigs[j].position; return true; } } } } if (currlevel == 9) { for (const uint16_t tileId : L3TWarpUpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABTWARPUP) { int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { InfoString = _("Up to town"); cursPosition = trigs[j].position; return true; } } } } } } return false; } bool ForceL4Trig() { for (const uint16_t tileId : L4UpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Up to level {:d}")), currlevel - 1); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { cursPosition = trigs[j].position; return true; } } } } for (const uint16_t tileId : L4DownList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Down to level {:d}")), currlevel + 1); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursPosition = trigs[j].position; return true; } } } } if (currlevel == 13) { for (const uint16_t tileId : L4TWarpUpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABTWARPUP) { int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { InfoString = _("Up to town"); cursPosition = trigs[j].position; return true; } } } } } } if (currlevel == 15) { for (const uint16_t tileId : L4PentaList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = _("Down to Diablo"); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursPosition = trigs[j].position; return true; } } } } } return false; } bool ForceHiveTrig() { for (const uint16_t tileId : L6UpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Up to Nest level {:d}")), currlevel - 17); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { cursPosition = trigs[j].position; return true; } } } } for (const uint16_t tileId : L6DownList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId || dPiece[cursPosition.x + 1][cursPosition.y] == tileId || dPiece[cursPosition.x + 2][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Down to level {:d}")), currlevel - 15); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursPosition = trigs[j].position; return true; } } } } if (currlevel == 17) { for (const uint16_t tileId : L6TWarpUpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABTWARPUP) { int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { InfoString = _("Up to town"); cursPosition = trigs[j].position; return true; } } } } } } return false; } bool ForceCryptTrig() { for (const uint16_t tileId : L5UpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Up to Crypt level {:d}")), currlevel - 21); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABPREVLVL) { cursPosition = trigs[j].position; return true; } } } } if (dPiece[cursPosition.x][cursPosition.y] == 316) { InfoString = _("Cornerstone of the World"); return true; } for (const uint16_t tileId : L5DownList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Down to Crypt level {:d}")), currlevel - 19); for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABNEXTLVL) { cursPosition = trigs[j].position; return true; } } } } if (currlevel == 21) { for (const uint16_t tileId : L5TWarpUpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { for (int j = 0; j < numtrigs; j++) { if (trigs[j]._tmsg == WM_DIABTWARPUP) { int dx = abs(trigs[j].position.x - cursPosition.x); int dy = abs(trigs[j].position.y - cursPosition.y); if (dx < 4 && dy < 4) { InfoString = _("Up to town"); cursPosition = trigs[j].position; return true; } } } } } } return false; } void Freeupstairs() { for (int i = 0; i < numtrigs; i++) { int tx = trigs[i].position.x; int ty = trigs[i].position.y; for (int yy = -2; yy <= 2; yy++) { for (int xx = -2; xx <= 2; xx++) { dFlags[tx + xx][ty + yy] |= DungeonFlag::Populated; } } } } bool ForceSKingTrig() { for (const uint16_t tileId : L1UpList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Back to Level {:d}")), Quests[Q_SKELKING]._qlevel); cursPosition = trigs[0].position; return true; } } return false; } bool ForceSChambTrig() { for (const uint16_t tileId : L2DownList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Back to Level {:d}")), Quests[Q_SCHAMB]._qlevel); cursPosition = trigs[0].position; return true; } } return false; } bool ForcePWaterTrig() { for (const uint16_t tileId : L3DownList) { if (dPiece[cursPosition.x][cursPosition.y] == tileId) { InfoString = fmt::format(fmt::runtime(_("Back to Level {:d}")), Quests[Q_PWATER]._qlevel); cursPosition = trigs[0].position; return true; } } return false; } bool ForceArenaTrig() { const uint16_t *checkList; size_t len; switch (setlvltype) { case DTYPE_TOWN: checkList = TownWarp1List; len = sizeof(TownWarp1List) / sizeof(TownWarp1List[0]); break; case DTYPE_CATHEDRAL: checkList = L1UpList; len = sizeof(L1UpList) / sizeof(L1UpList[0]); break; case DTYPE_CATACOMBS: checkList = L2TWarpUpList; len = sizeof(L2TWarpUpList) / sizeof(L2TWarpUpList[0]); break; case DTYPE_CAVES: checkList = L3TWarpUpList; len = sizeof(L3TWarpUpList) / sizeof(L3TWarpUpList[0]); break; case DTYPE_HELL: checkList = L4TWarpUpList; len = sizeof(L4TWarpUpList) / sizeof(L4TWarpUpList[0]); break; case DTYPE_NEST: checkList = L5TWarpUpList; len = sizeof(L5TWarpUpList) / sizeof(L5TWarpUpList[0]); break; case DTYPE_CRYPT: checkList = L6TWarpUpList; len = sizeof(L6TWarpUpList) / sizeof(L6TWarpUpList[0]); break; default: return false; } for (size_t i = 0; i < len; ++i) { if (dPiece[cursPosition.x][cursPosition.y] == checkList[i]) { InfoString = _("Up to town"); cursPosition = trigs[0].position; return true; } } return false; } void CheckTrigForce() { trigflag = false; if (ControlMode == ControlTypes::KeyboardAndMouse && GetMainPanel().contains(MousePosition)) { return; } if (!setlevel) { switch (leveltype) { case DTYPE_TOWN: trigflag = ForceTownTrig(); break; case DTYPE_CATHEDRAL: trigflag = ForceL1Trig(); break; case DTYPE_CATACOMBS: trigflag = ForceL2Trig(); break; case DTYPE_CAVES: trigflag = ForceL3Trig(); break; case DTYPE_HELL: trigflag = ForceL4Trig(); break; case DTYPE_NEST: trigflag = ForceHiveTrig(); break; case DTYPE_CRYPT: trigflag = ForceCryptTrig(); break; default: break; } if (leveltype != DTYPE_TOWN && !trigflag) { trigflag = ForceQuests(); } } else { switch (setlvlnum) { case SL_SKELKING: trigflag = ForceSKingTrig(); break; case SL_BONECHAMB: trigflag = ForceSChambTrig(); break; case SL_POISONWATER: trigflag = ForcePWaterTrig(); break; default: if (IsArenaLevel(setlvlnum)) trigflag = ForceArenaTrig(); break; } } } void CheckTriggers() { Player &myPlayer = *MyPlayer; if (myPlayer._pmode != PM_STAND) return; for (int i = 0; i < numtrigs; i++) { if (myPlayer.position.tile != trigs[i].position) { continue; } switch (trigs[i]._tmsg) { case WM_DIABNEXTLVL: if (gbIsSpawn && currlevel >= 2) { NetSendCmdLoc(MyPlayerId, true, CMD_WALKXY, { myPlayer.position.tile.x, myPlayer.position.tile.y + 1 }); myPlayer.Say(HeroSpeech::NotAChance); InitDiabloMsg(EMSG_NOT_IN_SHAREWARE); } else { StartNewLvl(myPlayer, trigs[i]._tmsg, currlevel + 1); } break; case WM_DIABPREVLVL: StartNewLvl(myPlayer, trigs[i]._tmsg, currlevel - 1); break; case WM_DIABRTNLVL: StartNewLvl(myPlayer, trigs[i]._tmsg, GetMapReturnLevel()); break; case WM_DIABTOWNWARP: if (gbIsMultiplayer) { bool abort = false; diablo_message abortflag; auto position = myPlayer.position.tile; if (trigs[i]._tlvl == 5 && myPlayer._pLevel < 8) { abort = true; position.y += 1; abortflag = EMSG_REQUIRES_LVL_8; } if (IsAnyOf(trigs[i]._tlvl, 9, 17) && myPlayer._pLevel < 13) { abort = true; position.x += 1; abortflag = EMSG_REQUIRES_LVL_13; } if (IsAnyOf(trigs[i]._tlvl, 13, 21) && myPlayer._pLevel < 17) { abort = true; position.y += 1; abortflag = EMSG_REQUIRES_LVL_17; } if (abort) { myPlayer.Say(HeroSpeech::ICantGetThereFromHere); InitDiabloMsg(abortflag); NetSendCmdLoc(MyPlayerId, true, CMD_WALKXY, position); return; } } StartNewLvl(myPlayer, trigs[i]._tmsg, trigs[i]._tlvl); break; case WM_DIABTWARPUP: TWarpFrom = currlevel; StartNewLvl(myPlayer, trigs[i]._tmsg, 0); break; default: app_fatal("Unknown trigger msg"); } } } bool EntranceBoundaryContains(Point entrance, Point position) { constexpr Displacement entranceOffsets[7] = { { 0, 0 }, { -1, 0 }, { 0, -1 }, { -1, -1 }, { -2, -1 }, { -1, -2 }, { -2, -2 } }; return std::any_of( std::begin(entranceOffsets), std::end(entranceOffsets), [&](auto offset) { return entrance + offset == position; }); } } // namespace devilution