Initial commit
This commit is contained in:
243
engines/ultima/ultima8/world/target_reticle_process.cpp
Normal file
243
engines/ultima/ultima8/world/target_reticle_process.cpp
Normal file
@@ -0,0 +1,243 @@
|
||||
/* 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/ultima8.h"
|
||||
#include "ultima/ultima8/gumps/message_box_gump.h"
|
||||
#include "ultima/ultima8/games/game_data.h"
|
||||
#include "ultima/ultima8/kernel/kernel.h"
|
||||
#include "ultima/ultima8/world/actors/actor.h"
|
||||
#include "ultima/ultima8/world/target_reticle_process.h"
|
||||
#include "ultima/ultima8/world/sprite_process.h"
|
||||
#include "ultima/ultima8/world/world.h"
|
||||
#include "ultima/ultima8/world/current_map.h"
|
||||
#include "ultima/ultima8/world/get_object.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima8 {
|
||||
|
||||
TargetReticleProcess *TargetReticleProcess::_instance = nullptr;
|
||||
|
||||
DEFINE_RUNTIME_CLASSTYPE_CODE(TargetReticleProcess)
|
||||
|
||||
TargetReticleProcess::TargetReticleProcess() : Process(), _reticleEnabled(true),
|
||||
_lastUpdate(0), _reticleSpriteProcess(0), _lastTargetDir(dir_current), _lastTargetItem(0),
|
||||
_reticleStyle(0) {
|
||||
_instance = this;
|
||||
_type = 1; // persistent
|
||||
if (GAME_IS_REGRET)
|
||||
_reticleStyle = 3;
|
||||
}
|
||||
|
||||
TargetReticleProcess::~TargetReticleProcess() {
|
||||
if (_instance == this)
|
||||
_instance = nullptr;
|
||||
}
|
||||
|
||||
void TargetReticleProcess::run() {
|
||||
Kernel *kernel = Kernel::get_instance();
|
||||
assert(kernel);
|
||||
uint32 frameno = kernel->getFrameNum();
|
||||
Actor *mainactor = getControlledActor();
|
||||
Process *spriteProc = nullptr;
|
||||
if (_reticleSpriteProcess != 0) {
|
||||
spriteProc = kernel->getProcess(_reticleSpriteProcess);
|
||||
}
|
||||
|
||||
if (!_reticleEnabled || (mainactor && !mainactor->isInCombat()) || !mainactor) {
|
||||
// Reticle not enabled, actor not in combat, or actor is gone.
|
||||
if (spriteProc) {
|
||||
spriteProc->terminate();
|
||||
}
|
||||
_reticleSpriteProcess = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_reticleSpriteProcess && (!spriteProc || spriteProc->is_terminated())) {
|
||||
// The sprite proc has finished but the target is still valid - replace
|
||||
// with one that just holds the last frame.
|
||||
Item *target = getItem(_lastTargetItem);
|
||||
if (target)
|
||||
putTargetReticleOnItem(target, true);
|
||||
}
|
||||
|
||||
if (frameno - _lastUpdate < 2 * Kernel::FRAMES_PER_SECOND) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = findTargetItem();
|
||||
if (spriteProc && changed) {
|
||||
// Terminate the old process.
|
||||
spriteProc->terminate();
|
||||
}
|
||||
_lastUpdate = frameno;
|
||||
}
|
||||
|
||||
bool TargetReticleProcess::findTargetItem() {
|
||||
Actor *mainactor = getControlledActor();
|
||||
CurrentMap *currentmap = World::get_instance()->getCurrentMap();
|
||||
bool changed = false;
|
||||
|
||||
if (!mainactor || !currentmap)
|
||||
return false;
|
||||
|
||||
Direction dir = mainactor->getDir();
|
||||
|
||||
Point3 pt = mainactor->getLocation();
|
||||
|
||||
Item *item = currentmap->findBestTargetItem(pt.x, pt.y, pt.z, dir, dirmode_16dirs);
|
||||
|
||||
if (item && item->getObjId() != _lastTargetItem) {
|
||||
Item *lastItem = getItem(_lastTargetItem);
|
||||
if (lastItem)
|
||||
lastItem->clearExtFlag(Item::EXT_TARGET);
|
||||
putTargetReticleOnItem(item, false);
|
||||
_lastTargetDir = dir;
|
||||
changed = true;
|
||||
} else if (!item) {
|
||||
if (_lastTargetItem) {
|
||||
debug("New reticle target: NONE");
|
||||
Item *lastItem = getItem(_lastTargetItem);
|
||||
if (lastItem)
|
||||
lastItem->clearExtFlag(Item::EXT_TARGET);
|
||||
}
|
||||
clearSprite();
|
||||
changed = true;
|
||||
}
|
||||
// else, already targeting the right thing. do nothing.
|
||||
return changed;
|
||||
}
|
||||
|
||||
void TargetReticleProcess::avatarMoved() {
|
||||
_lastUpdate = 0;
|
||||
}
|
||||
|
||||
void TargetReticleProcess::putTargetReticleOnItem(Item *item, bool only_last_frame) {
|
||||
// TODO: the game does a bunch of other maths here to pick the right location.
|
||||
// This is an over-simplification and is usually too high so it's
|
||||
// hacked a little lower.
|
||||
Point3 pt = item->getCentre();
|
||||
pt.z -= 8;
|
||||
|
||||
Process *p;
|
||||
const int first_frame = _reticleStyle * 6;
|
||||
const int last_frame = first_frame + 5;
|
||||
if (!only_last_frame)
|
||||
p = new SpriteProcess(0x59a, first_frame, last_frame, 1, 10, pt.x, pt.y, pt.z, false);
|
||||
else
|
||||
p = new SpriteProcess(0x59a, last_frame, last_frame, 1, 1000, pt.x, pt.y, pt.z, false);
|
||||
|
||||
_reticleSpriteProcess = Kernel::get_instance()->addProcess(p);
|
||||
_lastTargetItem = item->getObjId();
|
||||
item->setExtFlag(Item::EXT_TARGET);
|
||||
debug("New reticle target: %d (%d, %d, %d)", _lastTargetItem, pt.x, pt.y, pt.z);
|
||||
}
|
||||
|
||||
void TargetReticleProcess::itemMoved(Item *item) {
|
||||
assert(item);
|
||||
if (!_reticleSpriteProcess || item->getObjId() != _lastTargetItem) {
|
||||
clearSprite();
|
||||
return;
|
||||
}
|
||||
|
||||
Point3 pt = item->getCentre();
|
||||
|
||||
Actor *mainactor = getControlledActor();
|
||||
int actordir = -1;
|
||||
int dirtoitem = -2;
|
||||
if (mainactor) {
|
||||
actordir = mainactor->getDir();
|
||||
dirtoitem = mainactor->getDirToItemCentre(*item);
|
||||
}
|
||||
|
||||
SpriteProcess *spriteproc = dynamic_cast<SpriteProcess *>(Kernel::get_instance()->getProcess(_reticleSpriteProcess));
|
||||
|
||||
if (spriteproc) {
|
||||
if (actordir != _lastTargetDir || dirtoitem != _lastTargetDir) {
|
||||
spriteproc->terminate();
|
||||
_reticleSpriteProcess = 0;
|
||||
clearSprite();
|
||||
} else {
|
||||
spriteproc->move(pt.x, pt.y, pt.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TargetReticleProcess::clearSprite() {
|
||||
_reticleSpriteProcess = 0;
|
||||
if (_lastTargetItem) {
|
||||
Item *item = getItem(_lastTargetItem);
|
||||
if (item) {
|
||||
item->clearExtFlag(Item::EXT_TARGET);
|
||||
}
|
||||
}
|
||||
_lastTargetItem = 0;
|
||||
_lastTargetDir = dir_current;
|
||||
}
|
||||
|
||||
void TargetReticleProcess::toggle() {
|
||||
bool newstate = !getEnabled();
|
||||
Std::string msg = newstate ? _TL_("TARGETING RETICLE ACTIVE") : _TL_("TARGETING RETICLE INACTIVE");
|
||||
MessageBoxGump::Show("", msg, TEX32_PACK_RGB(0x70, 0x70, 0x70));
|
||||
setEnabled(newstate);
|
||||
}
|
||||
|
||||
void TargetReticleProcess::toggleReticleStyle() {
|
||||
if (GAME_IS_REMORSE) {
|
||||
_reticleStyle = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_reticleStyle++;
|
||||
if (_reticleStyle >= 4)
|
||||
_reticleStyle = 0;
|
||||
}
|
||||
|
||||
void TargetReticleProcess::saveData(Common::WriteStream *ws) {
|
||||
Process::saveData(ws);
|
||||
|
||||
ws->writeByte(_reticleEnabled ? 1 : 0);
|
||||
ws->writeUint32LE(_lastUpdate);
|
||||
ws->writeUint16LE(_reticleSpriteProcess);
|
||||
ws->writeByte(_lastTargetDir);
|
||||
ws->writeUint16LE(_lastTargetItem);
|
||||
if (GAME_IS_REGRET)
|
||||
ws->writeUint16LE(_reticleStyle);
|
||||
}
|
||||
|
||||
bool TargetReticleProcess::loadData(Common::ReadStream *rs, uint32 version) {
|
||||
if (!Process::loadData(rs, version)) return false;
|
||||
|
||||
_reticleEnabled = (rs->readByte() != 0);
|
||||
_lastUpdate = rs->readUint32LE();
|
||||
_reticleSpriteProcess = rs->readUint16LE();
|
||||
_lastTargetDir = static_cast<Direction>(rs->readByte());
|
||||
_lastTargetItem = rs->readUint16LE();
|
||||
if (GAME_IS_REGRET)
|
||||
_reticleStyle = rs->readUint16LE();
|
||||
|
||||
_type = 1; // should be persistent but older savegames may not know that.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // End of namespace Ultima8
|
||||
} // End of namespace Ultima
|
||||
Reference in New Issue
Block a user