Files
scummvm-cursorfix/engines/ultima/ultima8/gumps/item_relative_gump.cpp
2026-02-02 04:50:13 +01:00

188 lines
4.7 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 "ultima/ultima8/gumps/item_relative_gump.h"
#include "ultima/ultima8/gumps/game_map_gump.h"
#include "ultima/ultima8/world/container.h"
#include "ultima/ultima8/world/get_object.h"
namespace Ultima {
namespace Ultima8 {
DEFINE_RUNTIME_CLASSTYPE_CODE(ItemRelativeGump)
ItemRelativeGump::ItemRelativeGump() : Gump(), _ix(0), _iy(0) {
}
ItemRelativeGump::ItemRelativeGump(int32 x, int32 y, int32 width, int32 height,
uint16 owner, uint32 flags, int32 layer)
: Gump(x, y, width, height, owner, flags, layer), _ix(0), _iy(0) {
}
ItemRelativeGump::~ItemRelativeGump(void) {
}
void ItemRelativeGump::InitGump(Gump *newparent, bool take_focus) {
Gump::InitGump(newparent, take_focus);
GetItemLocation(0);
if (!newparent && _parent)
MoveOnScreen();
}
void ItemRelativeGump::MoveOnScreen() {
assert(_parent);
Common::Rect32 sd = _parent->getDims();
// first move back to our desired location
_x = 0;
_y = 0;
// get rectangle that gump occupies in desktops's coordinate space
int32 left, right, top, bottom;
left = -_dims.left;
right = left + _dims.width();
top = -_dims.top;
bottom = top + _dims.height();
GumpToParent(left, top);
GumpToParent(right, bottom);
int32 movex = 0, movey = 0;
if (left < -sd.left)
movex = -sd.left - left;
else if (right > -sd.left + sd.width())
movex = -sd.left + sd.width() - right;
if (top < -sd.top)
movey = -sd.top - top;
else if (bottom > -sd.top + sd.height())
movey = -sd.top + sd.height() - bottom;
Move(left + movex, top + movey);
}
// Paint the Gump (RenderSurface is relative to parent).
// Calls PaintThis and PaintChildren
void ItemRelativeGump::Paint(RenderSurface *surf, int32 lerp_factor, bool scaled) {
GetItemLocation(lerp_factor);
Gump::Paint(surf, lerp_factor, scaled);
}
// Convert a parent relative point to a gump point
void ItemRelativeGump::ParentToGump(int32 &px, int32 &py, PointRoundDir r) {
px -= _ix;
py -= _iy;
Gump::ParentToGump(px, py, r);
}
// Convert a gump point to parent relative point
void ItemRelativeGump::GumpToParent(int32 &gx, int32 &gy, PointRoundDir r) {
Gump::GumpToParent(gx, gy, r);
gx += _ix;
gy += _iy;
}
void ItemRelativeGump::GetItemLocation(int32 lerp_factor) {
Gump *gump = nullptr;
Item *it = getItem(_owner);
if (!it) {
// This shouldn't ever happen, the GumpNotifyProcess should
// close us before we get here
Close();
return;
}
Item *next;
Item *prev = nullptr;
while ((next = it->getParentAsContainer()) != nullptr) {
prev = it;
it = next;
gump = getGump(it->getGump());
if (gump) break;
}
int32 gx, gy;
bool found;
if (!gump) {
gump = GetRootGump()->FindGump<GameMapGump>();
if (!gump) {
warning("ItemRelativeGump::GetItemLocation(): Unable to find GameMapGump");
return;
}
found = gump->GetLocationOfItem(_owner, gx, gy, lerp_factor);
} else {
assert(prev);
found = gump->GetLocationOfItem(prev->getObjId(), gx, gy, lerp_factor);
}
if (found) {
// Convert the GumpSpaceCoord relative to the world/item gump
// into screenspace coords
gy = gy - it->getShapeInfo()->_z * 8 - 16;
} else {
// If location not found show near bottom center
Common::Rect32 r = gump->getDims();
gx = (r.left + r.right) / 2;
gy = r.bottom - 8;
}
gump->GumpToScreenSpace(gx, gy);
// Convert the screenspace coords into the coords of us
if (_parent)
_parent->ScreenSpaceToGump(gx, gy);
// Set x and y, and center us over it
_ix = gx - _dims.width() / 2;
_iy = gy - _dims.height();
if (_flags & FLAG_KEEP_VISIBLE)
MoveOnScreen();
}
void ItemRelativeGump::Move(int32 x, int32 y) {
ParentToGump(x, y);
_x += x;
_y += y;
}
void ItemRelativeGump::saveData(Common::WriteStream *ws) {
Gump::saveData(ws);
}
bool ItemRelativeGump::loadData(Common::ReadStream *rs, uint32 version) {
if (!Gump::loadData(rs, version)) return false;
return true;
}
} // End of namespace Ultima8
} // End of namespace Ultima