mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
1125 lines
29 KiB
C++
1125 lines
29 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "engines/stark/resources/item.h"
|
|
|
|
#include "engines/stark/formats/xrc.h"
|
|
#include "engines/stark/gfx/renderentry.h"
|
|
#include "engines/stark/model/animhandler.h"
|
|
#include "engines/stark/movement/movement.h"
|
|
#include "engines/stark/visual/actor.h"
|
|
|
|
#include "engines/stark/resources/anim.h"
|
|
#include "engines/stark/resources/animhierarchy.h"
|
|
#include "engines/stark/resources/bonesmesh.h"
|
|
#include "engines/stark/resources/bookmark.h"
|
|
#include "engines/stark/resources/floor.h"
|
|
#include "engines/stark/resources/floorface.h"
|
|
#include "engines/stark/resources/knowledgeset.h"
|
|
#include "engines/stark/resources/location.h"
|
|
#include "engines/stark/resources/pattable.h"
|
|
#include "engines/stark/resources/script.h"
|
|
#include "engines/stark/resources/textureset.h"
|
|
|
|
#include "engines/stark/services/global.h"
|
|
#include "engines/stark/services/services.h"
|
|
#include "engines/stark/services/stateprovider.h"
|
|
#include "engines/stark/services/userinterface.h"
|
|
#include "engines/stark/services/settings.h"
|
|
|
|
namespace Stark {
|
|
namespace Resources {
|
|
|
|
Object *Item::construct(Object *parent, byte subType, uint16 index, const Common::String &name) {
|
|
switch (subType) {
|
|
case kItemGlobalTemplate:
|
|
return new GlobalItemTemplate(parent, subType, index, name);
|
|
case kItemInventory:
|
|
return new InventoryItem(parent, subType, index, name);
|
|
case kItemLevelTemplate:
|
|
return new LevelItemTemplate(parent, subType, index, name);
|
|
case kItemStaticProp:
|
|
case kItemAnimatedProp:
|
|
return new FloorPositionedImageItem(parent, subType, index, name);
|
|
case kItemBackgroundElement:
|
|
case kItemBackground:
|
|
return new ImageItem(parent, subType, index, name);
|
|
case kItemModel:
|
|
return new ModelItem(parent, subType, index, name);
|
|
default:
|
|
error("Unknown item subtype %d", subType);
|
|
}
|
|
}
|
|
|
|
Item::Item(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
Object(parent, subType, index, name),
|
|
_enabled(true),
|
|
_characterIndex(0),
|
|
_movement(nullptr),
|
|
_movementSuspendedScript(nullptr) {
|
|
_type = TYPE;
|
|
}
|
|
|
|
Item::~Item() {
|
|
delete _movement;
|
|
}
|
|
|
|
void Item::readData(Formats::XRCReadStream *stream) {
|
|
_enabled = stream->readBool();
|
|
_characterIndex = stream->readSint32LE();
|
|
}
|
|
|
|
void Item::onGameLoop() {
|
|
Object::onGameLoop();
|
|
|
|
if (_enabled && _movement) {
|
|
_movement->onGameLoop();
|
|
|
|
if (_movement && _movement->hasEnded()) {
|
|
setMovement(nullptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Item::isEnabled() const {
|
|
return _enabled;
|
|
}
|
|
|
|
void Item::setEnabled(bool enabled) {
|
|
if (_enabled && !enabled) {
|
|
setMovement(nullptr);
|
|
}
|
|
|
|
_enabled = enabled;
|
|
}
|
|
|
|
int32 Item::getCharacterIndex() const {
|
|
return _characterIndex;
|
|
}
|
|
|
|
Gfx::RenderEntry *Item::getRenderEntry(const Common::Point &positionOffset) {
|
|
return nullptr;
|
|
}
|
|
|
|
Movement *Item::getMovement() const {
|
|
return _movement;
|
|
}
|
|
|
|
void Item::setMovement(Movement *movement) {
|
|
if (_movementSuspendedScript) {
|
|
if (_movement && _movement->hasReachedDestination()) {
|
|
_movementSuspendedScript->setResumeStatus(Script::kResumeComplete);
|
|
} else {
|
|
_movementSuspendedScript->setResumeStatus(Script::kResumeAbort);
|
|
}
|
|
_movementSuspendedScript = nullptr;
|
|
}
|
|
|
|
if (_movement && !_movement->hasEnded()) {
|
|
_movement->stop(true);
|
|
}
|
|
|
|
delete _movement;
|
|
_movement = movement;
|
|
}
|
|
|
|
void Item::setMovementSuspendedScript(Script *script) {
|
|
_movementSuspendedScript = script;
|
|
}
|
|
|
|
void Item::printData() {
|
|
debug("enabled: %d", _enabled);
|
|
debug("character: %d", _characterIndex);
|
|
}
|
|
|
|
void Item::saveLoad(ResourceSerializer *serializer) {
|
|
serializer->syncAsSint32LE(_enabled);
|
|
}
|
|
|
|
void Item::saveLoadCurrent(ResourceSerializer *serializer) {
|
|
bool hasMovement = _movement != nullptr && !_movement->hasEnded();
|
|
serializer->syncAsUint32LE(hasMovement, 8);
|
|
|
|
if (hasMovement) {
|
|
uint32 movementType = _movement != nullptr ? _movement->getType() : 0;
|
|
serializer->syncAsUint32LE(movementType);
|
|
|
|
if (serializer->isLoading()) {
|
|
_movement = Movement::construct(movementType, Object::cast<ItemVisual>(this));
|
|
}
|
|
|
|
_movement->saveLoad(serializer);
|
|
serializer->syncAsResourceReference(&_movementSuspendedScript);
|
|
|
|
if (serializer->isLoading()) {
|
|
_movement->start();
|
|
}
|
|
}
|
|
}
|
|
|
|
Common::Array<Common::Point> Item::listExitPositions() {
|
|
return Common::Array<Common::Point>();
|
|
}
|
|
|
|
ItemVisual::~ItemVisual() {
|
|
delete _renderEntry;
|
|
}
|
|
|
|
ItemVisual::ItemVisual(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
Item(parent, subType, index, name),
|
|
_renderEntry(nullptr),
|
|
_actionAnim(nullptr),
|
|
_animHierarchy(nullptr),
|
|
_currentAnimActivity(-1),
|
|
_clickable(true) {
|
|
_renderEntry = new Gfx::RenderEntry(this, getName());
|
|
}
|
|
|
|
void ItemVisual::readData(Formats::XRCReadStream *stream) {
|
|
Item::readData(stream);
|
|
|
|
_clickable = stream->readBool();
|
|
}
|
|
|
|
void ItemVisual::onAllLoaded() {
|
|
Item::onAllLoaded();
|
|
|
|
_animHierarchy = findChild<AnimHierarchy>(false);
|
|
|
|
_renderEntry->setClickable(_clickable);
|
|
|
|
if (_subType != kItemModel) {
|
|
setAnimActivity(Anim::kActionUsagePassive);
|
|
}
|
|
|
|
if (!_enabled) {
|
|
setEnabled(false);
|
|
}
|
|
|
|
Location *location = findParent<Location>();
|
|
if (location) {
|
|
location->registerCharacterItem(_characterIndex, this);
|
|
}
|
|
}
|
|
|
|
void ItemVisual::saveLoad(ResourceSerializer *serializer) {
|
|
Item::saveLoad(serializer);
|
|
|
|
serializer->syncAsSint32LE(_currentAnimActivity);
|
|
|
|
serializer->syncAsResourceReference(&_animHierarchy);
|
|
if (serializer->isLoading() && _animHierarchy) {
|
|
setAnimHierarchy(_animHierarchy);
|
|
}
|
|
|
|
serializer->syncAsResourceReference(&_actionAnim);
|
|
if (serializer->isLoading()) {
|
|
if (_actionAnim) {
|
|
_actionAnim->applyToItem(this);
|
|
} else {
|
|
setAnimActivity(_currentAnimActivity);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ItemVisual::saveLoadCurrent(ResourceSerializer *serializer) {
|
|
Item::saveLoadCurrent(serializer);
|
|
|
|
// Apply the animation once again now the data from the item templates has been loaded.
|
|
// This ensures template level textures and models are applied when loading.
|
|
|
|
serializer->syncAsSint32LE(_currentAnimActivity, 11);
|
|
serializer->syncAsResourceReference(&_animHierarchy, 11);
|
|
if (serializer->isLoading()) {
|
|
if (_animHierarchy) {
|
|
setAnimHierarchy(_animHierarchy);
|
|
}
|
|
}
|
|
|
|
serializer->syncAsResourceReference(&_actionAnim, 11);
|
|
if (serializer->isLoading()) {
|
|
if (_actionAnim) {
|
|
_actionAnim->applyToItem(this);
|
|
} else {
|
|
setAnimActivity(_currentAnimActivity);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ItemVisual::setEnabled(bool enabled) {
|
|
Item::setEnabled(enabled);
|
|
|
|
if (enabled) {
|
|
// If an action animation was selected while the item was disabled,
|
|
// honor it. This is not what the original engine did, but seems
|
|
// logical and fixes the Gribbler hurting animation in the forest.
|
|
if (!_actionAnim) {
|
|
_animHierarchy->selectItemAnim(this);
|
|
}
|
|
} else {
|
|
resetActionAnim();
|
|
_animHierarchy->unselectItemAnim(this);
|
|
}
|
|
}
|
|
|
|
ItemVisual *ItemVisual::getSceneInstance() {
|
|
return this;
|
|
}
|
|
|
|
int32 ItemVisual::getAnimActivity() const {
|
|
return _currentAnimActivity;
|
|
}
|
|
|
|
void ItemVisual::setAnimActivity(int32 activity) {
|
|
bool animNeedsUpdate = activity != _currentAnimActivity || _actionAnim != nullptr || _animHierarchy->getCurrentAnim() == nullptr;
|
|
|
|
resetActionAnim();
|
|
|
|
_currentAnimActivity = activity;
|
|
if (animNeedsUpdate && _animHierarchy) {
|
|
_animHierarchy->setItemAnim(this, activity);
|
|
}
|
|
}
|
|
|
|
void ItemVisual::printData() {
|
|
Item::printData();
|
|
|
|
debug("clickable: %d", _clickable);
|
|
}
|
|
|
|
Anim *ItemVisual::getAnim() const {
|
|
if (_actionAnim) {
|
|
return _actionAnim;
|
|
}
|
|
|
|
return _animHierarchy->getCurrentAnim();
|
|
}
|
|
|
|
Anim *ItemVisual::getActionAnim() const {
|
|
return _actionAnim;
|
|
}
|
|
|
|
void ItemVisual::setAnimHierarchy(AnimHierarchy *animHierarchy) {
|
|
resetActionAnim();
|
|
|
|
if (_animHierarchy) {
|
|
_animHierarchy->unselectItemAnim(this);
|
|
}
|
|
|
|
_animHierarchy = animHierarchy;
|
|
}
|
|
|
|
Visual *ItemVisual::getVisual() {
|
|
Anim *anim = getAnim();
|
|
|
|
if (!anim) {
|
|
return nullptr;
|
|
}
|
|
|
|
return anim->getVisual();
|
|
}
|
|
|
|
int ItemVisual::getHotspotIndexForPoint(const Common::Point &point) {
|
|
Anim *anim = getAnim();
|
|
if (anim) {
|
|
return anim->getPointHotspotIndex(point);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
bool ItemVisual::canPerformAction(uint32 action, uint32 hotspotIndex) {
|
|
PATTable *table = findChildWithOrder<PATTable>(hotspotIndex);
|
|
return table && table->canPerformAction(action);
|
|
}
|
|
|
|
bool ItemVisual::doAction(uint32 action, uint32 hotspotIndex) {
|
|
PATTable *table = findChildWithOrder<PATTable>(hotspotIndex);
|
|
if (table && table->canPerformAction(action)) {
|
|
return table->runScriptForAction(action);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ItemVisual::playActionAnim(Anim *anim) {
|
|
resetActionAnim();
|
|
|
|
_animHierarchy->unselectItemAnim(this);
|
|
_actionAnim = anim;
|
|
anim->applyToItem(this);
|
|
anim->playAsAction(this);
|
|
}
|
|
|
|
void ItemVisual::resetActionAnim() {
|
|
if (_actionAnim) {
|
|
_actionAnim->removeFromItem(this);
|
|
_actionAnim = nullptr;
|
|
|
|
// TODO: Add a condition to this?
|
|
_animHierarchy->selectItemAnim(this);
|
|
if (_subType == kItemModel) {
|
|
_animHierarchy->setItemAnim(this, Anim::kActorActivityIdle);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ItemVisual::setPosition2D(const Common::Point &position) {
|
|
warning("ItemVisual::setPosition2D is not implemented for this item type: %d (%s)", _subType, _name.c_str());
|
|
}
|
|
|
|
Common::String ItemVisual::getHotspotTitle(uint32 hotspotIndex) {
|
|
PATTable *table = findChildWithOrder<PATTable>(hotspotIndex);
|
|
Common::String title;
|
|
if (table) {
|
|
title = table->getName();
|
|
} else {
|
|
title = getName();
|
|
}
|
|
|
|
if (title.equalsIgnoreCase("Default April PAT")) {
|
|
return "April"; // The same hack exists in the original
|
|
}
|
|
|
|
return title;
|
|
}
|
|
|
|
Common::Array<Common::Point> ItemVisual::listExitPositionsImpl() {
|
|
Common::Array<PATTable *> pattables = listChildrenRecursive<PATTable>();
|
|
|
|
Common::Array<Common::Point> positions;
|
|
Common::Point invalidPosition(-1, -1);
|
|
|
|
for (uint i = 0; i < pattables.size(); ++i) {
|
|
if (pattables[i]->getDefaultAction() != PATTable::kActionExit) continue;
|
|
|
|
Anim *anim = getAnim();
|
|
if (!anim) continue;
|
|
|
|
Common::Point hotspot = anim->getHotspotPosition(i);
|
|
if (hotspot != invalidPosition) {
|
|
hotspot += _renderEntry->getPosition();
|
|
positions.push_back(hotspot);
|
|
}
|
|
}
|
|
|
|
return positions;
|
|
}
|
|
|
|
ItemTemplate::~ItemTemplate() {
|
|
}
|
|
|
|
ItemTemplate::ItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
Item(parent, subType, index, name),
|
|
_meshIndex(-1),
|
|
_textureNormalIndex(-1),
|
|
_textureFaceIndex(-1),
|
|
_animHierarchyIndex(-1),
|
|
_referencedItem(nullptr),
|
|
_instanciatedItem(nullptr) {
|
|
}
|
|
|
|
void ItemTemplate::onAllLoaded() {
|
|
Item::onAllLoaded();
|
|
|
|
BonesMesh *bonesMesh = findChild<BonesMesh>(false);
|
|
if (bonesMesh) {
|
|
_meshIndex = bonesMesh->getIndex();
|
|
}
|
|
|
|
TextureSet *textureNormal = findChildWithSubtype<TextureSet>(TextureSet::kTextureNormal, false);
|
|
if (textureNormal) {
|
|
_textureNormalIndex = textureNormal->getIndex();
|
|
}
|
|
|
|
TextureSet *textureFace = findChildWithSubtype<TextureSet>(TextureSet::kTextureFace, false);
|
|
if (textureFace) {
|
|
_textureFaceIndex = textureFace->getIndex();
|
|
}
|
|
}
|
|
|
|
void ItemTemplate::saveLoadCurrent(ResourceSerializer *serializer) {
|
|
Item::saveLoadCurrent(serializer);
|
|
|
|
serializer->syncAsSint32LE(_meshIndex);
|
|
serializer->syncAsSint32LE(_textureNormalIndex);
|
|
serializer->syncAsSint32LE(_textureFaceIndex);
|
|
serializer->syncAsSint32LE(_animHierarchyIndex);
|
|
}
|
|
|
|
void ItemTemplate::setInstanciatedItem(Item *instance) {
|
|
_instanciatedItem = instance;
|
|
}
|
|
|
|
ItemVisual *ItemTemplate::getSceneInstance() {
|
|
if (_instanciatedItem) {
|
|
return _instanciatedItem->getSceneInstance();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void ItemTemplate::setStockAnimHierachy(AnimHierarchy *animHierarchy) {
|
|
Object *animHierarchyParent = animHierarchy->findParent<Object>();
|
|
|
|
if (animHierarchyParent == this) {
|
|
_animHierarchyIndex = animHierarchy->getIndex();
|
|
} else {
|
|
_animHierarchyIndex = -1;
|
|
}
|
|
}
|
|
|
|
void ItemTemplate::setBonesMesh(int32 index) {
|
|
_meshIndex = index;
|
|
}
|
|
|
|
void ItemTemplate::setTexture(int32 index, uint32 textureType) {
|
|
if (textureType == TextureSet::kTextureNormal) {
|
|
_textureNormalIndex = index;
|
|
} else if (textureType == TextureSet::kTextureFace) {
|
|
_textureFaceIndex = index;
|
|
} else {
|
|
error("Unknown texture type %d", textureType);
|
|
}
|
|
|
|
// Reset the animation to apply the changes
|
|
ModelItem *sceneInstance = Resources::Object::cast<Resources::ModelItem>(getSceneInstance());
|
|
sceneInstance->updateAnim();
|
|
}
|
|
|
|
void ItemTemplate::setAnimHierarchy(AnimHierarchy *animHierarchy) {
|
|
setStockAnimHierachy(animHierarchy);
|
|
|
|
if (_instanciatedItem) {
|
|
_instanciatedItem->setAnimHierarchy(animHierarchy);
|
|
}
|
|
}
|
|
|
|
GlobalItemTemplate::~GlobalItemTemplate() {
|
|
}
|
|
|
|
GlobalItemTemplate::GlobalItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
ItemTemplate(parent, subType, index, name) {
|
|
_animHierarchyIndex = 0;
|
|
}
|
|
|
|
BonesMesh *GlobalItemTemplate::findBonesMesh() {
|
|
if (_meshIndex == -1) {
|
|
return nullptr;
|
|
} else {
|
|
BonesMesh *mesh = findChildWithIndex<BonesMesh>(_meshIndex);
|
|
if (mesh && !StarkSettings->getBoolSetting(Settings::kHighModel)) {
|
|
BonesMesh *lowMesh = findChildWithName<BonesMesh>(mesh->getName() + "_LO_RES");
|
|
if (lowMesh) {
|
|
mesh = lowMesh;
|
|
}
|
|
}
|
|
return mesh;
|
|
}
|
|
}
|
|
|
|
TextureSet *GlobalItemTemplate::findTextureSet(uint32 textureType) {
|
|
if (textureType == TextureSet::kTextureNormal) {
|
|
if (_textureNormalIndex == -1) {
|
|
return nullptr;
|
|
} else {
|
|
return findChildWithIndex<TextureSet>(_textureNormalIndex);
|
|
}
|
|
} else if (textureType == TextureSet::kTextureFace) {
|
|
if (_textureFaceIndex == -1) {
|
|
return nullptr;
|
|
} else {
|
|
return findChildWithIndex<TextureSet>(_textureFaceIndex);
|
|
}
|
|
} else {
|
|
error("Unknown texture type %d", textureType);
|
|
}
|
|
}
|
|
|
|
AnimHierarchy *GlobalItemTemplate::findStockAnimHierarchy() {
|
|
if (_animHierarchyIndex == -1) {
|
|
return nullptr;
|
|
} else {
|
|
return findChildWithIndex<AnimHierarchy>(_animHierarchyIndex);
|
|
}
|
|
}
|
|
|
|
InventoryItem::~InventoryItem() {
|
|
}
|
|
|
|
InventoryItem::InventoryItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
ItemVisual(parent, subType, index, name) {
|
|
}
|
|
|
|
Gfx::RenderEntry *InventoryItem::getRenderEntry(const Common::Point &positionOffset) {
|
|
if (_enabled) {
|
|
setAnimActivity(Anim::kUIUsageInventory);
|
|
|
|
Visual *visual = getVisual();
|
|
|
|
_renderEntry->setVisual(visual);
|
|
_renderEntry->setPosition(Common::Point());
|
|
} else {
|
|
_renderEntry->setVisual(nullptr);
|
|
}
|
|
|
|
return _renderEntry;
|
|
}
|
|
|
|
void InventoryItem::setEnabled(bool enabled) {
|
|
ItemVisual::setEnabled(enabled);
|
|
|
|
// Deselect the item in the inventory when removing it
|
|
int16 selectedInventoryItem = StarkUserInterface->getSelectedInventoryItem();
|
|
if (!enabled && selectedInventoryItem == getIndex()) {
|
|
StarkUserInterface->selectInventoryItem(-1);
|
|
}
|
|
|
|
KnowledgeSet *inventory = StarkGlobal->getInventory();
|
|
if (inventory) {
|
|
if (enabled) {
|
|
inventory->addItem(this);
|
|
} else {
|
|
inventory->removeItem(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
Visual *InventoryItem::getActionVisual(bool active) const {
|
|
if (active) {
|
|
return _animHierarchy->getVisualForUsage(Anim::kActionUsageActive);
|
|
} else {
|
|
return _animHierarchy->getVisualForUsage(Anim::kActionUsagePassive);
|
|
}
|
|
}
|
|
|
|
Visual *InventoryItem::getCursorVisual() const {
|
|
Visual *visual = _animHierarchy->getVisualForUsage(Anim::kUIUsageUseCursorPassive);
|
|
|
|
if (!visual) {
|
|
visual = _animHierarchy->getVisualForUsage(Anim::kUIUsageUseCursorActive);
|
|
}
|
|
|
|
if (!visual) {
|
|
visual = _animHierarchy->getVisualForUsage(Anim::kUIUsageInventory);
|
|
}
|
|
|
|
return visual;
|
|
}
|
|
|
|
|
|
LevelItemTemplate::~LevelItemTemplate() {
|
|
}
|
|
|
|
LevelItemTemplate::LevelItemTemplate(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
ItemTemplate(parent, subType, index, name) {
|
|
}
|
|
|
|
void LevelItemTemplate::readData(Formats::XRCReadStream *stream) {
|
|
ItemTemplate::readData(stream);
|
|
|
|
_reference = stream->readResourceReference();
|
|
}
|
|
|
|
void LevelItemTemplate::onAllLoaded() {
|
|
ItemTemplate::onAllLoaded();
|
|
|
|
_referencedItem = _reference.resolve<ItemTemplate>();
|
|
if (_referencedItem) {
|
|
_referencedItem->setInstanciatedItem(this);
|
|
}
|
|
}
|
|
|
|
BonesMesh *LevelItemTemplate::findBonesMesh() {
|
|
if (_meshIndex == -1) {
|
|
return _referencedItem->findBonesMesh();
|
|
} else {
|
|
BonesMesh *mesh = findChildWithIndex<BonesMesh>(_meshIndex);
|
|
if (mesh && !StarkSettings->getBoolSetting(Settings::kHighModel)) {
|
|
BonesMesh *lowMesh = findChildWithName<BonesMesh>(mesh->getName() + "_LO_RES");
|
|
if (lowMesh) {
|
|
mesh = lowMesh;
|
|
}
|
|
}
|
|
return mesh;
|
|
}
|
|
}
|
|
|
|
TextureSet *LevelItemTemplate::findTextureSet(uint32 textureType) {
|
|
if (textureType == TextureSet::kTextureNormal) {
|
|
if (_textureNormalIndex == -1) {
|
|
return _referencedItem->findTextureSet(textureType);
|
|
} else {
|
|
return findChildWithIndex<TextureSet>(_textureNormalIndex);
|
|
}
|
|
} else if (textureType == TextureSet::kTextureFace) {
|
|
if (_textureFaceIndex == -1) {
|
|
if (_referencedItem) {
|
|
return _referencedItem->findTextureSet(textureType);
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
} else {
|
|
return findChildWithIndex<TextureSet>(_textureFaceIndex);
|
|
}
|
|
} else {
|
|
error("Unknown texture type %d", textureType);
|
|
}
|
|
}
|
|
|
|
AnimHierarchy *LevelItemTemplate::findStockAnimHierarchy() {
|
|
if (_animHierarchyIndex == -1 && !_referencedItem) {
|
|
_animHierarchyIndex = 0; // Prefer referenced anim to local
|
|
}
|
|
|
|
if (_animHierarchyIndex == -1) {
|
|
return _referencedItem->findStockAnimHierarchy();
|
|
} else {
|
|
return findChildWithIndex<AnimHierarchy>(_animHierarchyIndex);
|
|
}
|
|
}
|
|
|
|
ItemTemplate *LevelItemTemplate::getItemTemplate() const {
|
|
return _referencedItem;
|
|
}
|
|
|
|
void LevelItemTemplate::printData() {
|
|
ItemTemplate::printData();
|
|
|
|
debug("reference: %s", _reference.describe().c_str());
|
|
}
|
|
|
|
FloorPositionedItem::~FloorPositionedItem() {
|
|
}
|
|
|
|
FloorPositionedItem::FloorPositionedItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
ItemVisual(parent, subType, index, name),
|
|
_direction3D(0.0),
|
|
_floorFaceIndex(-1),
|
|
_sortKeyOverride(false),
|
|
_sortKeyOverridenValue(0.0) {
|
|
}
|
|
|
|
Math::Vector3d FloorPositionedItem::getPosition3D() const {
|
|
return _position3D;
|
|
}
|
|
|
|
void FloorPositionedItem::setPosition3D(const Math::Vector3d &position) {
|
|
_position3D = position;
|
|
}
|
|
|
|
int32 FloorPositionedItem::getFloorFaceIndex() const {
|
|
return _floorFaceIndex;
|
|
}
|
|
|
|
void FloorPositionedItem::setFloorFaceIndex(int32 faceIndex) {
|
|
_floorFaceIndex = faceIndex;
|
|
_sortKeyOverride = false;
|
|
}
|
|
|
|
void FloorPositionedItem::placeOnBookmark(Bookmark *target) {
|
|
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
|
|
|
_position3D = target->getPosition();
|
|
|
|
// Find the floor face index the item is on
|
|
setFloorFaceIndex(floor->findFaceContainingPoint(_position3D));
|
|
|
|
// Set the z coordinate using the floor height at that position
|
|
if (_floorFaceIndex < 0) {
|
|
warning("Item '%s' has been placed out of the floor field", getName().c_str());
|
|
}
|
|
}
|
|
|
|
void FloorPositionedItem::placeDefaultPosition() {
|
|
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
|
FloorFace *face = floor->getFace(0);
|
|
|
|
_position3D = face->getCenter();
|
|
|
|
// Find the floor face index the item is on
|
|
setFloorFaceIndex(0);
|
|
|
|
// Set the z coordinate using the floor height at that position
|
|
floor->computePointHeightInFace(_position3D, 0);
|
|
}
|
|
|
|
Math::Vector3d FloorPositionedItem::getDirectionVector() const {
|
|
Math::Matrix3 rot;
|
|
rot.buildAroundZ(-_direction3D);
|
|
|
|
Math::Vector3d direction(1.0, 0.0, 0.0);
|
|
rot.transformVector(&direction);
|
|
|
|
return direction;
|
|
}
|
|
|
|
void FloorPositionedItem::setDirection(const Math::Angle &direction) {
|
|
_direction3D = direction.getDegrees(0.0);
|
|
}
|
|
|
|
void FloorPositionedItem::overrideSortKey(float sortKey) {
|
|
_sortKeyOverride = true;
|
|
_sortKeyOverridenValue = sortKey;
|
|
}
|
|
|
|
float FloorPositionedItem::getSortKey() const {
|
|
if (_sortKeyOverride) {
|
|
return _sortKeyOverridenValue;
|
|
}
|
|
|
|
Floor *floor = StarkGlobal->getCurrent()->getFloor();
|
|
|
|
if (_floorFaceIndex == -1) {
|
|
// warning("Undefined floor face index for item '%s'", getName().c_str());
|
|
return floor->getDistanceFromCamera(0);
|
|
}
|
|
|
|
return floor->getDistanceFromCamera(_floorFaceIndex);
|
|
}
|
|
|
|
void FloorPositionedItem::saveLoad(ResourceSerializer *serializer) {
|
|
ItemVisual::saveLoad(serializer);
|
|
serializer->syncAsVector3d(_position3D);
|
|
serializer->syncAsFloat(_direction3D);
|
|
serializer->syncAsSint32LE(_floorFaceIndex);
|
|
}
|
|
|
|
FloorPositionedImageItem::~FloorPositionedImageItem() {
|
|
}
|
|
|
|
FloorPositionedImageItem::FloorPositionedImageItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
FloorPositionedItem(parent, subType, index, name) {
|
|
}
|
|
|
|
void FloorPositionedImageItem::readData(Formats::XRCReadStream *stream) {
|
|
FloorPositionedItem::readData(stream);
|
|
|
|
setFloorFaceIndex(stream->readSint32LE());
|
|
_position = stream->readPoint();
|
|
|
|
// WORKAROUND: Fix the position of various items being incorrect in the game datafiles
|
|
Location *location = findParent<Location>();
|
|
if (_name == "Shelves" && location && location->getName() == "April's Room") {
|
|
_position = Common::Point(543, 77);
|
|
} else if (_name == "Door" && location && location->getName() == "Hallway") {
|
|
_position = Common::Point(328, 44);
|
|
} else if (_name == "Bench" && location && location->getName() == "Outside Border House") {
|
|
_position = Common::Point(707, 255);
|
|
} else if (_name == "Printer" && location && location->getName() == "Archives") {
|
|
_position = Common::Point(260, 119);
|
|
} else if (_name == "Prop04_chair01" && location && location->getName() == "Inn Night") {
|
|
_position = Common::Point(185, 324);
|
|
} else if (_name == "Prop05_chair02" && location && location->getName() == "Inn Night") {
|
|
_position = Common::Point(381, 329);
|
|
} else if (_name == "Gargoyle" && location && location->getName() == "Below Floating Mountain") {
|
|
_position = Common::Point(352, 0);
|
|
} else if (_name == "Computer" && location && location->getName() == "Vanguard Laboratory") {
|
|
_position = Common::Point(411, 141);
|
|
}
|
|
}
|
|
|
|
Gfx::RenderEntry *FloorPositionedImageItem::getRenderEntry(const Common::Point &positionOffset) {
|
|
if (_enabled) {
|
|
Visual *visual = getVisual();
|
|
_renderEntry->setVisual(visual);
|
|
|
|
if (getAnim() && getAnim()->getSubType() == Anim::kAnimVideo) {
|
|
// AnimVideos override the _position, but still need to move according to scroll-offsets
|
|
_renderEntry->setPosition(positionOffset);
|
|
} else {
|
|
_renderEntry->setPosition(_position - positionOffset);
|
|
}
|
|
_renderEntry->setSortKey(getSortKey());
|
|
} else {
|
|
_renderEntry->setVisual(nullptr);
|
|
}
|
|
|
|
return _renderEntry;
|
|
}
|
|
|
|
Common::Array<Common::Point> FloorPositionedImageItem::listExitPositions() {
|
|
return listExitPositionsImpl();
|
|
}
|
|
|
|
void FloorPositionedImageItem::setPosition2D(const Common::Point &position) {
|
|
_position = position;
|
|
}
|
|
|
|
void FloorPositionedImageItem::printData() {
|
|
FloorPositionedItem::printData();
|
|
|
|
debug("floorFaceIndex: %d", _floorFaceIndex);
|
|
debug("position: x %d, y %d", _position.x, _position.y);
|
|
}
|
|
|
|
ImageItem::~ImageItem() {
|
|
}
|
|
|
|
ImageItem::ImageItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
ItemVisual(parent, subType, index, name) {
|
|
}
|
|
|
|
void ImageItem::readData(Formats::XRCReadStream *stream) {
|
|
ItemVisual::readData(stream);
|
|
|
|
_position = stream->readPoint();
|
|
_reference = stream->readResourceReference();
|
|
}
|
|
|
|
Gfx::RenderEntry *ImageItem::getRenderEntry(const Common::Point &positionOffset) {
|
|
if (_enabled) {
|
|
Visual *visual = getVisual();
|
|
_renderEntry->setVisual(visual);
|
|
|
|
if (getAnim() && getAnim()->getSubType() == Anim::kAnimVideo) {
|
|
// AnimVideos override the _position, but still need to move according to scroll-offsets
|
|
_renderEntry->setPosition(positionOffset);
|
|
} else {
|
|
_renderEntry->setPosition(_position - positionOffset);
|
|
}
|
|
} else {
|
|
_renderEntry->setVisual(nullptr);
|
|
}
|
|
|
|
return _renderEntry;
|
|
}
|
|
|
|
void ImageItem::setPosition2D(const Common::Point &position) {
|
|
_position = position;
|
|
}
|
|
|
|
void ImageItem::printData() {
|
|
ItemVisual::printData();
|
|
|
|
debug("reference: %s", _reference.describe().c_str());
|
|
debug("position: x %d, y %d", _position.x, _position.y);
|
|
}
|
|
|
|
Common::Array<Common::Point> ImageItem::listExitPositions() {
|
|
return listExitPositionsImpl();
|
|
}
|
|
|
|
ModelItem::~ModelItem() {
|
|
delete _animHandler;
|
|
}
|
|
|
|
ModelItem::ModelItem(Object *parent, byte subType, uint16 index, const Common::String &name) :
|
|
FloorPositionedItem(parent, subType, index, name),
|
|
_meshIndex(-1),
|
|
_textureNormalIndex(-1),
|
|
_textureFaceIndex(-1),
|
|
_referencedItem(nullptr),
|
|
_animHandler(nullptr) {
|
|
}
|
|
|
|
void ModelItem::readData(Formats::XRCReadStream *stream) {
|
|
FloorPositionedItem::readData(stream);
|
|
|
|
_reference = stream->readResourceReference();
|
|
}
|
|
|
|
void ModelItem::onAllLoaded() {
|
|
FloorPositionedItem::onAllLoaded();
|
|
|
|
BonesMesh *bonesMesh = findChild<BonesMesh>(false);
|
|
if (bonesMesh) {
|
|
_meshIndex = bonesMesh->getIndex();
|
|
}
|
|
|
|
TextureSet *textureNormal = findChildWithSubtype<TextureSet>(TextureSet::kTextureNormal, false);
|
|
if (textureNormal) {
|
|
_textureNormalIndex = textureNormal->getIndex();
|
|
}
|
|
|
|
TextureSet *textureFace = findChildWithSubtype<TextureSet>(TextureSet::kTextureFace, false);
|
|
if (textureFace) {
|
|
_textureFaceIndex = textureFace->getIndex();
|
|
}
|
|
|
|
_referencedItem = _reference.resolve<ItemTemplate>();
|
|
if (_referencedItem) {
|
|
_referencedItem->setInstanciatedItem(this);
|
|
}
|
|
|
|
_animHandler = new AnimHandler();
|
|
}
|
|
|
|
void ModelItem::onEnterLocation() {
|
|
FloorPositionedItem::onEnterLocation();
|
|
|
|
if (_referencedItem) {
|
|
_referencedItem->setInstanciatedItem(this);
|
|
}
|
|
|
|
if (_referencedItem) {
|
|
_animHierarchy = _referencedItem->findStockAnimHierarchy();
|
|
}
|
|
|
|
setAnimActivity(Anim::kActorActivityIdle);
|
|
}
|
|
|
|
void ModelItem::onExitLocation() {
|
|
FloorPositionedItem::onExitLocation();
|
|
|
|
resetActionAnim();
|
|
if (_animHierarchy) {
|
|
_animHierarchy->unselectItemAnim(this);
|
|
}
|
|
}
|
|
|
|
void ModelItem::setBonesMesh(int32 index) {
|
|
_meshIndex = index;
|
|
|
|
if (_meshIndex != -1) {
|
|
updateAnim();
|
|
}
|
|
}
|
|
|
|
BonesMesh *ModelItem::findBonesMesh() {
|
|
// Prefer retrieving the mesh from the anim hierarchy
|
|
BonesMesh *bonesMesh = _animHierarchy->findBonesMesh();
|
|
|
|
// Otherwise, use a children mesh, or a referenced mesh
|
|
if (!bonesMesh) {
|
|
if (_meshIndex == -1) {
|
|
bonesMesh = _referencedItem->findBonesMesh();
|
|
} else {
|
|
bonesMesh = findChildWithIndex<BonesMesh>(_meshIndex);
|
|
if (bonesMesh && !StarkSettings->getBoolSetting(Settings::kHighModel)) {
|
|
BonesMesh *lowMesh = findChildWithName<BonesMesh>(bonesMesh->getName() + "_LO_RES");
|
|
if (lowMesh) {
|
|
bonesMesh = lowMesh;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return bonesMesh;
|
|
}
|
|
|
|
void ModelItem::setTexture(int32 index, uint32 textureType) {
|
|
if (textureType == TextureSet::kTextureNormal) {
|
|
_textureNormalIndex = index;
|
|
} else if (textureType == TextureSet::kTextureFace) {
|
|
_textureFaceIndex = index;
|
|
} else {
|
|
error("Unknown texture type %d", textureType);
|
|
}
|
|
}
|
|
|
|
TextureSet *ModelItem::findTextureSet(uint32 textureType) {
|
|
// Prefer retrieving the mesh from the anim hierarchy
|
|
TextureSet *textureSet = _animHierarchy->findTextureSet(textureType);
|
|
|
|
// Otherwise, use a children mesh, or a referenced mesh
|
|
if (!textureSet) {
|
|
if (textureType == TextureSet::kTextureNormal) {
|
|
if (_textureNormalIndex == -1) {
|
|
textureSet = _referencedItem->findTextureSet(textureType);
|
|
} else {
|
|
textureSet = findChildWithIndex<TextureSet>(_textureNormalIndex);
|
|
}
|
|
} else if (textureType == TextureSet::kTextureFace) {
|
|
if (_textureFaceIndex == -1) {
|
|
if (_referencedItem) {
|
|
textureSet = _referencedItem->findTextureSet(textureType);
|
|
}
|
|
} else {
|
|
textureSet = findChildWithIndex<TextureSet>(_textureFaceIndex);
|
|
}
|
|
} else {
|
|
error("Unknown texture type %d", textureType);
|
|
}
|
|
}
|
|
|
|
return textureSet;
|
|
}
|
|
|
|
void ModelItem::updateAnim() {
|
|
Anim *anim = getAnim();
|
|
if (anim && anim->getSubType() == Anim::kAnimSkeleton) {
|
|
anim->removeFromItem(this);
|
|
anim->applyToItem(this);
|
|
}
|
|
}
|
|
|
|
Gfx::RenderEntry *ModelItem::getRenderEntry(const Common::Point &positionOffset) {
|
|
if (_enabled) {
|
|
Visual *visual = getVisual();
|
|
|
|
if (!visual) {
|
|
_animHierarchy->selectItemAnim(this);
|
|
visual = getVisual();
|
|
}
|
|
|
|
_renderEntry->setVisual(visual);
|
|
_renderEntry->setPosition3D(_position3D, _direction3D);
|
|
_renderEntry->setSortKey(getSortKey());
|
|
} else {
|
|
_renderEntry->setVisual(nullptr);
|
|
}
|
|
|
|
return _renderEntry;
|
|
}
|
|
|
|
ItemTemplate *ModelItem::getItemTemplate() const {
|
|
return _referencedItem;
|
|
}
|
|
|
|
Anim *ModelItem::getIdleActionAnim() const {
|
|
if (_animHierarchy) {
|
|
return _animHierarchy->getIdleActionAnim();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void ModelItem::saveLoadCurrent(ResourceSerializer *serializer) {
|
|
FloorPositionedItem::saveLoadCurrent(serializer);
|
|
|
|
serializer->syncAsSint32LE(_meshIndex);
|
|
serializer->syncAsSint32LE(_textureNormalIndex);
|
|
serializer->syncAsSint32LE(_textureFaceIndex);
|
|
}
|
|
|
|
void ModelItem::printData() {
|
|
FloorPositionedItem::printData();
|
|
|
|
debug("reference: %s", _reference.describe().c_str());
|
|
}
|
|
|
|
void ModelItem::resetAnimationBlending() {
|
|
_animHandler->resetBlending();
|
|
}
|
|
|
|
AnimHandler *ModelItem::getAnimHandler() const {
|
|
return _animHandler;
|
|
}
|
|
|
|
void ItemTemplate::onEnterLocation() {
|
|
Object::onEnterLocation();
|
|
|
|
if (_referencedItem) {
|
|
_referencedItem->setInstanciatedItem(this);
|
|
}
|
|
}
|
|
} // End of namespace Resources
|
|
} // End of namespace Stark
|