[Scummvm-git-logs] scummvm master -> 99a402e35e6f752943280b489a3bccb710287dee

sev- noreply at scummvm.org
Wed Jul 8 11:38:23 UTC 2026


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
99a402e35e DM: Replace raw thing-data casts with typed struct arrays


Commit: 99a402e35e6f752943280b489a3bccb710287dee
    https://github.com/scummvm/scummvm/commit/99a402e35e6f752943280b489a3bccb710287dee
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-07-08T13:38:18+02:00

Commit Message:
DM: Replace raw thing-data casts with typed struct arrays

Thing data was previously accessed via pointer casts on raw uint16 arrays. Each type is now parsed into its own typed Common::Array<T> at load time.

Changed paths:
    engines/dm/champion.cpp
    engines/dm/console.cpp
    engines/dm/dm.cpp
    engines/dm/dungeonman.cpp
    engines/dm/dungeonman.h
    engines/dm/eventman.cpp
    engines/dm/gfx.cpp
    engines/dm/group.cpp
    engines/dm/group.h
    engines/dm/inventory.cpp
    engines/dm/loadsave.cpp
    engines/dm/menus.cpp
    engines/dm/movesens.cpp
    engines/dm/objectman.cpp
    engines/dm/projexpl.cpp
    engines/dm/timeline.cpp


