aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBendegúz Nagy2016-07-01 13:15:41 +0200
committerBendegúz Nagy2016-08-26 23:02:22 +0200
commitbf4ae50e6ba18fdd9c7dedb1e40a467b58fd9ac1 (patch)
tree17ce5c7dc460dc3c5f865ab86e3b1c803ed46aaa
parentd312ac086d0a1cd19c784e1fd7752652f8896ad8 (diff)
downloadscummvm-rg350-bf4ae50e6ba18fdd9c7dedb1e40a467b58fd9ac1.tar.gz
scummvm-rg350-bf4ae50e6ba18fdd9c7dedb1e40a467b58fd9ac1.tar.bz2
scummvm-rg350-bf4ae50e6ba18fdd9c7dedb1e40a467b58fd9ac1.zip
DM: Add F0115_DUNGEONVIEW_DrawObjectsCreaturesProjectilesExplosions_CPSEF
-rw-r--r--engines/dm/dungeonman.h17
-rw-r--r--engines/dm/gfx.cpp846
-rw-r--r--engines/dm/gfx.h52
-rw-r--r--engines/dm/group.h4
4 files changed, 913 insertions, 6 deletions
diff --git a/engines/dm/dungeonman.h b/engines/dm/dungeonman.h
index f3faafdf21..dcf1659c79 100644
--- a/engines/dm/dungeonman.h
+++ b/engines/dm/dungeonman.h
@@ -468,18 +468,30 @@ public:
}; // @ JUNK
class Projectile {
+public:
Thing _nextThing;
Thing _object;
byte _kineticEnergy;
byte _damageEnergy;
uint16 _timerIndex;
-public:
explicit Projectile(uint16 *rawDat) : _nextThing(rawDat[0]), _object(rawDat[1]), _kineticEnergy(rawDat[2]),
_damageEnergy(rawDat[3]), _timerIndex(rawDat[4]) {}
Thing getNextThing() { return _nextThing; }
}; // @ PROJECTILE
+#define kExplosionType_Fireball 0 // @ C000_EXPLOSION_FIREBALL
+#define kExplosionType_Slime 1 // @ C001_EXPLOSION_SLIME
+#define kExplosionType_LightningBolt 2 // @ C002_EXPLOSION_LIGHTNING_BOLT
+#define kExplosionType_HarmNonMaterial 3 // @ C003_EXPLOSION_HARM_NON_MATERIAL
+#define kExplosionType_OpenDoor 4 // @ C004_EXPLOSION_OPEN_DOOR
+#define kExplosionType_PoisonBolt 6 // @ C006_EXPLOSION_POISON_BOLT
+#define kExplosionType_PoisonCloud 7 // @ C007_EXPLOSION_POISON_CLOUD
+#define kExplosionType_Smoke 40 // @ C040_EXPLOSION_SMOKE
+#define kExplosionType_Fluxcage 50 // @ C050_EXPLOSION_FLUXCAGE
+#define kExplosionType_RebirthStep1 100 // @ C100_EXPLOSION_REBIRTH_STEP1
+#define kExplosionType_RebirthStep2 101 // @ C101_EXPLOSION_REBIRTH_STEP2
+
class Explosion {
Thing _nextThing;
uint16 _attributes;
@@ -487,6 +499,9 @@ public:
explicit Explosion(uint16 *rawDat) : _nextThing(rawDat[0]), _attributes(rawDat[1]) {}
Thing getNextThing() { return _nextThing; }
+ uint16 getType() { return _attributes & 0x7F; }
+ uint16 getAttack() { return (_attributes >> 8) & 0xFF; }
+ uint16 getCentered() { return (_attributes >> 7) & 0x1; }
}; // @ EXPLOSION
diff --git a/engines/dm/gfx.cpp b/engines/dm/gfx.cpp
index 4506f3ec36..81b7e64423 100644
--- a/engines/dm/gfx.cpp
+++ b/engines/dm/gfx.cpp
@@ -33,6 +33,8 @@
#include "gfx.h"
#include "dungeonman.h"
+#include "group.h"
+#include "timeline.h"
namespace DM {
@@ -988,7 +990,7 @@ void DisplayMan::blitToBitmap(byte *srcBitmap, uint16 srcWidth, uint16 srcHeight
void DisplayMan::blitBoxFilledWithMaskedBitmapToScreen(byte* src, byte* mask, byte* tmp, Box& box,
int16 lastUnitIndex, int16 firstUnitIndex, int16 destPixelWidth, Color transparent,
- int16 xPos, int16 yPos, int16 height2, Viewport& viewport) {
+ int16 xPos, int16 yPos, int16 destHeight, int16 height2, Viewport& viewport) {
blitBoxFilledWithMaskedBitmap(src, _vgaBuffer, mask, tmp, box, lastUnitIndex, firstUnitIndex, _screenWidth, transparent, xPos, yPos, _screenHeight, height2, viewport);
}
@@ -1959,12 +1961,852 @@ int16 gCenteredExplosionCoordinates[15][2] = { // @ G0225_aai_Graphic558_Centere
{-53, 60}, /* D0L */
{276, 60}}; /* D0R */
-void DisplayMan::drawObjectsCreaturesProjectilesExplosions(Thing thingParam, direction directionParam, int16 mapXpos,
+#define kBlitDoNotUseMask 0x0080 // @ MASK0x0080_DO_NOT_USE_MASK
+
+void DisplayMan::cthulhu(Thing thingParam, direction directionParam, int16 mapXpos,
int16 mapYpos, int16 viewSquareIndex, uint16 orderedViewCellOrdinals) {
+ DungeonMan &dunMan = *_vm->_dungeonMan;
+
+ // AL_0 shared
+ uint16 &AL_0_creatureIndexRed = *(uint16*)&thingParam;
+ uint16 &AL_0_creatureGraphicInfoRed = *(uint16*)&thingParam;
+ uint16 &AL_0_creaturePosX = *(uint16*)&thingParam;
+ // AL_1 shared
+ int16 &AL_1_viewSquareExplosionIndex = viewSquareIndex;
+ // AL_2 shared
+ int16 L0126_i_Multiple;
+ int16 &AL_2_viewCell = L0126_i_Multiple;
+ int16 &AL_2_cellPurpleMan = L0126_i_Multiple;
+ int16 &AL_2_explosionSize = L0126_i_Multiple;
+ // AL_4 shared
+ int16 L0127_i_Multiple;
+ int16 &AL_4_thingType = L0127_i_Multiple;
+ int16 &AL_4_nativeBitmapIndex = L0127_i_Multiple;
+ int16 &AL_4_xPos = L0127_i_Multiple;
+ int16 &AL_4_groupCells = L0127_i_Multiple;
+ int16 &AL_4_normalizdByteWidth = L0127_i_Multiple;
+ int16 &AL_4_yPos = L0127_i_Multiple;
+ int16 &AL_4_projectileAspect = L0127_i_Multiple;
+ int16 &AL_4_explosionType = L0127_i_Multiple;
+ int16 &AL_4_explosionAspectIndex = L0127_i_Multiple;
+ // AL_6 shared
+ byte *L0128_puc_Multiple;
+ byte *&AL_6_bitmapRedBanana = L0128_puc_Multiple;
+
+ ObjectAspect *objectAspect;
+ uint32 remainingViewCellOrdinalsToProcess;
+ byte* paletteChanges;
+ byte* bitmapGreenAnt;
+ byte* coordinateSet;
+ int16 derivedBitmapIndex;
+
+ int16 byteWidth;
+ int16 heightRedEagle;
+ int16 viewLane; /* The lane (center/left/right) that the specified square is part of */
+ int16 cellYellowBear;
+ int16 paddingPixelCount;
+ int16 heightGreenGoat;
+ bool useAlcoveObjectImage; /* C1_TRUE for objects that have a special graphic when drawn in an alcove, like the Chest */
+ bool flipHorizontal;
+ bool drawingGrabbableObject;
+ Box boxByteGreen;
+ Thing firstThingToDraw; /* Initialized to thingParam and never changed afterwards. Used as a backup of the specified first object to draw */
+
+ int16 cellCounter;
+ uint16 objectShiftIndex;
+
+ uint16 L0150_ui_Multiple;
+ uint16 &AL_8_shiftSetIndex = L0150_ui_Multiple;
+ uint16 &AL_8_projectileScaleIndex = L0150_ui_Multiple;
+
+ Thing groupThing;
+ Group* group;
+ ActiveGroup* activeGroup;
+ CreatureInfo* creatureInfo;
+ CreatureAspect* creatureAspectStruct;
+ int16 creatureSize;
+ int16 creatureDirectionDelta;
+ int16 creatureGraphicInfoGreen;
+ int16 creatureAspectInt;
+ int16 creatureIndexGreen;
+ int16 transparentColor;
+ int16 sourceByteWidth;
+ int16 sourceHeight;
+ int16 creaturePaddingPixelCount;
+ bool twoHalfSquareCreaturesFrontView;
+ bool drawingLastBackRowCell;
+ bool useCreatureSideBitmap;
+ bool useCreatureBackBitmap;
+ bool useCreatureSpecialD2FrontBitmap;
+ bool useCreatureAttackBitmap;
+ bool useFlippedHorizontallyCreatureFrontImage;
+
+/* Set to C1_TRUE when the last creature that the function should draw is being drawn. This is used to avoid processing the code to draw creatures for the remaining square cells */
+ bool drawCreaturesCompleted;
+
+ int16 doorFrontViewDrawingPass; /* Value 0, 1 or 2 */
+ int16 scale;
+ bool derivedBitmapInCache;
+ Projectile* projectile;
+ byte projectileCoordinates[2];
+ int16 projectilePosX;
+ int16 projectileDirection;
+ int16 projectileAspectType;
+ int16 projectileBitmapIndexData;
+ bool doNotScaleWithKineticEnergy;
+
+/* When true, the code section to draw an object is called (with a goto) to draw the projectile, then the code section goes back to projectile processing with another goto */
+ bool drawProjectileAsObject;
+
+ bool sqaureHasProjectile;
+ uint16 currentViewCellToDraw;
+ bool projectileFlipVertical;
+ bool projectileAspectTypeHasBackGraphicAndRotation;
+ bool flipVertical;
+ Explosion* explosion;
+ Explosion* fluxcageExplosion;
+ int16* explosionCoordinates;
+ int16 explosionScale;
+ bool squareHasExplosion;
+ bool rebirthExplosion;
+ bool smoke;
+ FieldAspect fieldAspect;
+
+
+ if (thingParam == Thing::_endOfList)
+ return;
+
+ group = 0;
+ groupThing = Thing::_none;
+ drawCreaturesCompleted = sqaureHasProjectile = squareHasExplosion = false;
+ cellCounter = 0;
+ firstThingToDraw = thingParam;
+ if (getFlag(orderedViewCellOrdinals, kCellOrder_DoorFront)) { /* If the function call is to draw objects on a door square viewed from the front */
+/* Two function calls are made in that case to draw objects on both sides of the door frame.
+The door and its frame are drawn between the two calls. This value indicates the drawing pass so that
+creatures are drawn in the right order and so that Fluxcages are not drawn twice */
+ doorFrontViewDrawingPass = (orderedViewCellOrdinals & 0x1) + 1;
+ orderedViewCellOrdinals >>= 4; /* Remove the first nibble that was used for the door front view pass */
+ } else {
+ doorFrontViewDrawingPass = 0; /* The function call is not to draw objects on a door square viewed from the front */
+ }
+
+ bool drawAlcoveObjects = !(remainingViewCellOrdinalsToProcess = orderedViewCellOrdinals);
+ uint16 viewSquareIndexBackup = viewSquareIndex;
+ viewLane = (viewSquareIndex + 3) % 3;
+
+
+ do {
+/* Draw objects */
+ if (drawAlcoveObjects) {
+ AL_2_viewCell = kViewCellAlcove; /* Index of coordinates to draw objects in alcoves */
+ cellYellowBear = returnOppositeDir(directionParam); /* Alcove is on the opposite direction of the viewing direction */
+ objectShiftIndex = 2;
+ } else {
+ AL_2_viewCell = _vm->ordinalToIndex((int16)remainingViewCellOrdinalsToProcess & 0x000F); /* View cell is the index of coordinates to draw object */
+ currentViewCellToDraw = AL_2_viewCell;
+ remainingViewCellOrdinalsToProcess >>= 4; /* Proceed to the next cell ordinal */
+ cellCounter++;
+ cellYellowBear = (AL_2_viewCell + directionParam) % 3; /* Convert view cell to absolute cell */
+ thingParam = firstThingToDraw;
+ viewSquareIndex = viewSquareIndexBackup; /* Restore value as it may have been modified while drawing a creature */
+ objectShiftIndex = 0;
+ }
+
+ objectShiftIndex += (cellYellowBear & 0x0001) << 3;
+ drawProjectileAsObject = false;
+ do {
+ if ((AL_4_thingType = thingParam.getType()) == kGroupThingType) {
+ groupThing = thingParam;
+ continue;
+ }
+ if (AL_4_thingType == kProjectileThingType) {
+ sqaureHasProjectile = true;
+ continue;
+ }
+ if (AL_4_thingType == kExplosionThingType) {
+ squareHasExplosion = true;
+ continue;
+ }
+
+ /* Square where objects are visible and object is located on cell being processed */
+ if ((viewSquareIndex >= kViewSquare_D3C) && (viewSquareIndex <= kViewSquare_D0C) && (thingParam.getCell() == cellYellowBear)) {
+ objectAspect = &(gObjectAspects[gObjectInfo[dunMan.getObjectInfoIndex(thingParam)]._objectAspectIndex]);
+ AL_4_nativeBitmapIndex = kFirstObjectGraphicIndice + objectAspect->_firstNativeBitmapRelativeIndex;
+ if (useAlcoveObjectImage = (drawAlcoveObjects && getFlag(objectAspect->_graphicInfo, kObjectAlcoveMask) && !viewLane)) {
+ AL_4_nativeBitmapIndex++;
+ }
+ coordinateSet = gObjectCoordinateSets[objectAspect->_coordinateSet][viewSquareIndex][AL_2_viewCell];
+ if (!coordinateSet[1]) /* If object is not visible */
+ continue;
+T0115015_DrawProjectileAsObject:
+ flipHorizontal = getFlag(objectAspect->_graphicInfo, kObjectFlipOnRightMask) &&
+ !useAlcoveObjectImage &&
+ ((viewLane == kViewLaneRight) || (!viewLane && ((AL_2_viewCell == kViewCellFrontRight) || (AL_2_viewCell == kViewCellBackRight))));
+ /* Flip horizontally if object graphic requires it and is not being drawn in an alcove and the object is
+ either on the right lane or on the right column of the center lane */
+ paddingPixelCount = 0;
+
+ if ((viewSquareIndex == kViewSquare_D0C) || ((viewSquareIndex >= kViewSquare_D1C) && (AL_2_viewCell >= kViewCellBackRight))) {
+ /* If object is in the center lane (only D0C or D1C with condition above) and is not a projectile */
+ drawingGrabbableObject = (!viewLane && !drawProjectileAsObject);
+ AL_8_shiftSetIndex = kShiftSet_D0BackD1Front;
+ AL_6_bitmapRedBanana = getBitmap(AL_4_nativeBitmapIndex); /* Use base graphic, no resizing */
+ byteWidth = objectAspect->_width;
+ heightRedEagle = objectAspect->_height;
+ if (flipHorizontal) {
+ memcpy(_tmpBitmap, AL_6_bitmapRedBanana, byteWidth * heightRedEagle * sizeof(byte));
+ flipBitmapHorizontal(_tmpBitmap, byteWidth, heightRedEagle);
+ AL_6_bitmapRedBanana = _tmpBitmap;
+ }
+ } else {
+ drawingGrabbableObject = false;
+ derivedBitmapIndex = kDerivedBitmapFirstObject + objectAspect->_firstDerivedBitmapRelativeIndex;
+ if ((viewSquareIndex >= kViewSquare_D1C) || ((viewSquareIndex >= kViewSquare_D2C) && (AL_2_viewCell >= kViewCellBackRight))) {
+ derivedBitmapIndex++;
+ AL_8_shiftSetIndex = kShiftSet_D1BackD2Front;
+ byteWidth = getScaledDimension(objectAspect->_width, kScale20_D2);
+ heightRedEagle = getScaledDimension(objectAspect->_height, kScale20_D2);
+ paletteChanges = gPalChangesFloorOrn_D2;
+ } else {
+ AL_8_shiftSetIndex = kShiftSet_D2BackD3Front;
+ byteWidth = getScaledDimension(objectAspect->_width, kScale16_D3);
+ heightRedEagle = getScaledDimension(objectAspect->_height, kScale16_D3);
+ paletteChanges = gPalChangesFloorOrn_D3;
+ }
+ if (flipHorizontal) {
+ derivedBitmapIndex += 2;
+ paddingPixelCount = (7 - ((byteWidth / 2 - 1) & 0x0007)) << 1;
+ } else if (useAlcoveObjectImage) {
+ derivedBitmapIndex += 4;
+ }
+
+ if (isDerivedBitmapInCache(derivedBitmapIndex)) {
+ AL_6_bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
+ } else {
+ bitmapGreenAnt = getBitmap(AL_4_nativeBitmapIndex);
+ blitToBitmapShrinkWithPalChange(bitmapGreenAnt, objectAspect->_width, objectAspect->_height, AL_6_bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex),
+ byteWidth, heightRedEagle, paletteChanges);
+ if (flipHorizontal) {
+ flipBitmapHorizontal(AL_6_bitmapRedBanana, byteWidth, heightRedEagle);
+ }
+ warning("IGNORED CODE: F0493_CACHE_AddDerivedBitmap");
+ }
+ }
+ AL_4_xPos = coordinateSet[0];
+ boxByteGreen._y2 = coordinateSet[1] + 1;
+ if (!drawProjectileAsObject) { /* If drawing an object that is not a projectile */
+ AL_4_xPos += gShiftSets[AL_8_shiftSetIndex][gObjectPileShiftSetIndices[objectShiftIndex][0]];
+ boxByteGreen._y2 += gShiftSets[AL_8_shiftSetIndex][gObjectPileShiftSetIndices[objectShiftIndex][1]];
+ objectShiftIndex++; /* The next object drawn will use the next shift values */
+ if (drawAlcoveObjects) {
+ if (objectShiftIndex >= 14) {
+ objectShiftIndex = 2;
+ }
+ } else {
+ objectShiftIndex &= 0x000F;
+ }
+ }
+ boxByteGreen._y1 = boxByteGreen._y2 - (heightRedEagle - 1) - 1;
+ if (boxByteGreen._y2 > 136) {
+ boxByteGreen._y2 = 136;
+ }
+ boxByteGreen._x2 = MIN(224, AL_4_xPos + byteWidth);
+ if (boxByteGreen._x1 = MAX(0, AL_4_xPos - byteWidth + 1)) {
+ if (flipHorizontal) {
+ AL_4_xPos = paddingPixelCount;
+ } else {
+ AL_4_xPos = 0;
+ }
+ } else {
+ AL_4_xPos = byteWidth - AL_4_xPos - 1;
+ }
+
+ if (drawingGrabbableObject) {
+ bitmapGreenAnt = AL_6_bitmapRedBanana;
+ Box *AL_6_boxPtrRed = &dunMan._dungeonViewClickableBoxes[AL_2_viewCell];
+ if (AL_6_boxPtrRed->_x1 == 255) { /* If the grabbable object is the first */
+ *AL_6_boxPtrRed = boxByteGreen;
+
+ if ((heightGreenGoat = AL_6_boxPtrRed->_y2 - AL_6_boxPtrRed->_y1) < 15) { /* If the box is too small then enlarge it a little */
+ heightGreenGoat = heightGreenGoat >> 1;
+ AL_6_boxPtrRed->_y1 += heightGreenGoat - 7;
+ if (heightGreenGoat < 4) {
+ AL_6_boxPtrRed->_y2 -= heightGreenGoat - 3;
+ }
+ }
+ } else { /* If there are several grabbable objects then enlarge the box so it includes all objects */
+ AL_6_boxPtrRed->_x1 = MIN(AL_6_boxPtrRed->_x1, boxByteGreen._x1);
+ AL_6_boxPtrRed->_x2 = MIN(AL_6_boxPtrRed->_x2, boxByteGreen._x2);
+ AL_6_boxPtrRed->_y1 = MIN(AL_6_boxPtrRed->_y1, boxByteGreen._y1);
+ AL_6_boxPtrRed->_y2 = MIN(AL_6_boxPtrRed->_y2, boxByteGreen._y2);
+ }
+ AL_6_bitmapRedBanana = bitmapGreenAnt;
+ dunMan._pileTopObject[AL_2_viewCell] = thingParam; /* The object is at the top of the pile */
+ }
+ blitToScreen(AL_6_bitmapRedBanana, byteWidth, AL_4_xPos, 0, boxByteGreen, kColorFlesh, gDungeonViewport);
+
+ if (drawProjectileAsObject)
+ goto T0115171_BackFromT0115015_DrawProjectileAsObject;
+ }
+ } while ((thingParam = dunMan.getNextThing(thingParam)) != Thing::_endOfList);
+ if (AL_2_viewCell == kViewCellAlcove)
+ break; /* End of processing when drawing objects in an alcove */
+ if (viewSquareIndex < kViewSquare_D3C)
+ break; /* End of processing if square is too far away at D4 */
+ /* Draw creatures */
+
+ /* If (draw cell on the back row or second cell being processed) and (no more cells to draw or next cell to draw is a cell on the front row) */
+ drawingLastBackRowCell = ((AL_2_viewCell <= kViewCellFrontRight) || (cellCounter == 1))
+ && (!remainingViewCellOrdinalsToProcess || ((remainingViewCellOrdinalsToProcess & 0x0000000F) >= 3));
+
+ if ((groupThing == Thing::_none) || drawCreaturesCompleted)
+ goto T0115129_DrawProjectiles; /* Skip code to draw creatures */
+ if (group == nullptr) { /* If all creature data and info has not already been gathered */
+ group = (Group*)dunMan.getThingData(groupThing);
+ activeGroup = &_vm->_groupMan->_activeGroups[group->getActiveGroupIndex()];
+ creatureInfo = &gCreatureInfo[group->_type];
+ creatureAspectStruct = &gCreatureAspects[creatureInfo->_creatureAspectIndex];
+ creatureSize = getFlag(creatureInfo->_attributes, kMaskCreatureInfo_size);
+ creatureGraphicInfoGreen = creatureInfo->_graphicInfo;
+ }
+ objectAspect = (ObjectAspect*)creatureAspectStruct;
+ if (AL_0_creatureIndexRed = _vm->_groupMan->getCreatureOrdinalInCell(group, cellYellowBear)) { /* If there is a creature on the cell being processed */
+ AL_0_creatureIndexRed--; /* Convert ordinal to index */
+ creatureIndexGreen = AL_0_creatureIndexRed;
+ } else if (creatureSize == kMaskCreatureSizeHalf) {
+ AL_0_creatureIndexRed = 0;
+ creatureIndexGreen = -1;
+ } else {
+ goto T0115129_DrawProjectiles; /* No creature to draw at cell, skip to projectiles */
+ }
+
+ creatureDirectionDelta = (directionParam - _vm->_groupMan->getCreatureValue(activeGroup->_directions, AL_0_creatureIndexRed)) % 3;
+ twoHalfSquareCreaturesFrontView = false;
+ if ((AL_4_groupCells = activeGroup->_cells) == kCreatureTypeSingleCenteredCreature) { /* If there is a single centered creature in the group */
+ if (remainingViewCellOrdinalsToProcess || (doorFrontViewDrawingPass == 1))
+/* Do not draw a single centered creature now, wait until second pass (for a front view door)
+ or until all cells have been drawn so the creature is drawn over all the objects on the floor */
+ goto T0115129_DrawProjectiles;
+ drawCreaturesCompleted = true;
+ if ((creatureSize == kMaskCreatureSizeHalf) && (creatureDirectionDelta & 0x0001)) { /* Side view of half square creature */
+ AL_2_viewCell = kHalfSizedViewCell_CenterColumn;
+ } else {
+ AL_2_viewCell = kHalfSizedViewCell_FrontRow;
+ }
+ } else if ((creatureSize == kMaskCreatureSizeHalf) && (drawingLastBackRowCell || !remainingViewCellOrdinalsToProcess || (creatureIndexGreen < 0))) {
+ if (drawingLastBackRowCell && (doorFrontViewDrawingPass != 2)) {
+ if ((creatureIndexGreen >= 0) && (creatureDirectionDelta & 0x0001)) {
+ AL_2_viewCell = kHalfSizedViewCell_BackRow; /* Side view of a half square creature on the back row. Drawn during pass 1 for a door square */
+ } else {
+ goto T0115129_DrawProjectiles;
+ }
+ } else if ((doorFrontViewDrawingPass != 1) && !remainingViewCellOrdinalsToProcess) {
+ if (creatureDirectionDelta & 0x0001) {
+ if (creatureIndexGreen >= 0) {
+ AL_2_viewCell = kHalfSizedViewCell_FrontRow; /* Side view of a half square creature on the front row. Drawn during pass 2 for a door square */
+ } else {
+ goto T0115129_DrawProjectiles;
+ }
+ } else {
+ drawCreaturesCompleted = true;
+ if (creatureIndexGreen < 0) {
+ creatureIndexGreen = 0;
+ }
+ twoHalfSquareCreaturesFrontView = group->getCount();
+ if (((AL_4_groupCells = _vm->_groupMan->getCreatureValue(AL_4_groupCells, AL_0_creatureIndexRed)) == directionParam)
+ || (AL_4_groupCells == returnPrevVal(directionParam))) {
+ AL_2_viewCell = kHalfSizedViewCell_LeftColumn;
+ } else {
+ AL_2_viewCell = kHalfSizedViewCell_RightColumn;
+ }
+ }
+ } else {
+ goto T0115129_DrawProjectiles;
+ }
+
+ } else if (creatureSize != kMaskCreatureSizeQuarter)
+ goto T0115129_DrawProjectiles;
+
+
+ creatureAspectInt = activeGroup->_aspect[creatureIndexGreen];
+ if (viewSquareIndex > kViewSquare_D0C) {
+ viewSquareIndex--;
+ }
+T0115077_DrawSecondHalfSquareCreature:
+ coordinateSet = gCreatureCoordinateSets[((CreatureAspect*)objectAspect)->getCoordSet()][viewSquareIndex][AL_2_viewCell];
+ if (!coordinateSet[1])
+ goto T0115126_CreatureNotVisible;
+ AL_0_creatureGraphicInfoRed = creatureGraphicInfoGreen;
+ AL_4_nativeBitmapIndex = kFirstCreatureGraphicIndice + ((CreatureAspect*)objectAspect)->_firstNativeBitmapRelativeIndex; /* By default, assume using the front image */
+ derivedBitmapIndex = ((CreatureAspect*)objectAspect)->_firstDerivedBitmapIndex;
+ if (useCreatureSideBitmap = getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskSide) && (creatureDirectionDelta & 0x0001)) {
+ useCreatureAttackBitmap = useFlippedHorizontallyCreatureFrontImage = useCreatureBackBitmap = false;
+ AL_4_nativeBitmapIndex++; /* Skip the front image. Side image is right after the front image */
+ derivedBitmapIndex += 2;
+ sourceByteWidth = byteWidth = ((CreatureAspect*)objectAspect)->_byteWidthSide;
+ sourceHeight = heightRedEagle = ((CreatureAspect*)objectAspect)->_heightSide;
+ } else {
+ useCreatureBackBitmap = getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskBack) && (creatureDirectionDelta == 0);
+ if (useCreatureAttackBitmap = !useCreatureBackBitmap && getFlag(creatureAspectInt, kMaskActiveGroupIsAttacking)
+ && getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskAttack)) {
+
+ useFlippedHorizontallyCreatureFrontImage = false;
+ sourceByteWidth = byteWidth = ((CreatureAspect*)objectAspect)->_byteWidthAttack;
+ sourceHeight = heightRedEagle = ((CreatureAspect*)objectAspect)->_heightAttack;
+ AL_4_nativeBitmapIndex++; /* Skip the front image */
+ derivedBitmapIndex += 2;
+ if (getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskSide)) {
+ AL_4_nativeBitmapIndex++; /* If the creature has a side image, it preceeds the attack image */
+ derivedBitmapIndex += 2;
+ }
+ if (getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskBack)) {
+ AL_4_nativeBitmapIndex++; /* If the creature has a back image, it preceeds the attack image */
+ derivedBitmapIndex += 2;
+ }
+ } else {
+ sourceByteWidth = byteWidth = ((CreatureAspect*)objectAspect)->_byteWidthFront;
+ sourceHeight = heightRedEagle = ((CreatureAspect*)objectAspect)->_heightFront;
+ if (useCreatureBackBitmap) {
+ useFlippedHorizontallyCreatureFrontImage = false;
+ if (getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskSide)) {
+ AL_4_nativeBitmapIndex += 2; /* If the creature has a side image, it preceeds the back image */
+ derivedBitmapIndex += 4;
+ } else {
+ AL_4_nativeBitmapIndex++; /* If the creature does not have a side image, the back image follows the front image */
+ derivedBitmapIndex += 2;
+ }
+ } else {
+ if (useFlippedHorizontallyCreatureFrontImage = getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskFlipNonAttack)
+ && getFlag(creatureAspectInt, kMaskActiveGroupFlipBitmap)) {
+ derivedBitmapIndex += 2;
+ if (getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskSide)) {
+ derivedBitmapIndex += 2;
+ }
+ if (getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskBack)) {
+ derivedBitmapIndex += 2;
+ }
+ if (getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskAttack)) {
+ derivedBitmapIndex += 2;
+ }
+ }
+ }
+ }
+ }
+ if (viewSquareIndex >= kViewSquare_D1C) { /* Creature is on D1 */
+ creaturePaddingPixelCount = 0;
+ AL_8_shiftSetIndex = kShiftSet_D0BackD1Front;
+ transparentColor = ((CreatureAspect*)objectAspect)->getTranspColour();
+ if (useCreatureSideBitmap) {
+ AL_6_bitmapRedBanana = getBitmap(AL_4_nativeBitmapIndex);
+ if (creatureDirectionDelta == 1) {
+ memcpy(_tmpBitmap, AL_6_bitmapRedBanana, byteWidth * heightRedEagle * sizeof(byte));
+ flipBitmapHorizontal(_tmpBitmap, byteWidth, heightRedEagle);
+ AL_6_bitmapRedBanana = _tmpBitmap;
+ }
+ } else {
+ if (useCreatureBackBitmap || !useFlippedHorizontallyCreatureFrontImage) {
+ AL_6_bitmapRedBanana = getBitmap(AL_4_nativeBitmapIndex);
+ if (useCreatureAttackBitmap && getFlag(creatureAspectInt, kMaskActiveGroupFlipBitmap)) {
+ memcpy(_tmpBitmap, AL_6_bitmapRedBanana, byteWidth * heightRedEagle * sizeof(byte));
+ flipBitmapHorizontal(_tmpBitmap, byteWidth, heightRedEagle);
+ AL_6_bitmapRedBanana = _tmpBitmap;
+ }
+ } else { /* Use first additional derived graphic: front D1 */
+ if (isDerivedBitmapInCache(derivedBitmapIndex)) { /* If derived graphic is already in memory */
+ AL_6_bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
+ } else {
+ bitmapGreenAnt = getBitmap(AL_4_nativeBitmapIndex);
+ if (getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskFlipNonAttack)) {
+ AL_6_bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
+ memcpy(AL_6_bitmapRedBanana, bitmapGreenAnt, byteWidth * heightRedEagle * sizeof(byte));
+ flipBitmapHorizontal(AL_6_bitmapRedBanana, byteWidth, heightRedEagle);
+ }
+ warning("IGNORED CODE: F0493_CACHE_AddDerivedBitmap");
+ }
+ }
+ }
+ } else { /* Creature is on D2 or D3 */
+ if (useFlippedHorizontallyCreatureFrontImage) {
+ derivedBitmapIndex++; /* Skip front D1 image in additional graphics */
+ }
+ if (viewSquareIndex >= kViewSquare_D2C) { /* Creature is on D2 */
+ derivedBitmapIndex++; /* Skip front D3 image in additional graphics */
+ AL_8_shiftSetIndex = kShiftSet_D1BackD2Front;
+ useCreatureSpecialD2FrontBitmap = getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskSpecialD2Front)
+ && !useCreatureSideBitmap && !useCreatureBackBitmap && !useCreatureAttackBitmap;
+ paletteChanges = gPalChangesCreature_D2;
+ scale = kScale20_D2;
+ } else { /* Creature is on D3 */
+ AL_8_shiftSetIndex = kShiftSet_D2BackD3Front;
+ useCreatureSpecialD2FrontBitmap = false;
+ paletteChanges = gPalChangesCreature_D3;
+ scale = kScale16_D3;
+ }
+ byteWidth = getScaledDimension(sourceByteWidth, scale);
+ heightRedEagle = getScaledDimension(sourceHeight, scale);
+ transparentColor = paletteChanges[((CreatureAspect*)objectAspect)->getTranspColour()] / 10;
+ if (derivedBitmapInCache = isDerivedBitmapInCache(derivedBitmapIndex)) {
+ AL_6_bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
+ } else {
+ bitmapGreenAnt = getBitmap(AL_4_nativeBitmapIndex);
+ AL_6_bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
+ blitToBitmapShrinkWithPalChange(bitmapGreenAnt, sourceByteWidth, sourceHeight, AL_6_bitmapRedBanana, byteWidth, heightRedEagle, paletteChanges);
+ warning("IGNORED CODE: F0493_CACHE_AddDerivedBitmap");
+ }
+ if ((useCreatureSideBitmap && (creatureDirectionDelta == 1)) || /* If creature is viewed from the right, the side view must be flipped */
+ (useCreatureAttackBitmap && getFlag(creatureAspectInt, kMaskActiveGroupFlipBitmap)) ||
+ (useCreatureSpecialD2FrontBitmap && getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskSpecialD2FrontIsFlipped)) ||
+ (useFlippedHorizontallyCreatureFrontImage && getFlag(AL_0_creatureGraphicInfoRed, kCreatureInfoGraphicMaskFlipNonAttack))) { /* If the graphic should be flipped */
+ if (!useFlippedHorizontallyCreatureFrontImage || !derivedBitmapInCache) {
+ AL_4_normalizdByteWidth = byteWidth;
+ warning("SUPER WARNING: we might need getNormalizedByteWidthM77");
+ if (!useFlippedHorizontallyCreatureFrontImage) {
+ memcpy(_tmpBitmap, AL_6_bitmapRedBanana, AL_4_normalizdByteWidth * heightRedEagle * sizeof(byte));
+ AL_6_bitmapRedBanana = _tmpBitmap;
+ }
+ flipBitmapHorizontal(AL_6_bitmapRedBanana, AL_4_normalizdByteWidth, heightRedEagle);
+ }
+ creaturePaddingPixelCount = (7 - ((byteWidth / 2 - 1) & 0x0007)) << 1;
+ } else {
+ creaturePaddingPixelCount = 0;
+ }
+ }
+ AL_4_yPos = coordinateSet[1];
+ AL_4_yPos += gShiftSets[AL_8_shiftSetIndex][getVerticalOffsetM23(creatureAspectInt)];
+ boxByteGreen._y2 = MIN(AL_4_yPos, (int16)135) + 1;
+ boxByteGreen._y1 = MIN(0, AL_4_yPos - (heightRedEagle - 1));
+ AL_4_xPos = coordinateSet[0];
+ AL_4_xPos += gShiftSets[AL_8_shiftSetIndex][getHorizontalOffsetM22(creatureAspectInt)];
+ if (viewLane == kViewLaneLeft) {
+ AL_4_xPos -= 100;
+ } else {
+ if (viewLane) { /* Lane right */
+ AL_4_xPos += 100;
+ }
+ }
+ if (boxByteGreen._x2 = 1 + MIN(MAX(0, AL_4_xPos + byteWidth), 223) <= 1)
+ goto T0115126_CreatureNotVisible;
+ if (boxByteGreen._x1 = MIN(MAX(0, AL_4_xPos - byteWidth + 1), 223)) {
+ if (boxByteGreen._x1 == 223)
+ goto T0115126_CreatureNotVisible;
+ AL_0_creaturePosX = creaturePaddingPixelCount;
+ } else {
+ AL_0_creaturePosX = creaturePaddingPixelCount + (byteWidth - AL_4_xPos - 1);
+ }
+ warning("SUPER WARNINIG: we might nee noralized with on byteWidth");
+ blitToScreen(AL_6_bitmapRedBanana, byteWidth, AL_0_creaturePosX, 0, boxByteGreen, (Color)transparentColor, gDungeonViewport);
+
+T0115126_CreatureNotVisible:
+ if (twoHalfSquareCreaturesFrontView) {
+ twoHalfSquareCreaturesFrontView = false;
+ creatureAspectInt = activeGroup->_aspect[!creatureIndexGreen]; /* Aspect of the other creature in the pair */
+ if (AL_2_viewCell == kHalfSizedViewCell_RightColumn) {
+ AL_2_viewCell = kHalfSizedViewCell_LeftColumn;
+ } else {
+ AL_2_viewCell = kHalfSizedViewCell_RightColumn;
+ }
+ goto T0115077_DrawSecondHalfSquareCreature;
+ }
+ /* Draw projectiles */
+T0115129_DrawProjectiles:
+ if (!sqaureHasProjectile
+ || ((viewSquareIndex = viewSquareIndexBackup) > kViewSquare_D0C)
+/* If there is no projectile to draw or if projectiles are not visible on the specified square or on the cell being drawn */
+ || (!(projectilePosX = gObjectCoordinateSets[0][viewSquareIndex][AL_2_viewCell = currentViewCellToDraw][0])))
+ continue;
+ thingParam = firstThingToDraw; /* Restart processing list of objects from the beginning. The next loop draws only projectile objects among the list */
+
+ do {
+ if ((thingParam.getType() == kProjectileThingType) && (thingParam.getCell() == cellYellowBear)) {
+ projectile = (Projectile*)dunMan.getThingData(thingParam);
+ if ((AL_4_projectileAspect = dunMan.getProjectileAspect(projectile->_object)) < 0) { /* Negative value: projectile aspect is the ordinal of a PROJECTIL_ASPECT */
+ objectAspect = (ObjectAspect*)&gProjectileAspect[_vm->ordinalToIndex(-AL_4_projectileAspect)];
+ AL_4_nativeBitmapIndex = ((ProjectileAspect*)objectAspect)->_firstNativeBitmapRelativeIndex + kFirstProjectileGraphicIndice;
+ projectileAspectType = getFlag(((ProjectileAspect*)objectAspect)->_graphicInfo, kProjectileAspectTypeMask);
+ if (((doNotScaleWithKineticEnergy = !getFlag(((ProjectileAspect*)objectAspect)->_graphicInfo, kProjectileScaleWithKineticEnergyMask))
+ || (projectile->_kineticEnergy == 255)) && (viewSquareIndex == kViewSquare_D0C)) {
+ scale = 0; /* Use native bitmap without resizing */
+ byteWidth = ((ProjectileAspect*)objectAspect)->_width;
+ heightRedEagle = ((ProjectileAspect*)objectAspect)->_height;
+ } else {
+ AL_8_projectileScaleIndex = ((viewSquareIndex / 3) << 1) + (AL_2_viewCell >> 1);
+ scale = gProjectileScales[AL_8_projectileScaleIndex];
+ if (!doNotScaleWithKineticEnergy) {
+ scale = (scale * MAX(96, projectile->_kineticEnergy + 1)) >> 8;
+ }
+ byteWidth = getScaledDimension(((ProjectileAspect*)objectAspect)->_width, scale);
+ heightRedEagle = getScaledDimension(((ProjectileAspect*)objectAspect)->_height, scale);
+ }
+ if (projectileAspectTypeHasBackGraphicAndRotation = (projectileAspectType == kProjectileAspectHasBackGraphicRotation)) {
+ projectileFlipVertical = ((mapXpos + mapYpos) & 0x0001);
+ }
+ if (projectileAspectType == kProjectileAspectHasNone) {
+ projectileBitmapIndexData = 0;
+ flipVertical = flipHorizontal = false;
+ } else {
+ if (isOrientedWestEast((direction)(projectileDirection = _vm->_timeline->_events[projectile->_timerIndex]._C._projectile.getDir()))
+ != isOrientedWestEast(directionParam)) {
+ if (projectileAspectType == kProjectileAspectHasRotation) {
+ projectileBitmapIndexData = 1;
+ } else {
+ projectileBitmapIndexData = 2;
+ }
+ if (projectileAspectTypeHasBackGraphicAndRotation) {
+ flipHorizontal = !AL_2_viewCell || (AL_2_viewCell == kViewCellBackLeft);
+ if (!(flipVertical = projectileFlipVertical)) {
+ flipHorizontal = !flipHorizontal;
+ }
+ } else {
+ flipVertical = false;
+ flipHorizontal = (returnNextVal(directionParam) == projectileDirection);
+ }
+ } else {
+/* If the projectile does not have a back graphic or has one but is not seen from the back or if it has a back graphic and rotation and should be flipped vertically */
+ if ((projectileAspectType >= kProjectileAspectHasRotation)
+ || ((projectileAspectType == kProjectileAspectBackGraphic)
+ && (projectileDirection != directionParam)) || (projectileAspectTypeHasBackGraphicAndRotation && projectileFlipVertical)) {
+ projectileBitmapIndexData = 0;
+ } else {
+ projectileBitmapIndexData = 1;
+ }
+ flipVertical = projectileAspectTypeHasBackGraphicAndRotation && (AL_2_viewCell < kViewCellBackRight);
+ flipHorizontal = getFlag(((ProjectileAspect*)objectAspect)->_graphicInfo, kProjectileSideMask)
+ && !((viewLane == kViewLaneRight) || (!viewLane && ((AL_2_viewCell == kViewCellFrontRight) || (AL_2_viewCell == kViewCellBackRight))));
+ }
+ }
+ AL_4_nativeBitmapIndex += projectileBitmapIndexData;
+ paddingPixelCount = 0;
+ if (!scale) {
+ AL_6_bitmapRedBanana = getBitmap(AL_4_nativeBitmapIndex);
+ } else {
+ if (flipHorizontal) {
+ paddingPixelCount = (7 - ((byteWidth / 2 - 1) & 0x0007)) << 1;
+ }
+ derivedBitmapIndex = kDerivedBitmapFirstProjectile + ((ProjectileAspect*)objectAspect)->_firstNativeBitmapRelativeIndex + (projectileBitmapIndexData * 6);
+ if (doNotScaleWithKineticEnergy && isDerivedBitmapInCache(derivedBitmapIndex) + AL_8_projectileScaleIndex) {
+ AL_6_bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
+ } else {
+ bitmapGreenAnt = getBitmap(AL_4_nativeBitmapIndex);
+ if (doNotScaleWithKineticEnergy) {
+ AL_6_bitmapRedBanana = getDerivedBitmap(derivedBitmapIndex);
+ } else {
+ AL_6_bitmapRedBanana = _tmpBitmap;
+ }
+ blitToBitmapShrinkWithPalChange(bitmapGreenAnt, ((ProjectileAspect*)objectAspect)->_width, ((ProjectileAspect*)objectAspect)->_height,
+ AL_6_bitmapRedBanana, byteWidth, heightRedEagle, _palChangesProjectile[AL_8_projectileScaleIndex >> 1]);
+ if (doNotScaleWithKineticEnergy) {
+ warning("IGNORED CODE F0493_CACHE_AddDerivedBitmap");
+ }
+ }
+ }
+ if (flipHorizontal || flipVertical) {
+ warning("might need noralized bytewidth");
+ AL_4_normalizdByteWidth = byteWidth;
+ if (AL_6_bitmapRedBanana != _tmpBitmap) {
+ memcpy(_tmpBitmap, AL_6_bitmapRedBanana, AL_4_normalizdByteWidth * heightRedEagle * sizeof(byte));
+ AL_6_bitmapRedBanana = _tmpBitmap;
+ }
+ if (flipVertical) {
+ flipBitmapVertical(AL_6_bitmapRedBanana, AL_4_normalizdByteWidth, heightRedEagle);
+ }
+ if (flipHorizontal) {
+ flipBitmapHorizontal(AL_6_bitmapRedBanana, AL_4_normalizdByteWidth, heightRedEagle);
+ }
+ }
+ boxByteGreen._y2 = (heightRedEagle >> 1) + 47 + 1;
+ boxByteGreen._y1 = 47 - (heightRedEagle >> 1) + !(heightRedEagle & 0x0001);
+ boxByteGreen._x2 = MIN(223, projectilePosX + byteWidth) + 1;
+ if (boxByteGreen._x1 = MAX(0, projectilePosX - byteWidth + 1)) {
+ if (flipHorizontal) {
+ AL_4_xPos = paddingPixelCount;
+ } else {
+ AL_4_xPos = 0;
+ }
+ } else {
+/* BUG0_06 Graphical glitch when drawing projectiles or explosions. If a projectile or explosion bitmap
+is cropped because it is only partly visible on the left side of the viewport (boxByteGreen.X1 = 0) and
+the bitmap is flipped horizontally (flipHorizontal = C1_TRUE) then a wrong part of the bitmap is drawn on
+screen. To fix this bug, "+ paddingPixelCount" must be added to the second parameter of this function call */
+ AL_4_xPos = MAX(paddingPixelCount, (int16)(byteWidth - projectilePosX - 1));
+ }
+ blitToScreen(AL_6_bitmapRedBanana, byteWidth, AL_4_xPos, 0, boxByteGreen, kColorFlesh, gDungeonViewport);
+ } else { /* Positive value: projectile aspect is the index of a OBJECT_ASPECT */
+ useAlcoveObjectImage = false;
+ projectileCoordinates[0] = projectilePosX;
+ projectileCoordinates[1] = 47;
+ coordinateSet = projectileCoordinates;
+ objectAspect = &gObjectAspects[AL_4_projectileAspect];
+ AL_4_nativeBitmapIndex = objectAspect->_firstNativeBitmapRelativeIndex + kFirstObjectGraphicIndice;
+ drawProjectileAsObject = true;
+/* Go to code section to draw an object. Once completed, it jumps back to T0115171_BackFromT0115015_DrawProjectileAsObject below */
+ goto T0115015_DrawProjectileAsObject;
+ }
+ }
+T0115171_BackFromT0115015_DrawProjectileAsObject:;
+ } while ((thingParam = dunMan.getNextThing(thingParam)) != Thing::_endOfList);
+
+ } while (remainingViewCellOrdinalsToProcess);
+
+
+ /* Draw explosions */
+ if (!squareHasExplosion)
+ return;
+ fluxcageExplosion = 0;
+ AL_1_viewSquareExplosionIndex = viewSquareIndexBackup + 3; /* Convert square index to square index for explosions */
+ uint16 explosionScaleIndex = AL_1_viewSquareExplosionIndex / 3;
+ thingParam = firstThingToDraw; /* Restart processing list of things from the beginning. The next loop draws only explosion things among the list */
+ do {
+ if (thingParam.getType() == kExplosionThingType) {
+ AL_2_cellPurpleMan = thingParam.getCell();
+ explosion = (Explosion*)dunMan.getThingData(thingParam);
+ if ((rebirthExplosion = ((unsigned int)(AL_4_explosionType = explosion->getType()) >= kExplosionType_RebirthStep1))
+ && ((AL_1_viewSquareExplosionIndex < kViewSquare_D3C_Explosion)
+ || (AL_1_viewSquareExplosionIndex > kViewSquare_D1C_Explosion)
+ || (AL_2_cellPurpleMan != cellYellowBear))) /* If explosion is rebirth and is not visible */
+ continue;
+ smoke = false;
+ if ((AL_4_explosionType == kExplosionType_Fireball) || (AL_4_explosionType == kExplosionType_LightningBolt) || (AL_4_explosionType == kExplosionType_RebirthStep2)) {
+ AL_4_explosionAspectIndex = kExplosionAspectFire;
+ } else {
+ if ((AL_4_explosionType == kExplosionType_PoisonBolt) || (AL_4_explosionType == kExplosionType_PoisonCloud)) {
+ AL_4_explosionAspectIndex = kExplosionAspectPoison;
+ } else {
+ if (AL_4_explosionType == kExplosionType_Smoke) {
+ smoke = true;
+ AL_4_explosionAspectIndex = kExplosionAspectSmoke;
+ } else {
+ if (AL_4_explosionType == kExplosionType_RebirthStep1) {
+ objectAspect = (ObjectAspect*)&gProjectileAspect[_vm->ordinalToIndex(-dunMan.getProjectileAspect(Thing::_explLightningBolt))];
+ AL_6_bitmapRedBanana = getBitmap(((ProjectileAspect*)objectAspect)->_firstNativeBitmapRelativeIndex + (kFirstProjectileGraphicIndice + 1));
+ explosionCoordinates = gRebirthStep1ExplosionCoordinates[AL_1_viewSquareExplosionIndex - 3];
+ byteWidth = getScaledDimension((((ProjectileAspect*)objectAspect)->_width), explosionCoordinates[2]);
+ heightRedEagle = getScaledDimension((((ProjectileAspect*)objectAspect)->_height), explosionCoordinates[2]);
+ if (AL_1_viewSquareExplosionIndex != kViewSquare_D1C_Explosion) {
+ blitToBitmapShrinkWithPalChange(AL_6_bitmapRedBanana,
+ ((ProjectileAspect*)objectAspect)->_width, ((ProjectileAspect*)objectAspect)->_height, _tmpBitmap,
+ byteWidth, heightRedEagle, gPalChangesNoChanges);
+ AL_6_bitmapRedBanana = _tmpBitmap;
+ }
+ goto T0115200_DrawExplosion;
+ }
+ if (AL_4_explosionType == kExplosionType_Fluxcage) {
+ if (AL_1_viewSquareExplosionIndex >= kViewSquare_D3L_Explosion) {
+ fluxcageExplosion = explosion;
+ }
+ continue;
+ }
+ AL_4_explosionAspectIndex = kExplosionAspectSpell;
+ }
+ }
+ }
+ if (AL_1_viewSquareExplosionIndex == kViewSquare_D0C_Explosion) {
+ if (smoke) {
+ AL_4_explosionAspectIndex--; /* Smoke uses the same graphics as Poison Cloud, but with palette changes */
+ }
+ AL_4_explosionAspectIndex = AL_4_explosionAspectIndex * 3; /* 3 graphics per explosion pattern */
+ if (AL_2_explosionSize = (explosion->getAttack() >> 5)) {
+ AL_4_explosionAspectIndex++; /* Use second graphic in the pattern for medium explosion attack */
+ if (AL_2_explosionSize > 3) {
+ AL_4_explosionAspectIndex++; /* Use third graphic in the pattern for large explosion attack */
+ }
+ }
+ warning("IGNORED CODE: F0491_CACHE_IsDerivedBitmapInCache");
+ AL_6_bitmapRedBanana = getBitmap(AL_4_explosionAspectIndex + kFirstExplosionPatternGraphicIndice);
+ if (smoke) {
+ blitToBitmapShrinkWithPalChange(AL_6_bitmapRedBanana, 48, 32, _tmpBitmap, 48, 32, gPalChangeSmoke);
+ AL_6_bitmapRedBanana = _tmpBitmap;
+ }
+ blitBoxFilledWithMaskedBitmapToScreen(AL_6_bitmapRedBanana, nullptr, getDerivedBitmap(kDerivedBitmapViewport), gBoxExplosionPattern_D0C,
+ _vm->_rnd->getRandomNumber(4) + 87, _vm->_rnd->getRandomNumber(64),
+ 224, (Color)(kBlitDoNotUseMask | kColorFlesh), 0, 0, 136, 93);
+ warning("IGNORED CODE: F0493_CACHE_AddDerivedBitmap");
+ warning("IGNORED CODE: F0493_CACHE_AddDerivedBitmap");
+ } else {
+ if (rebirthExplosion) {
+ explosionCoordinates = gRebirthStep2ExplosionCoordinates[AL_1_viewSquareExplosionIndex - 3];
+ explosionScale = explosionCoordinates[2];
+ } else {
+ if (explosion->getCentered()) {
+ explosionCoordinates = gCenteredExplosionCoordinates[AL_1_viewSquareExplosionIndex];
+ } else {
+ if ((AL_2_cellPurpleMan == directionParam) || (AL_2_cellPurpleMan == returnPrevVal(directionParam))) {
+ AL_2_viewCell = kViewCellFronLeft;
+ } else {
+ AL_2_viewCell = kViewCellFrontRight;
+ }
+ explosionCoordinates = gExplosionCoordinates[AL_1_viewSquareExplosionIndex][AL_2_viewCell];
+ }
+ explosionScale = MAX(4, (MAX(48, explosion->getAttack() + 1) * gExplosionBaseScales[explosionScaleIndex]) >> 8) & (int16)0xFFFE;
+ }
+ AL_6_bitmapRedBanana = getExplosionBitmap(AL_4_explosionAspectIndex, explosionScale, byteWidth, heightRedEagle);
+T0115200_DrawExplosion:
+ flipVertical = _vm->_rnd->getRandomNumber(2);
+ paddingPixelCount = 0;
+ if (flipHorizontal = _vm->_rnd->getRandomNumber(2)) {
+ paddingPixelCount = (7 - ((byteWidth / 2 - 1) & 0x0007)) << 1; /* Number of unused pixels in the units on the right of the bitmap */
+ }
+ boxByteGreen._y2 = MIN(135, explosionCoordinates[1] + (heightRedEagle >> 1)) + 1;
+ AL_4_yPos = MAX(0, explosionCoordinates[1] - (heightRedEagle >> 1) + !(heightRedEagle & 0x0001));
+ if (AL_4_yPos >= 136)
+ continue;
+ boxByteGreen._y1 = AL_4_yPos;
+ if ((AL_4_xPos = MIN(223, explosionCoordinates[0] + byteWidth)) < 0)
+ continue;
+ boxByteGreen._x2 = AL_4_xPos + 1;
+ AL_4_xPos = explosionCoordinates[0];
+ if (boxByteGreen._x1 = MIN(MAX(0, AL_4_xPos - byteWidth + 1), 223)) {
+ AL_4_xPos = paddingPixelCount;
+ } else {
+/* BUG0_07 Graphical glitch when drawing explosions. If an explosion bitmap is cropped because it is only partly visible on the
+left side of the viewport (boxByteGreen.X1 = 0) and the bitmap is not flipped horizontally (flipHorizontal = C0_FALSE) then the
+variable paddingPixelCount is not set before being used here. Its previous value (defined while drawing something else) is used
+and may cause an incorrect bitmap to be drawn */
+ AL_4_xPos = MIN(paddingPixelCount,(int16)( byteWidth / 2 - AL_4_xPos - 1));
+
+/* BUG0_06 Graphical glitch when drawing projectiles or explosions. If a projectile or explosion bitmap is cropped because it is
+only partly visible on the left side of the viewport (boxByteGreen.X1 = 0) and the bitmap is flipped horizontally (flipHorizontal = C1_TRUE)
+then a wrong part of the bitmap is drawn on screen. To fix this bug, "+ paddingPixelCount" must be added to the second parameter of this function call */
+ }
+ if (boxByteGreen._x2 - 1 <= boxByteGreen._x1)
+ continue;
+ warning("might need M77_NORMALIZED_BYTE_WIDTH");
+ byteWidth = byteWidth;
+ if (flipHorizontal || flipVertical) {
+ memcpy(_tmpBitmap, AL_6_bitmapRedBanana, byteWidth * heightRedEagle);
+ AL_6_bitmapRedBanana = _tmpBitmap;
+ }
+ if (flipHorizontal) {
+ flipBitmapHorizontal(AL_6_bitmapRedBanana, byteWidth, heightRedEagle);
+ }
+ if (flipVertical) {
+ flipBitmapVertical(AL_6_bitmapRedBanana, byteWidth, heightRedEagle);
+ }
+ blitToScreen(AL_6_bitmapRedBanana, byteWidth, AL_4_xPos, 0, boxByteGreen, kColorFlesh, gDungeonViewport);
+ }
+ }
+ } while ((thingParam = dunMan.getNextThing(thingParam)) != Thing::_endOfList);
+/* Fluxcage is an explosion displayed as a field (like teleporters), above all other graphics */
+ if ((fluxcageExplosion != 0) && (doorFrontViewDrawingPass != 1) && !_doNotDrawFluxcagesDuringEndgame) {
+ AL_1_viewSquareExplosionIndex -= 3; /* Convert square index for explosions back to square index */
+ fieldAspect = gFieldAspects[viewSquareIndex];
+ (fieldAspect._nativeBitmapRelativeIndex)++; /* NativeBitmapRelativeIndex is now the index of the Fluxcage field graphic */
+ drawField(&fieldAspect, *(Box*)&gFrameWalls[viewSquareIndex]);
+ }
}
+uint16 DisplayMan::getNormalizedByteWidthM77(uint16 byteWidth) {
+ return (byteWidth + 7) & 0xFFF8;
+}
+
+uint16 DisplayMan::getVerticalOffsetM23(uint16 val) {
+ return (val >> 3) & 0x7;
+}
+uint16 DisplayMan::getHorizontalOffsetM22(uint16 val) {
+ return (val & 0x7);
+}
bool DisplayMan::isDerivedBitmapInCache(int16 derivedBitmapIndex) {
if (_derivedBitmaps == nullptr) {
diff --git a/engines/dm/gfx.h b/engines/dm/gfx.h
index 07a0806ea4..8a116b59c7 100644
--- a/engines/dm/gfx.h
+++ b/engines/dm/gfx.h
@@ -37,6 +37,44 @@
namespace DM {
+/* View lanes */
+#define kViewLaneCenter 0 // @ C0_VIEW_LANE_CENTER
+#define kViewLaneLeft 1 // @ C1_VIEW_LANE_LEFT
+#define kViewLaneRight 2 // @ C2_VIEW_LANE_RIGHT
+
+#define kHalfSizedViewCell_LeftColumn 0 // @ C00_VIEW_CELL_LEFT_COLUMN
+#define kHalfSizedViewCell_RightColumn 1 // @ C01_VIEW_CELL_RIGHT_COLUMN
+#define kHalfSizedViewCell_BackRow 2 // @ C02_VIEW_CELL_BACK_ROW
+#define kHalfSizedViewCell_CenterColumn 3 // @ C03_VIEW_CELL_CENTER_COLUMN
+#define kHalfSizedViewCell_FrontRow 4 // @ C04_VIEW_CELL_FRONT_ROW
+
+/* Shift sets */
+#define kShiftSet_D0BackD1Front 0 // @ C0_SHIFT_SET_D0_BACK_OR_D1_FRONT
+#define kShiftSet_D1BackD2Front 1 // @ C1_SHIFT_SET_D1_BACK_OR_D2_FRONT
+#define kShiftSet_D2BackD3Front 2 // @ C2_SHIFT_SET_D2_BACK_OR_D3_FRONT
+
+#define kCellOrder_DoorFront 0x0008 // @ MASK0x0008_DOOR_FRONT
+#define kCellOrder_Alcove 0x0000 // @ C0000_CELL_ORDER_ALCOVE
+#define kCellOrder_BackLeft 0x0001 // @ C0001_CELL_ORDER_BACKLEFT
+#define kCellOrder_BackRight 0x0002 // @ C0002_CELL_ORDER_BACKRIGHT
+#define kCellOrder_DoorPass1_BackLeft 0x0018 // @ C0018_CELL_ORDER_DOORPASS1_BACKLEFT
+#define kCellOrder_BackLeft_BackRight 0x0021 // @ C0021_CELL_ORDER_BACKLEFT_BACKRIGHT
+#define kCellOrder_DoorPass1_BackRight 0x0028 // @ C0028_CELL_ORDER_DOORPASS1_BACKRIGHT
+#define kCellOrder_BackRight_FrontRight 0x0032 // @ C0032_CELL_ORDER_BACKRIGHT_FRONTRIGHT
+#define kCellOrder_DoorPass2_FrontRight 0x0039 // @ C0039_CELL_ORDER_DOORPASS2_FRONTRIGHT
+#define kCellOrder_BackLeft_FrontLeft 0x0041 // @ C0041_CELL_ORDER_BACKLEFT_FRONTLEFT
+#define kCellOrder_DoorPass2_FrontLeft 0x0049 // @ C0049_CELL_ORDER_DOORPASS2_FRONTLEFT
+#define kCellOrder_DoorPass1_BackRight_BackLeft 0x0128 // @ C0128_CELL_ORDER_DOORPASS1_BACKRIGHT_BACKLEFT
+#define kCellOrder_DoorPass1_BackLeft_BackRight 0x0218 // @ C0218_CELL_ORDER_DOORPASS1_BACKLEFT_BACKRIGHT
+#define kCellOrder_BackLeft_BackRight_FrontRight 0x0321 // @ C0321_CELL_ORDER_BACKLEFT_BACKRIGHT_FRONTRIGHT
+#define kCellOrder_BackRight_FrontLeft_FrontRight 0x0342 // @ C0342_CELL_ORDER_BACKRIGHT_FRONTLEFT_FRONTRIGHT
+#define kCellOrder_DoorPass2_FrontLeft_FrontRight 0x0349 // @ C0349_CELL_ORDER_DOORPASS2_FRONTLEFT_FRONTRIGHT
+#define kCellOrder_BackRight_BackLeft_FrontLeft 0x0412 // @ C0412_CELL_ORDER_BACKRIGHT_BACKLEFT_FRONTLEFT
+#define kCellOrder_BackLeft_FrontRight_FrontLeft 0x0431 // @ C0431_CELL_ORDER_BACKLEFT_FRONTRIGHT_FRONTLEFT
+#define kCellOrder_DoorPass2_FrontRight_FrontLeft 0x0439 // @ C0439_CELL_ORDER_DOORPASS2_FRONTRIGHT_FRONTLEFT
+#define kCellOrder_BackLeft_BackRight_FrontLeft_FrontRight 0x3421 // @ C3421_CELL_ORDER_BACKLEFT_BACKRIGHT_FRONTLEFT_FRONTRIGHT
+#define kCellOrder_BackRight_BackLeft_FrontRight_FrontLeft 0x4312 // @ C4312_CELL_ORDER_BACKRIGHT_BACKLEFT_FRONTRIGHT_FRONTLEFT
+
#define kFloorSetGraphicCount 2 // @ C002_FLOOR_SET_GRAPHIC_COUNT
#define kWallSetGraphicCount 13 // @ C013_WALL_SET_GRAPHIC_COUNT
@@ -167,7 +205,11 @@ enum GraphicIndice {
kFloorOrn_15_D3L_footprints = 241, // @ C241_GRAPHIC_FLOOR_ORNAMENT_15_D3L_FOOTPRINTS
kFieldMask_D3R_GraphicIndice = 69, // @ C069_GRAPHIC_FIELD_MASK_D3R
kFieldTeleporterGraphicIndice = 73, // @ C073_GRAPHIC_FIELD_TELEPORTER
- kFirstExplosionGraphicIndice = 348 // @ C348_GRAPHIC_FIRST_EXPLOSION
+ kFirstExplosionGraphicIndice = 348, // @ C348_GRAPHIC_FIRST_EXPLOSION
+ kFirstObjectGraphicIndice = 360, // @ C360_GRAPHIC_FIRST_OBJECT
+ kFirstCreatureGraphicIndice = 446, // @ C446_GRAPHIC_FIRST_CREATURE
+ kFirstProjectileGraphicIndice = 316, // @ C316_GRAPHIC_FIRST_PROJECTILE
+ kFirstExplosionPatternGraphicIndice = 351 // @ C351_GRAPHIC_FIRST_EXPLOSION_PATTERN
};
extern uint16 gPalSwoosh[16];
@@ -284,6 +326,7 @@ public:
FieldAspect(uint16 native, uint16 base, uint16 transparent, byte mask, uint16 byteWidth, uint16 height, uint16 xPos, uint16 bitplane)
: _nativeBitmapRelativeIndex(native), _baseStartUnitIndex(base), _transparentColor(transparent), _mask(mask),
_pixelWidth(byteWidth * 2), _height(height), _xPos(xPos), _bitplaneWordCount(bitplane) {}
+ FieldAspect() {}
}; // @ FIELD_ASPECT
@@ -455,7 +498,7 @@ public:
int16 xPos, int16 yPos, int16 destHeight, int16 height2, Viewport &viewport = gDefultViewPort); // @ F0133_VIDEO_BlitBoxFilledWithMaskedBitmap
void blitBoxFilledWithMaskedBitmapToScreen(byte *src, byte *mask, byte *tmp, Box &box, int16 lastUnitIndex,
int16 firstUnitIndex, int16 destPixelWidth, Color transparent,
- int16 xPos, int16 yPos, int16 height2, Viewport &viewport = gDungeonViewport); // @ F0133_VIDEO_BlitBoxFilledWithMaskedBitmap
+ int16 xPos, int16 yPos, int16 destHeight, int16 height2, Viewport &viewport = gDungeonViewport); // @ F0133_VIDEO_BlitBoxFilledWithMaskedBitmap
void flipBitmapHorizontal(byte *bitmap, uint16 width, uint16 height);
void flipBitmapVertical(byte *bitmap, uint16 width, uint16 height);
@@ -473,9 +516,12 @@ public:
int16 getScaledBitmapPixelCount(int16 pixelWidth, int16 pixelHeight, int16 scale); // @ F0459_START_GetScaledBitmapByteCount
int16 getScaledDimension(int16 dimension, int16 scale); // @ M78_SCALED_DIMENSION
- void drawObjectsCreaturesProjectilesExplosions(Thing thingParam, direction directionParam,
+ void cthulhu(Thing thingParam, direction directionParam,
int16 mapXpos, int16 mapYpos, int16 viewSquareIndex,
uint16 orderedViewCellOrdinals); // @ F0115_DUNGEONVIEW_DrawObjectsCreaturesProjectilesExplosions_CPSEF
+ uint16 getNormalizedByteWidthM77(uint16 byteWidth); // @ M77_NORMALIZED_BYTE_WIDTH
+ uint16 getVerticalOffsetM23(uint16 val); // @ M23_VERTICAL_OFFSET
+ uint16 getHorizontalOffsetM22(uint16 val); // @ M22_HORIZONTAL_OFFSET
int16 _championPortraitOrdinal; // @ G0289_i_DungeonView_ChampionPortraitOrdinal
int16 _currMapAlcoveOrnIndices[kAlcoveOrnCount]; // @ G0267_ai_CurrentMapAlcoveOrnamentIndices
diff --git a/engines/dm/group.h b/engines/dm/group.h
index 49ec009d94..0c2233dcb7 100644
--- a/engines/dm/group.h
+++ b/engines/dm/group.h
@@ -82,6 +82,10 @@ enum CreatureType {
#define kMaskCreatureInfo_archenemy 0x2000 // @ MASK0x2000_ARCHENEMY
#define kMaskCreatureInfo_magicmap 0x4000 // @ MASK0x4000_MAGICMAP
+
+#define kMaskActiveGroupFlipBitmap 0x0040 // @ MASK0x0040_FLIP_BITMAP
+#define kMaskActiveGroupIsAttacking 0x0080 // @ MASK0x0080_IS_ATTACKING
+
class ActiveGroup {
public:
int _groupThingIndex;