Good eye.
This brings up a host of related bugs, which include the following:
* A mirror protects a fuse from igniting after being hit by a bomb.
* A mirror will prevent a scroll from falling if the bridge/platform it's on falls/moves.
* If there are multiple Conquer Tokens in the room and one is covered by a mirror, then you can activate one Conquer Token, then move the mirror and activate the second Conquer Token (causing an assertion). This also works with Power Tokens and Disarm Tokens, but those are really just a cosmetic change (no assertion error).
* I've also noticed that through some quick testing that Mirrors do not drop if the Trapdoor they're on falls "
normally"
. Obviously, this can only happen in very rare circumstances, like if a Trapdoor-dropping Character appears on top of the mirror and then moves off the square. This is all because it uses the DestroyTrapdoor subroutine, which does not check for Mirrors. Naturally, this also saves any Scroll that happens to be under the Mirror too.
Many of these things also occur in DROD RPG due to the same code being used. That said, DROD RPG needs a good look at mirror persistence anyhow, so it can wait until that's cleared up.
Scrolls, Tokens and Fuses should be the only objects affected by this (since, to my knowledge, they're the only items that can be covered by a mirror).
In some cases, the easiest fix is going to be checking for the existence of a Mirror before a particular Switch statement. However, some things need a little more careful coding to get them to perform as expected. As some examples:
CDbRoom::CheckForFallingAt
//These objects fall into pit/water.
switch (wTSquare)
{
case T_STATION:
case T_BOMB: case T_ORB:
case T_SCROLL:
case T_POTION_K: case T_POTION_I: case T_POTION_D: case T_POTION_C: case T_POTION_SP:
case T_MIRROR:
Plot(wX, wY, T_EMPTY);
if (bIsWater(wOSquare))
CueEvents.Add(CID_Splash, new CCoord(wX, wY), true);
else
CueEvents.Add(CID_ObjectFell, new CMoveCoordEx(wX, wY, NO_ORIENTATION, wTSquare), true);
// If there's a scroll under the mirror, invisibly make it fall too
if (wTSquare == T_MIRROR)
{
const UINT wCoveredSquare = GetTSquare(wX,wY);
if (wCoveredSquare == T_SCROLL)
Plot(wX, wY, T_EMPTY);
}
break;
CDbRoom::CloseYellowDoor
switch (GetTSquare(wSX, wSY))
{
case T_FUSE:
Plot(wSX, wSY, T_EMPTY);
this->LitFuses.erase(wSX, wSY);
break;
case T_MIRROR:
if (this->coveredTSquares.GetAt(wSX, wSY) == T_FUSE)
this->coveredTSquares.Remove(wSX, wSY);
break;
}
CDbRoom::ChangeTiles
case SwordDisarm:
case PowerTarget:
case ConquerToken:
//Toggle on-off state of all tokens of this type in the room.
for (wY=this->wRoomRows; wY--; )
for (wX=this->wRoomCols; wX--; )
{
const UINT wTSquare = GetTSquare(wX,wY);
if (GetTSquare(wX,wY) == T_TOKEN)
if (wTSquare == T_TOKEN)
{
const BYTE tParam = GetTParam(wX, wY);
if ((RoomTokenType)calcTokenType(tParam) == tType)
{
SetTParam(wX, wY, tParam + TOKEN_ACTIVE); //toggle on-off
this->PlotsMade.insert(wX,wY);
}
}
if ((wTSquare == T_MIRROR) && (this->coveredTSquares.GetAt(wX, wY) == T_TOKEN))
{
const BYTE tParam = GetTParam(wX, wY);
if ((RoomTokenType)calcTokenType(tParam) == tType)
{
SetTParam(wX, wY, tParam + TOKEN_ACTIVE); //toggle on-off
}
}
}
break;
Note that that last change will also require a fix to GetTParam to remove an Assertion error, since it currently doesn't expect us to change the TParam of a token underneath a mirror.
Not sure if the bomb-protection aspect "
should"
be changed -- it's in the same class of bugs, but you could argue that it might be an interesting mechanic and have an aspect of intuitiveness to it. Or it could just annoy people with yet another mechanic to remember. Easily fixed, anyways.