diff --git a/engines/dm/champion.cpp b/engines/dm/champion.cpp
index 88afc8598d7..299c7ec550d 100644
--- a/engines/dm/champion.cpp
+++ b/engines/dm/champion.cpp
@@ -305,11 +305,11 @@ void ChampionMan::applyModifiersToStatistics(Champion *champ, int16 slotIndex, i
 	if (((thingType == kDMThingTypeWeapon) || (thingType == kDMThingTypeArmour))
 		&& (slotIndex >= kDMSlotReadyHand) && (slotIndex <= kDMSlotQuiverLine1_1)) {
 		if (thingType == kDMThingTypeWeapon) {
-			Weapon *weapon = (Weapon *)_vm->_dungeonMan->getThingData(thing);
+			Weapon *weapon = _vm->_dungeonMan->getWeapon(thing);
 			cursed = weapon->getCursed();
 		} else {
 			// k6_ArmourThingType
-			Armour *armour = (Armour *)_vm->_dungeonMan->getThingData(thing);
+			Armour *armour = _vm->_dungeonMan->getArmour(thing);
 			cursed = armour->getCursed();
 		}
 
@@ -545,7 +545,6 @@ void ChampionMan::addObjectInSlot(ChampionIndex champIndex, Thing thing, Champio
 	IconIndice iconIndex = objMan.getIconIndex(thing);
 	bool isInventoryChampion = (_vm->indexToOrdinal(champIndex) == invMan._inventoryChampionOrdinal);
 	applyModifiersToStatistics(champ, slotIndex, iconIndex, 1, thing);
-	uint16 *rawObjPtr = dunMan.getThingData(thing);
 
 	if (slotIndex < kDMSlotHead) {
 		if (slotIndex == kDMSlotActionHand) {
@@ -554,13 +553,13 @@ void ChampionMan::addObjectInSlot(ChampionIndex champIndex, Thing thing, Champio
 				menuMan.clearActingChampion();
 
 			if ((iconIndex >= kDMIconIndiceScrollOpen) && (iconIndex <= kDMIconIndiceScrollClosed)) {
-				((Scroll *)rawObjPtr)->setClosed(false);
+				dunMan.getScroll(thing)->setClosed(false);
 				drawChangedObjectIcons();
 			}
 		}
 
 		if (iconIndex == kDMIconIndiceWeaponTorchUnlit) {
-			((Weapon *)rawObjPtr)->setLit(true);
+			dunMan.getWeapon(thing)->setLit(true);
 			invMan.setDungeonViewPalette();
 			drawChangedObjectIcons();
 		} else if (isInventoryChampion && (slotIndex == kDMSlotActionHand) &&
@@ -569,12 +568,12 @@ void ChampionMan::addObjectInSlot(ChampionIndex champIndex, Thing thing, Champio
 		}
 	} else if (slotIndex == kDMSlotNeck) {
 		if ((iconIndex >= kDMIconIndiceJunkIllumuletUnequipped) && (iconIndex <= kDMIconIndiceJunkIllumuletEquipped)) {
-			((Junk *)rawObjPtr)->setChargeCount(1);
+			dunMan.getJunk(thing)->setChargeCount(1);
 			_party._magicalLightAmount += _lightPowerToLightAmount[2];
 			invMan.setDungeonViewPalette();
 			iconIndex = (IconIndice)(iconIndex + 1);
 		} else if ((iconIndex >= kDMIconIndiceJunkJewelSymalUnequipped) && (iconIndex <= kDMIconIndiceJunkJewelSymalEquipped)) {
-			((Junk *)rawObjPtr)->setChargeCount(1);
+			dunMan.getJunk(thing)->setChargeCount(1);
 			iconIndex = (IconIndice)(iconIndex + 1);
 		}
 	}
@@ -687,14 +686,13 @@ Thing ChampionMan::getObjectRemovedFromSlot(uint16 champIndex, uint16 slotIndex)
 	// Remove object modifiers
 	applyModifiersToStatistics(curChampion, slotIndex, curIconIndex, -1, curThing);
 
-	Weapon *curWeapon = (Weapon *)dungeon.getThingData(curThing);
 	if (slotIndex == kDMSlotNeck) {
 		if ((curIconIndex >= kDMIconIndiceJunkIllumuletUnequipped) && (curIconIndex <= kDMIconIndiceJunkIllumuletEquipped)) {
-			((Junk *)curWeapon)->setChargeCount(0);
+			dungeon.getJunk(curThing)->setChargeCount(0);
 			_party._magicalLightAmount -= _lightPowerToLightAmount[2];
 			inventory.setDungeonViewPalette();
 		} else if ((curIconIndex >= kDMIconIndiceJunkJewelSymalUnequipped) && (curIconIndex <= kDMIconIndiceJunkJewelSymalEquipped)) {
-			((Junk *)curWeapon)->setChargeCount(0);
+			dungeon.getJunk(curThing)->setChargeCount(0);
 		}
 	}
 
@@ -709,13 +707,13 @@ Thing ChampionMan::getObjectRemovedFromSlot(uint16 champIndex, uint16 slotIndex)
 				_vm->_menuMan->clearActingChampion();
 
 			if ((curIconIndex >= kDMIconIndiceScrollOpen) && (curIconIndex <= kDMIconIndiceScrollClosed)) {
-				((Scroll *)curWeapon)->setClosed(true);
+				dungeon.getScroll(curThing)->setClosed(true);
 				drawChangedObjectIcons();
 			}
 		}
 
 		if ((curIconIndex >= kDMIconIndiceWeaponTorchUnlit) && (curIconIndex <= kDMIconIndiceWeaponTorchLit)) {
-			curWeapon->setLit(false);
+			dungeon.getWeapon(curThing)->setLit(false);
 			inventory.setDungeonViewPalette();
 			drawChangedObjectIcons();
 		}
@@ -857,8 +855,8 @@ int16 ChampionMan::getWoundDefense(int16 champIndex, uint16 woundIndex) {
 	for (int16 slotIndex = kDMSlotReadyHand; slotIndex <= kDMSlotActionHand; slotIndex++) {
 		Thing curThing = curChampion->_slots[slotIndex];
 		if (curThing.getType() == kDMThingTypeArmour) {
-			ArmourInfo *armorInfo = (ArmourInfo *)dungeon.getThingData(curThing);
-			armorInfo = &dungeon._armourInfos[((Armour *)armorInfo)->getType()];
+			Armour *armour = dungeon.getArmour(curThing);
+			ArmourInfo *armorInfo = &dungeon._armourInfos[armour->getType()];
 			if (getFlag(armorInfo->_attributes, kDMArmourAttributeShield))
 				armorShieldDefense += ((getStrength(champIndex, slotIndex) + dungeon.getArmourDefense(armorInfo, useSharpDefense)) * woundDefenseFactor[woundIndex]) >> ((slotIndex == woundIndex) ? 4 : 5);
 		}
@@ -872,8 +870,8 @@ int16 ChampionMan::getWoundDefense(int16 champIndex, uint16 woundIndex) {
 	if (woundIndex > kDMSlotActionHand) {
 		Thing curThing = curChampion->_slots[woundIndex];
 		if (curThing.getType() == kDMThingTypeArmour) {
-			ArmourInfo *armourInfo = (ArmourInfo *)dungeon.getThingData(curThing);
-			woundDefense += dungeon.getArmourDefense(&dungeon._armourInfos[((Armour *)armourInfo)->getType()], useSharpDefense);
+			Armour *armour = dungeon.getArmour(curThing);
+			woundDefense += dungeon.getArmourDefense(&dungeon._armourInfos[armour->getType()], useSharpDefense);
 		}
 	}
 
@@ -1511,7 +1509,7 @@ void ChampionMan::championKill(uint16 champIndex) {
 	Thing unusedThing = dungeon.getUnusedThing(kDMMaskChampionBones | kDMThingTypeJunk);
 	uint16 curCell = 0;
 	if (unusedThing != _vm->_thingNone) {
-		Junk *L0966_ps_Junk = (Junk *)dungeon.getThingData(unusedThing);
+		Junk *L0966_ps_Junk = dungeon.getJunk(unusedThing);
 		L0966_ps_Junk->setType(kDMJunkTypeBones);
 		L0966_ps_Junk->setDoNotDiscard(true);
 		L0966_ps_Junk->setChargeCount(champIndex);
diff --git a/engines/dm/console.cpp b/engines/dm/console.cpp
index 6c2082529c8..0da5659a416 100644
--- a/engines/dm/console.cpp
+++ b/engines/dm/console.cpp
@@ -257,28 +257,19 @@ bool Console::Cmd_gimme(int argc, const char** argv) {
 	requestedItemName.deleteLastChar();
 
 	for (int16 thingType = 0; thingType < 16; ++thingType) { // 16 number of item types
-		uint16 *thingDataArray = _vm->_dungeonMan->_thingData[thingType];
-		uint16 thingTypeSize = _vm->_dungeonMan->_thingDataWordCount[thingType];
 		uint16 thingCount = _vm->_dungeonMan->_dungeonFileHeader._thingCounts[thingType];
 
 		Thing dummyThing(0);
 		dummyThing.setType(thingType);
 		for (int16 thingIndex = 0; thingIndex < thingCount; ++thingIndex) {
 			dummyThing.setIndex(thingIndex);
-			uint16 *rawType = _vm->_dungeonMan->getThingData(dummyThing);
-			if (rawType[0] == _vm->_thingNone.toUint16())
+			if (_vm->_dungeonMan->getNextThing(dummyThing) == _vm->_thingNone)
 				continue;
 			int16 iconIndex = _vm->_objectMan->getIconIndex(dummyThing);
 			if (iconIndex >= 0 && iconIndex < kDMObjectNameCount) {
 				const char *displayName = _vm->_objectMan->_objectNames[iconIndex];
 				if (cstrEquals(displayName, requestedItemName.c_str())) {
-					uint16 *newThingData = new uint16[(thingCount + 1) * thingTypeSize];
-					memcpy(newThingData, thingDataArray, sizeof(uint16) * thingTypeSize * thingCount);
-					delete[] thingDataArray;
-					for (uint16 i = 0; i < thingTypeSize; ++i)
-						newThingData[thingCount * thingTypeSize + i] = newThingData[thingIndex * thingTypeSize + i];
-					_vm->_dungeonMan->_dungeonFileHeader._thingCounts[thingType]++;
-					_vm->_dungeonMan->_thingData[thingType] = newThingData;
+					_vm->_dungeonMan->duplicateThing(dummyThing);
 					dummyThing.setIndex(thingCount);
 					_vm->_championMan->addObjectInSlot((ChampionIndex)0, dummyThing, (ChampionSlot)29);
 					debugPrintf("Item gimmed to the first champion, last slot\n");
diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp
index 12d3fabd50a..29c8894d6e1 100644
--- a/engines/dm/dm.cpp
+++ b/engines/dm/dm.cpp
@@ -921,7 +921,7 @@ void DMEngine::fuseSequence() {
 	lordChaosMapX += _dirIntoStepCountEast[_dungeonMan->_partyDir];
 	lordChaosMapY += _dirIntoStepCountNorth[_dungeonMan->_partyDir];
 	Thing lordChaosThing = _groupMan->groupGetThing(lordChaosMapX, lordChaosMapY);
-	Group *lordGroup = (Group*)_dungeonMan->getThingData(lordChaosThing);
+	Group *lordGroup = _dungeonMan->getGroup(lordChaosThing);
 	lordGroup->_health[0] = 10000;
 	_dungeonMan->setGroupCells(lordGroup, kDMCreatureTypeSingleCenteredCreature, _dungeonMan->_partyMapIndex);
 	_dungeonMan->setGroupDirections(lordGroup, returnOppositeDir(_dungeonMan->_partyDir), _dungeonMan->_partyMapIndex);
@@ -934,7 +934,7 @@ void DMEngine::fuseSequence() {
 		Thing curThing = _dungeonMan->getSquareFirstObject(fluxCageMapX, fluxcageMapY);
 		while (curThing != _thingEndOfList) {
 			if (curThing.getType() == kDMThingTypeExplosion) {
-				Explosion *curExplosion = (Explosion*)_dungeonMan->getThingData(curThing);
+				Explosion *curExplosion = _dungeonMan->getExplosion(curThing);
 				if (curExplosion->getType() == kDMExplosionTypeFluxcage) {
 					_dungeonMan->unlinkThingFromList(curThing, Thing(0), fluxCageMapX, fluxcageMapY);
 					curExplosion->setNextThing(_thingNone);
diff --git a/engines/dm/dungeonman.cpp b/engines/dm/dungeonman.cpp
index eb649333f29..87b98c02152 100644
--- a/engines/dm/dungeonman.cpp
+++ b/engines/dm/dungeonman.cpp
@@ -418,8 +418,6 @@ DungeonMan::DungeonMan(DMEngine *dmEngine) : _vm(dmEngine) {
 	_dungeonColumnsCumulativeSquareThingCount = nullptr;
 	_squareFirstThings = nullptr;
 	_dungeonTextData = nullptr;
-	for (uint16 i = 0; i < 16; ++i)
-		_thingData[i] = nullptr;
 
 	_dungeonMapData = nullptr;
 	_partyDir = (Direction)0;
@@ -467,8 +465,6 @@ DungeonMan::~DungeonMan() {
 	delete[] _squareFirstThings;
 	delete[] _dungeonTextData;
 	delete[] _dungeonMapData;
-	for (uint16 i = 0; i < 16; ++i)
-		delete[] _thingData[i];
 
 	delete[] _dungeonRawMapData;
 }
@@ -693,26 +689,166 @@ void DungeonMan::loadDungeonFile(Common::InSaveFile *file) {
 		if (thingStoreWordCount == 0)
 			continue;
 
-		if (!_vm->_restartGameRequest) {
-			delete[] _thingData[thingType];
-			_thingData[thingType] = new uint16[_dungeonFileHeader._thingCounts[thingType] * thingStoreWordCount];
+		switch (thingType) {
+		case kDMThingTypeDoor:
+			_doors.clear();
+			_doors.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypeTeleporter:
+			_teleporters.clear();
+			_teleporters.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMstringTypeText:
+			_textStrings.clear();
+			_textStrings.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypeSensor:
+			_sensors.clear();
+			_sensors.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypeGroup:
+			_groups.clear();
+			_groups.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypeWeapon:
+			_weapons.clear();
+			_weapons.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypeArmour:
+			_armours.clear();
+			_armours.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypeScroll:
+			_scrolls.clear();
+			_scrolls.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypePotion:
+			_potions.clear();
+			_potions.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypeContainer:
+			_containers.clear();
+			_containers.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypeJunk:
+			_junks.clear();
+			_junks.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypeProjectile:
+			_projectiles.clear();
+			_projectiles.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
+		case kDMThingTypeExplosion:
+			_explosions.clear();
+			_explosions.resize(_dungeonFileHeader._thingCounts[thingType]);
+			break;
 		}
 
-		if ((thingType == kDMThingTypeGroup || thingType == kDMThingTypeProjectile) && !file) { // !file because save files have diff. structure than dungeon.dat
-			for (uint16 i = 0; i < thingCount; ++i) {
-				uint16 *nextSlot = _thingData[thingType] + i *thingStoreWordCount;
-				for (uint16 j = 0; j < thingStoreWordCount; ++j) {
-					if (j == 2 || j == 3)
-						nextSlot[j] = dunDataStream->readByte();
-					else
-						nextSlot[j] = dunDataStream->readUint16BE();
+		for (uint16 i = 0; i < thingCount; ++i) {
+			switch (thingType) {
+			case kDMThingTypeDoor: {
+				Door &door = _doors[i];
+				door._nextThing = Thing(dunDataStream->readUint16BE());
+				door._attributes = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMThingTypeTeleporter: {
+				Teleporter &tele = _teleporters[i];
+				tele._nextThing = Thing(dunDataStream->readUint16BE());
+				tele._attributes = dunDataStream->readUint16BE();
+				tele._destMapIndex = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMstringTypeText: {
+				TextString &text = _textStrings[i];
+				text._nextThing = Thing(dunDataStream->readUint16BE());
+				text._textDataRef = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMThingTypeSensor: {
+				Sensor &sens = _sensors[i];
+				sens._nextThing = Thing(dunDataStream->readUint16BE());
+				sens._datAndType = dunDataStream->readUint16BE();
+				sens._attributes = dunDataStream->readUint16BE();
+				sens._action = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMThingTypeGroup: {
+				Group &grp = _groups[i];
+				grp._nextThing = Thing(dunDataStream->readUint16BE());
+				grp._slot = Thing(dunDataStream->readUint16BE());
+				if (!file) {
+					grp._type = (CreatureType)dunDataStream->readByte();
+					grp._cells = dunDataStream->readByte();
+				} else {
+					grp._type = (CreatureType)dunDataStream->readUint16BE();
+					grp._cells = dunDataStream->readUint16BE();
 				}
+				grp._health[0] = dunDataStream->readUint16BE();
+				grp._health[1] = dunDataStream->readUint16BE();
+				grp._health[2] = dunDataStream->readUint16BE();
+				grp._health[3] = dunDataStream->readUint16BE();
+				grp._flags = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMThingTypeWeapon: {
+				Weapon &weap = _weapons[i];
+				weap._nextThing = Thing(dunDataStream->readUint16BE());
+				weap._desc = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMThingTypeArmour: {
+				Armour &arm = _armours[i];
+				arm._nextThing = Thing(dunDataStream->readUint16BE());
+				arm._attributes = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMThingTypeScroll: {
+				Scroll &scr = _scrolls[i];
+				scr._nextThing = Thing(dunDataStream->readUint16BE());
+				scr._attributes = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMThingTypePotion: {
+				Potion &pot = _potions[i];
+				pot._nextThing = Thing(dunDataStream->readUint16BE());
+				pot._attributes = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMThingTypeContainer: {
+				Container &cont = _containers[i];
+				cont._nextThing = Thing(dunDataStream->readUint16BE());
+				cont._slot = Thing(dunDataStream->readUint16BE());
+				cont._type = dunDataStream->readUint16BE();
+				dunDataStream->readUint16BE(); // unused 4th word
+				break;
+			}
+			case kDMThingTypeJunk: {
+				Junk &jnk = _junks[i];
+				jnk._nextThing = Thing(dunDataStream->readUint16BE());
+				jnk._attributes = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMThingTypeProjectile: {
+				Projectile &proj = _projectiles[i];
+				proj._nextThing = Thing(dunDataStream->readUint16BE());
+				proj._slot = Thing(dunDataStream->readUint16BE());
+				if (!file) {
+					proj._kineticEnergy = dunDataStream->readByte();
+					proj._attack = dunDataStream->readByte();
+				} else {
+					proj._kineticEnergy = dunDataStream->readUint16BE();
+					proj._attack = dunDataStream->readUint16BE();
+				}
+				proj._eventIndex = dunDataStream->readUint16BE();
+				break;
+			}
+			case kDMThingTypeExplosion: {
+				Explosion &expl = _explosions[i];
+				expl._nextThing = Thing(dunDataStream->readUint16BE());
+				expl._attributes = dunDataStream->readUint16BE();
+				break;
 			}
-		} else {
-			for (uint16 i = 0; i < thingCount; ++i) {
-				uint16 *nextSlot = _thingData[thingType] + i *thingStoreWordCount;
-				for (uint16 j = 0; j < thingStoreWordCount; ++j)
-					nextSlot[j] = dunDataStream->readUint16BE();
 			}
 		}
 
@@ -720,8 +856,50 @@ void DungeonMan::loadDungeonFile(Common::InSaveFile *file) {
 			if ((thingType == kDMThingTypeGroup) || thingType >= kDMThingTypeProjectile)
 				timeline._eventMaxCount += _dungeonFileHeader._thingCounts[thingType];
 
-			for (uint16 i = 0; i < additionalThingCounts[thingType]; ++i)
-				(_thingData[thingType] + (thingCount + i) * thingStoreWordCount)[0] = _vm->_thingNone.toUint16();
+			for (uint16 i = 0; i < additionalThingCounts[thingType]; ++i) {
+				uint16 idx = thingCount + i;
+				switch (thingType) {
+				case kDMThingTypeDoor:
+					_doors[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypeTeleporter:
+					_teleporters[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMstringTypeText:
+					_textStrings[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypeSensor:
+					_sensors[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypeGroup:
+					_groups[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypeWeapon:
+					_weapons[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypeArmour:
+					_armours[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypeScroll:
+					_scrolls[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypePotion:
+					_potions[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypeContainer:
+					_containers[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypeJunk:
+					_junks[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypeProjectile:
+					_projectiles[idx]._nextThing = _vm->_thingNone;
+					break;
+				case kDMThingTypeExplosion:
+					_explosions[idx]._nextThing = _vm->_thingNone;
+					break;
+				}
+			}
 		}
 	}
 
@@ -907,13 +1085,14 @@ T0172010_ClosedFakeWall:
 			ThingType curThingType = curThing.getType();
 			int16 AL0310_i_SideIndex = _vm->normalizeModulo4(curThing.getCell() - dir);
 			if (AL0310_i_SideIndex) { /* Invisible on the back wall if 0 */
-				Sensor *curSensor = (Sensor *)getThingData(curThing);
 				if (curThingType == kDMstringTypeText) {
-					if (((TextString *)curSensor)->isVisible()) {
+					TextString *curText = getTextString(curThing);
+					if (curText->isVisible()) {
 						aspectArray[AL0310_i_SideIndex + 1] = _currMapInscriptionWallOrnIndex + 1;
 						displMan._inscriptionThing = curThing; /* BUG0_76 The same text is drawn on multiple sides of a wall square. The engine stores only a single text to draw on a wall in a global variable. Even if different texts are placed on different sides of the wall, the same text is drawn on each affected side */
 					}
 				} else {
+					Sensor *curSensor = getSensor(curThing);
 					aspectArray[AL0310_i_SideIndex + 1] = curSensor->getAttrOrnOrdinal();
 					if (curSensor->getType() == kDMSensorWallChampionPortrait) {
 						displMan._championPortraitOrdinal = _vm->indexToOrdinal(curSensor->getData());
@@ -958,7 +1137,7 @@ T0172010_ClosedFakeWall:
 
 		while ((curThing != _vm->_thingEndOfList) && (curThing.getType() <= kDMThingTypeSensor)) {
 			if (curThing.getType() == kDMThingTypeSensor) {
-				Sensor *curSensor = (Sensor *)getThingData(curThing);
+				Sensor *curSensor = getSensor(curThing);
 				aspectArray[kDMSquareAspectFloorOrn] = curSensor->getAttrOrnOrdinal();
 			}
 			curThing = getNextThing(curThing);
@@ -1034,16 +1213,133 @@ bool DungeonMan::isWallOrnAnAlcove(int16 wallOrnIndex) {
 	return false;
 }
 
-uint16 *DungeonMan::getThingData(Thing thing) {
-	return _thingData[thing.getType()] + thing.getIndex() * _thingDataWordCount[thing.getType()];
+Door *DungeonMan::getDoor(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeDoor);
+	return &(_doors[thing.getIndex()]);
+}
+
+Teleporter *DungeonMan::getTeleporter(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeTeleporter);
+	return &(_teleporters[thing.getIndex()]);
+}
+
+TextString *DungeonMan::getTextString(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMstringTypeText);
+	return &(_textStrings[thing.getIndex()]);
+}
+
+Sensor *DungeonMan::getSensor(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeSensor);
+	return &(_sensors[thing.getIndex()]);
+}
+
+Group *DungeonMan::getGroup(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeGroup);
+	return &(_groups[thing.getIndex()]);
+}
+
+Weapon *DungeonMan::getWeapon(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeWeapon);
+	return &(_weapons[thing.getIndex()]);
+}
+
+Armour *DungeonMan::getArmour(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeArmour);
+	return &(_armours[thing.getIndex()]);
+}
+
+Scroll *DungeonMan::getScroll(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeScroll);
+	return &(_scrolls[thing.getIndex()]);
+}
+
+Potion *DungeonMan::getPotion(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypePotion);
+	return &(_potions[thing.getIndex()]);
+}
+
+Container *DungeonMan::getContainer(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeContainer);
+	return &(_containers[thing.getIndex()]);
+}
+
+Junk *DungeonMan::getJunk(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeJunk);
+	return &(_junks[thing.getIndex()]);
+}
+
+Projectile *DungeonMan::getProjectile(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeProjectile);
+	return &(_projectiles[thing.getIndex()]);
 }
 
-uint16 *DungeonMan::getSquareFirstThingData(int16 mapX, int16 mapY) {
-	return getThingData(getSquareFirstThing(mapX, mapY));
+Explosion *DungeonMan::getExplosion(Thing thing) {
+	if (thing == _vm->_thingNone || thing == _vm->_thingEndOfList)
+		return nullptr;
+	assert(thing.getType() == kDMThingTypeExplosion);
+	return &(_explosions[thing.getIndex()]);
 }
 
 Thing DungeonMan::getNextThing(Thing thing) {
-	return Thing(getThingData(thing)[0]);
+	if (thing == _vm->_thingNone)
+		return _vm->_thingNone;
+	if (thing == _vm->_thingEndOfList)
+		return _vm->_thingEndOfList;
+
+	switch (thing.getType()) {
+	case kDMThingTypeDoor:
+		return _doors[thing.getIndex()]._nextThing;
+	case kDMThingTypeTeleporter:
+		return _teleporters[thing.getIndex()]._nextThing;
+	case kDMstringTypeText:
+		return _textStrings[thing.getIndex()]._nextThing;
+	case kDMThingTypeSensor:
+		return _sensors[thing.getIndex()]._nextThing;
+	case kDMThingTypeGroup:
+		return _groups[thing.getIndex()]._nextThing;
+	case kDMThingTypeWeapon:
+		return _weapons[thing.getIndex()]._nextThing;
+	case kDMThingTypeArmour:
+		return _armours[thing.getIndex()]._nextThing;
+	case kDMThingTypeScroll:
+		return _scrolls[thing.getIndex()]._nextThing;
+	case kDMThingTypePotion:
+		return _potions[thing.getIndex()]._nextThing;
+	case kDMThingTypeContainer:
+		return _containers[thing.getIndex()]._nextThing;
+	case kDMThingTypeJunk:
+		return _junks[thing.getIndex()]._nextThing;
+	case kDMThingTypeProjectile:
+		return _projectiles[thing.getIndex()]._nextThing;
+	case kDMThingTypeExplosion:
+		return _explosions[thing.getIndex()]._nextThing;
+	default:
+		return _vm->_thingNone;
+	}
 }
 
 void DungeonMan::decodeText(char *destString, size_t maxSize, Thing thing, int16 type) {
@@ -1128,7 +1424,7 @@ void DungeonMan::decodeText(char *destString, size_t maxSize, Thing thing, int16
 		{0,   0,  0,  0, 0, 0, 0, 0}
 	};
 
-	TextString textString(_thingData[kDMstringTypeText] + thing.getIndex() * _thingDataWordCount[kDMstringTypeText]);
+	TextString &textString = *getTextString(thing);
 	if ((textString.isVisible()) || (type & kDMMaskDecodeEvenIfInvisible)) {
 		type &= ~kDMMaskDecodeEvenIfInvisible;
 		char sepChar;
@@ -1193,6 +1489,58 @@ void DungeonMan::decodeText(char *destString, size_t maxSize, Thing thing, int16
 	*destString = ((type == kDMTextTypeInscription) ? 0x81 : '\0');
 }
 
+Door *DungeonMan::getDoor(uint16 index) {
+	return &(_doors[index]);
+}
+
+Teleporter *DungeonMan::getTeleporter(uint16 index) {
+	return &(_teleporters[index]);
+}
+
+TextString *DungeonMan::getTextString(uint16 index) {
+	return &(_textStrings[index]);
+}
+
+Sensor *DungeonMan::getSensor(uint16 index) {
+	return &(_sensors[index]);
+}
+
+Group *DungeonMan::getGroup(uint16 index) {
+	return &(_groups[index]);
+}
+
+Weapon *DungeonMan::getWeapon(uint16 index) {
+	return &(_weapons[index]);
+}
+
+Armour *DungeonMan::getArmour(uint16 index) {
+	return &(_armours[index]);
+}
+
+Scroll *DungeonMan::getScroll(uint16 index) {
+	return &(_scrolls[index]);
+}
+
+Potion *DungeonMan::getPotion(uint16 index) {
+	return &(_potions[index]);
+}
+
+Container *DungeonMan::getContainer(uint16 index) {
+	return &(_containers[index]);
+}
+
+Junk *DungeonMan::getJunk(uint16 index) {
+	return &(_junks[index]);
+}
+
+Projectile *DungeonMan::getProjectile(uint16 index) {
+	return &(_projectiles[index]);
+}
+
+Explosion *DungeonMan::getExplosion(uint16 index) {
+	return &(_explosions[index]);
+}
+
 Thing DungeonMan::getUnusedThing(uint16 thingType) {
 	int16 thingCount = _dungeonFileHeader._thingCounts[getFlag(thingType, kDMMaskThingType)];
 	if (thingType == (kDMMaskChampionBones | kDMThingTypeJunk)) {
@@ -1200,32 +1548,25 @@ Thing DungeonMan::getUnusedThing(uint16 thingType) {
 	} else if (thingType == kDMThingTypeJunk)
 		thingCount -= 3; /* Always keep 3 unused JUNK things for the bones of dead champions */
 
-	int16 thingIdx = thingCount;
-	int16 thingDataByteCount = _thingDataWordCount[thingType] >> 1;
-	Thing *thingPtr = (Thing *)_thingData[thingType];
-
 	Thing curThing;
-	for (;;) { /*_Infinite loop_*/
-		if (*thingPtr == _vm->_thingNone) { /* If thing data is unused */
-			curThing = Thing((thingType << 10) | (thingCount - thingIdx));
-			break;
-		}
-		if (--thingIdx) { /* If there are thing data left to process */
-			thingPtr += thingDataByteCount; /* Proceed to the next thing data */
-		} else {
-			curThing = getDiscardThing(thingType);
-			if (curThing == _vm->_thingNone)
-				return _vm->_thingNone;
-
-			thingPtr = (Thing *)getThingData(curThing);
+	bool found = false;
+	for (int16 i = 0; i < thingCount; ++i) {
+		curThing = Thing((thingType << 10) | i);
+		Thing *nextPtr = getNextThingPtr(curThing);
+		if (*nextPtr == _vm->_thingNone) {
+			found = true;
 			break;
 		}
 	}
-	for (uint16 i = 0; i < thingDataByteCount; i++) {
-		thingPtr[i].set(0);
+
+	if (!found) {
+		curThing = getDiscardThing(thingType);
+		if (curThing == _vm->_thingNone)
+			return _vm->_thingNone;
 	}
 
-	*thingPtr = _vm->_thingEndOfList;
+	resetThing(curThing);
+	*getNextThingPtr(curThing) = _vm->_thingEndOfList;
 	return curThing;
 }
 
@@ -1261,31 +1602,30 @@ uint16 DungeonMan::getObjectWeight(Thing thing) {
 	// Initialization is not present in original
 	// Set to 0 by default as it's the default value used for _vm->_none
 	uint16 weight = 0;
-	Junk *junk = (Junk *)getThingData(thing);
-
 	switch (thing.getType()) {
 	case kDMThingTypeWeapon:
-		weight = _weaponInfos[((Weapon *)junk)->getType()]._weight;
+		weight = _weaponInfos[getWeapon(thing)->getType()]._weight;
 		break;
 	case kDMThingTypeArmour:
-		weight = _armourInfos[((Armour *)junk)->getType()]._weight;
+		weight = _armourInfos[getArmour(thing)->getType()]._weight;
 		break;
-	case kDMThingTypeJunk:
-		weight = junkInfo[junk->getType()];
-		if (junk->getType() == kDMJunkTypeWaterskin)
-			weight += junk->getChargeCount() << 1;
-
+	case kDMThingTypeJunk: {
+		Junk *jnk = getJunk(thing);
+		weight = junkInfo[jnk->getType()];
+		if (jnk->getType() == kDMJunkTypeWaterskin)
+			weight += jnk->getChargeCount() << 1;
 		break;
+	}
 	case kDMThingTypeContainer:
 		weight = 50;
-		thing = ((Container *)junk)->getSlot();
+		thing = getContainer(thing)->getSlot();
 		while (thing != _vm->_thingEndOfList) {
 			weight += getObjectWeight(thing);
 			thing = getNextThing(thing);
 		}
 		break;
 	case kDMThingTypePotion:
-		if (((Potion *)junk)->getType() == kDMPotionTypeEmptyFlask)
+		if (getPotion(thing)->getType() == kDMPotionTypeEmptyFlask)
 			weight = 1;
 		else
 			weight = 3;
@@ -1301,20 +1641,19 @@ uint16 DungeonMan::getObjectWeight(Thing thing) {
 }
 
 int16 DungeonMan::getObjectInfoIndex(Thing thing) {
-	uint16 *rawType = getThingData(thing);
 	switch (thing.getType()) {
 	case kDMThingTypeScroll:
 		return kDMObjectInfoIndexFirstScroll;
 	case kDMThingTypeContainer:
-		return kDMObjectInfoIndexFirstContainer + Container(rawType).getType();
+		return kDMObjectInfoIndexFirstContainer + getContainer(thing)->getType();
 	case kDMThingTypeJunk:
-		return kDMObjectInfoIndexFirstJunk + Junk(rawType).getType();
+		return kDMObjectInfoIndexFirstJunk + getJunk(thing)->getType();
 	case kDMThingTypeWeapon:
-		return kDMObjectInfoIndexFirstWeapon + Weapon(rawType).getType();
+		return kDMObjectInfoIndexFirstWeapon + getWeapon(thing)->getType();
 	case kDMThingTypeArmour:
-		return kDMObjectInfoIndexFirstArmour + Armour(rawType).getType();
+		return kDMObjectInfoIndexFirstArmour + getArmour(thing)->getType();
 	case kDMThingTypePotion:
-		return kDMObjectInfoIndexFirstPotion + Potion(rawType).getType();
+		return kDMObjectInfoIndexFirstPotion + getPotion(thing)->getType();
 	default:
 		return -1;
 	}
@@ -1324,8 +1663,7 @@ void DungeonMan::linkThingToList(Thing thingToLink, Thing thingInList, int16 map
 	if (thingToLink == _vm->_thingEndOfList)
 		return;
 
-	Thing *thingPtr = (Thing *)getThingData(thingToLink);
-	*thingPtr = _vm->_thingEndOfList;
+	*getNextThingPtr(thingToLink) = _vm->_thingEndOfList;
 	/* If mapX >= 0 then the thing is linked to the list of things on the specified square else it is linked at the end of the specified thing list */
 	if (mapX >= 0) {
 		byte *currSquare = &_currMapData[mapX][mapY];
@@ -1358,12 +1696,11 @@ void DungeonMan::linkThingToList(Thing thingToLink, Thing thingInList, int16 map
 	while (nextThing != _vm->_thingEndOfList)
 		nextThing = getNextThing(thingInList = nextThing);
 
-	thingPtr = (Thing *)getThingData(thingInList);
-	*thingPtr = thingToLink;
+	*getNextThingPtr(thingInList) = thingToLink;
 }
 
 WeaponInfo *DungeonMan::getWeaponInfo(Thing thing) {
-	Weapon *weapon = (Weapon *)getThingData(thing);
+	Weapon *weapon = getWeapon(thing);
 	return &_weaponInfos[weapon->getType()];
 }
 
@@ -1464,14 +1801,12 @@ Thing DungeonMan::getDiscardThing(uint16 thingType) {
 					do {
 						ThingType squareThingType = squareThing.getType();
 						if (squareThingType == kDMThingTypeSensor) {
-							Thing *squareThingData = (Thing *)getThingData(squareThing);
-							if (((Sensor *)squareThingData)->getType()) /* If sensor is not disabled */
+							if (getSensor(squareThing)->getType()) /* If sensor is not disabled */
 								break;
 						} else if (squareThingType == thingType) {
-							Thing *squareThingData = (Thing *)getThingData(squareThing);
 							switch (thingType) {
 							case kDMThingTypeGroup:
-								if (((Group *)squareThingData)->getDoNotDiscard())
+								if (getGroup(squareThing)->getDoNotDiscard())
 									continue;
 								// fall through
 							case kDMThingTypeProjectile:
@@ -1486,28 +1821,28 @@ Thing DungeonMan::getDiscardThing(uint16 thingType) {
 								}
 								break;
 							case kDMThingTypeArmour:
-								if (((Armour *)squareThingData)->getDoNotDiscard())
+								if (getArmour(squareThing)->getDoNotDiscard())
 									continue;
 
 								setCurrentMap(mapIndex);
 								_vm->_moveSens->getMoveResult(squareThing, currMapX, currMapY, kDMMapXNotOnASquare, 0);
 								break;
 							case kDMThingTypeWeapon:
-								if (((Weapon *)squareThingData)->getDoNotDiscard())
+								if (getWeapon(squareThing)->getDoNotDiscard())
 									continue;
 
 								setCurrentMap(mapIndex);
 								_vm->_moveSens->getMoveResult(squareThing, currMapX, currMapY, kDMMapXNotOnASquare, 0);
 								break;
 							case kDMThingTypeJunk:
-								if (((Junk *)squareThingData)->getDoNotDiscard())
+								if (getJunk(squareThing)->getDoNotDiscard())
 									continue;
 
 								setCurrentMap(mapIndex);
 								_vm->_moveSens->getMoveResult(squareThing, currMapX, currMapY, kDMMapXNotOnASquare, 0);
 								break;
 							case kDMThingTypePotion:
-								if (((Potion *)squareThingData)->getDoNotDiscard())
+								if (getPotion(squareThing)->getDoNotDiscard())
 									continue;
 
 								setCurrentMap(mapIndex);
@@ -1540,7 +1875,7 @@ Thing DungeonMan::getDiscardThing(uint16 thingType) {
 }
 
 uint16 DungeonMan::getCreatureAttributes(Thing thing) {
-	Group *currGroup = (Group *)getThingData(thing);
+	Group *currGroup = getGroup(thing);
 	return _creatureInfos[currGroup->_type]._attributes;
 }
 
@@ -1559,7 +1894,7 @@ void DungeonMan::setGroupDirections(Group *group, int16 dir, uint16 mapIndex) {
 }
 
 bool DungeonMan::isCreatureAllowedOnMap(Thing thing, uint16 mapIndex) {
-	CreatureType creatureType = ((Group *)getThingData(thing))->_type;
+	CreatureType creatureType = getGroup(thing)->_type;
 	Map *map = &_dungeonMaps[mapIndex];
 	byte *allowedCreatureType = _dungeonMapData[mapIndex][map->_width] + map->_height + 1;
 	for (int16 L0234_i_Counter = map->_creatureTypeCount; L0234_i_Counter > 0; L0234_i_Counter--) {
@@ -1577,12 +1912,11 @@ void DungeonMan::unlinkThingFromList(Thing thingToUnlink, Thing thingInList, int
 	clearFlag(tmp, 0xC000);
 	thingToUnlink = Thing(tmp);
 
-	Thing *thingPtr = nullptr;
+	Thing *thingPtr = getNextThingPtr(thingToUnlink);
 	if (mapX >= 0) {
-		thingPtr = (Thing *)getThingData(thingToUnlink);
 		uint16 firstThingIndex = getSquareFirstThingIndex(mapX, mapY);
 		Thing *currThing = &_squareFirstThings[firstThingIndex]; /* BUG0_01 Coding error without consequence. The engine does not check that there are things at the specified square coordinates. f160_getSquareFirstThingIndex would return -1 for an empty square. No consequence as the function is never called with the coordinates of an empty square (except in the case of BUG0_59) */
-		if ((*thingPtr == _vm->_thingEndOfList) && (((Thing *)currThing)->getTypeAndIndex() == thingToUnlink.toUint16())) { /* If the thing to unlink is the last thing on the square */
+		if ((*thingPtr == _vm->_thingEndOfList) && (currThing->getTypeAndIndex() == thingToUnlink.toUint16())) { /* If the thing to unlink is the last thing on the square */
 			clearFlag(_currMapData[mapX][mapY], kDMSquareMaskThingListPresent);
 			uint16 squareFirstThingIdx = _dungeonFileHeader._squareFirstThingCount - 1;
 			for (uint16 i = 0; i < squareFirstThingIdx - firstThingIndex; ++i)
@@ -1597,7 +1931,7 @@ void DungeonMan::unlinkThingFromList(Thing thingToUnlink, Thing thingInList, int
 			*thingPtr = _vm->_thingEndOfList;
 			return;
 		}
-		if (((Thing *)currThing)->getTypeAndIndex() == thingToUnlink.toUint16()) {
+		if (currThing->getTypeAndIndex() == thingToUnlink.toUint16()) {
 			*currThing = *thingPtr;
 			*thingPtr = _vm->_thingEndOfList;
 			return;
@@ -1614,9 +1948,7 @@ void DungeonMan::unlinkThingFromList(Thing thingToUnlink, Thing thingInList, int
 		}
 		currThing = getNextThing(thingInList = currThing);
 	}
-	thingPtr = (Thing *)getThingData(thingInList);
-	*thingPtr = getNextThing(currThing);
-	thingPtr = (Thing *)getThingData(thingToUnlink);
+	*getNextThingPtr(thingInList) = getNextThing(currThing);
 	*thingPtr = _vm->_thingEndOfList;
 }
 
@@ -1680,10 +2012,13 @@ Thing DungeonMan::getObjForProjectileLaucherOrObjGen(uint16 iconIndex) {
 	if (unusedThing == _vm->_thingNone)
 		return _vm->_thingNone;
 
-	Junk *junkPtr = (Junk *)getThingData(unusedThing);
-	junkPtr->setType(junkType); /* Also works for WEAPON in cases other than Boulder */
-	if ((iconIndex == kDMIconIndiceWeaponTorchUnlit) && ((Weapon *)junkPtr)->isLit()) /* BUG0_65 Torches created by object generator or projectile launcher sensors have no charges. Charges are only defined if the Torch is lit which is not possible at the time it is created */
-		((Weapon *)junkPtr)->setChargeCount(15);
+	if (thingType == kDMThingTypeJunk) {
+		getJunk(unusedThing)->setType(junkType);
+	} else {
+		getWeapon(unusedThing)->setType(junkType);
+		if ((iconIndex == kDMIconIndiceWeaponTorchUnlit) && getWeapon(unusedThing)->isLit()) /* BUG0_65 Torches created by object generator or projectile launcher sensors have no charges. Charges are only defined if the Torch is lit which is not possible at the time it is created */
+			getWeapon(unusedThing)->setChargeCount(15);
+	}
 
 	return unusedThing;
 }
@@ -1694,4 +2029,118 @@ int16 DungeonMan::getRandomOrnamentIndex(uint16 val1, uint16 val2, int16 modulo)
 			  + _dungeonFileHeader._ornamentRandomSeed) & 0xFFFF) >> 2) % modulo; /* Pseudorandom number generator */
 }
 
+void DungeonMan::duplicateThing(Thing thing) {
+	uint16 thingType = thing.getType();
+	uint16 thingIndex = thing.getIndex();
+	switch (thingType) {
+	case kDMThingTypeWeapon:
+		_weapons.push_back(_weapons[thingIndex]);
+		_weapons.back()._nextThing = _vm->_thingEndOfList;
+		break;
+	case kDMThingTypeArmour:
+		_armours.push_back(_armours[thingIndex]);
+		_armours.back()._nextThing = _vm->_thingEndOfList;
+		break;
+	case kDMThingTypeScroll:
+		_scrolls.push_back(_scrolls[thingIndex]);
+		_scrolls.back()._nextThing = _vm->_thingEndOfList;
+		break;
+	case kDMThingTypePotion:
+		_potions.push_back(_potions[thingIndex]);
+		_potions.back()._nextThing = _vm->_thingEndOfList;
+		break;
+	case kDMThingTypeContainer:
+		_containers.push_back(_containers[thingIndex]);
+		_containers.back()._nextThing = _vm->_thingEndOfList;
+		break;
+	case kDMThingTypeJunk:
+		_junks.push_back(_junks[thingIndex]);
+		_junks.back()._nextThing = _vm->_thingEndOfList;
+		break;
+	default:
+		return;
+	}
+	_dungeonFileHeader._thingCounts[thingType]++;
+}
+
+Thing *DungeonMan::getNextThingPtr(Thing thing) {
+	switch (thing.getType()) {
+	case kDMThingTypeDoor:
+		return &_doors[thing.getIndex()]._nextThing;
+	case kDMThingTypeTeleporter:
+		return &_teleporters[thing.getIndex()]._nextThing;
+	case kDMstringTypeText:
+		return &_textStrings[thing.getIndex()]._nextThing;
+	case kDMThingTypeSensor:
+		return &_sensors[thing.getIndex()]._nextThing;
+	case kDMThingTypeGroup:
+		return &_groups[thing.getIndex()]._nextThing;
+	case kDMThingTypeWeapon:
+		return &_weapons[thing.getIndex()]._nextThing;
+	case kDMThingTypeArmour:
+		return &_armours[thing.getIndex()]._nextThing;
+	case kDMThingTypeScroll:
+		return &_scrolls[thing.getIndex()]._nextThing;
+	case kDMThingTypePotion:
+		return &_potions[thing.getIndex()]._nextThing;
+	case kDMThingTypeContainer:
+		return &_containers[thing.getIndex()]._nextThing;
+	case kDMThingTypeJunk:
+		return &_junks[thing.getIndex()]._nextThing;
+	case kDMThingTypeProjectile:
+		return &_projectiles[thing.getIndex()]._nextThing;
+	case kDMThingTypeExplosion:
+		return &_explosions[thing.getIndex()]._nextThing;
+	default:
+		return nullptr;
+	}
 }
+
+void DungeonMan::resetThing(Thing thing) {
+	uint16 index = thing.getIndex();
+	switch (thing.getType()) {
+	case kDMThingTypeDoor:
+		_doors[index] = Door();
+		break;
+	case kDMThingTypeTeleporter:
+		_teleporters[index] = Teleporter();
+		break;
+	case kDMstringTypeText:
+		_textStrings[index] = TextString();
+		break;
+	case kDMThingTypeSensor:
+		_sensors[index] = Sensor();
+		break;
+	case kDMThingTypeGroup:
+		_groups[index] = Group();
+		break;
+	case kDMThingTypeWeapon:
+		_weapons[index] = Weapon();
+		break;
+	case kDMThingTypeArmour:
+		_armours[index] = Armour();
+		break;
+	case kDMThingTypeScroll:
+		_scrolls[index] = Scroll();
+		break;
+	case kDMThingTypePotion:
+		_potions[index] = Potion();
+		break;
+	case kDMThingTypeContainer:
+		_containers[index] = Container();
+		break;
+	case kDMThingTypeJunk:
+		_junks[index] = Junk();
+		break;
+	case kDMThingTypeProjectile:
+		_projectiles[index] = Projectile();
+		break;
+	case kDMThingTypeExplosion:
+		_explosions[index] = Explosion();
+		break;
+	default:
+		break;
+	}
+}
+
+} // namespace DM
diff --git a/engines/dm/dungeonman.h b/engines/dm/dungeonman.h
index 9c8666a60b4..fdf859a8b26 100644
--- a/engines/dm/dungeonman.h
+++ b/engines/dm/dungeonman.h
@@ -333,10 +333,10 @@ public:
 }; // @ CREATURE_INFO
 
 class Door {
+public:
 	Thing _nextThing;
 	uint16 _attributes;
-public:
-	explicit Door(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
+	Door() : _nextThing(0), _attributes(0) {}
 	Thing getNextThing() { return _nextThing; }
 	bool isMeleeDestructible() { return (_attributes >> 8) & 1; }
 	bool isMagicDestructible() { return (_attributes >> 7) & 1; }
@@ -347,11 +347,11 @@ public:
 }; // @ DOOR
 
 class Teleporter {
+public:
 	Thing _nextThing;
 	uint16 _attributes;
 	uint16 _destMapIndex;
-public:
-	explicit Teleporter(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]), _destMapIndex(rawDat[2]) {}
+	Teleporter() : _nextThing(0), _attributes(0), _destMapIndex(0) {}
 	Thing getNextThing() { return _nextThing; }
 	bool isAudible() { return (_attributes >> 15) & 1; }
 	TeleporterScope getScope() { return (TeleporterScope)((_attributes >> 13) & 3); }
@@ -363,10 +363,10 @@ public:
 }; // @ TELEPORTER
 
 class TextString {
+public:
 	Thing _nextThing;
 	uint16 _textDataRef;
-public:
-	explicit TextString(uint16 *rawDat) : _nextThing(rawDat[0]), _textDataRef(rawDat[1]) {}
+	TextString() : _nextThing(0), _textDataRef(0) {}
 
 	Thing getNextThing() { return _nextThing; }
 	uint16 getWordOffset() { return _textDataRef >> 3; }
@@ -375,12 +375,12 @@ public:
 }; // @ TEXTSTRING
 
 class Sensor {
+public:
 	Thing _nextThing;
 	uint16 _datAndType;
 	uint16 _attributes; // A
 	uint16 _action; // B
-public:
-	explicit Sensor(uint16 *rawDat) : _nextThing(rawDat[0]), _datAndType(rawDat[1]), _attributes(rawDat[2]), _action(rawDat[3]) {}
+	Sensor() : _nextThing(0), _datAndType(0), _attributes(0), _action(0) {}
 
 	Thing getNextThing() { return _nextThing; }
 	void setNextThing(Thing thing) { _nextThing = thing; }
@@ -413,10 +413,10 @@ public:
 }; // @ SENSOR
 
 class Weapon {
+public:
 	Thing _nextThing;
 	uint16 _desc;
-public:
-	explicit Weapon(uint16 *rawDat) : _nextThing(rawDat[0]), _desc(rawDat[1]) {}
+	Weapon() : _nextThing(0), _desc(0) {}
 
 	WeaponType getType() { return (WeaponType)(_desc & 0x7F); }
 	void setType(uint16 val) { _desc = (_desc & ~0x7F) | (val & 0x7F); }
@@ -440,10 +440,10 @@ public:
 }; // @ WEAPON
 
 class Armour {
+public:
 	Thing _nextThing;
 	uint16 _attributes;
-public:
-	explicit Armour(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
+	Armour() : _nextThing(0), _attributes(0) {}
 
 	ArmourType getType() { return (ArmourType)(_attributes & 0x7F); }
 	Thing getNextThing() { return _nextThing; }
@@ -452,13 +452,15 @@ public:
 	uint16 getDoNotDiscard() { return (_attributes >> 7) & 1; }
 	uint16 getChargeCount() { return (_attributes >> 9) & 0xF; }
 	void setChargeCount(uint16 val) { _attributes = (_attributes & ~(0xF << 9)) | ((val & 0xF) << 9); }
+	void setType(uint16 val) { _attributes = (_attributes & ~0x7F) | (val & 0x7F); }
+	void setCursed(uint16 val) { _attributes = (_attributes & ~(1 << 8)) | ((val & 1) << 8); }
 }; // @ ARMOUR
 
 class Scroll {
+public:
 	Thing _nextThing;
 	uint16 _attributes;
-public:
-	explicit Scroll(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
+	Scroll() : _nextThing(0), _attributes(0) {}
 	void set(Thing next, uint16 attribs) {
 		_nextThing = next;
 		_attributes = attribs;
@@ -478,7 +480,7 @@ class Potion {
 public:
 	Thing _nextThing;
 	uint16 _attributes;
-	explicit Potion(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
+	Potion() : _nextThing(0), _attributes(0) {}
 
 	PotionType getType() { return (PotionType)((_attributes >> 8) & 0x7F); }
 	void setType(PotionType val) { _attributes = (_attributes & ~(0x7F << 8)) | ((val & 0x7F) << 8); }
@@ -489,11 +491,11 @@ public:
 }; // @ POTION
 
 class Container {
+public:
 	Thing _nextThing;
 	Thing _slot;
 	uint16 _type;
-public:
-	explicit Container(uint16 *rawDat) : _nextThing(rawDat[0]), _slot(rawDat[1]), _type(rawDat[2]) {}
+	Container() : _nextThing(0), _slot(0), _type(0) {}
 
 	uint16 getType() { return (_type >> 1) & 0x3; }
 	Thing &getSlot() { return _slot; }
@@ -501,10 +503,10 @@ public:
 }; // @ CONTAINER
 
 class Junk {
+public:
 	Thing _nextThing;
 	uint16 _attributes;
-public:
-	explicit Junk(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
+	Junk() : _nextThing(0), _attributes(0) {}
 
 	JunkType getType() { return (JunkType)(_attributes & 0x7F); }
 	void setType(uint16 val) { _attributes = (_attributes & ~0x7F) | (val & 0x7F); }
@@ -515,6 +517,7 @@ public:
 
 	Thing getNextThing() { return _nextThing; }
 	void setNextThing(Thing thing) { _nextThing = thing; }
+	void setCursed(uint16 val) { _attributes = (_attributes & ~(1 << 8)) | ((val & 1) << 8); }
 }; // @ JUNK
 
 class Projectile {
@@ -524,16 +527,15 @@ public:
 	uint16 _kineticEnergy;
 	uint16 _attack;
 	uint16 _eventIndex;
-	explicit Projectile(uint16 *rawDat) : _nextThing(rawDat[0]), _slot(rawDat[1]), _kineticEnergy(rawDat[2]),
-		_attack(rawDat[3]), _eventIndex(rawDat[4]) {}
+	Projectile() : _nextThing(0), _slot(0), _kineticEnergy(0), _attack(0), _eventIndex(0) {}
 
 }; // @ PROJECTILE
 
 class Explosion {
+public:
 	Thing _nextThing;
 	uint16 _attributes;
-public:
-	explicit Explosion(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
+	Explosion() : _nextThing(0), _attributes(0) {}
 
 	Thing getNextThing() { return _nextThing; }
 	Thing setNextThing(Thing val) { return _nextThing = val; }
@@ -628,8 +630,37 @@ public:
 	void setCurrentMap(uint16 mapIndex); // @ F0173_DUNGEON_SetCurrentMap
 	Thing getSquareFirstThing(int16 mapX, int16 mapY); // @ F0161_DUNGEON_GetSquareFirstThing
 	Thing getNextThing(Thing thing); // @ F0159_DUNGEON_GetNextThing(THING P0280_T_Thing)
-	uint16 *getThingData(Thing thing); // @ F0156_DUNGEON_GetThingData
-	uint16 *getSquareFirstThingData(int16 mapX, int16 mapY); // @ F0157_DUNGEON_GetSquareFirstThingData
+	Door *getDoor(Thing thing);
+	Teleporter *getTeleporter(Thing thing);
+	TextString *getTextString(Thing thing);
+	Sensor *getSensor(Thing thing);
+	Group *getGroup(Thing thing);
+	Weapon *getWeapon(Thing thing);
+	Armour *getArmour(Thing thing);
+	Scroll *getScroll(Thing thing);
+	Potion *getPotion(Thing thing);
+	Container *getContainer(Thing thing);
+	Junk *getJunk(Thing thing);
+	Projectile *getProjectile(Thing thing);
+	Explosion *getExplosion(Thing thing);
+
+	Door *getDoor(uint16 index);
+	Teleporter *getTeleporter(uint16 index);
+	TextString *getTextString(uint16 index);
+	Sensor *getSensor(uint16 index);
+	Group *getGroup(uint16 index);
+	Weapon *getWeapon(uint16 index);
+	Armour *getArmour(uint16 index);
+	Scroll *getScroll(uint16 index);
+	Potion *getPotion(uint16 index);
+	Container *getContainer(uint16 index);
+	Junk *getJunk(uint16 index);
+	Projectile *getProjectile(uint16 index);
+	Explosion *getExplosion(uint16 index);
+
+	void duplicateThing(Thing thing);
+	Thing *getNextThingPtr(Thing thing);
+	void resetThing(Thing thing);
 
 	// TODO: this does stuff other than load the file!
 	void loadDungeonFile(Common::InSaveFile *file);	// @ F0434_STARTEND_IsLoadDungeonSuccessful_CPSC
@@ -671,7 +702,20 @@ public:
 	uint16 *_dungeonColumnsCumulativeSquareThingCount; // @ G0280_pui_DungeonColumnsCumulativeSquareThingCount
 	Thing *_squareFirstThings; // @ G0283_pT_SquareFirstThings
 	uint16 *_dungeonTextData; // @ G0260_pui_DungeonTextData
-	uint16 *_thingData[16]; // @ G0284_apuc_ThingData
+	// @ G0284_apuc_ThingData
+	Common::Array<Door> _doors;
+	Common::Array<Teleporter> _teleporters;
+	Common::Array<TextString> _textStrings;
+	Common::Array<Sensor> _sensors;
+	Common::Array<Group> _groups;
+	Common::Array<Weapon> _weapons;
+	Common::Array<Armour> _armours;
+	Common::Array<Scroll> _scrolls;
+	Common::Array<Potion> _potions;
+	Common::Array<Container> _containers;
+	Common::Array<Junk> _junks;
+	Common::Array<Projectile> _projectiles;
+	Common::Array<Explosion> _explosions;
 	byte ***_dungeonMapData; // @ G0279_pppuc_DungeonMapData
 
 	Direction _partyDir; // @ G0308_i_PartyDirection
diff --git a/engines/dm/eventman.cpp b/engines/dm/eventman.cpp
index b5561a7d08d..214cec3347b 100644
--- a/engines/dm/eventman.cpp
+++ b/engines/dm/eventman.cpp
@@ -1169,8 +1169,8 @@ void EventManager::commandProcessType80ClickInDungeonView(int16 posX, int16 posY
 		int16 mapY = _vm->_dungeonMan->_partyMapY + _vm->_dirIntoStepCountNorth[_vm->_dungeonMan->_partyDir];
 
 		if (_vm->_championMan->_leaderEmptyHanded) {
-			Junk *junkPtr = (Junk*)_vm->_dungeonMan->getSquareFirstThingData(mapX, mapY);
-			if ((((Door*)junkPtr)->hasButton()) && _vm->_dungeonMan->_dungeonViewClickableBoxes[kDMViewCellDoorButtonOrWallOrn].isPointInside(posX, posY - 33)) {
+			Door *doorPtr = _vm->_dungeonMan->getDoor(_vm->_dungeonMan->getSquareFirstThing(mapX, mapY));
+			if (doorPtr && (doorPtr->hasButton()) && _vm->_dungeonMan->_dungeonViewClickableBoxes[kDMViewCellDoorButtonOrWallOrn].isPointInside(posX, posY - 33)) {
 				_vm->_stopWaitingForPlayerInput = true;
 				_vm->_sound->requestPlay(kDMSoundIndexSwitch, _vm->_dungeonMan->_partyMapX, _vm->_dungeonMan->_partyMapY, kDMSoundModePlayIfPrioritized);
 				_vm->_moveSens->addEvent(kDMEventTypeDoor, mapX, mapY, kDMCellNorthWest, kDMSensorEffectToggle, _vm->_gameTime + 1);
@@ -1194,7 +1194,6 @@ void EventManager::commandProcessType80ClickInDungeonView(int16 posX, int16 posY
 		}
 	} else {
 		Thing thingHandObject = _vm->_championMan->_leaderHandObject;
-		Junk *junkPtr = (Junk*)_vm->_dungeonMan->getThingData(thingHandObject);
 		if (_vm->_dungeonMan->_squareAheadElement == kDMElementTypeWall) {
 			for (uint16 currViewCell = kDMViewCellFronLeft; currViewCell < kDMViewCellFrontRight + 1; currViewCell++) {
 				if (boxObjectPiles[currViewCell].isPointInside(posX, posY)) {
@@ -1210,9 +1209,9 @@ void EventManager::commandProcessType80ClickInDungeonView(int16 posX, int16 posY
 						uint16 iconIdx = _vm->_objectMan->getIconIndex(thingHandObject);
 						uint16 weight = _vm->_dungeonMan->getObjectWeight(thingHandObject);
 						if ((iconIdx >= kDMIconIndiceJunkWater) && (iconIdx <= kDMIconIndiceJunkWaterSkin))
-							junkPtr->setChargeCount(3); /* Full */
+							_vm->_dungeonMan->getJunk(thingHandObject)->setChargeCount(3); /* Full */
 						else if (iconIdx == kDMIconIndicePotionEmptyFlask)
-							((Potion*)junkPtr)->setType(kDMPotionTypeWaterFlask);
+							_vm->_dungeonMan->getPotion(thingHandObject)->setType(kDMPotionTypeWaterFlask);
 						else {
 							commandProcessType80ClickInDungeonViewTouchFrontWall();
 							return;
@@ -1279,7 +1278,7 @@ void EventManager::commandProcessCommands160To162ClickInResurrectReincarnatePane
 	Thing thing = dunMan.getSquareFirstThing(mapX, mapY);
 	for (;;) { // infinite
 		if (thing.getType() == kDMThingTypeSensor) {
-			((Sensor*)dunMan.getThingData(thing))->setTypeDisabled();
+			dunMan.getSensor(thing)->setTypeDisabled();
 			break;
 		}
 		thing = dunMan.getNextThing(thing);
@@ -1364,7 +1363,7 @@ void EventManager::processType80_clickInDungeonView_grabLeaderHandObject(uint16
 		Thing groupThing = _vm->_groupMan->groupGetThing(mapX, mapY);
 		if ((groupThing != _vm->_thingEndOfList) &&
 			!_vm->_moveSens->isLevitating(groupThing) &&
-			_vm->_groupMan->getCreatureOrdinalInCell((Group*)_vm->_dungeonMan->getThingData(groupThing), _vm->normalizeModulo4(viewCell + _vm->_dungeonMan->_partyDir))) {
+			_vm->_groupMan->getCreatureOrdinalInCell(_vm->_dungeonMan->getGroup(groupThing), _vm->normalizeModulo4(viewCell + _vm->_dungeonMan->_partyDir))) {
 			return; /* It is not possible to grab an object on floor if there is a non levitating creature on its cell */
 		}
 	}
@@ -1397,7 +1396,7 @@ void EventManager::clickInDungeonViewDropLeaderHandObject(uint16 viewCell) {
 	Thing removedThing = _vm->_championMan->getObjectRemovedFromLeaderHand();
 	_vm->_moveSens->getMoveResult(_vm->thingWithNewCell(removedThing, currCell), kDMMapXNotOnASquare, 0, mapX, mapY);
 	if (droppingIntoAnAlcove && _vm->_dungeonMan->_isFacingViAltar && (_vm->_objectMan->getIconIndex(removedThing) == kDMIconIndiceJunkChampionBones)) {
-		Junk *removedJunk = (Junk*)_vm->_dungeonMan->getThingData(removedThing);
+		Junk *removedJunk = _vm->_dungeonMan->getJunk(removedThing);
 		TimelineEvent newEvent;
 		newEvent._mapTime = _vm->setMapAndTime(_vm->_dungeonMan->_partyMapIndex, _vm->_gameTime + 1);
 		newEvent._type = kDMEventTypeViAltarRebirth;
diff --git a/engines/dm/gfx.cpp b/engines/dm/gfx.cpp
index 5a9b0187e0d..8a8fbb856cf 100644
--- a/engines/dm/gfx.cpp
+++ b/engines/dm/gfx.cpp
@@ -1281,7 +1281,7 @@ void DisplayMan::drawDoor(uint16 doorThingIndex, DoorState doorState, int16 *doo
 	DungeonMan &dungeon = *_vm->_dungeonMan;
 
 	DoorFrames *doorFramesTemp = doorFrames;
-	Door *door = (Door *)(dungeon._thingData[kDMThingTypeDoor]) + doorThingIndex;
+	Door *door = dungeon.getDoor(doorThingIndex);
 	uint16 doorType = door->getType();
 	memmove(_tmpBitmap, getNativeBitmapOrGraphic(doorNativeBitmapIndices[doorType]), byteCount * 2);
 	drawDoorOrnament(door->getOrnOrdinal(), doorOrnament);
@@ -1534,7 +1534,7 @@ void DisplayMan::drawSquareD3R(Direction dir, int16 posX, int16 posY) {
 		drawObjectsCreaturesProjectilesExplosions(Thing(squareAspect[kDMSquareAspectFirstGroupOrObject]), dir, posX, posY, kDMViewSquareD3R, kDMCellOrderDoorPass1BackRightBackLeft);
 		memmove(_tmpBitmap, _bitmapWallSetDoorFrameLeftD3L, 32 * 44);
 		drawDoorFrameBitmapFlippedHorizontally(_tmpBitmap, &doorFrameRightD3R);
-		if (((Door *)_vm->_dungeonMan->_thingData[kDMThingTypeDoor])[squareAspect[kDMSquareAspectDoorThingIndex]].hasButton())
+		if (_vm->_dungeonMan->getDoor(squareAspect[kDMSquareAspectDoorThingIndex])->hasButton())
 			drawDoorButton(_vm->indexToOrdinal(k0_DoorButton), kDMDoorButtonD3R);
 
 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex],
@@ -1614,7 +1614,7 @@ void DisplayMan::drawSquareD3C(Direction dir, int16 posX, int16 posY) {
 		drawWallSetBitmap(_bitmapWallSetDoorFrameLeftD3C, doorFrameLeftD3C);
 		memmove(_tmpBitmap, _bitmapWallSetDoorFrameLeftD3C, 32 * 44);
 		drawDoorFrameBitmapFlippedHorizontally(_tmpBitmap, &doorFrameRightD3C);
-		if (((Door *)dungeon._thingData[kDMThingTypeDoor])[squareAspect[kDMSquareAspectDoorThingIndex]].hasButton())
+		if (dungeon.getDoor(squareAspect[kDMSquareAspectDoorThingIndex])->hasButton())
 			drawDoorButton(_vm->indexToOrdinal(k0_DoorButton), kDMDoorButtonD3C);
 
 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState],
@@ -1865,7 +1865,7 @@ void DisplayMan::drawSquareD2C(Direction dir, int16 posX, int16 posY) {
 		drawWallSetBitmap(_bitmapWallSetDoorFrameLeftD2C, doorFrameLeftD2C);
 		memcpy(_tmpBitmap, _bitmapWallSetDoorFrameLeftD2C, 48 * 65);
 		drawDoorFrameBitmapFlippedHorizontally(_tmpBitmap, &doorFrameRightD2C);
-		if (((Door *)dungeon._thingData[kDMThingTypeDoor])[squareAspect[kDMSquareAspectDoorThingIndex]].hasButton())
+		if (dungeon.getDoor(squareAspect[kDMSquareAspectDoorThingIndex])->hasButton())
 			drawDoorButton(_vm->indexToOrdinal(k0_DoorButton), kDMDoorButtonD2C);
 
 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState],
@@ -2114,7 +2114,7 @@ void DisplayMan::drawSquareD1C(Direction dir, int16 posX, int16 posY) {
 		drawWallSetBitmap(_bitmapWallSetDoorFrameTopD1LCR, doorFrameTopD1C);
 		drawWallSetBitmap(_bitmapWallSetDoorFrameLeftD1C, _doorFrameLeftD1C);
 		drawWallSetBitmap(_bitmapWallSetDoorFrameRightD1C, _doorFrameRightD1C);
-		if (((Door *)dungeon._thingData[kDMThingTypeDoor])[squareAspect[kDMSquareAspectDoorThingIndex]].hasButton())
+		if (dungeon.getDoor(squareAspect[kDMSquareAspectDoorThingIndex])->hasButton())
 			drawDoorButton(_vm->indexToOrdinal(k0_DoorButton), kDMDoorButtonD1C);
 
 		drawDoor(squareAspect[kDMSquareAspectDoorThingIndex], (DoorState)squareAspect[kDMSquareAspectDoorState],
@@ -3366,7 +3366,7 @@ T0115015_DrawProjectileAsObject:
 			goto T0115129_DrawProjectiles; /* Skip code to draw creatures */
 
 		if (group == nullptr) { /* If all creature data and info has not already been gathered */
-			group = (Group *)dungeon.getThingData(groupThing);
+			group = dungeon.getGroup(groupThing);
 			CreatureInfo *creatureInfo = &dungeon._creatureInfos[group->_type];
 			creatureAspectStruct = &_creatureAspects219[creatureInfo->_creatureAspectIndex];
 			creatureSize = getFlag(creatureInfo->_attributes, kDMCreatureMaskSize);
@@ -3620,7 +3620,7 @@ T0115129_DrawProjectiles:
 		thingParam = firstThingToDraw; /* Restart processing list of objects from the beginning. The next loop draws only projectile objects among the list */
 		do {
 			if ((thingParam.getType() == kDMThingTypeProjectile) && (thingParam.getCell() == cellYellowBear)) {
-				Projectile *projectile = (Projectile *)dungeon.getThingData(thingParam);
+				Projectile *projectile = dungeon.getProjectile(thingParam);
 				AL_4_projectileAspect = dungeon.getProjectileAspect(projectile->_slot);
 				if (AL_4_projectileAspect < 0) { /* Negative value: projectile aspect is the ordinal of a PROJECTIL_ASPECT */
 					objectAspect = (ObjectAspect *)&_projectileAspect[_vm->ordinalToIndex(-AL_4_projectileAspect)];
@@ -3751,7 +3751,7 @@ T0115171_BackFromT0115015_DrawProjectileAsObject:;
 	do {
 		if (thingParam.getType() == kDMThingTypeExplosion) {
 			AL_2_cellPurpleMan = thingParam.getCell();
-			Explosion *explosion = (Explosion *)dungeon.getThingData(thingParam);
+			Explosion *explosion = dungeon.getExplosion(thingParam);
 			AL_4_explosionType = explosion->getType();
 			bool rebirthExplosion = ((uint16)AL_4_explosionType >= kDMExplosionTypeRebirthStep1);
 			if (rebirthExplosion && ((AL_1_viewSquareExplosionIndex < kDMViewSquareD3CExplosion) || (AL_1_viewSquareExplosionIndex > kDMViewSquareD1CExplosion) || (AL_2_cellPurpleMan != cellYellowBear))) /* If explosion is rebirth and is not visible */
diff --git a/engines/dm/group.cpp b/engines/dm/group.cpp
index 9b65c5c8a02..5a58ac0f20a 100644
--- a/engines/dm/group.cpp
+++ b/engines/dm/group.cpp
@@ -142,7 +142,7 @@ uint16 GroupMan::getCreatureValue(uint16 groupVal, uint16 creatureIndex) {
 void GroupMan::dropGroupPossessions(int16 mapX, int16 mapY, Thing groupThing, SoundMode soundMode) {
 	DungeonMan &dungeon = *_vm->_dungeonMan;
 
-	Group *group = (Group *)dungeon.getThingData(groupThing);
+	Group *group = dungeon.getGroup(groupThing);
 	CreatureType creatureType = group->_type;
 	if ((soundMode != kDMSoundModeDoNotPlaySound) && getFlag(dungeon._creatureInfos[creatureType]._attributes, kDMCreatureMaskDropFixedPoss)) {
 		int16 creatureIndex = group->getCount();
@@ -295,10 +295,19 @@ void GroupMan::dropCreatureFixedPossessions(CreatureType creatureType, int16 map
 			continue;
 		}
 
-		Weapon *currWeapon = (Weapon *)dungeon.getThingData(nextUnusedThing);
-		/* The same pointer type is used no matter the actual type k5_WeaponThingType, k6_ArmourThingType or k10_JunkThingType */
-		currWeapon->setType(currFixedPossession);
-		currWeapon->setCursed(cursedPossessions);
+		if (currThingType == kDMThingTypeWeapon) {
+			Weapon *w = dungeon.getWeapon(nextUnusedThing);
+			w->setType(currFixedPossession);
+			w->setCursed(cursedPossessions);
+		} else if (currThingType == kDMThingTypeArmour) {
+			Armour *a = dungeon.getArmour(nextUnusedThing);
+			a->setType(currFixedPossession);
+			a->setCursed(cursedPossessions);
+		} else if (currThingType == kDMThingTypeJunk) {
+			Junk *j = dungeon.getJunk(nextUnusedThing);
+			j->setType(currFixedPossession);
+			j->setCursed(cursedPossessions);
+		}
 		nextUnusedThing = _vm->thingWithNewCell(nextUnusedThing, ((cell == kDMCreatureTypeSingleCenteredCreature) || !_vm->getRandomNumber(4)) ? _vm->getRandomNumber(4) : cell);
 		_vm->_moveSens->getMoveResult(nextUnusedThing, kDMMapXNotOnASquare, 0, mapX, mapY);
 		currFixedPossession = *fixedPossessions++;
@@ -368,7 +377,9 @@ bool GroupMan::isDestVisibleFromSource(uint16 dir, int16 srcMapX, int16 srcMapY,
 bool GroupMan::groupIsDoorDestoryedByAttack(uint16 mapX, uint16 mapY, int16 attack, bool magicAttack, int16 ticks) {
 	DungeonMan &dungeon = *_vm->_dungeonMan;
 
-	Door *curDoor = (Door *)dungeon.getSquareFirstThingData(mapX, mapY);
+	Door *curDoor = dungeon.getDoor(dungeon.getSquareFirstThing(mapX, mapY));
+	if (!curDoor)
+		return false;
 	if ((magicAttack && !curDoor->isMagicDestructible()) || (!magicAttack && !curDoor->isMeleeDestructible()))
 		return false;
 
@@ -512,7 +523,7 @@ void GroupMan::groupDelete(int16 mapX, int16 mapY) {
 
 	DungeonMan &dungeon = *_vm->_dungeonMan;
 
-	Group *group = (Group *)dungeon.getThingData(groupThing);
+	Group *group = dungeon.getGroup(groupThing);
 	for (uint16 i = 0; i < 4; ++i)
 		group->_health[i] = 0;
 	_vm->_moveSens->getMoveResult(groupThing, mapX, mapY, kDMMapXNotOnASquare, 0);
@@ -619,7 +630,7 @@ void GroupMan::processEvents29to41(int16 eventMapX, int16 eventMapY, TimelineEve
 
 	ChampionMan &championMan = *_vm->_championMan;
 
-	Group *curGroup = (Group *)dungeon.getThingData(groupThing);
+	Group *curGroup = dungeon.getGroup(groupThing);
 	CreatureInfo creatureInfo = dungeon._creatureInfos[curGroup->_type];
 	/* Update the event */
 	TimelineEvent nextEvent;
@@ -1130,7 +1141,7 @@ bool GroupMan::isMovementPossible(CreatureInfo *creatureInfo, int16 mapX, int16
 		Thing curThing = dungeon.getSquareFirstThing(mapX, mapY);
 		while (curThing != _vm->_thingEndOfList) {
 			if ((curThing).getType() == kDMThingTypeExplosion) {
-				Explosion *explosion = (Explosion *)dungeon.getThingData(curThing);
+				Explosion *explosion = dungeon.getExplosion(curThing);
 				if (explosion->getType() == kDMExplosionTypeFluxcage) {
 					_fluxCages[dir] = true;
 					_fluxCageCount++;
@@ -1142,7 +1153,7 @@ bool GroupMan::isMovementPossible(CreatureInfo *creatureInfo, int16 mapX, int16
 		}
 	}
 	if ((curSquareType == kDMElementTypeTeleporter) && getFlag(curSquare, kDMSquareMaskTeleporterOpen) && (creatureInfo->getWariness() >= 10)) {
-		Teleporter *curTeleporter = (Teleporter *)dungeon.getSquareFirstThingData(mapX, mapY);
+		Teleporter *curTeleporter = dungeon.getTeleporter(dungeon.getSquareFirstThing(mapX, mapY));
 		if (getFlag(curTeleporter->getScope(), kDMTeleporterScopeCreatures) && !dungeon.isCreatureAllowedOnMap(_currGroupThing, curTeleporter->getTargetMapIndex())) {
 			_groupMovBlockedByWallStairsPitFakeWalFluxCageTeleporter = true;
 			return false;
@@ -1154,8 +1165,8 @@ bool GroupMan::isMovementPossible(CreatureInfo *creatureInfo, int16 mapX, int16
 		return false;
 
 	if (curSquareType == kDMElementTypeDoor) {
-		Teleporter *curTeleporter = (Teleporter *)dungeon.getSquareFirstThingData(mapX, mapY);
-		if (((Square(curSquare).getDoorState()) > (((Door *)curTeleporter)->opensVertically() ? CreatureInfo::getHeight(creatureInfo->_attributes) : 1)) && ((Square(curSquare).getDoorState()) != kDMDoorStateDestroyed) && !getFlag(creatureInfo->_attributes, kDMCreatureMaskNonMaterial)) {
+		Door *curDoor = dungeon.getDoor(dungeon.getSquareFirstThing(mapX, mapY));
+		if (((Square(curSquare).getDoorState()) > (curDoor->opensVertically() ? CreatureInfo::getHeight(creatureInfo->_attributes) : 1)) && ((Square(curSquare).getDoorState()) != kDMDoorStateDestroyed) && !getFlag(creatureInfo->_attributes, kDMCreatureMaskNonMaterial)) {
 			_groupMovementBlockedByDoor = true;
 			return false;
 		}
@@ -1289,7 +1300,7 @@ bool GroupMan::isViewPartyBlocked(uint16 mapX, uint16 mapY) {
 	uint16 curSquare = dungeon._currMapData[mapX][mapY];
 	int16 curSquareType = Square(curSquare).getType();
 	if (curSquareType == kDMElementTypeDoor) {
-		Door *curDoor = (Door *)dungeon.getSquareFirstThingData(mapX, mapY);
+		Door *curDoor = dungeon.getDoor(dungeon.getSquareFirstThing(mapX, mapY));
 		int16 curDoorState = Square(curSquare).getDoorState();
 		return ((curDoorState == kDMDoorStateThreeFourth) || (curDoorState == kDMDoorStateClosed)) && !getFlag(dungeon._currMapDoorInfo[curDoor->getType()]._attributes, kDMMaskDoorInfoCreaturesCanSeeThrough);
 	}
@@ -1299,7 +1310,7 @@ bool GroupMan::isViewPartyBlocked(uint16 mapX, uint16 mapY) {
 int32 GroupMan::getCreatureAspectUpdateTime(ActiveGroup *activeGroup, int16 creatureIndex, bool isAttacking) {
 	DungeonMan &dungeon = *_vm->_dungeonMan;
 
-	Group *group = &(((Group *)dungeon._thingData[kDMThingTypeGroup])[activeGroup->_groupThingIndex]);
+	Group *group = dungeon.getGroup(activeGroup->_groupThingIndex);
 	CreatureType creatureType = group->_type;
 	uint16 creatureGraphicInfo = dungeon._creatureInfos[creatureType]._graphicInfo;
 	bool processGroup = (creatureIndex < 0);
@@ -1707,7 +1718,7 @@ int16 GroupMan::getChampionDamage(Group *group, uint16 champIndex) {
 
 void GroupMan::dropMovingCreatureFixedPossession(Thing thing, int16 mapX, int16 mapY) {
 	if (_dropMovingCreatureFixedPossCellCount) {
-		Group *group = (Group *)_vm->_dungeonMan->getThingData(thing);
+		Group *group = _vm->_dungeonMan->getGroup(thing);
 		CreatureType creatureType = group->_type;
 		while (_dropMovingCreatureFixedPossCellCount) {
 			dropCreatureFixedPossessions(creatureType, mapX, mapY, _dropMovingCreatureFixedPossessionsCell[--_dropMovingCreatureFixedPossCellCount], kDMSoundModePlayOneTickLater);
@@ -1718,7 +1729,7 @@ void GroupMan::dropMovingCreatureFixedPossession(Thing thing, int16 mapX, int16
 void GroupMan::startWandering(int16 mapX, int16 mapY) {
 	DungeonMan &dungeon = *_vm->_dungeonMan;
 
-	Group *L0332_ps_Group = (Group *)dungeon.getThingData(groupGetThing(mapX, mapY));
+	Group *L0332_ps_Group = dungeon.getGroup(groupGetThing(mapX, mapY));
 	if (L0332_ps_Group->getBehaviour() >= kDMBehaviorUnknown4)
 		L0332_ps_Group->setBehaviour(kDMBehaviorWander);
 
@@ -1746,8 +1757,7 @@ void GroupMan::addActiveGroup(Thing thing, int16 mapX, int16 mapY) {
 	_currActiveGroupCount++;
 
 	activeGroup->_groupThingIndex = (thing).getIndex();
-	Group *curGroup = (Group *)(dungeon._thingData[kDMThingTypeGroup] +
-		dungeon._thingDataWordCount[kDMThingTypeGroup] * activeGroup->_groupThingIndex);
+	Group *curGroup = dungeon.getGroup(activeGroup->_groupThingIndex);
 
 	activeGroup->_cells = curGroup->_cells;
 	curGroup->getActiveGroupIndex() = activeGroupIndex;
@@ -1767,7 +1777,7 @@ void GroupMan::removeActiveGroup(uint16 activeGroupIndex) {
 		return;
 
 	ActiveGroup *activeGroup = &_activeGroups[activeGroupIndex];
-	Group *group = &((Group *)_vm->_dungeonMan->_thingData[kDMThingTypeGroup])[activeGroup->_groupThingIndex];
+	Group *group = _vm->_dungeonMan->getGroup(activeGroup->_groupThingIndex);
 	_currActiveGroupCount--;
 	group->_cells = activeGroup->_cells;
 	group->setDir(_vm->normalizeModulo4(activeGroup->_directions));
@@ -1816,7 +1826,7 @@ Thing GroupMan::groupGetGenerated(CreatureType creatureType, int16 healthMultipl
 		|| (groupThing == _vm->_thingNone)) {
 		return _vm->_thingNone;
 	}
-	Group *group = (Group *)dungeon.getThingData(groupThing);
+	Group *group = dungeon.getGroup(groupThing);
 	group->_slot = _vm->_thingEndOfList;
 	group->setDoNotDiscard(false);
 	group->setDir(dir);
@@ -1869,7 +1879,7 @@ int16 GroupMan::getMeleeTargetCreatureOrdinal(int16 groupX, int16 groupY, int16
 	if (groupThing == _vm->_thingEndOfList)
 		return 0;
 
-	Group *group = (Group *)_vm->_dungeonMan->getThingData(groupThing);
+	Group *group = _vm->_dungeonMan->getGroup(groupThing);
 	signed char orderedCellsToAttack[4];
 	setOrderedCellsToAttack(orderedCellsToAttack, groupX, groupY, partyX, partyY, champCell);
 	uint16 counter = 0;
@@ -1979,7 +1989,7 @@ void GroupMan::fluxCageAction(int16 mapX, int16 mapY) {
 		return;
 
 	dungeon.linkThingToList(unusedThing, Thing(0), mapX, mapY);
-	(((Explosion *)dungeon._thingData[kDMThingTypeExplosion])[unusedThing.getIndex()]).setType(kDMExplosionTypeFluxcage);
+	dungeon.getExplosion(unusedThing)->setType(kDMExplosionTypeFluxcage);
 	TimelineEvent newEvent;
 	newEvent._mapTime = _vm->setMapAndTime(dungeon._currMapIndex, _vm->_gameTime + 100);
 	newEvent._type = kDMEventTypeRemoveFluxcage;
@@ -2017,7 +2027,7 @@ uint16 GroupMan::isLordChaosOnSquare(int16 mapX, int16 mapY) {
 	if (thing == _vm->_thingEndOfList)
 		return 0;
 
-	Group *group = (Group *)_vm->_dungeonMan->getThingData(thing);
+	Group *group = _vm->_dungeonMan->getGroup(thing);
 	if (group->_type == kDMCreatureTypeLordChaos)
 		return thing.toUint16();
 
@@ -2033,7 +2043,7 @@ bool GroupMan::isFluxcageOnSquare(int16 mapX, int16 mapY) {
 
 	Thing thing = dungeon.getSquareFirstThing(mapX, mapY);
 	while (thing != _vm->_thingEndOfList) {
-		if ((thing.getType() == kDMThingTypeExplosion) && (((Explosion *)dungeon._thingData[kDMThingTypeExplosion])[thing.getIndex()].getType() == kDMExplosionTypeFluxcage))
+		if ((thing.getType() == kDMThingTypeExplosion) && (dungeon.getExplosion(thing)->getType() == kDMExplosionTypeFluxcage))
 			return true;
 
 		thing = dungeon.getNextThing(thing);
diff --git a/engines/dm/group.h b/engines/dm/group.h
index 468debec04e..43785a5ae09 100644
--- a/engines/dm/group.h
+++ b/engines/dm/group.h
@@ -132,13 +132,8 @@ public:
 	uint16 _cells;
 	uint16 _health[4];
 	uint16 _flags;
-public:
-	explicit Group(uint16 *rawDat) : _nextThing(rawDat[0]), _slot(rawDat[1]), _cells(rawDat[3]), _flags(rawDat[8]) {
-		_type = (CreatureType)rawDat[2];
-		_health[0] = rawDat[4];
-		_health[1] = rawDat[5];
-		_health[2] = rawDat[6];
-		_health[3] = rawDat[7];
+	Group() : _nextThing(0), _slot(0), _type((CreatureType)0), _cells(0), _flags(0) {
+		_health[0] = _health[1] = _health[2] = _health[3] = 0;
 	}
 
 	uint16 &getActiveGroupIndex() { return _cells; }
diff --git a/engines/dm/inventory.cpp b/engines/dm/inventory.cpp
index fbf49a21b7d..4d1ae04dda7 100644
--- a/engines/dm/inventory.cpp
+++ b/engines/dm/inventory.cpp
@@ -281,7 +281,7 @@ void InventoryMan::closeChest() {
 	bool processFirstChestSlot = true;
 	if (_openChest == _vm->_thingNone)
 		return;
-	Container *container = (Container *)dunMan.getThingData(_openChest);
+	Container *container = dunMan.getContainer(_openChest);
 	_openChest = _vm->_thingNone;
 	container->getSlot() = _vm->_thingEndOfList;
 	Thing prevThing;
@@ -292,7 +292,7 @@ void InventoryMan::closeChest() {
 
 			if (processFirstChestSlot) {
 				processFirstChestSlot = false;
-				*dunMan.getThingData(thing) = _vm->_thingEndOfList.toUint16();
+				*dunMan.getNextThingPtr(thing) = _vm->_thingEndOfList;
 				container->getSlot() = prevThing = thing;
 			} else {
 				dunMan.linkThingToList(thing, prevThing, kDMMapXNotOnASquare, 0);
@@ -494,13 +494,12 @@ void InventoryMan::drawPanelObject(Thing thingToDraw, bool pressingEye) {
 	if (_vm->_pressingEye || _vm->_pressingMouth)
 		closeChest();
 
-	uint16 *rawThingPtr = dungeon.getThingData(thingToDraw);
 	drawPanelObjectDescriptionString("\f"); // form feed
 	ThingType thingType = thingToDraw.getType();
 	if (thingType == kDMThingTypeScroll)
-		drawPanelScroll((Scroll *)rawThingPtr);
+		drawPanelScroll(dungeon.getScroll(thingToDraw));
 	else if (thingType == kDMThingTypeContainer)
-		openAndDrawChest(thingToDraw, (Container *)rawThingPtr, pressingEye);
+		openAndDrawChest(thingToDraw, dungeon.getContainer(thingToDraw), pressingEye);
 	else {
 		IconIndice iconIndex = objMan.getIconIndex(thingToDraw);
 		dispMan.blitToViewport(dispMan.getNativeBitmapOrGraphic(kDMGraphicIdxPanelEmpty),
@@ -514,10 +513,10 @@ void InventoryMan::drawPanelObject(Thing thingToDraw, bool pressingEye) {
 			switch (_vm->getGameLanguage()) { // localized
 			case Common::FR_FRA:
 				// Fix original bug dur to a cut&paste error: string was concatenated then overwritten by the name
-				str = Common::String::format("%s %s", objMan._objectNames[iconIndex], champMan._champions[((Junk *)rawThingPtr)->getChargeCount()]._name);
+				str = Common::String::format("%s %s", objMan._objectNames[iconIndex], champMan._champions[dungeon.getJunk(thingToDraw)->getChargeCount()]._name);
 				break;
 			default: // German and English versions are the same
-				str = Common::String::format("%s %s", champMan._champions[((Junk *)rawThingPtr)->getChargeCount()]._name, objMan._objectNames[iconIndex]);
+				str = Common::String::format("%s %s", champMan._champions[dungeon.getJunk(thingToDraw)->getChargeCount()]._name, objMan._objectNames[iconIndex]);
 				break;
 			}
 
@@ -525,7 +524,7 @@ void InventoryMan::drawPanelObject(Thing thingToDraw, bool pressingEye) {
 		} else if ((thingType == kDMThingTypePotion)
 				   && (iconIndex != kDMIconIndicePotionWaterFlask)
 				   && (champMan.getSkillLevel((ChampionIndex)_vm->ordinalToIndex(_inventoryChampionOrdinal), kDMSkillPriest) > 1)) {
-			str = ('_' + ((Potion *)rawThingPtr)->getPower() / 40);
+			str = ('_' + dungeon.getPotion(thingToDraw)->getPower() / 40);
 			str += " ";
 			str += objMan._objectNames[iconIndex];
 			descString = str;
@@ -544,7 +543,7 @@ void InventoryMan::drawPanelObject(Thing thingToDraw, bool pressingEye) {
 		switch (thingType) {
 		case kDMThingTypeWeapon: {
 			potentialAttribMask = kDMDescriptionMaskCursed | kDMDescriptionMaskPoisoned | kDMDescriptionMaskBroken;
-			Weapon *weapon = (Weapon *)rawThingPtr;
+			Weapon *weapon = dungeon.getWeapon(thingToDraw);
 			actualAttribMask = (weapon->getCursed() << 3) | (weapon->getPoisoned() << 1) | (weapon->getBroken() << 2);
 			if ((iconIndex >= kDMIconIndiceWeaponTorchUnlit)
 				&& (iconIndex <= kDMIconIndiceWeaponTorchLit)
@@ -567,13 +566,13 @@ void InventoryMan::drawPanelObject(Thing thingToDraw, bool pressingEye) {
 		}
 		case kDMThingTypeArmour: {
 			potentialAttribMask = kDMDescriptionMaskCursed | kDMDescriptionMaskBroken;
-			Armour *armour = (Armour *)rawThingPtr;
+			Armour *armour = dungeon.getArmour(thingToDraw);
 			actualAttribMask = (armour->getCursed() << 3) | (armour->getBroken() << 2);
 			break;
 		}
 		case kDMThingTypePotion: {
 			potentialAttribMask = kDMDescriptionMaskConsumable;
-			Potion *potion = (Potion *)rawThingPtr;
+			Potion *potion = dungeon.getPotion(thingToDraw);
 			actualAttribMask = dungeon._objectInfos[kDMObjectInfoIndexFirstPotion + potion->getType()].getAllowedSlots();
 			break;
 		}
@@ -584,7 +583,7 @@ void InventoryMan::drawPanelObject(Thing thingToDraw, bool pressingEye) {
 				const char *descStringDE[4] = {"(LEER)", "(FAST LEER)", "(FAST VOLL)", "(VOLL)"};
 				const char *descStringFR[4] = {"(VIDE)", "(PRESQUE VIDE)", "(PRESQUE PLEINE)", "(PLEINE)"};
 
-				Junk *junk = (Junk *)rawThingPtr;
+				Junk *junk = dungeon.getJunk(thingToDraw);
 				switch (_vm->getGameLanguage()) { // localized
 				case Common::DE_DEU:
 					descString = descStringDE[junk->getChargeCount()];
@@ -622,7 +621,7 @@ void InventoryMan::drawPanelObject(Thing thingToDraw, bool pressingEye) {
 
 				drawPanelObjectDescriptionString(str.c_str());
 			} else {
-				Junk *junk = (Junk *)rawThingPtr;
+				Junk *junk = dungeon.getJunk(thingToDraw);
 				potentialAttribMask = kDMDescriptionMaskConsumable;
 				actualAttribMask = dungeon._objectInfos[kDMObjectInfoIndexFirstJunk + junk->getType()].getAllowedSlots();
 			}
@@ -705,7 +704,7 @@ void InventoryMan::setDungeonViewPalette() {
 				Thing slotThing = curChampion->_slots[slotIndex];
 				if ((_vm->_objectMan->getObjectType(slotThing) >= kDMIconIndiceWeaponTorchUnlit) &&
 					(_vm->_objectMan->getObjectType(slotThing) <= kDMIconIndiceWeaponTorchLit)) {
-					Weapon *curWeapon = (Weapon *)dungeon.getThingData(slotThing);
+					Weapon *curWeapon = dungeon.getWeapon(slotThing);
 					*curTorchLightPower = curWeapon->getChargeCount();
 				} else {
 					*curTorchLightPower = 0;
@@ -775,7 +774,7 @@ void InventoryMan::decreaseTorchesLightPower() {
 		while (slotIndex--) {
 			int16 iconIndex = _vm->_objectMan->getIconIndex(curChampion->_slots[slotIndex]);
 			if ((iconIndex >= kDMIconIndiceWeaponTorchUnlit) && (iconIndex <= kDMIconIndiceWeaponTorchLit)) {
-				Weapon *curWeapon = (Weapon *)dungeon.getThingData(curChampion->_slots[slotIndex]);
+				Weapon *curWeapon = dungeon.getWeapon(curChampion->_slots[slotIndex]);
 				if (curWeapon->getChargeCount()) {
 					if (curWeapon->setChargeCount(curWeapon->getChargeCount() - 1) == 0) {
 						curWeapon->setDoNotDiscard(false);
@@ -928,9 +927,9 @@ void InventoryMan::clickOnMouth() {
 	uint16 handThingWeight = dungeon.getObjectWeight(handThing);
 	uint16 championIndex = _vm->ordinalToIndex(_inventoryChampionOrdinal);
 	Champion *curChampion = &championMan._champions[championIndex];
-	Junk *junkData = (Junk *)dungeon.getThingData(handThing);
 	bool removeObjectFromLeaderHand;
 	if ((iconIndex >= kDMIconIndiceJunkWater) && (iconIndex <= kDMIconIndiceJunkWaterSkin)) {
+		Junk *junkData = dungeon.getJunk(handThing);
 		if (!(junkData->getChargeCount()))
 			return;
 
@@ -940,7 +939,7 @@ void InventoryMan::clickOnMouth() {
 	} else if (handThingType == kDMThingTypePotion)
 		removeObjectFromLeaderHand = false;
 	else {
-		junkData->setNextThing(_vm->_thingNone);
+		*dungeon.getNextThingPtr(handThing) = _vm->_thingNone;
 		removeObjectFromLeaderHand = true;
 	}
 	_vm->_eventMan->showMouse();
@@ -948,16 +947,17 @@ void InventoryMan::clickOnMouth() {
 		championMan.getObjectRemovedFromLeaderHand();
 
 	if (handThingType == kDMThingTypePotion) {
-		uint16 potionPower = ((Potion *)junkData)->getPower();
+		Potion *potion = dungeon.getPotion(handThing);
+		uint16 potionPower = potion->getPower();
 		uint16 counter = ((511 - potionPower) / (32 + (potionPower + 1) / 8)) >> 1;
 		uint16 adjustedPotionPower = (potionPower / 25) + 8; /* Value between 8 and 18 */
 
-		switch (((Potion *)junkData)->getType()) {
+		switch (potion->getType()) {
 		case kDMPotionTypeRos:
 			adjustStatisticCurrentValue(curChampion, kDMStatDexterity, adjustedPotionPower);
 			break;
 		case kDMPotionTypeKu:
-			adjustStatisticCurrentValue(curChampion, kDMStatStrength, (((Potion *)junkData)->getPower() / 35) + 5); /* Value between 5 and 12 */
+			adjustStatisticCurrentValue(curChampion, kDMStatStrength, (potion->getPower() / 35) + 5); /* Value between 5 and 12 */
 			break;
 		case kDMPotionTypeDane:
 			adjustStatisticCurrentValue(curChampion, kDMStatWisdom, adjustedPotionPower);
@@ -995,7 +995,7 @@ void InventoryMan::clickOnMouth() {
 			}
 			break;
 		case kDMPotionTypeVi: {
-			uint16 healWoundIterationCount = MAX(1, (((Potion *)junkData)->getPower() / 42));
+			uint16 healWoundIterationCount = MAX(1, (potion->getPower() / 42));
 			curChampion->_currHealth += curChampion->_maxHealth / counter;
 			uint16 wounds = curChampion->_wounds;
 			if (wounds) { /* If the champion is wounded */
@@ -1016,7 +1016,7 @@ void InventoryMan::clickOnMouth() {
 		default:
 			break;
 		}
-		((Potion *)junkData)->setType(kDMPotionTypeEmptyFlask);
+		potion->setType(kDMPotionTypeEmptyFlask);
 	} else if ((iconIndex >= kDMIconIndiceJunkApple) && (iconIndex < kDMIconIndiceJunkIronKey))
 		curChampion->_food = MIN(curChampion->_food + foodAmounts[iconIndex - kDMIconIndiceJunkApple], 2048);
 
diff --git a/engines/dm/loadsave.cpp b/engines/dm/loadsave.cpp
index 3b567325058..bef83562b9e 100644
--- a/engines/dm/loadsave.cpp
+++ b/engines/dm/loadsave.cpp
@@ -387,9 +387,106 @@ bool DMEngine::writeCompleteSaveFile(int16 saveSlot, Common::String& saveDescrip
 		file->writeUint16BE(_dungeonMan->_dungeonTextData[i]);
 
 	// save _g284_thingData
-	for (uint16 thingIndex = 0; thingIndex < 16; ++thingIndex)
-		for (uint16 i = 0; i < _dungeonMan->_thingDataWordCount[thingIndex] * _dungeonMan->_dungeonFileHeader._thingCounts[thingIndex]; ++i)
-			file->writeUint16BE(_dungeonMan->_thingData[thingIndex][i]);
+	for (uint16 thingIndex = 0; thingIndex < 16; ++thingIndex) {
+		uint16 count = _dungeonMan->_dungeonFileHeader._thingCounts[thingIndex];
+		for (uint16 i = 0; i < count; ++i) {
+			switch (thingIndex) {
+			case kDMThingTypeDoor: {
+				Door &door = _dungeonMan->_doors[i];
+				file->writeUint16BE(door._nextThing.toUint16());
+				file->writeUint16BE(door._attributes);
+				break;
+			}
+			case kDMThingTypeTeleporter: {
+				Teleporter &tele = _dungeonMan->_teleporters[i];
+				file->writeUint16BE(tele._nextThing.toUint16());
+				file->writeUint16BE(tele._attributes);
+				file->writeUint16BE(tele._destMapIndex);
+				break;
+			}
+			case kDMstringTypeText: {
+				TextString &text = _dungeonMan->_textStrings[i];
+				file->writeUint16BE(text._nextThing.toUint16());
+				file->writeUint16BE(text._textDataRef);
+				break;
+			}
+			case kDMThingTypeSensor: {
+				Sensor &sens = _dungeonMan->_sensors[i];
+				file->writeUint16BE(sens._nextThing.toUint16());
+				file->writeUint16BE(sens._datAndType);
+				file->writeUint16BE(sens._attributes);
+				file->writeUint16BE(sens._action);
+				break;
+			}
+			case kDMThingTypeGroup: {
+				Group &grp = _dungeonMan->_groups[i];
+				file->writeUint16BE(grp._nextThing.toUint16());
+				file->writeUint16BE(grp._slot.toUint16());
+				file->writeUint16BE((uint16)grp._type);
+				file->writeUint16BE(grp._cells);
+				file->writeUint16BE(grp._health[0]);
+				file->writeUint16BE(grp._health[1]);
+				file->writeUint16BE(grp._health[2]);
+				file->writeUint16BE(grp._health[3]);
+				file->writeUint16BE(grp._flags);
+				break;
+			}
+			case kDMThingTypeWeapon: {
+				Weapon &weap = _dungeonMan->_weapons[i];
+				file->writeUint16BE(weap._nextThing.toUint16());
+				file->writeUint16BE(weap._desc);
+				break;
+			}
+			case kDMThingTypeArmour: {
+				Armour &arm = _dungeonMan->_armours[i];
+				file->writeUint16BE(arm._nextThing.toUint16());
+				file->writeUint16BE(arm._attributes);
+				break;
+			}
+			case kDMThingTypeScroll: {
+				Scroll &scr = _dungeonMan->_scrolls[i];
+				file->writeUint16BE(scr._nextThing.toUint16());
+				file->writeUint16BE(scr._attributes);
+				break;
+			}
+			case kDMThingTypePotion: {
+				Potion &pot = _dungeonMan->_potions[i];
+				file->writeUint16BE(pot._nextThing.toUint16());
+				file->writeUint16BE(pot._attributes);
+				break;
+			}
+			case kDMThingTypeContainer: {
+				Container &cont = _dungeonMan->_containers[i];
+				file->writeUint16BE(cont._nextThing.toUint16());
+				file->writeUint16BE(cont._slot.toUint16());
+				file->writeUint16BE(cont._type);
+				file->writeUint16BE(0); // unused 4th word
+				break;
+			}
+			case kDMThingTypeJunk: {
+				Junk &jnk = _dungeonMan->_junks[i];
+				file->writeUint16BE(jnk._nextThing.toUint16());
+				file->writeUint16BE(jnk._attributes);
+				break;
+			}
+			case kDMThingTypeProjectile: {
+				Projectile &proj = _dungeonMan->_projectiles[i];
+				file->writeUint16BE(proj._nextThing.toUint16());
+				file->writeUint16BE(proj._slot.toUint16());
+				file->writeUint16BE(proj._kineticEnergy);
+				file->writeUint16BE(proj._attack);
+				file->writeUint16BE(proj._eventIndex);
+				break;
+			}
+			case kDMThingTypeExplosion: {
+				Explosion &expl = _dungeonMan->_explosions[i];
+				file->writeUint16BE(expl._nextThing.toUint16());
+				file->writeUint16BE(expl._attributes);
+				break;
+			}
+			}
+		}
+	}
 
 	// save _g276_dungeonRawMapData
 	for (uint32 i = 0; i < _dungeonMan->_dungeonFileHeader._rawMapDataSize; ++i)
diff --git a/engines/dm/menus.cpp b/engines/dm/menus.cpp
index 795e5575c5c..d6c5c584b7c 100644
--- a/engines/dm/menus.cpp
+++ b/engines/dm/menus.cpp
@@ -668,7 +668,7 @@ int16 MenuMan::getChampionSpellCastResult(uint16 champIndex) {
 			if (unusedObject == _vm->_thingNone)
 				break;
 
-			Junk *junkData = (Junk *)dungeon.getThingData(unusedObject);
+			Junk *junkData = dungeon.getJunk(unusedObject);
 			junkData->setType(kDMJunkTypeZokathra);
 			ChampionSlot slotIndex;
 			if (curChampion->_slots[kDMSlotReadyHand] == _vm->_thingNone)
@@ -823,7 +823,7 @@ Potion *MenuMan::getEmptyFlaskInHand(Champion *champ, Thing *potionThing) {
 		Thing curThing = champ->_slots[slotIndex];
 		if ((curThing != _vm->_thingNone) && (_vm->_objectMan->getIconIndex(curThing) == kDMIconIndicePotionEmptyFlask)) {
 			*potionThing = curThing;
-			return (Potion *)dungeon.getThingData(curThing);
+			return dungeon.getPotion(curThing);
 		}
 	}
 	return nullptr;
@@ -1083,7 +1083,7 @@ bool MenuMan::isActionPerformed(uint16 champIndex, int16 actionIndex) {
 
 	DungeonMan &dungeon = *_vm->_dungeonMan;
 
-	Weapon *weaponInHand = (Weapon *)dungeon.getThingData(curChampion->_slots[kDMSlotActionHand]);
+	Thing slotActionThing = curChampion->_slots[kDMSlotActionHand];
 
 	int16 nextMapX = dungeon._partyMapX;
 	int16 nextMapY = dungeon._partyMapY;
@@ -1177,6 +1177,7 @@ bool MenuMan::isActionPerformed(uint16 champIndex, int16 actionIndex) {
 			break;
 		}
 
+		Weapon *weaponInHand = dungeon.getWeapon(slotActionThing);
 		WeaponInfo *weaponInfoActionHand = &dungeon._weaponInfos[weaponInHand->getType()];
 		WeaponInfo *weaponInfoReadyHand = dungeon.getWeaponInfo(curChampion->_slots[kDMSlotReadyHand]);
 		int16 actionHandWeaponClass = weaponInfoActionHand->_class;
@@ -1327,14 +1328,14 @@ bool MenuMan::isActionPerformed(uint16 champIndex, int16 actionIndex) {
 		break;
 	case kDMActionFreezeLife: {
 		int16 freezeTicks;
-		if (weaponInHand->getType() == (int)kDMJunkTypeMagicalBoxBlue) {
+		if (slotActionThing.getType() == kDMThingTypeJunk && dungeon.getJunk(slotActionThing)->getType() == kDMJunkTypeMagicalBoxBlue) {
 			freezeTicks = 30;
 			championMan.getObjectRemovedFromSlot(champIndex, kDMSlotActionHand);
-			weaponInHand->setNextThing(_vm->_thingNone);
-		} else if (weaponInHand->getType() == (int)kDMJunkTypeMagicalBoxGreen) {
+			dungeon.getJunk(slotActionThing)->setNextThing(_vm->_thingNone);
+		} else if (slotActionThing.getType() == kDMThingTypeJunk && dungeon.getJunk(slotActionThing)->getType() == kDMJunkTypeMagicalBoxGreen) {
 			freezeTicks = 125;
 			championMan.getObjectRemovedFromSlot(champIndex, kDMSlotActionHand);
-			weaponInHand->setNextThing(_vm->_thingNone);
+			dungeon.getJunk(slotActionThing)->setNextThing(_vm->_thingNone);
 		} else {
 			freezeTicks = 70;
 			decrementCharges(curChampion);
@@ -1396,23 +1397,25 @@ void MenuMan::setChampionDirectionToPartyDirection(Champion *champ) {
 
 void MenuMan::decrementCharges(Champion *champ) {
 	Thing slotActionThing = champ->_slots[kDMSlotActionHand];
-	Junk *slotActionData = (Junk *)_vm->_dungeonMan->getThingData(slotActionThing);
 	switch (slotActionThing.getType()) {
-	case kDMThingTypeWeapon:
-		if (((Weapon *)slotActionData)->getChargeCount()) {
-			((Weapon *)slotActionData)->setChargeCount(((Weapon *)slotActionData)->getChargeCount() - 1);
-		}
+	case kDMThingTypeWeapon: {
+		Weapon *w = _vm->_dungeonMan->getWeapon(slotActionThing);
+		if (w->getChargeCount())
+			w->setChargeCount(w->getChargeCount() - 1);
 		break;
-	case kDMThingTypeArmour:
-		if (((Armour *)slotActionData)->getChargeCount()) {
-			((Armour *)slotActionData)->setChargeCount(((Armour *)slotActionData)->getChargeCount() - 1);
-		}
+	}
+	case kDMThingTypeArmour: {
+		Armour *a = _vm->_dungeonMan->getArmour(slotActionThing);
+		if (a->getChargeCount())
+			a->setChargeCount(a->getChargeCount() - 1);
 		break;
-	case kDMThingTypeJunk:
-		if (slotActionData->getChargeCount()) {
-			slotActionData->setChargeCount(slotActionData->getChargeCount() - 1);
-		}
+	}
+	case kDMThingTypeJunk: {
+		Junk *j = _vm->_dungeonMan->getJunk(slotActionThing);
+		if (j->getChargeCount())
+			j->setChargeCount(j->getChargeCount() - 1);
 		break;
+	}
 	default:
 		break;
 	}
@@ -1546,7 +1549,7 @@ bool MenuMan::isMeleeActionPerformed(int16 champIndex, Champion *champ, int16 ac
 		if ((_vm->_objectMan->getIconIndex(champ->_slots[kDMSlotActionHand]) == kDMIconIndiceWeaponVorpalBlade) || (actionIndex == kDMActionDisrupt)) {
 			setFlag(actionHitProbability, kDMActionMaskHitNonMaterialCreatures);
 		}
-		_actionDamage = _vm->_groupMan->getMeleeActionDamage(champ, champIndex, (Group *)dungeon.getThingData(_actionTargetGroupThing), _vm->ordinalToIndex(targetCreatureOrdinal), targetMapX, targetMapY, actionHitProbability, actionDamageFactor, skillIndex);
+		_actionDamage = _vm->_groupMan->getMeleeActionDamage(champ, champIndex, dungeon.getGroup(_actionTargetGroupThing), _vm->ordinalToIndex(targetCreatureOrdinal), targetMapX, targetMapY, actionHitProbability, actionDamageFactor, skillIndex);
 		return true;
 	}
 
@@ -1590,7 +1593,7 @@ bool MenuMan::isGroupFrightenedByAction(int16 champIndex, uint16 actionIndex, in
 	}
 
 	frightAmount += championMan.getSkillLevel(champIndex, kDMSkillInfluence);
-	Group *targetGroup = (Group *)dungeon.getThingData(_actionTargetGroupThing);
+	Group *targetGroup = dungeon.getGroup(_actionTargetGroupThing);
 	CreatureInfo *creatureInfo = &dungeon._creatureInfos[targetGroup->_type];
 	uint16 fearResistance = creatureInfo->getFearResistance();
 	if ((fearResistance > _vm->getRandomNumber(frightAmount)) || (fearResistance == kDMImmuneToFear)) {
@@ -1752,14 +1755,13 @@ void MenuMan::setActionList(ActionSet *actionSet) {
 int16 MenuMan::getActionObjectChargeCount() {
 	ChampionMan &championMan = *_vm->_championMan;
 	Thing slotActionThing = championMan._champions[_vm->ordinalToIndex(championMan._actingChampionOrdinal)]._slots[kDMSlotActionHand];
-	Junk *junkData = (Junk *)_vm->_dungeonMan->getThingData(slotActionThing);
 	switch (slotActionThing.getType()) {
 	case kDMThingTypeWeapon:
-		return ((Weapon *)junkData)->getChargeCount();
+		return _vm->_dungeonMan->getWeapon(slotActionThing)->getChargeCount();
 	case kDMThingTypeArmour:
-		return ((Armour *)junkData)->getChargeCount();
+		return _vm->_dungeonMan->getArmour(slotActionThing)->getChargeCount();
 	case kDMThingTypeJunk:
-		return junkData->getChargeCount();
+		return _vm->_dungeonMan->getJunk(slotActionThing)->getChargeCount();
 	default:
 		return 1;
 	}
diff --git a/engines/dm/movesens.cpp b/engines/dm/movesens.cpp
index d8f82df7e87..cfee2e9fd16 100644
--- a/engines/dm/movesens.cpp
+++ b/engines/dm/movesens.cpp
@@ -76,7 +76,7 @@ bool MovesensMan::sensorIsTriggeredByClickOnWall(int16 mapX, int16 mapY, uint16
 		if (ProcessedThingType == kDMThingTypeSensor) {
 			int16 cellIdx = thingBeingProcessed.getCell();
 			sensorCountToProcessPerCell[cellIdx]--;
-			Sensor *currentSensor = (Sensor *)dungeon.getThingData(thingBeingProcessed);
+			Sensor *currentSensor = dungeon.getSensor(thingBeingProcessed);
 			SensorType processedSensorType = currentSensor->getType();
 			if (processedSensorType == kDMSensorDisabled)
 				continue;
@@ -111,7 +111,7 @@ bool MovesensMan::sensorIsTriggeredByClickOnWall(int16 mapX, int16 mapY, uint16
 				if (!doNotTriggerSensor && (processedSensorType == kDMSensorWallOrnClickWithSpecObjRemovedSensor)) {
 					if (lastProcessedThing == thingBeingProcessed) /* If the sensor is the only one of its type on the cell */
 						break;
-					Sensor *lastSensor = (Sensor *)dungeon.getThingData(lastProcessedThing);
+					Sensor *lastSensor = dungeon.getSensor(lastProcessedThing);
 					lastSensor->setNextThing(currentSensor->getNextThing());
 					currentSensor->setNextThing(_vm->_thingNone);
 					thingBeingProcessed = lastProcessedThing;
@@ -186,7 +186,7 @@ bool MovesensMan::sensorIsTriggeredByClickOnWall(int16 mapX, int16 mapY, uint16
 					_vm->_sound->requestPlay(kDMSoundIndexSwitch, dungeon._partyMapX, dungeon._partyMapY, kDMSoundModePlayIfPrioritized);
 
 				if (!_vm->_championMan->_leaderEmptyHanded && ((processedSensorType == kDMSensorWallOrnClickWithSpecObjRemoved) || (processedSensorType == kDMSensorWallOrnClickWithSpecObjRemovedRotateSensors) || (processedSensorType == kDMSensorWallOrnClickWithSpecObjRemovedSensor))) {
-					Thing *leaderThing = (Thing *)dungeon.getThingData(leaderHandObject);
+					Thing *leaderThing = dungeon.getNextThingPtr(leaderHandObject);
 					*leaderThing = _vm->_thingNone;
 					_vm->_championMan->getObjectRemovedFromLeaderHand();
 					leaderHandObject = _vm->_thingNone;
@@ -254,8 +254,7 @@ bool MovesensMan::getMoveResult(Thing thing, int16 mapX, int16 mapY, int16 destM
 			requiredTeleporterScope = (kDMTeleporterScopeCreatures | kDMTeleporterScopeObjectsOrParty);
 
 		if (thingType == kDMThingTypeProjectile) {
-			Teleporter *L0712_ps_Teleporter = (Teleporter *)dungeon.getThingData(thing);
-			_moveResultDir = (_vm->_timeline->_events[((Projectile *)L0712_ps_Teleporter)->_eventIndex])._Cu._projectile.getDir();
+			_moveResultDir = (_vm->_timeline->_events[dungeon.getProjectile(thing)->_eventIndex])._Cu._projectile.getDir();
 		}
 
 		int16 destinationSquareData = 0;
@@ -267,7 +266,7 @@ bool MovesensMan::getMoveResult(Thing thing, int16 mapX, int16 mapY, int16 destM
 				if (!getFlag(destinationSquareData, kDMSquareMaskTeleporterOpen))
 					break;
 
-				Teleporter *teleporter = (Teleporter *)dungeon.getSquareFirstThingData(destMapX, destMapY);
+				Teleporter *teleporter = dungeon.getTeleporter(dungeon.getSquareFirstThing(destMapX, destMapY));
 				if ((teleporter->getScope() == kDMTeleporterScopeCreatures) && (thingType != kDMThingTypeGroup))
 					break;
 
@@ -335,7 +334,7 @@ bool MovesensMan::getMoveResult(Thing thing, int16 mapX, int16 mapY, int16 destM
 						_useRopeToClimbDownPit = false;
 					} else if (thingType == kDMThingTypeGroup) {
 						dungeon.setCurrentMap(mapIndexSource);
-						uint16 outcome = _vm->_groupMan->getDamageAllCreaturesOutcome((Group *)dungeon.getThingData(thing), mapX, mapY, 20, false);
+						uint16 outcome = _vm->_groupMan->getDamageAllCreaturesOutcome(dungeon.getGroup(thing), mapX, mapY, 20, false);
 						dungeon.setCurrentMap(mapIndexDestination);
 						fallKilledGroup = (outcome == kDMKillOutcomeAllCreaturesInGroup);
 						if (fallKilledGroup)
@@ -433,8 +432,7 @@ bool MovesensMan::getMoveResult(Thing thing, int16 mapX, int16 mapY, int16 destM
 		} else {
 			if (thingType == kDMThingTypeGroup) {
 				dungeon.setCurrentMap(mapIndexDestination);
-				Teleporter *L0712_ps_Teleporter = (Teleporter *)dungeon.getThingData(thing);
-				int16 activeGroupIndex = ((Group *)L0712_ps_Teleporter)->getActiveGroupIndex();
+				int16 activeGroupIndex = dungeon.getGroup(thing)->getActiveGroupIndex();
 				if (((mapIndexDestination == dungeon._partyMapIndex) && (destMapX == dungeon._partyMapX) && (destMapY == dungeon._partyMapY)) || (_vm->_groupMan->groupGetThing(destMapX, destMapY) != _vm->_thingEndOfList)) { /* If a group tries to move to the party square or over another group then create an event to move the group later */
 					dungeon.setCurrentMap(mapIndexSource);
 					if (mapX >= 0)
@@ -446,8 +444,7 @@ bool MovesensMan::getMoveResult(Thing thing, int16 mapX, int16 mapY, int16 destM
 					createEventMoveGroup(thing, destMapX, destMapY, mapIndexDestination, audibleTeleporter);
 					return true; /* The specified group thing cannot be moved because the party or another group is on the destination square */
 				}
-				Group *tmpGroup = (Group *)dungeon._thingData[kDMThingTypeGroup];
-				uint16 movementSoundIndex = getSound((CreatureType)tmpGroup[thing.getIndex()]._type);
+				uint16 movementSoundIndex = getSound((CreatureType)dungeon.getGroup(thing)->_type);
 				if (movementSoundIndex < kDMSoundCount)
 					_vm->_sound->requestPlay(movementSoundIndex, destMapX, destMapY, kDMSoundModePlayIfPrioritized);
 
@@ -529,7 +526,7 @@ bool MovesensMan::moveIsKilledByProjectileImpact(int16 srcMapX, int16 srcMapY, i
 		}
 	} else {
 		impactType = kDMElementTypeCreature;
-		Group *curGroup = (Group *)dungeon.getThingData(thing);
+		Group *curGroup = dungeon.getGroup(thing);
 		int16 creatureAlive = 0;
 		for (uint16 cellIdx = kDMCellNorthWest; cellIdx < kDMCellSouthWest + 1; cellIdx++) {
 			creatureAlive |= curGroup->_health[cellIdx];
@@ -566,7 +563,7 @@ T0266017_CheckProjectileImpacts:
 	Thing curThing = dungeon.getSquareFirstThing(projectileMapX, projectileMapY);
 	while (curThing != _vm->_thingEndOfList) {
 		if ((curThing.getType() == kDMThingTypeProjectile) &&
-			(_vm->_timeline->_events[(((Projectile *)dungeon._thingData[kDMThingTypeProjectile])[curThing.getIndex()])._eventIndex]._type != kDMEventTypeMoveProjectileIgnoreImpacts)) {
+			(_vm->_timeline->_events[dungeon.getProjectile(curThing)->_eventIndex]._type != kDMEventTypeMoveProjectileIgnoreImpacts)) {
 			int16 championOrCreatureOrdinal = championOrCreatureOrdinalInCell[curThing.getCell()];
 			if (championOrCreatureOrdinal && _vm->_projexpl->hasProjectileImpactOccurred(impactType, srcMapX, srcMapY, _vm->ordinalToIndex(championOrCreatureOrdinal), curThing)) {
 				_vm->_projexpl->projectileDeleteEvent(curThing);
@@ -649,7 +646,7 @@ int16 MovesensMan::getSound(CreatureType creatureType) {
 
 int16 MovesensMan::getTeleporterRotatedGroupResult(Teleporter *teleporter, Thing thing, uint16 mapIndex) {
 	DungeonMan &dungeon = *_vm->_dungeonMan;
-	Group *group = (Group *)dungeon.getThingData(thing);
+	Group *group = dungeon.getGroup(thing);
 	Direction rotation = teleporter->getRotation();
 	uint16 groupDirections = _vm->_groupMan->getGroupDirections(group, mapIndex);
 
@@ -760,7 +757,7 @@ void MovesensMan::processThingAdditionOrRemoval(uint16 mapX, uint16 mapY, Thing
 	for (curThing = dungeon.getSquareFirstThing(mapX, mapY); curThing != _vm->_thingEndOfList; curThing = dungeon.getNextThing(curThing)) {
 		uint16 curThingType = curThing.getType();
 		if (curThingType == kDMThingTypeSensor) {
-			Sensor *curSensor = (Sensor *)dungeon.getThingData(curThing);
+			Sensor *curSensor = dungeon.getSensor(curThing);
 			if (curSensor->getType() == kDMSensorDisabled)
 				continue;
 
@@ -888,7 +885,7 @@ bool MovesensMan::isObjectInPartyPossession(int16 objectType) {
 					return true;
 
 				if (curObjectType == kDMIconIndiceContainerChestClosed) {
-					Container *container = (Container *)dungeon.getThingData(curThing);
+					Container *container = dungeon.getContainer(curThing);
 					curThing = container->getSlot();
 					while (curThing != _vm->_thingEndOfList) {
 						if (_vm->_objectMan->getObjectType(curThing) == objectType)
@@ -974,7 +971,7 @@ void MovesensMan::processRotationEffect() {
 				|| ((_sensorRotationEffCell != kDMCellAny) && ((int16)firstSensorThing.getCell() != _sensorRotationEffCell))) {
 				firstSensorThing = dungeon.getNextThing(firstSensorThing);
 			}
-			Sensor *firstSensor = (Sensor *)dungeon.getThingData(firstSensorThing);
+			Sensor *firstSensor = dungeon.getSensor(firstSensorThing);
 			Thing lastSensorThing = firstSensor->getNextThing();
 			while ((lastSensorThing != _vm->_thingEndOfList)
 				&& ((lastSensorThing.getType() != kDMThingTypeSensor)
@@ -984,11 +981,11 @@ void MovesensMan::processRotationEffect() {
 			if (lastSensorThing == _vm->_thingEndOfList)
 				break;
 			dungeon.unlinkThingFromList(firstSensorThing, Thing(0), _sensorRotationEffMapX, _sensorRotationEffMapY);
-			Sensor *lastSensor = (Sensor *)dungeon.getThingData(lastSensorThing);
+			Sensor *lastSensor = dungeon.getSensor(lastSensorThing);
 			lastSensorThing = dungeon.getNextThing(lastSensorThing);
 			while (((lastSensorThing != _vm->_thingEndOfList) && (lastSensorThing.getType() == kDMThingTypeSensor))) {
 				if ((_sensorRotationEffCell == kDMCellAny) || ((int16)lastSensorThing.getCell() == _sensorRotationEffCell))
-					lastSensor = (Sensor *)dungeon.getThingData(lastSensorThing);
+					lastSensor = dungeon.getSensor(lastSensorThing);
 				lastSensorThing = dungeon.getNextThing(lastSensorThing);
 			}
 			firstSensor->setNextThing(lastSensor->getNextThing());
diff --git a/engines/dm/objectman.cpp b/engines/dm/objectman.cpp
index 09056d27bf2..acd4b9eb155 100644
--- a/engines/dm/objectman.cpp
+++ b/engines/dm/objectman.cpp
@@ -149,23 +149,22 @@ IconIndice ObjectMan::getIconIndex(Thing thing) {
 		if (((iconIndex < kDMIconIndiceWeaponDagger) && (iconIndex >= kDMIconIndiceJunkCompassNorth)) ||
 			((iconIndex >= kDMIconIndicePotionMaPotionMonPotion) && (iconIndex <= kDMIconIndicePotionWaterFlask)) ||
 			(iconIndex == kDMIconIndicePotionEmptyFlask)) {
-			Junk *junkThing = (Junk*)_vm->_dungeonMan->getThingData(thing);
 			switch (iconIndex) {
 			case kDMIconIndiceJunkCompassNorth:
 				iconIndex += _vm->_dungeonMan->_partyDir;
 				break;
 			case kDMIconIndiceWeaponTorchUnlit:
-				if (((Weapon*)junkThing)->isLit())
-					iconIndex += chargeCountToTorchType[((Weapon*)junkThing)->getChargeCount()];
+				if (_vm->_dungeonMan->getWeapon(thing)->isLit())
+					iconIndex += chargeCountToTorchType[_vm->_dungeonMan->getWeapon(thing)->getChargeCount()];
 				break;
 			case kDMIconIndiceScrollOpen:
-				if (((Scroll*)junkThing)->getClosed())
+				if (_vm->_dungeonMan->getScroll(thing)->getClosed())
 					iconIndex++;
 				break;
 			case kDMIconIndiceJunkWater:
 			case kDMIconIndiceJunkIllumuletUnequipped:
 			case kDMIconIndiceJunkJewelSymalUnequipped:
-				if (junkThing->getChargeCount())
+				if (_vm->_dungeonMan->getJunk(thing)->getChargeCount())
 					iconIndex++;
 				break;
 			case kDMIconIndiceWeaponBoltBladeStormEmpty:
@@ -174,7 +173,7 @@ IconIndice ObjectMan::getIconIndex(Thing thing) {
 			case kDMIconIndiceWeaponFuryRaBladeEmpty:
 			case kDMIconIndiceWeaponEyeOfTimeEmpty:
 			case kDMIconIndiceWeaponStaffOfClawsEmpty:
-				if (((Weapon*)junkThing)->getChargeCount())
+				if (_vm->_dungeonMan->getWeapon(thing)->getChargeCount())
 					iconIndex++;
 				break;
 			default:
@@ -239,7 +238,7 @@ void ObjectMan::drawLeaderObjectName(Thing thing) {
 	Common::String objectName;
 	int16 iconIndex = getIconIndex(thing);
 	if (iconIndex == kDMIconIndiceJunkChampionBones) {
-		Junk *junk = (Junk*)_vm->_dungeonMan->getThingData(thing);
+		Junk *junk = _vm->_dungeonMan->getJunk(thing);
 		Common::String champBonesName;
 
 		switch (_vm->getGameLanguage()) { // localized
diff --git a/engines/dm/projexpl.cpp b/engines/dm/projexpl.cpp
index ba60479d8c7..369fb37f00f 100644
--- a/engines/dm/projexpl.cpp
+++ b/engines/dm/projexpl.cpp
@@ -50,7 +50,7 @@ void ProjExpl::createProjectile(Thing thing, int16 mapX, int16 mapY, uint16 cell
 		return;
 
 	projectileThing = _vm->thingWithNewCell(projectileThing, cell);
-	Projectile *projectilePtr = (Projectile *)_vm->_dungeonMan->getThingData(projectileThing);
+	Projectile *projectilePtr = _vm->_dungeonMan->getProjectile(projectileThing);
 	projectilePtr->_slot = thing;
 	projectilePtr->_kineticEnergy = MIN((int16)kineticEnergy, (int16)255);
 	projectilePtr->_attack = attack;
@@ -72,7 +72,7 @@ void ProjExpl::createProjectile(Thing thing, int16 mapX, int16 mapY, uint16 cell
 }
 
 bool ProjExpl::hasProjectileImpactOccurred(int16 impactType, int16 mapXCombo, int16 mapYCombo, int16 cell, Thing projectileThing) {
-	Projectile *projectileThingData = (Projectile *)_vm->_dungeonMan->getThingData(Thing(projectileThing));
+	Projectile *projectileThingData = _vm->_dungeonMan->getProjectile(Thing(projectileThing));
 	bool removePotion = false;
 	int16 potionPower = 0;
 	_creatureDamageOutcome = kDMKillOutcomeNoCreaturesInGroup;
@@ -81,13 +81,13 @@ bool ProjExpl::hasProjectileImpactOccurred(int16 impactType, int16 mapXCombo, in
 	Potion *potion = nullptr;
 	Thing explosionThing = _vm->_thingNone;
 	if (projectileAssociatedThingType == kDMThingTypePotion) {
-		Group *projectileAssociatedGroup = (Group *)_vm->_dungeonMan->getThingData(projectileAssociatedThing);
-		PotionType potionType = ((Potion *)projectileAssociatedGroup)->getType();
+		Potion *projectileAssociatedGroup = _vm->_dungeonMan->getPotion(projectileAssociatedThing);
+		PotionType potionType = projectileAssociatedGroup->getType();
 		if ((potionType == kDMPotionTypeVen) || (potionType == kDMPotionTypeFulBomb)) {
 			explosionThing = (potionType == kDMPotionTypeVen) ? _vm->_thingExplPoisonCloud: _vm->_thingExplFireBall;
 			removePotion = true;
-			potionPower = ((Potion *)projectileAssociatedGroup)->getPower();
-			potion = (Potion *)projectileAssociatedGroup;
+			potionPower = projectileAssociatedGroup->getPower();
+			potion = projectileAssociatedGroup;
 		}
 	}
 	bool createExplosionOnImpact = (projectileAssociatedThingType == kDMThingTypeExplosion) && (projectileAssociatedThing != _vm->_thingExplSlime) && (projectileAssociatedThing != _vm->_thingExplPoisonBolt);
@@ -114,7 +114,9 @@ bool ProjExpl::hasProjectileImpactOccurred(int16 impactType, int16 mapXCombo, in
 	case kDMElementTypeDoor: {
 		byte curSquare = _vm->_dungeonMan->_currMapData[projectileTargetMapX][projectileTargetMapY];
 		int16 curDoorState = Square(curSquare).getDoorState();
-		Door *curDoor = (Door *)_vm->_dungeonMan->getSquareFirstThingData(projectileTargetMapX, projectileTargetMapY);
+		Door *curDoor = _vm->_dungeonMan->getDoor(_vm->_dungeonMan->getSquareFirstThing(projectileTargetMapX, projectileTargetMapY));
+		if (!curDoor)
+			return false;
 		if ((curDoorState != kDMDoorStateDestroyed) && (projectileAssociatedThing == _vm->_thingExplOpenDoor)) {
 			if (curDoor->hasButton())
 				_vm->_moveSens->addEvent(kDMEventTypeDoor, projectileTargetMapX, projectileTargetMapY, kDMCellNorthWest, kDMSensorEffectToggle, _vm->_gameTime + 1);
@@ -156,7 +158,7 @@ bool ProjExpl::hasProjectileImpactOccurred(int16 impactType, int16 mapXCombo, in
 		championAttack = attack = getProjectileImpactAttack(projectileThingData, projectileAssociatedThing);
 		break;
 	case kDMElementTypeCreature: {
-		Group *curGroup = (Group *)_vm->_dungeonMan->getThingData(_vm->_groupMan->groupGetThing(projectileTargetMapX, projectileTargetMapY));
+		Group *curGroup = _vm->_dungeonMan->getGroup(_vm->_groupMan->groupGetThing(projectileTargetMapX, projectileTargetMapY));
 		uint16 curCreatureIndex = _vm->_groupMan->getCreatureOrdinalInCell(curGroup, cell);
 		if (!curCreatureIndex)
 			return false;
@@ -182,7 +184,7 @@ bool ProjExpl::hasProjectileImpactOccurred(int16 impactType, int16 mapXCombo, in
 			if (!createExplosionOnImpact && (outcome == kDMKillOutcomeNoCreaturesInGroup)
 			&& (projectileAssociatedThingType == kDMThingTypeWeapon)
 			&& getFlag(curCreatureInfo->_attributes, kDMCreatureMaskKeepThrownSharpWeapon)) {
-				Weapon *weapon = (Weapon *)_vm->_dungeonMan->getThingData(projectileAssociatedThing);
+				Weapon *weapon = _vm->_dungeonMan->getWeapon(projectileAssociatedThing);
 				WeaponType weaponType = weapon->getType();
 				if ((weaponType == kDMWeaponDagger) || (weaponType == kDMWeaponArrow)
 				|| (weaponType == kDMWeaponSlayer) || (weaponType == kDMWeaponPoisonDart)
@@ -278,7 +280,7 @@ void ProjExpl::createExplosion(Thing explThing, uint16 attack, uint16 mapXCombo,
 	if (unusedThing == _vm->_thingNone)
 		return;
 
-	Explosion *explosion = &((Explosion *)_vm->_dungeonMan->_thingData[kDMThingTypeExplosion])[(unusedThing).getIndex()];
+	Explosion *explosion = _vm->_dungeonMan->getExplosion(unusedThing);
 	int16 projectileTargetMapX;
 	int16 projectileTargetMapY;
 	uint16 projectileMapX = mapXCombo;
@@ -331,7 +333,7 @@ void ProjExpl::createExplosion(Thing explThing, uint16 attack, uint16 mapXCombo,
 			} else {
 				unusedThing = _vm->_groupMan->groupGetThing(projectileMapX, projectileMapY);
 				if (unusedThing != _vm->_thingEndOfList) {
-					Group *creatureGroup = (Group *)_vm->_dungeonMan->getThingData(unusedThing);
+					Group *creatureGroup = _vm->_dungeonMan->getGroup(unusedThing);
 					CreatureInfo *creatureInfo = &_vm->_dungeonMan->_creatureInfos[creatureGroup->_type];
 					int16 creatureFireResistance = creatureInfo->getFireResistance();
 					if (creatureFireResistance != kDMImmuneToFire) {
@@ -368,18 +370,18 @@ int16 ProjExpl::projectileGetImpactCount(int16 impactType, int16 mapX, int16 map
 }
 
 void ProjExpl::projectileDeleteEvent(Thing thing) {
-	Projectile *projectile = (Projectile *)_vm->_dungeonMan->getThingData(thing);
+	Projectile *projectile = _vm->_dungeonMan->getProjectile(thing);
 	_vm->_timeline->deleteEvent(projectile->_eventIndex);
 }
 
 void ProjExpl::projectileDelete(Thing projectileThing, Thing *groupSlot, int16 mapX, int16 mapY) {
-	Projectile *projectile = (Projectile *)_vm->_dungeonMan->getThingData(projectileThing);
+	Projectile *projectile = _vm->_dungeonMan->getProjectile(projectileThing);
 	Thing projectileSlotThing = projectile->_slot;
 	if (projectileSlotThing.getType() != kDMThingTypeExplosion) {
 		if (groupSlot != nullptr) {
 			Thing previousThing = *groupSlot;
 			if (previousThing == _vm->_thingEndOfList) {
-				Thing *genericThing = (Thing *)_vm->_dungeonMan->getThingData(projectileSlotThing);
+				Thing *genericThing = _vm->_dungeonMan->getNextThingPtr(projectileSlotThing);
 				*genericThing = _vm->_thingEndOfList;
 				*groupSlot = projectileSlotThing;
 			} else
@@ -397,7 +399,7 @@ void ProjExpl::processEvents48To49(TimelineEvent *event) {
 	TimelineEvent *curEvent = &firstEvent;
 	Thing projectileThingNewCell = Thing(curEvent->_Bu._slot);
 	Thing projectileThing  = projectileThingNewCell;
-	Projectile *projectile = (Projectile *)_vm->_dungeonMan->getThingData(projectileThing);
+	Projectile *projectile = _vm->_dungeonMan->getProjectile(projectileThing);
 	int16 destinationMapX = curEvent->_Cu._projectile.getMapX();
 	int16 destinationMapY = curEvent->_Cu._projectile.getMapY();
 
@@ -474,7 +476,7 @@ void ProjExpl::processEvents48To49(TimelineEvent *event) {
 void ProjExpl::processEvent25(TimelineEvent *event) {
 	uint16 mapX = event->_Bu._location._mapX;
 	uint16 mapY = event->_Bu._location._mapY;
-	Explosion *explosion = &((Explosion *)_vm->_dungeonMan->_thingData[kDMThingTypeExplosion])[Thing((event->_Cu._slot)).getIndex()];
+	Explosion *explosion = _vm->_dungeonMan->getExplosion(Thing(event->_Cu._slot));
 	int16 curSquareType = Square(_vm->_dungeonMan->_currMapData[mapX][mapY]).getType();
 	bool explosionOnPartySquare = (_vm->_dungeonMan->_currMapIndex == _vm->_dungeonMan->_partyMapIndex) && (mapX == _vm->_dungeonMan->_partyMapX) && (mapY == _vm->_dungeonMan->_partyMapY);
 	Thing groupThing = _vm->_groupMan->groupGetThing(mapX, mapY);
@@ -485,7 +487,7 @@ void ProjExpl::processEvent25(TimelineEvent *event) {
 	CreatureType creatureType;
 	creatureType = kDMCreatureTypeGiantScorpion; // Value of 0 as default to avoid possible uninitialized usage
 	if (groupThing != _vm->_thingEndOfList) {
-		group = (Group *)_vm->_dungeonMan->getThingData(groupThing);
+		group = _vm->_dungeonMan->getGroup(groupThing);
 		creatureType = group->_type;
 		creatureInfo = &_vm->_dungeonMan->_creatureInfos[creatureType];
 	}
diff --git a/engines/dm/timeline.cpp b/engines/dm/timeline.cpp
index 4aae9c1317b..055d289652f 100644
--- a/engines/dm/timeline.cpp
+++ b/engines/dm/timeline.cpp
@@ -308,7 +308,7 @@ void Timeline::processTimeline() {
 			case kDMEventTypeRemoveFluxcage:
 				if (!_vm->_gameWon) {
 					_vm->_dungeonMan->unlinkThingFromList(Thing(newEvent._Cu._slot), Thing(0), newEvent._Bu._location._mapX, newEvent._Bu._location._mapY);
-					Explosion *explosion = (Explosion *)_vm->_dungeonMan->getThingData(Thing(newEvent._Cu._slot));
+					Explosion *explosion = _vm->_dungeonMan->getExplosion(Thing(newEvent._Cu._slot));
 					explosion->setNextThing(_vm->_thingNone);
 				}
 				break;
@@ -392,7 +392,7 @@ void Timeline::processEventDoorAnimation(TimelineEvent *event) {
 	event->_mapTime++;
 	int16 sensorEffect = event->_Cu.A._effect;
 	if (sensorEffect == kDMSensorEffectClear) {
-		Door *curDoor = (Door *)_vm->_dungeonMan->getSquareFirstThingData(mapX, mapY);
+		Door *curDoor = _vm->_dungeonMan->getDoor(_vm->_dungeonMan->getSquareFirstThing(mapX, mapY));
 		bool verticalDoorFl = curDoor->opensVertically();
 		if ((_vm->_dungeonMan->_currMapIndex == _vm->_dungeonMan->_partyMapIndex) && (mapX == _vm->_dungeonMan->_partyMapX)
 		 && (mapY == _vm->_dungeonMan->_partyMapY) && (doorState != kDMDoorStateOpen)) {
@@ -414,7 +414,7 @@ void Timeline::processEventDoorAnimation(TimelineEvent *event) {
 		uint16 creatureAttributes;
 		if ((groupThing != _vm->_thingEndOfList) && !getFlag((creatureAttributes = _vm->_dungeonMan->getCreatureAttributes(groupThing)), kDMCreatureMaskNonMaterial)) {
 			if (doorState >= (verticalDoorFl ? CreatureInfo::getHeight(creatureAttributes) : 1)) { /* Creature height or 1 */
-				if (_vm->_groupMan->getDamageAllCreaturesOutcome((Group *)_vm->_dungeonMan->getThingData(groupThing), mapX, mapY, 5, true) != kDMKillOutcomeAllCreaturesInGroup)
+				if (_vm->_groupMan->getDamageAllCreaturesOutcome(_vm->_dungeonMan->getGroup(groupThing), mapX, mapY, 5, true) != kDMKillOutcomeAllCreaturesInGroup)
 					_vm->_groupMan->processEvents29to41(mapX, mapY, kDMEventTypeCreateReactionDangerOnSquare, 0);
 
 				int16 nextState = (int16)doorState - 1;
@@ -547,7 +547,7 @@ void Timeline::moveTeleporterOrPitSquareThings(uint16 mapX, uint16 mapY) {
 			_vm->_moveSens->getMoveResult(curThing, mapX, mapY, mapX, mapY);
 
 		if (curThingType == kDMThingTypeProjectile) {
-			Projectile *projectile = (Projectile *)_vm->_dungeonMan->getThingData(curThing);
+			Projectile *projectile = _vm->_dungeonMan->getProjectile(curThing);
 			TimelineEvent *newEvent;
 			newEvent = &_events[projectile->_eventIndex];
 			newEvent->_Cu._projectile.setMapX(_vm->_moveSens->_moveResultMapX);
@@ -593,13 +593,13 @@ void Timeline::processEventSquareWall(TimelineEvent *event) {
 	while (curThing != _vm->_thingEndOfList) {
 		int16 curThingType = curThing.getType();
 		if ((curThingType == kDMstringTypeText) && (curThing.getCell() == event->_Cu.A._cell)) {
-			TextString *textString = (TextString *)_vm->_dungeonMan->getThingData(curThing);
+			TextString *textString = _vm->_dungeonMan->getTextString(curThing);
 			if (event->_Cu.A._effect == kDMSensorEffectToggle)
 				textString->setVisible(!textString->isVisible());
 			else
 				textString->setVisible(event->_Cu.A._effect == kDMSensorEffectSet);
 		} else if (curThingType == kDMThingTypeSensor) {
-			Sensor *curThingSensor = (Sensor *)_vm->_dungeonMan->getThingData(curThing);
+			Sensor *curThingSensor = _vm->_dungeonMan->getSensor(curThing);
 			uint16 curSensorType = curThingSensor->getType();
 			uint16 curSensorData = curThingSensor->getData();
 			if (curSensorType == kDMSensorWallCountdown) {
@@ -723,7 +723,7 @@ void Timeline::processEventSquareCorridor(TimelineEvent *event) {
 	while (curThing != _vm->_thingEndOfList) {
 		int16 curThingType = curThing.getType();
 		if (curThingType == kDMstringTypeText) {
-			TextString *textString = (TextString *)_vm->_dungeonMan->getThingData(curThing);
+			TextString *textString = _vm->_dungeonMan->getTextString(curThing);
 			bool textCurrentlyVisible = textString->isVisible();
 			if (event->_Cu.A._effect == kDMSensorEffectToggle)
 				textString->setVisible(!textCurrentlyVisible);
@@ -735,7 +735,7 @@ void Timeline::processEventSquareCorridor(TimelineEvent *event) {
 				_vm->_textMan->printMessage(kDMColorWhite, _vm->_stringBuildBuffer);
 			}
 		} else if (curThingType == kDMThingTypeSensor) {
-			Sensor *curSensor = (Sensor *)_vm->_dungeonMan->getThingData(curThing);
+			Sensor *curSensor = _vm->_dungeonMan->getSensor(curThing);
 			if (curSensor->getType() == kDMSensorFloorGroupGenerator) {
 				int16 creatureCount = curSensor->getAttrValue();
 				if (getFlag(creatureCount, kDMMaskRandomizeGeneratedCreatureCount))
@@ -789,7 +789,7 @@ T0252001:
 	} else {
 		if (!randomDirectionMoveRetried) {
 			randomDirectionMoveRetried = true;
-			Group *group = (Group *)_vm->_dungeonMan->getThingData(Thing(event->_Cu._slot));
+			Group *group = _vm->_dungeonMan->getGroup(Thing(event->_Cu._slot));
 			if ((group->_type == kDMCreatureTypeLordChaos) && !_vm->getRandomNumber(4)) {
 				switch (_vm->getRandomNumber(4)) {
 				case 0:
@@ -820,7 +820,7 @@ void Timeline::procesEventEnableGroupGenerator(TimelineEvent *event) {
 	Thing curThing = _vm->_dungeonMan->getSquareFirstThing(event->_Bu._location._mapX, event->_Bu._location._mapY);
 	while (curThing != _vm->_thingNone) {
 		if ((curThing.getType()) == kDMThingTypeSensor) {
-			Sensor *curSensor = (Sensor *)_vm->_dungeonMan->getThingData(curThing);
+			Sensor *curSensor = _vm->_dungeonMan->getSensor(curThing);
 			if (curSensor->getType() == kDMSensorDisabled) {
 				curSensor->setDatAndTypeWithOr(kDMSensorFloorGroupGenerator);
 				return;
@@ -950,7 +950,7 @@ T0255002:
 			if ((curThing.getCell() == cell) && (curThing.getType() == kDMThingTypeJunk)) {
 				int16 iconIndex = _vm->_objectMan->getIconIndex(curThing);
 				if (iconIndex == kDMIconIndiceJunkChampionBones) {
-					Junk *junkData = (Junk *)_vm->_dungeonMan->getThingData(curThing);
+					Junk *junkData = _vm->_dungeonMan->getJunk(curThing);
 					if (junkData->getChargeCount() == championIndex) {
 						_vm->_dungeonMan->unlinkThingFromList(curThing, Thing(0), mapX, mapY); /* BUG0_25 When a champion dies, no bones object is created so it is not possible to bring the champion back to life at an altar of Vi. Each time a champion is brought back to life, the bones object is removed from the dungeon but it is not marked as unused and thus becomes an orphan. After a large number of champion deaths, all JUNK things are exhausted and the game cannot create any more. This also affects the creation of JUNK things dropped by some creatures when they die (Screamer, Rockpile, Magenta Worm, Pain Rat, Red Dragon) */
 						junkData->setNextThing(_vm->_thingNone);




More information about the Scummvm-git-logs mailing list