Example #1
0
void UserInterface::inventoryAnim() {
	Scene &scene = _vm->_game->_scene;
	if (_vm->_game->_screenObjects._inputMode == kInputConversation ||
			_vm->_game->_screenObjects._inputMode == kInputLimitedSentences ||
			_invSpritesIndex < 0)
		return;

	// Move to the next frame number in the sequence, resetting if at the end
	SpriteAsset *asset = scene._sprites[_invSpritesIndex];
	if (++_invFrameNumber > asset->getCount())
		_invFrameNumber = 1;

	// Loop through the slots list for inventory animation entry
	for (uint i = 0; i < _uiSlots.size(); ++i) {
		if (_uiSlots[i]._segmentId == IMG_SPINNING_OBJECT)
			_uiSlots[i]._flags = IMG_FULL_UPDATE;
	}

	// Add a new slot entry for the inventory animation
	UISlot slot;
	slot._flags = IMG_UPDATE;
	slot._segmentId = IMG_SPINNING_OBJECT;
	slot._frameNumber = _invFrameNumber;
	slot._spritesIndex = _invSpritesIndex;
	slot._position = Common::Point(160, 3);

	_uiSlots.push_back(slot);
}
Example #2
0
int MadsSpriteSlots::addSprites(const char *resName, bool suppressErrors, int flags) {
	// If errors are suppressed, first check if the resource exists
	if (suppressErrors) {
		if (!_vm->res()->resourceExists(resName))
			return -1;
	}

	// Append on a '.SS' suffix if the resource doesn't already have an extension
	char buffer[100];
	strncpy(buffer, resName, 95);
	buffer[95] = '\0';
	if (!strchr(buffer, '.'))
		strcat(buffer, ".SS");

	// Get the sprite set
	Common::SeekableReadStream *data = _vm->res()->get(buffer);
	SpriteAsset *spriteSet = new SpriteAsset(_vm, data, data->size(), buffer, false, flags);
	spriteSet->translate(_madsVm->_palette);
	assert(spriteSet != NULL);

	_sprites.push_back(spriteSet);
	_vm->res()->toss(buffer);

	return _sprites.size() - 1;
}
Example #3
0
void SpriteSlots::drawBackground() {
	Scene &scene = _vm->_game->_scene;

	// Initial draw loop for any active sprites in the background
	for (uint i = 0; i < size(); ++i) {
		SpriteSlot &spriteSlot = (*this)[i];
		DirtyArea &dirtyArea = scene._dirtyAreas[i];

		if (spriteSlot._flags >= IMG_STATIC) {
			// Foreground sprite, so we can ignore it
			dirtyArea._active = false;
		} else {
			dirtyArea._active = true;
			dirtyArea.setSpriteSlot(&spriteSlot);

			if (spriteSlot._flags == IMG_DELTA) {
				// Background object, so need to draw it
				assert(spriteSlot._frameNumber > 0);
				SpriteAsset *asset = scene._sprites[spriteSlot._spritesIndex];
				MSprite *frame = asset->getFrame(spriteSlot._frameNumber - 1);

				Common::Point pt = spriteSlot._position;
				if (spriteSlot._scale != -1) {
					// Adjust the drawing position
					pt.x -= frame->w / 2;
					pt.y -= frame->h - 1;
				}

				if (spriteSlot._depth <= 1) {
					scene._backgroundSurface.transBlitFrom(*frame, pt, frame->getTransparencyIndex());
				} else if (scene._depthStyle == 0) {
					scene._backgroundSurface.copyFrom(*frame, pt, spriteSlot._depth, &scene._depthSurface,
						-1, false, frame->getTransparencyIndex());
				} else {
					scene._backgroundSurface.transBlitFrom(*frame, pt, frame->getTransparencyIndex());
				}
			}
		}
	}

	// Mark any remaning sprite slot dirty areas as inactive
	for (uint i = size(); i < SPRITE_SLOTS_MAX_SIZE; ++i)
		scene._dirtyAreas[i]._active = false;

	// Flag any active text display
	for (uint i = 0; i < scene._textDisplay.size(); ++i) {
		TextDisplay &textDisplay = scene._textDisplay[i];
		DirtyArea &dirtyArea = scene._dirtyAreas[i + SPRITE_SLOTS_MAX_SIZE];

		if (textDisplay._expire >= 0 || !textDisplay._active) {
			dirtyArea._active = false;
		} else {
			dirtyArea._active = true;
			dirtyArea.setTextDisplay(&textDisplay);
		}
	}
}
Example #4
0
bool Console::cmdShowSprite(int argc, const char **argv) {
	View *view = _vm->_viewManager->getView(VIEWID_SCENE);
	if (view == NULL)
		DebugPrintf("The scene view isn't currently active\n");
	else if (argc < 2)
		DebugPrintf("Usage: %s resource_name\n", argv[0]);
	else {
		char resourceName[20];
		strncpy(resourceName, argv[1], 15);
		resourceName[15] = '\0';
		if (!strchr(resourceName, '.'))
			strcat(resourceName, ".SS");

		_vm->_viewManager->moveToFront(view);
		Common::SeekableReadStream *data = _vm->res()->get(resourceName);
		SpriteAsset *asset = new SpriteAsset(_vm, data, data->size(), resourceName);
		_vm->res()->toss(resourceName);

		RGBList *palData = new RGBList(asset->getColorCount(), asset->getPalette(), true);
		_vm->_palette->addRange(palData);

		// Get the scene background surface
		M4Surface *bg = _vm->_scene->getBackgroundSurface();

		// Write the sprite onto the screen
		int x = 0, y = 0, yMax = 0;
		for (int index = 0; index < asset->getCount(); index++) {
			M4Sprite *spr = asset->getFrame(index);
			spr->translate(palData);		// sprite pixel translation

			if ((x + spr->width() >= bg->width()) && (yMax != 0)) {
				x = 0;
				y += yMax;
				yMax = 0;
			}

			if (y >= bg->height())
				break;

			// FIXME: We assume that the transparent color is the color of the top left pixel
			byte *transparentColor = (byte *)spr->pixels;

			spr->copyTo(bg, x, y, (int)*transparentColor);

			x += spr->width();
			yMax = MAX(yMax, spr->height());
		}

		view->restore(0, 0, view->width(), view->height());
		return false;
	}

	return true;
}
Example #5
0
void DirtyArea::setUISlot(const UISlot *slot) {
	int type = slot->_flags;
	if (type <= IMG_UPDATE_ONLY)
		type += -IMG_UPDATE_ONLY;
	if (type >= 0x40)
		type &= ~0x40;

	MSurface &intSurface = _vm->_game->_scene._userInterface;
	switch (type) {
	case IMG_REFRESH:
		_bounds.left = 0;
		_bounds.top = 0;
		setArea(intSurface.w, intSurface.h, intSurface.w, intSurface.h);
		break;

	case IMG_OVERPRINT:
		_bounds.left = slot->_position.x;
		_bounds.top = slot->_position.y;
		_bounds.setWidth(slot->_width);
		_bounds.setHeight(slot->_height);
		setArea(slot->_width, slot->_height, intSurface.w, intSurface.h);
		break;

	default: {
		SpriteAsset *asset = _vm->_game->_scene._sprites[slot->_spritesIndex];
		MSprite *frame = asset->getFrame(slot->_frameNumber - 1);
		int w = frame->w;
		int h = frame->h;

		if (slot->_segmentId == IMG_SPINNING_OBJECT) {
			_bounds.left = slot->_position.x;
			_bounds.top = slot->_position.y;
		} else {
			_bounds.left = slot->_position.x + w / 2;
			_bounds.top = slot->_position.y - h + 1;
		}

		setArea(w, h, intSurface.w, intSurface.h);
		break;
	}
	}
}
Example #6
0
void UISlots::draw(bool updateFlag, bool delFlag) {
	Scene &scene = _vm->_game->_scene;
	UserInterface &userInterface = scene._userInterface;
	DirtyArea *dirtyAreaPtr = nullptr;

	// Loop through setting up the dirty areas
	for (uint idx = 0; idx < size(); ++idx) {
		DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];
		UISlot &slot = (*this)[idx];

		if (slot._flags >= IMG_STATIC) {
			dirtyArea._active = false;
		} else {
			dirtyArea.setUISlot(&slot);
			dirtyArea._textActive = true;
			if (slot._segmentId == IMG_SPINNING_OBJECT && slot._flags == IMG_FULL_UPDATE) {
				dirtyArea._active = false;
				dirtyAreaPtr = &dirtyArea;
			}
		}
	}

	userInterface._dirtyAreas.merge(1, userInterface._uiSlots.size());
	if (dirtyAreaPtr)
		dirtyAreaPtr->_active = true;

	// Copy parts of the user interface background that need to be erased
	for (uint idx = 0; idx < size(); ++idx) {
		DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];
		UISlot &slot = (*this)[idx];

		if (dirtyArea._active && dirtyArea._bounds.width() > 0
				&& dirtyArea._bounds.height() > 0 && slot._flags > -20) {

			if (slot._flags >= IMG_ERASE) {
				// Merge area
				userInterface.mergeFrom(&userInterface._surface, dirtyArea._bounds,
					Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top));
			} else {
				// Copy area
				userInterface._surface.copyTo(&userInterface, dirtyArea._bounds,
					Common::Point(dirtyArea._bounds.left, dirtyArea._bounds.top));
			}
		}
	}

	for (uint idx = 0; idx < size(); ++idx) {
		DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];
		UISlot &slot = (*this)[idx];

		int slotType = slot._flags;
		if (slotType >= IMG_STATIC) {
			dirtyArea.setUISlot(&slot);
			if (!updateFlag)
				slotType &= ~0x40;

			dirtyArea._textActive = slotType > 0;
			slot._flags &= 0x40;
		}
	}

	userInterface._dirtyAreas.merge(1, userInterface._uiSlots.size());

	for (uint idx = 0; idx < size(); ++idx) {
		DirtyArea *dirtyArea = &userInterface._dirtyAreas[idx];
		UISlot &slot = (*this)[idx];

		if (slot._flags >= IMG_STATIC && !(slot._flags & 0x40)) {
			if (!dirtyArea->_active) {
				do {
					dirtyArea = dirtyArea->_mergedArea;
				} while (!dirtyArea->_active);
			}

			if (dirtyArea->_textActive) {
				SpriteAsset *asset = scene._sprites[slot._spritesIndex];

				// Get the frame details
				int frameNumber = ABS(slot._frameNumber);
				bool flipped = slot._frameNumber < 0;

				if (slot._segmentId == IMG_SPINNING_OBJECT) {
					MSprite *sprite = asset->getFrame(frameNumber - 1);
					sprite->copyTo(&userInterface, slot._position,
						sprite->getTransparencyIndex());
				} else {
					MSprite *sprite = asset->getFrame(frameNumber - 1);

					if (flipped) {
						MSurface *spr = sprite->flipHorizontal();
						userInterface.mergeFrom(spr, spr->getBounds(), slot._position,
							sprite->getTransparencyIndex());
						delete spr;
					} else {
						userInterface.mergeFrom(sprite, sprite->getBounds(), slot._position,
							sprite->getTransparencyIndex());
					}
				}
			}
		}
	}

	// Mark areas of the screen surface for updating
	if (updateFlag) {
		for (uint idx = 0; idx < size(); ++idx) {
			DirtyArea &dirtyArea = userInterface._dirtyAreas[idx];

			if (dirtyArea._active && dirtyArea._textActive &&
				dirtyArea._bounds.width() > 0 && dirtyArea._bounds.height() > 0) {
				// Flag area of screen as needing update
				Common::Rect r = dirtyArea._bounds;
				r.translate(0, scene._interfaceY);
				_vm->_screen.copyRectToScreen(r);
			}
		}
	}

	// Post-processing to remove slots no longer needed
	for (int idx = (int)size() - 1; idx >= 0; --idx) {
		UISlot &slot = (*this)[idx];

		if (slot._flags < IMG_STATIC) {
			if (delFlag || updateFlag)
				remove_at(idx);
			else if (slot._flags > -20)
				slot._flags -= 20;
		} else {
			if (updateFlag)
				slot._flags &= ~0x40;
			else
				slot._flags |= 0x40;
		}
	}
}
Example #7
0
// TODO: calculate width and height, show text, show face if it exists
// TODO: this has been tested with Dragonsphere only, there are some differences
// in the sprites used in Phantom
void MadsScene::showMADSV2TextBox(char *text, int x, int y, char *faceName) {
	int repeatX = 40;	// FIXME: this is hardcoded
	int repeatY = 30;	// FIXME: this is hardcoded
	int curX = x, curY = y;
	int topRightX = x;	// TODO: this is probably not needed
	Common::SeekableReadStream *data = _vm->res()->get("box.ss");
	SpriteAsset *boxSprites = new SpriteAsset(_vm, data, data->size(), "box.ss");
	_vm->res()->toss("box.ss");

	RGBList *palData = new RGBList(boxSprites->getColorCount(), boxSprites->getPalette(), true);
	_vm->_palette->addRange(palData);

	for (int i = 0; i < boxSprites->getCount(); i++)
		boxSprites->getFrame(i)->translate(palData);		// sprite pixel translation

	// Top left corner
	boxSprites->getFrame(topLeft)->copyTo(_backgroundSurface, x, curY);
	curX += boxSprites->getFrame(topLeft)->width();

	// Top line
	for (int i = 0; i < repeatX; i++) {
		boxSprites->getFrame(top)->copyTo(_backgroundSurface, curX, curY + 3);
		curX += boxSprites->getFrame(top)->width();
	}

	// Top right corner
	boxSprites->getFrame(topRight)->copyTo(_backgroundSurface, curX, curY);
	topRightX = curX;

	// Top middle
	// FIXME: the transparent color for this is also the black border color
	boxSprites->getFrame(topMiddle)->copyTo(_backgroundSurface,
											x + (curX - x) / 2 - boxSprites->getFrame(topMiddle)->width() / 2,
											curY - 5, 167);
	curX = x;
	curY += boxSprites->getFrame(topLeft)->height();

	// -----------------------------------------------------------------------------------------------

	// Draw contents
	for (int i = 0; i < repeatY; i++) {
		for (int j = 0; j < repeatX; j++) {
			if (j == 0) {
				boxSprites->getFrame(left)->copyTo(_backgroundSurface, curX + 3, curY);
				curX += boxSprites->getFrame(left)->width();
			} else if (j == repeatX - 1) {
				curX = topRightX - 2;
				boxSprites->getFrame(right)->copyTo(_backgroundSurface, curX + 3, curY + 1);
			} else {
				// TODO: the background of the contents follows a pattern which is not understood yet
				if (j % 2 == 0) {
					boxSprites->getFrame(filler1)->copyTo(_backgroundSurface, curX + 3, curY);
					curX += boxSprites->getFrame(filler1)->width();
				} else {
					boxSprites->getFrame(filler2)->copyTo(_backgroundSurface, curX + 3, curY);
					curX += boxSprites->getFrame(filler2)->width();
				}
			}
		}	// for j
		curX = x;
		curY += boxSprites->getFrame(left)->height();
	}	// for i

	// -----------------------------------------------------------------------------------------------
	curX = x;

	// Bottom left corner
	boxSprites->getFrame(bottomLeft)->copyTo(_backgroundSurface, curX, curY);
	curX += boxSprites->getFrame(bottomLeft)->width();

	// Bottom line
	for (int i = 0; i < repeatX; i++) {
		boxSprites->getFrame(bottom)->copyTo(_backgroundSurface, curX, curY + 1);
		curX += boxSprites->getFrame(bottom)->width();
	}

	// Bottom right corner
	boxSprites->getFrame(bottomRight)->copyTo(_backgroundSurface, curX, curY + 1);
}
Example #8
0
void Player::update() {
	Scene &scene = _vm->_game->_scene;

	if (_forceRefresh || (_visible != _priorVisible)) {
		int slotIndex = getSpriteSlot();
		if (slotIndex >= 0)
			scene._spriteSlots[slotIndex]._flags = IMG_ERASE;

		int newDepth = 1;
		int yp = MIN(_playerPos.y, (int16)(MADS_SCENE_HEIGHT - 1));

		for (int idx = 1; idx < DEPTH_BANDS_SIZE; ++idx) {
			if (scene._sceneInfo->_depthList[newDepth] >= yp)
				newDepth = idx + 1;
		}
		_currentDepth = newDepth;

		// Get the scale
		int newScale = getScale(_playerPos.y);
		_currentScale = MIN(newScale, 100);

		if (_visible) {
			// Player sprite needs to be rendered
			SpriteSlot slot;
			slot._flags = IMG_UPDATE;
			slot._seqIndex = PLAYER_SEQ_INDEX;
			slot._spritesIndex = _spritesStart + _spritesIdx;
			slot._frameNumber = _mirror ? -_frameNumber : _frameNumber;
			slot._position.x = _playerPos.x;
			slot._position.y = _playerPos.y + (_centerOfGravity * newScale) / 100;
			slot._depth = newDepth;
			slot._scale = newScale;

			if (slotIndex >= 0) {
				// Check if the existing player slot has the same details, and can be re-used
				SpriteSlot &s2 = scene._spriteSlots[slotIndex];
				bool equal = (s2._seqIndex == slot._seqIndex)
					&& (s2._spritesIndex == slot._spritesIndex)
					&& (s2._frameNumber == slot._frameNumber)
					&& (s2._position == slot._position)
					&& (s2._depth == slot._depth)
					&& (s2._scale == slot._scale);

				if (equal)
					// Undo the prior expiry of the player sprite
					s2._flags = IMG_STATIC;
				else
					slotIndex = -1;
			}

			if (slotIndex < 0) {
				// New slot needed, so allocate one and copy the slot data
				slotIndex = scene._spriteSlots.add();
				scene._spriteSlots[slotIndex] = slot;
			}

			// If changing a scene, check to change the scene when the player
			// has moved off-screen
			if (_walkOffScreen) {
				SpriteAsset *asset = scene._sprites[slot._spritesIndex];
				MSprite *frame = asset->getFrame(_frameNumber - 1);
				int xScale = frame->w * newScale / 200;
				int yScale = frame->h * newScale / 100;
				int playerX = slot._position.x;
				int playerY = slot._position.y;

				if ((playerX + xScale) < 0 || (playerX + xScale) >= MADS_SCREEN_WIDTH ||
						playerY < 0 || (playerY + yScale) >= MADS_SCENE_HEIGHT) {
					scene._nextSceneId = _walkOffScreen;
					_walkOffScreen = 0;
					_walkAnywhere = false;
				}
			}

		}
	}

	_beenVisible |= _visible;
	_priorVisible = _visible;
	_forceRefresh = false;
}