Okay, finally spent a few hours getting my compiler up and running again. Here's my attempt to implement a CueEvent-style fix to the original bug in Build 84.
Click here to view the secret text
×void CDbRoom::SwitchTarstuff(CCueEvents &CueEvents, const UINT wType1, const UINT wType2)
//Switch these two tarstuff types in the room, including monster types.
{
CMonsterFactory mf(this->pCurrentGame);
const bool bTar = wType1 == T_TAR || wType2 == T_TAR;
const bool bMud = wType1 == T_MUD || wType2 == T_MUD;
const bool bGel = wType1 == T_GEL || wType2 == T_GEL;
const CUEEVENT_ID eGrowth1 = bTar ? CID_TarGrew : CID_MudGrew;
const CUEEVENT_ID eGrowth2 = bGel ? CID_GelGrew : CID_MudGrew;
UINT wX, wY;
CCueEvents Ignored;
for (wY=0; wY<this->wRoomRows; ++wY)
for (wX=0; wX<this->wRoomCols; ++wX)
{
//Switch tarstuff.
const UINT wTTile = GetTSquare(wX,wY);
if (wTTile == wType1)
Plot(wX,wY, wType2);
else if (wTTile == wType2)
Plot(wX,wY, wType1);
//Swap monster types.
CMonster *pMonster = GetMonsterAtSquare(wX,wY);
if (pMonster)
{
const int nType = SwapTarstuffRoles(pMonster->wType, bTar, bMud, bGel);
if (nType != -1)
{
//Create new monster and insert in list where old monster was.
CMonster *pNew = mf.GetNewMonster((const MONSTERTYPE)nType);
pNew->wX = pNew->wPrevX = wX;
pNew->wY = pNew->wPrevY = wY;
pNew->wO = pMonster->wO;
++this->wMonsterCount;
pNew->pNext = pMonster->pNext;
pNew->pPrevious = pMonster->pPrevious;
if (pNew->pNext)
pNew->pNext->pPrevious = pNew;
if (pNew->pPrevious)
pNew->pPrevious->pNext = pNew;
if (pMonster == this->pLastMonster)
this->pLastMonster = pNew;
if (pMonster == this->pFirstMonster)
this->pFirstMonster = pNew;
if (bIsMother(pMonster->wType))
{
if (CueEvents.Remove(eGrowth1,pMonster))
CueEvents.Add(eGrowth2,pNew);
if (CueEvents.Remove(eGrowth2,pMonster))
CueEvents.Add(eGrowth1,pNew);
}
pMonster->pNext = pMonster->pPrevious = NULL;
KillMonster(pMonster, Ignored);
SetMonsterSquare(pNew);
}
}
}
if (CueEvents.HasOccurred(eGrowth1) && CueEvents.GetOccurrenceCount(eGrowth1) == 0)
CueEvents.ClearEvent(eGrowth1);
if (CueEvents.HasOccurred(eGrowth2) && CueEvents.GetOccurrenceCount(eGrowth2) == 0)
CueEvents.ClearEvent(eGrowth2);
//If player is in a tar role, switch player role.
const int nSwappedPlayerType = SwapTarstuffRoles(this->pCurrentGame->swordsman.wAppearance, bTar, bMud, bGel);
if (nSwappedPlayerType >= 0)
this->pCurrentGame->SetPlayerRole(nSwappedPlayerType);
}
Obviously, these changes will also require the addition of the CueEvents parameter for SwitchTarstuff in DbRooms.h and in the three calls to it in CDbRoom::ActivateToken.
I had to manually check that if a Growth Event's monsters are all deleted, then the CueEvent itself should be removed, since simply using Remove on it and reducing it to 0 entries didn't work -- it caused an assertion in GrowTar where it expected a monster to be found. Don't know if there's a better way to make the switch between CueEvents: how is it usually handled for prematurely killed mothers?
I have, however, tested this fix with a handful of rooms: stuff revolving around babies now work fine once more (Museum of Ooze, for example), and the fix appears to work as intended in Murder in the Basement, as well as with a test room I quickly put together with Invisibility Potions, Mothers, Tokens, Mimics and NPCs. Can't say I've exhaustively tested, but it seems promising to start with. By only concern is if anything needs the CueEvent prior to its switch -- but the only thing I can easily think of is Characters which can only check if a CueEvent has occurred, and that's more a Movement Order problem for the architect than something we should deal with, I think.