scummvm/engines/prince/mob.cpp
2021-12-26 18:48:43 +01:00

268 lines
6.3 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 "prince/prince.h"
#include "prince/mob.h"
#include "prince/animation.h"
#include "prince/font.h"
namespace Prince {
bool Mob::loadFromStream(Common::SeekableReadStream &stream) {
int32 pos = stream.pos();
uint16 visible = stream.readUint16LE();
if (visible == 0xFFFF)
return false;
_visible = visible;
_type = stream.readUint16LE();
_rect.left = stream.readUint16LE();
_rect.top = stream.readUint16LE();
_rect.right = stream.readUint16LE();
_rect.bottom = stream.readUint16LE();
_mask = stream.readUint16LE();
_examPosition.x = stream.readUint16LE();
_examPosition.y = stream.readUint16LE();
_examDirection = (Direction)stream.readUint16LE();
_usePosition.x = stream.readByte();
_usePosition.y = stream.readByte();
_useDirection = (Direction)stream.readUint16LE();
uint32 nameOffset = stream.readUint32LE();
uint32 examTextOffset = stream.readUint32LE();
byte c;
stream.seek(nameOffset);
_name.clear();
while ((c = stream.readByte()))
_name += c;
stream.seek(examTextOffset);
_examText.clear();
c = stream.readByte();
if (c) {
_examText += c;
do {
c = stream.readByte();
_examText += c;
} while (c != 255);
}
stream.seek(pos + 32);
return true;
}
void Mob::setData(AttrId dataId, uint16 value) {
switch (dataId) {
case kMobExamDir:
_examDirection = (Direction)value;
break;
case kMobExamX:
_examPosition.x = value;
break;
case kMobExamY:
_examPosition.y = value;
break;
default:
assert(false);
}
}
uint16 Mob::getData(AttrId dataId) {
switch (dataId) {
case kMobVisible:
return _visible;
case kMobExamDir:
return _examDirection;
case kMobExamX:
return _examPosition.x;
case kMobExamY:
return _examPosition.y;
default:
assert(false);
return 0;
}
}
int PrinceEngine::getMob(Common::Array<Mob> &mobList, bool usePriorityList, int posX, int posY) {
Common::Point pointPos(posX, posY);
int mobListSize;
if (usePriorityList) {
mobListSize = _mobPriorityList.size();
} else {
mobListSize = mobList.size();
}
for (int mobNumber = 0; mobNumber < mobListSize; mobNumber++) {
Mob *mob = nullptr;
if (usePriorityList) {
mob = &mobList[_mobPriorityList[mobNumber]];
} else {
mob = &mobList[mobNumber];
}
if (mob->_visible) {
continue;
}
int type = mob->_type & 7;
switch (type) {
case 0:
case 1:
//normal_mob
if (!mob->_rect.contains(pointPos)) {
continue;
}
break;
case 3:
//mob_obj
if (mob->_mask < kMaxObjects) {
int nr = _objSlot[mob->_mask];
if (nr != 0xFF) {
Object &obj = *_objList[nr];
Common::Rect objectRect(obj._x, obj._y, obj._x + obj._width, obj._y + obj._height);
if (objectRect.contains(pointPos)) {
Graphics::Surface *objSurface = obj.getSurface();
byte *pixel = (byte *)objSurface->getBasePtr(posX - obj._x, posY - obj._y);
if (*pixel != 255) {
break;
}
}
}
}
continue;
break;
case 2:
case 5:
//check_ba_mob
if (!_backAnimList[mob->_mask].backAnims.empty()) {
int currentAnim = _backAnimList[mob->_mask]._seq._currRelative;
Anim &backAnim = _backAnimList[mob->_mask].backAnims[currentAnim];
if (backAnim._animData != nullptr) {
if (!backAnim._state) {
Common::Rect backAnimRect(backAnim._currX, backAnim._currY, backAnim._currX + backAnim._currW, backAnim._currY + backAnim._currH);
if (backAnimRect.contains(pointPos)) {
int phase = backAnim._showFrame;
int phaseFrameIndex = backAnim._animData->getPhaseFrameIndex(phase);
Graphics::Surface *backAnimSurface = backAnim._animData->getFrame(phaseFrameIndex);
byte pixel = *(byte *)backAnimSurface->getBasePtr(posX - backAnim._currX, posY - backAnim._currY);
if (pixel != 255) {
if (type == 5) {
if (mob->_rect.contains(pointPos)) {
break;
}
} else {
break;
}
}
}
}
}
}
continue;
break;
default:
//not_part_ba
continue;
break;
}
if (usePriorityList) {
return _mobPriorityList[mobNumber];
} else {
return mobNumber;
}
}
return -1;
}
int PrinceEngine::checkMob(Graphics::Surface *screen, Common::Array<Mob> &mobList, bool usePriorityList) {
if (_mouseFlag == 0 || _mouseFlag == 3) {
return -1;
}
Common::Point mousePos = _system->getEventManager()->getMousePos();
int mobNumber = getMob(mobList, usePriorityList, mousePos.x + _picWindowX, mousePos.y);
if (mobNumber != -1) {
Common::String mobName = mobList[mobNumber]._name;
if (getLanguage() == Common::DE_DEU) {
for (uint i = 0; i < mobName.size(); i++) {
switch (mobName[i]) {
case '\xc4':
mobName.setChar('\x83', i);
break;
case '\xd6':
mobName.setChar('\x84', i);
break;
case '\xdc':
mobName.setChar('\x85', i);
break;
case '\xdf':
mobName.setChar('\x7f', i);
break;
case '\xe4':
mobName.setChar('\x80', i);
break;
case '\xf6':
mobName.setChar('\x81', i);
break;
case '\xfc':
mobName.setChar('\x82', i);
break;
default:
break;
}
}
}
uint16 textW = getTextWidth(mobName.c_str());
uint16 x = mousePos.x - textW / 2;
if (x > screen->w) {
x = 0;
}
if (x + textW > screen->w) {
x = screen->w - textW;
}
uint16 y = mousePos.y - _font->getFontHeight();
if (y > screen->h) {
y = _font->getFontHeight() - 2;
}
_font->drawString(screen, mobName, x, y, screen->w, 216);
}
return mobNumber;
}
} // End of namespace Prince