PINK: added basic cursor implementation, fixed sequenceAudio restarting and skipping, fixed various mem leaks, hopefully fixed finding of transparent color index.

This commit is contained in:
whiterandrek 2018-04-02 08:57:56 +03:00 committed by Eugene Sandulenko
parent e48ac17f68
commit 49d5ea28c0
39 changed files with 623 additions and 184 deletions

View File

@ -45,68 +45,10 @@
#include <engines/pink/objects/actors/cursor_actor.h>
#include <engines/pink/objects/handlers/handler_timer.h>
#include <engines/pink/objects/actors/inventory_actor.h>
#include "constants.h"
namespace Pink {
enum {
kMaxClassLength = 32,
kMaxStringLength = 64, // adjust
kNullObject = 0
};
enum {
kActionHide,
kActionLoop,
kActionPlay,
kActionPlayWithSfx,
kActionSfx,
kActionSound,
kActionStill,
kActionTalk,
kActionText,
kActor,
kAudioInfoPDAButton,
kConditionGameVariable,
kConditionInventoryItemOwner,
kConditionModuleVariable,
kConditionNotInventoryItemOwner,
kConditionNotModuleVariable,
kConditionNotPageVariable,
kConditionPageVariable,
kCursorActor,
kGamePage,
kHandlerLeftClick,
kHandlerStartPage,
kHandlerTimer,
kHandlerTimerActions,
kHandlerTimerSequences,
kHandlerUseClick,
kInventoryActor,
kInventoryItem,
kLeadActor,
kModuleProxy,
kPDAButtonActor,
kParlSqPink,
kPubPink,
kSeqTimer,
kSequence,
kSequenceAudio,
kSequenceItem,
kSequenceItemDefaultAction,
kSequenceItemLeader,
kSequenceItemLeaderAudio,
kSideEffectExit,
kSideEffectGameVariable,
kSideEffectInventoryItemOwner,
kSideEffectLocation,
kSideEffectModuleVariable,
kSideEffectPageVariable,
kSideEffectRandomPageVariable,
kSupportingActor,
kWalkAction,
kWalkLocation
};
static const struct RuntimeClass {
const char *name;
int id;

View File

@ -21,6 +21,7 @@
*/
#include <common/stream.h>
#include <graphics/surface.h>
#include "cel_decoder.h"
namespace Pink {
@ -79,6 +80,18 @@ const Graphics::Surface *CelDecoder::getCurrentFrame() {
return track->getCurrentFrame();
}
Common::Point CelDecoder::getCenter() {
CelVideoTrack *track = (CelVideoTrack*) getTrack(0);
if (!track)
return {0,0};
return track->getCenter();
}
Common::Rect &CelDecoder::getRectangle() {
CelVideoTrack *track = (CelVideoTrack*) getTrack(0);
return track->getRect();
}
CelDecoder::CelVideoTrack::CelVideoTrack(Common::SeekableReadStream *stream, uint16 frameCount, uint16 width, uint16 height, bool skipHeader)
: FlicVideoTrack(stream, frameCount, width, height, 1), _center(0,0), _transparentColourIndex(0){
readHeader();
@ -100,33 +113,21 @@ void CelDecoder::CelVideoTrack::readPrefixChunk() {
switch (subchunkType) {
case CEL_DATA:
debug("%u", _fileStream->readUint16LE());
_fileStream->readUint16LE();
_center.x = _fileStream->readUint16LE();
_center.y = _fileStream->readUint16LE();
debug("stretch x: %u", _fileStream->readUint16LE());
debug("stretch y: %u", _fileStream->readUint16LE());
debug("rotation x: %u", _fileStream->readUint16LE());
debug("rotation y: %u", _fileStream->readUint16LE());
debug("rotation z: %u", _fileStream->readUint16LE());
debug("current Frame: %u", _fileStream->readUint16LE());
debug("next frame offset: %u",_fileStream->readUint32LE());
debug("tcolor: %u", _transparentColourIndex = _fileStream->readUint16LE());
for (int j = 0; j < 18; ++j) {
debug("%u", _fileStream->readUint16LE());
}
break;
default:
error("Unknown subchunk type");
_fileStream->skip(subchunkSize - 6);
break;
}
_rect = Common::Rect::center(_center.x, _center.y, _surface->w, _surface->h);
}
void CelDecoder::CelVideoTrack::readHeader() {
_fileStream->readUint16LE(); // flags
// Note: The normal delay is a 32-bit integer (dword), whereas the overridden delay is a 16-bit integer (word)
// the frame delay is the FLIC "speed", in milliseconds.
_fileStream->readUint16LE();
_frameDelay = _startFrameDelay = _fileStream->readUint32LE();
_fileStream->seek(80);
@ -137,7 +138,6 @@ void CelDecoder::CelVideoTrack::readHeader() {
readPrefixChunk();
}
// Seek to the first frame
_fileStream->seek(_offsetFrame1);
}
@ -157,4 +157,42 @@ const Graphics::Surface *CelDecoder::CelVideoTrack::getCurrentFrame() {
return _surface;
}
Common::Point CelDecoder::CelVideoTrack::getCenter() {
return _center;
}
Common::Rect &CelDecoder::CelVideoTrack::getRect() {
return _rect;
}
#define FRAME_TYPE 0xF1FA
const Graphics::Surface *CelDecoder::CelVideoTrack::decodeNextFrame() {
// Read chunk
/*uint32 frameSize = */ _fileStream->readUint32LE();
uint16 frameType = _fileStream->readUint16LE();
switch (frameType) {
case FRAME_TYPE:
handleFrame();
break;
default:
error("FlicDecoder::decodeFrame(): unknown main chunk type (type = 0x%02X)", frameType);
break;
}
_curFrame++;
_nextFrameStartTime += _frameDelay;
if (_atRingFrame) {
// If we decoded the ring frame, seek to the second frame
_atRingFrame = false;
_fileStream->seek(_offsetFrame2);
}
if (_curFrame == 0)
_transparentColourIndex = *(byte*)_surface->getBasePtr(0,0);
return _surface;
}
} // End of namepsace Pink

View File

@ -32,6 +32,9 @@ class CelDecoder : public Video::FlicDecoder {
public:
uint32 getX();
uint32 getY();
Common::Point getCenter();
Common::Rect &getRectangle();
uint16 getTransparentColourIndex();
const Graphics::Surface *getCurrentFrame();
@ -45,14 +48,19 @@ protected:
uint32 getX() const;
uint32 getY() const;
Common::Point getCenter();
Common::Rect &getRect();
uint16 getTransparentColourIndex();
const Graphics::Surface *getCurrentFrame();
private:
const Graphics::Surface *decodeNextFrame();
void readPrefixChunk();
uint16 _transparentColourIndex;
Common::Point _center;
Common::Rect _rect;
byte _transparentColourIndex;
};
};

136
engines/pink/constants.h Normal file
View File

@ -0,0 +1,136 @@
/* 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 2
* 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef PINK_CONSTANTS_H
#define PINK_CONSTANTS_H
namespace Pink {
enum {
kMaxClassLength = 32,
kMaxStringLength = 64,
kNullObject = 0
};
enum {
kActionHide,
kActionLoop,
kActionPlay,
kActionPlayWithSfx,
kActionSfx,
kActionSound,
kActionStill,
kActionTalk,
kActionText,
kActor,
kAudioInfoPDAButton,
kConditionGameVariable,
kConditionInventoryItemOwner,
kConditionModuleVariable,
kConditionNotInventoryItemOwner,
kConditionNotModuleVariable,
kConditionNotPageVariable,
kConditionPageVariable,
kCursorActor,
kGamePage,
kHandlerLeftClick,
kHandlerStartPage,
kHandlerTimer,
kHandlerTimerActions,
kHandlerTimerSequences,
kHandlerUseClick,
kInventoryActor,
kInventoryItem,
kLeadActor,
kModuleProxy,
kPDAButtonActor,
kParlSqPink,
kPubPink,
kSeqTimer,
kSequence,
kSequenceAudio,
kSequenceItem,
kSequenceItemDefaultAction,
kSequenceItemLeader,
kSequenceItemLeaderAudio,
kSideEffectExit,
kSideEffectGameVariable,
kSideEffectInventoryItemOwner,
kSideEffectLocation,
kSideEffectModuleVariable,
kSideEffectPageVariable,
kSideEffectRandomPageVariable,
kSupportingActor,
kWalkAction,
kWalkLocation
};
enum {
kCursorsCount = 11
};
enum {
kLoadingCursor = 0,
kExitForwardCursor = 1,
kExitLeftCursor = 2,
kExitRightCursor = 3,
kDefaultCursor = 4,
kClickableFirstFrameCursor = 5,
kClickableSecondFrameCursor = 6,
kNotClickableCursor = 7,
kHoldingItemCursor = 8,
kPDAFirstCursor = 9,
kPDASecondCursor = 10
};
// values are from Hokus Pokus
enum {
kPokusLoadingCursorID = 135,
kPokusExitForwardCursorID = 138,
kPokusExitLeftCursorID = 133,
kPokusExitRightCursorID = 134,
kPokusClickableFirstCursorID = 137,
kPokusClickableSecondCursorID = 136,
kPokusClickableThirdCursorID = 145,
kPokusNotClickableCursorID = 140,
kPokusHoldingItemCursorID = 147,
kPokusPDAFirstCursorID = 141,
kPokusPDASecondCursorID = 144
};
// from Peril
// it contains cursors whose ids differ
enum {
kPerilClickableThirdCursorID = 140,
kPerilNotClickableCursorID = 139,
kPerilPDASecondCursorID = 142
};
enum {
kLoadingSave = 1,
kLoadingNewGame = 0
};
} // End of namespace Pink
#endif

View File

@ -21,9 +21,57 @@
*/
#include "cursor_mgr.h"
#include "pink.h"
namespace Pink {
CursorMgr::CursorMgr(GamePage *page) : _page(page) {}
CursorMgr::CursorMgr(PinkEngine *game, GamePage *page)
: _actor(nullptr), _page(page), _game(game),
_isPlayingAnimation(0), _firstFrameIndex(0)
{}
CursorMgr::~CursorMgr() {}
void CursorMgr::setCursor(uint index, Common::Point point) {
if (index == kClickableFirstFrameCursor) {
if (!_isPlayingAnimation) {
_isPlayingAnimation = 1;
_time = _game->getTotalPlayTime();
_firstFrameIndex = index;
_isSecondFrame = 0;
_game->setCursor(index);
}
}
else {
_isPlayingAnimation = 0;
_game->setCursor(index);
}
}
void CursorMgr::update() {
if (!_isPlayingAnimation)
return;
uint newTime = _game->getTotalPlayTime();
if (newTime - _time > 0xC8){
_time = newTime;
_isSecondFrame = !_isSecondFrame;
_game->setCursor(_firstFrameIndex + _isSecondFrame);
}
}
void CursorMgr::setCursor(Common::String &cursorName, Common::Point point) {
uint index;
if (cursorName == "ExitLeft") {
index = kExitLeftCursor;
}
else if (cursorName == "ExitRight"){
index = kExitRightCursor;
}
else if (cursorName == "ExitForward")
index = kExitForwardCursor;
else assert(0);
setCursor(index, point);
}
} // End of namespace Pink

View File

@ -23,21 +23,35 @@
#ifndef PINK_CURSOR_MGR_H
#define PINK_CURSOR_MGR_H
#include "engines/pink/objects/object.h"
#include <graphics/wincursor.h>
#include <engines/pink/objects/object.h>
#include <common/rect.h>
namespace Pink {
class Actor;
class GamePage;
class PinkEngine;
class CursorMgr : public Object {
public:
CursorMgr(GamePage *page);
CursorMgr(PinkEngine *game, GamePage *page);
~CursorMgr();
void update();
void setCursor(uint index, Common::Point point);
void setCursor(Common::String &cursorName, Common::Point point);
private:
Actor *_actor;
GamePage *_page;
PinkEngine *_game;
uint _time;
uint _firstFrameIndex;
bool _isPlayingAnimation;
bool _isSecondFrame;
};
} // End of namespace Pink

View File

@ -33,6 +33,7 @@ static const ADGameDescription gameDescriptions[] = {
0,{
{"PPTP.ORB", NULL, NULL, -1},
{"PPTP.BRO", NULL, NULL, -1},
{"PPTP.EXE", NULL, NULL, -1},
AD_LISTEND},
Common::EN_ANY,
Common::kPlatformWindows,
@ -41,8 +42,10 @@ static const ADGameDescription gameDescriptions[] = {
},
{
"pokus",
0,
AD_ENTRY1s("hpp.ORB", NULL, -1),
0, {
{"HPP.orb", NULL, NULL, -1},
{"hpp.exe", NULL, NULL, -1},
AD_LISTEND},
Common::EN_ANY,
Common::kPlatformWindows,
ADGF_UNSTABLE,

View File

@ -32,28 +32,28 @@ Director::Director(OSystem *system)
: _system(system), showBounds(0) {}
void Director::draw() {
_system->fillScreen(0);
for (int i = 0; i < _sprites.size(); ++i) {
CelDecoder *decoder = _sprites[i]->getDecoder();
drawSprite(decoder);
drawSprite(_sprites[i]);
}
_system->updateScreen();
}
void Director::drawSprite(CelDecoder *decoder) {
void Director::drawSprite(ActionCEL *sprite) {
CelDecoder *decoder = sprite->getDecoder();
const Graphics::Surface *surface;
if (decoder->needsUpdate())
surface = decoder->decodeNextFrame();
else surface = decoder->getCurrentFrame();
uint16 colourIndex = decoder->getTransparentColourIndex();
if (!showBounds && colourIndex != 0) {
if (!showBounds) {
Graphics::Surface *screen = _system->lockScreen();
for (int y = 0; y < decoder->getHeight(); ++y) {
for (int x = 0; x < decoder->getWidth(); ++x) {
byte spritePixelColourIndex = *(byte*)surface->getBasePtr(x, y);
if (spritePixelColourIndex != colourIndex && spritePixelColourIndex != 229) { // hack because sprite have wrong colour index
uint16 spritePixelColourIndex = *(byte*)surface->getBasePtr(x, y);
if (spritePixelColourIndex != decoder->getTransparentColourIndex()) {
*(byte *) screen->getBasePtr(decoder->getX() + x, decoder->getY() + y) = spritePixelColourIndex;
}
}
@ -115,4 +115,16 @@ void Director::clear() {
_sprites.clear();
}
Actor *Director::getActorByPoint(Common::Point point) {
for (int i = _sprites.size() - 1; i > 0; --i) {
CelDecoder *decoder = _sprites[i]->getDecoder();
if (decoder->getRectangle().contains(point) &&
*(byte*)decoder->getCurrentFrame()->getBasePtr(640 - point.x, 480 - point.y)
!= decoder->getTransparentColourIndex())
return _sprites[i]->getActor();
}
return nullptr;
}
}

View File

@ -25,9 +25,11 @@
#include <common/array.h>
#include <common/system.h>
#include <common/rect.h>
namespace Pink {
class Actor;
class ActionCEL;
class ActionSound;
class CelDecoder;
@ -49,10 +51,11 @@ public:
void clear();
Actor *getActorByPoint(Common::Point point);
bool showBounds;
private:
void drawSprite(CelDecoder *decoder);
void drawSprite(ActionCEL *sprite);
OSystem *_system;
Common::Array<ActionCEL*> _sprites;
Common::Array<ActionSound*> _sounds;

View File

@ -40,6 +40,8 @@ public:
virtual bool initPalette(Director *director) { return 0;}
Actor *getActor() { return _actor;}
protected:
Actor *_actor;
};

View File

@ -23,6 +23,7 @@
#include <common/debug.h>
#include "action_cel.h"
#include <pink/objects/actors/actor.h>
#include <graphics/surface.h>
#include "engines/pink/archive.h"
#include "engines/pink/objects/pages/game_page.h"
#include "pink/pink.h"
@ -44,6 +45,7 @@ void ActionCEL::start(bool unk) {
if (!_decoder)
_decoder = _actor->getPage()->loadCel(_fileName);
_actor->getPage()->getGame()->getDirector()->addSprite(this);
this->onStart();
}

View File

@ -55,7 +55,7 @@ void ActionLoop::update() {
// for now it supports only forward loop animation
if (_style == kForward) {
if (_decoder->endOfVideo()){
debug("ACTION LOOP : NEXT ITERATION");
//debug("ACTION LOOP : NEXT ITERATION");
_decoder->rewind();
}
}

View File

@ -93,7 +93,8 @@ void ActionSfx::play(GamePage *page) {
if (!_sound)
_sound = page->loadSound(_sfxName);
_sound->play(Audio::Mixer::SoundType::kSFXSoundType, _volume, 0);
if (!_sound->isPlaying())
_sound->play(Audio::Mixer::SoundType::kSFXSoundType, _volume, 0);
}
ActionSfx::~ActionSfx() {

View File

@ -31,12 +31,11 @@ namespace Pink {
class ActionSfx;
class ActionPlayWithSfx : public ActionPlay {
public:
virtual ~ActionPlayWithSfx();
virtual void deserialize(Archive &archive);
virtual void toConsole();
virtual void update();
public:
virtual void end();
protected:

View File

@ -20,10 +20,12 @@
*
*/
#include <engines/pink/constants.h>
#include "actor.h"
#include "engines/pink/objects/pages/game_page.h"
#include "lead_actor.h"
#include "engines/pink/objects/actions/action.h"
#include "pink/cursor_mgr.h"
namespace Pink {
@ -122,4 +124,14 @@ bool Actor::initPallete(Director *director) {
return false;
}
void Actor::onMouseOver(Common::Point point, CursorMgr *mgr) {
mgr->setCursor(kDefaultCursor, point);
}
Actor::~Actor() {
for (int i = 0; i < _actions.size(); ++i) {
delete _actions[i];
}
}
} // End of namespace Pink

View File

@ -24,6 +24,7 @@
#define PINK_ACTOR_H
#include <common/array.h>
#include <common/rect.h>
#include "engines/pink/objects/object.h"
namespace Pink {
@ -32,6 +33,7 @@ class GamePage;
class Action;
class Sequencer;
class Director;
class CursorMgr;
class Actor : public NamedObject {
public:
@ -39,6 +41,7 @@ public:
: _page(nullptr), _action(nullptr),
_isActionEnded(1)
{};
~Actor();
virtual void deserialize(Archive &archive);
virtual void toConsole();
@ -61,6 +64,9 @@ public:
virtual void update() {};
virtual void onMouseOver(Common::Point point, CursorMgr *mgr);
virtual bool isClickable() { return 0;}
protected:
GamePage *_page;
Action *_action;

View File

@ -29,13 +29,13 @@
#include "engines/pink/archive.h"
#include "engines/pink/objects/pages/game_page.h"
#include "engines/pink/pink.h"
#include "supporting_actor.h"
namespace Pink {
void LeadActor::deserialize(Archive &archive) {
_state = kReady;
Actor::deserialize(archive);
_state = kReady;
_cursorMgr = static_cast<CursorMgr*>(archive.readObject());
_walkMgr = static_cast<WalkMgr*>(archive.readObject());
_sequencer = static_cast<Sequencer*>(archive.readObject());
@ -70,18 +70,36 @@ LeadActor::State LeadActor::getState() const {
void LeadActor::update() {
switch (_state) {
case kReady:
_sequencer->update();
//fall-through intended
case kMoving:
_cursorMgr->update();
break;
case kInDialog1:
case kInDialog2:
_sequencer->update();
break;
case kInventory:
case kPDA:
break;
case kPlayingVideo:
_sequencer->update();
if (!_sequencer->_context){
_state = kUnk_Loading;
_page->getGame()->changeScene(_page);
}
default:
break;
case kUnk_Loading:
break;
}
}
void LeadActor::OnKeyboardButtonClick(Common::KeyCode code) {
void LeadActor::onKeyboardButtonClick(Common::KeyCode code) {
switch(_state) {
case kMoving:
switch (code){
@ -116,6 +134,73 @@ void LeadActor::OnKeyboardButtonClick(Common::KeyCode code) {
}
}
void LeadActor::start(bool isHandler) {
if (isHandler && _state != kPlayingVideo){
_state = kReady;
}
updateCursor({0,0});
}
void LeadActor::onMouseMove(Common::Point point) {
if (_state != kPDA)
updateCursor(point);
else error("pda is not supported");
}
void LeadActor::updateCursor(Common::Point point) {
switch (_state) {
case kReady:
case kMoving: {
Director *director = _page->getGame()->getDirector();
Actor *actor = director->getActorByPoint(point);
if (actor)
actor->onMouseOver(point, _cursorMgr);
else _cursorMgr->setCursor(kDefaultCursor, point);
break;
}
case kInDialog1:
case kInDialog2:
case kPlayingVideo:
_cursorMgr->setCursor(kNotClickableCursor, point);
break;
case kPDA:
case kInventory:
_cursorMgr->setCursor(kDefaultCursor, point);
break;
default:
break;
}
}
void LeadActor::onLeftButtonClick(Common::Point point) {
switch (_state) {
case kReady:
case kMoving: {
Actor *actor = _page->getGame()->getDirector()->getActorByPoint(point);
if (this == actor){
// inventory is not implemented
return;
}
if (actor->isClickable() &&
((SupportingActor*) actor)->isLeftClickHandlers())
break;
}
case kPDA:
break;
case kInventory:
break;
default:
break;
}
}
void ParlSqPink::toConsole() {
debug("ParlSqPink: _name = %s", _name.c_str());
for (int i = 0; i < _actions.size(); ++i) {

View File

@ -24,6 +24,7 @@
#define PINK_LEAD_ACTOR_H
#include <common/keyboard.h>
#include <common/rect.h>
#include "actor.h"
namespace Pink {
@ -58,8 +59,14 @@ public:
void start(bool isHandler);
void update();
void OnKeyboardButtonClick(Common::KeyCode code);
void onKeyboardButtonClick(Common::KeyCode code);
void onLeftButtonClick(Common::Point point);
void onMouseMove(Common::Point point);
private:
void updateCursor(Common::Point point);
State _state;
CursorMgr *_cursorMgr;
WalkMgr *_walkMgr;

View File

@ -23,7 +23,8 @@
#include "supporting_actor.h"
#include <engines/pink/archive.h>
#include <engines/pink/objects/actions/action.h>
#include <common/debug.h>
#include <engines/pink/constants.h>
#include "pink/cursor_mgr.h"
namespace Pink {
@ -42,4 +43,18 @@ void SupportingActor::toConsole() {
_handlerMgr.toConsole();
}
void SupportingActor::onMouseOver(Common::Point point, CursorMgr *mgr) {
if (isLeftClickHandlers()){
if (!_cursor.empty()){
mgr->setCursor(_cursor, point);
}
else mgr->setCursor(kClickableFirstFrameCursor, point);
}
else Actor::onMouseOver(point, mgr);
}
bool SupportingActor::isLeftClickHandlers() {
return _handlerMgr.isLeftClickHandler(this);
}
} // End of namespace Pink

View File

@ -33,6 +33,11 @@ public:
virtual void deserialize(Archive &archive);
virtual void toConsole();
virtual void onMouseOver(Common::Point point, CursorMgr *mgr);
virtual bool isClickable() { return 1; }
bool isLeftClickHandlers();
private:
HandlerMgr _handlerMgr;
Common::String _location;

View File

@ -32,7 +32,7 @@ void Pink::ConditionVariable::deserialize(Archive &archive) {
archive >> _name >> _value;
}
bool Pink::ConditionGameVariable::evaluate(LeadActor *leadActor) {
bool Pink::ConditionGameVariable::evaluate(Actor *leadActor) {
return leadActor->getPage()->getModule()->getGame()->checkValueOfVariable(_name, _value);
}
@ -40,7 +40,7 @@ void ConditionGameVariable::toConsole() {
debug("\t\tConditionGameVariable: _name=%s, _value=%s", _name.c_str(), _value.c_str());
}
bool Pink::ConditionModuleVariable::evaluate(LeadActor *leadActor) {
bool Pink::ConditionModuleVariable::evaluate(Actor *leadActor) {
return leadActor->getPage()->getModule()->checkValueOfVariable(_name, _value);
}
@ -48,7 +48,7 @@ void ConditionModuleVariable::toConsole() {
debug("\t\tConditionModuleVariable: _name=%s, _value=%s", _name.c_str(), _value.c_str());
}
bool Pink::ConditionNotModuleVariable::evaluate(LeadActor *leadActor) {
bool Pink::ConditionNotModuleVariable::evaluate(Actor *leadActor) {
return !ConditionModuleVariable::evaluate(leadActor);
}
@ -56,7 +56,7 @@ void ConditionNotModuleVariable::toConsole() {
debug("\t\tConditionNotModuleVariable: _name=%s, _value=%s", _name.c_str(), _value.c_str());
}
bool ConditionPageVariable::evaluate(LeadActor *leadActor) {
bool ConditionPageVariable::evaluate(Actor *leadActor) {
return leadActor->getPage()->checkValueOfVariable(_name, _value);
}
@ -64,7 +64,7 @@ void ConditionPageVariable::toConsole() {
debug("\t\tConditionPageVariable: _name=%s, _value=%s", _name.c_str(), _value.c_str());
}
bool ConditionNotPageVariable::evaluate(LeadActor *leadActor) {
bool ConditionNotPageVariable::evaluate(Actor *leadActor) {
return !ConditionPageVariable::evaluate(leadActor);
}
@ -76,7 +76,7 @@ void ConditionInventoryItemOwner::deserialize(Archive &archive) {
archive >> _item >> _owner;
}
bool ConditionInventoryItemOwner::evaluate(LeadActor *leadActor) {
bool ConditionInventoryItemOwner::evaluate(Actor *leadActor) {
InventoryMgr *mgr = leadActor->getPage()->getModule()->getInventoryMgr();
InventoryItem *item = mgr->findInventoryItem(_item);
return item->getCurrentOwner() == _owner;
@ -86,7 +86,7 @@ void ConditionInventoryItemOwner::toConsole() {
debug("\t\tConditionInventoryItemOwner: _item=%s, _owner=%s", _item.c_str(), _owner.c_str());
}
bool ConditionNotInventoryItemOwner::evaluate(LeadActor *leadActor) {
bool ConditionNotInventoryItemOwner::evaluate(Actor *leadActor) {
return !ConditionInventoryItemOwner::evaluate(leadActor);
}

View File

@ -32,14 +32,14 @@ class LeadActor;
class Condition : public Object {
public:
virtual void deserialize(Archive &archive) = 0;
virtual bool evaluate(LeadActor *leadActor) = 0;
virtual bool evaluate(Actor *leadActor) = 0;
};
class ConditionVariable : public Condition {
public:
virtual void deserialize(Archive &archive);
virtual bool evaluate(LeadActor *leadActor) = 0;
virtual bool evaluate(Actor *actor) = 0;
protected:
Common::String _name;
@ -49,7 +49,7 @@ protected:
class ConditionGameVariable : public ConditionVariable {
public:
virtual void toConsole();
virtual bool evaluate(LeadActor *leadActor);
virtual bool evaluate(Actor *actor);
};
/*
@ -62,32 +62,32 @@ class ConditionNotGameVariable : public ConditionGameVariable {
class ConditionModuleVariable : public ConditionVariable {
public:
virtual void toConsole();
virtual bool evaluate(LeadActor *leadActor);
virtual bool evaluate(Actor *actor);
};
class ConditionNotModuleVariable : public ConditionModuleVariable {
public:
virtual void toConsole();
virtual bool evaluate(LeadActor *leadActor);
virtual bool evaluate(Actor *actor);
};
class ConditionPageVariable : public ConditionVariable {
public:
virtual void toConsole();
virtual bool evaluate(LeadActor *leadActor);
virtual bool evaluate(Actor *actor);
};
class ConditionNotPageVariable : public ConditionPageVariable {
public:
virtual void toConsole();
virtual bool evaluate(LeadActor *leadActor);
virtual bool evaluate(Actor *actor);
};
class ConditionInventoryItemOwner : public Condition {
public:
virtual void toConsole();
virtual void deserialize(Archive &archive);
virtual bool evaluate(LeadActor *leadActor);
virtual bool evaluate(Actor *actor);
protected:
Common::String _item;
@ -97,7 +97,7 @@ protected:
class ConditionNotInventoryItemOwner : public ConditionInventoryItemOwner {
public:
virtual void toConsole();
virtual bool evaluate(LeadActor *leadActor);
virtual bool evaluate(Actor *actor);
};
} // End of namespace Pink

View File

@ -37,7 +37,7 @@ void Handler::deserialize(Archive &archive) {
archive >> _sideEffects;
}
bool Handler::isSuitable(LeadActor *actor) {
bool Handler::isSuitable(Actor *actor) {
for (int i = 0; i < _conditions.size(); ++i) {
if (!_conditions[i]->evaluate(actor)){
return false;
@ -56,6 +56,15 @@ void Handler::onMessage(LeadActor *actor) {
executeSideEffects(actor);
}
Handler::~Handler() {
for (int i = 0; i < _sideEffects.size(); ++i) {
delete _sideEffects[i];
}
for (int i = 0; i < _conditions.size(); ++i) {
delete _conditions[i];
}
}
void HandlerSequences::deserialize(Archive &archive) {
Handler::deserialize(archive);
archive >> _sequences;

View File

@ -33,12 +33,14 @@ namespace Pink {
class Condition;
class SideEffect;
class LeadActor;
class Actor;
class Handler : public Object {
public:
~Handler();
virtual void deserialize(Archive &archive);
virtual void onMessage(LeadActor *actor);
bool isSuitable(LeadActor *actor);
bool isSuitable(Actor *actor);
protected:
void executeSideEffects(LeadActor *actor);

View File

@ -27,4 +27,13 @@ void HandlerMgr::toConsole() {
}
}
bool HandlerMgr::isLeftClickHandler(Actor *actor) {
for (int i = 0; i < _leftClickHandlers.size(); ++i) {
if (_leftClickHandlers[i]->isSuitable(actor))
return true;
}
return false;
}
}

View File

@ -31,6 +31,7 @@ namespace Pink {
class HandlerLeftClick;
class HandlerUseClick;
class HandlerTimer;
class Actor;
class HandlerMgr : public Object {
public:
@ -38,6 +39,8 @@ public:
virtual void toConsole();
bool isLeftClickHandler(Actor *actor);
private:
Common::Array<HandlerLeftClick*> _leftClickHandlers;
Common::Array<HandlerUseClick*> _useClickHandlers;

View File

@ -93,6 +93,12 @@ InventoryMgr *Module::getInventoryMgr() {
return &_invMgr;
}
Module::~Module() {
for (int i = 0; i < _pages.size(); ++i) {
delete _pages[i];
}
}
} // End of namespace Pink

View File

@ -43,6 +43,7 @@ class GamePage;
class Module : public NamedObject {
public:
Module(PinkEngine *game, const Common::String &name);
~Module();
void load(Archive &archive);
void init(bool isLoadingSave, const Common::String &pageName);

View File

@ -77,7 +77,7 @@ void GamePage::init(bool isLoadingSave) {
isHandler = initHandler();
}
//_leadActor->start(isHandler);
_leadActor->start(isHandler);
}
bool GamePage::initHandler() {
@ -92,7 +92,7 @@ bool GamePage::initHandler() {
void GamePage::loadManagers() {
perhapsIsLoaded = true;
_cursorMgr = new CursorMgr(this);
_cursorMgr = new CursorMgr(_module->getGame(), this);
_walkMgr = new WalkMgr;
_sequencer = new Sequencer(this);
@ -137,4 +137,19 @@ void GamePage::toConsole() {
}
}
GamePage::~GamePage() {
delete _cursorMgr;
delete _walkMgr;
delete _sequencer;
for (int i = 0; i < _handlers.size(); ++i) {
delete _handlers[i];
}
}
GamePage::GamePage()
: _cursorMgr(nullptr), _walkMgr(nullptr), _sequencer(nullptr)
{
}
} // End of namespace Pink

View File

@ -34,6 +34,8 @@ class HandlerStartPage;
class GamePage : public Page {
public:
GamePage();
~GamePage();
virtual void deserialize(Archive &archive);
virtual void load(Archive &archive);

View File

@ -65,4 +65,10 @@ void Page::init() {
}
}
Page::~Page() {
for (int i = 0; i < _actors.size(); ++i) {
delete _actors[i];
}
}
} // End of namespace Pink

View File

@ -36,7 +36,7 @@ class LeadActor;
class Page : public NamedObject {
public:
~Page();
void load(Archive &archive);
Actor *findActor(Common::String &name);
Sound* loadSound(Common::String &fileName);

View File

@ -134,6 +134,11 @@ void Sequence::skipItemsTo(int index) {
}
}
void Sequence::skipSubSequence() {
if (_context->getNextItemIndex() < _context->getSequence()->getItems().size())
_context->getSequence()->start(0);
}
void SequenceAudio::deserialize(Archive &archive) {
Sequence::deserialize(archive);
archive >> _soundName;
@ -182,4 +187,8 @@ void SequenceAudio::restart() {
Sequence::restart();
}
void SequenceAudio::skipToLastSubSequence() {
end();
}
} // End of namespace Pink

View File

@ -49,9 +49,11 @@ public:
virtual void update();
virtual void restart();
void skipToLastSubSequence();
virtual void skipSubSequence();
virtual void skipToLastSubSequence();
void skipItemsTo(int index);
public:
SequenceContext *_context;
Sequencer *_sequencer;
@ -69,9 +71,13 @@ public:
virtual void init(int unk);
virtual void start(int unk);
virtual void end();
virtual void update();
virtual void restart();
virtual void skipSubSequence() {};
virtual void skipToLastSubSequence();
private:
Common::String _soundName;
Sound *_sound;

View File

@ -73,7 +73,8 @@ void Sequencer::toConsole() {
}
void Sequencer::update() {
_context->_sequence->update();
if (_context)
_context->_sequence->update();
}
void Sequencer::removeContext(SequenceContext *context) {
@ -82,8 +83,8 @@ void Sequencer::removeContext(SequenceContext *context) {
}
void Sequencer::skipSubSequence() {
if (_context && _context->getNextItemIndex() < _context->getSequence()->getItems().size())
_context->getSequence()->start(0);
if (_context)
_context->getSequence()->skipSubSequence();
}
void Sequencer::restartSequence() {

View File

@ -28,6 +28,8 @@
#include "engines/pink/objects/module.h"
#include "engines/pink/objects/actors/lead_actor.h"
#include <graphics/surface.h>
#include <graphics/cursorman.h>
#include <common/winexe_pe.h>
namespace Pink {
@ -51,6 +53,9 @@ Pink::PinkEngine::~PinkEngine() {
for (uint i = 0; i < _modules.size(); ++i) {
delete _modules[i];
}
for (int j = 0; j < _cursors.size(); ++j) {
delete _cursors[j];
}
DebugMan.clearAllDebugChannels();
}
@ -65,7 +70,7 @@ Common::Error PinkEngine::init() {
Common::String orbName{_desc.filesDescriptions[0].fileName};
Common::String broName{_desc.filesDescriptions[1].fileName};
if (!broName.empty()){
if (strcmp(_desc.gameId, "peril") == 0){
_bro = new BroFile();
}
else debug("This game doesn't need to use bro");
@ -74,8 +79,11 @@ Common::Error PinkEngine::init() {
return Common::kNoGameDataFoundError;
}
// TODO load cursor
if (!loadCursors())
return Common::kNoGameDataFoundError;
setCursor(kLoadingCursor);
_system->showMouse(1);
_orb.loadGame(this);
const Common::String empty;
@ -86,10 +94,8 @@ Common::Error PinkEngine::init() {
Common::Error Pink::PinkEngine::run() {
Common::Error error = init();
if (error.getCode() != Common::kNoError){
if (error.getCode() != Common::kNoError)
return error;
}
while(!shouldQuit()){
Common::Event event;
@ -99,15 +105,15 @@ Common::Error Pink::PinkEngine::run() {
case Common::EVENT_RTL:
return Common::kNoError;
case Common::EVENT_MOUSEMOVE:
_actor->onMouseMove(event.mouse);
break;
case Common::EVENT_LBUTTONDOWN:
_actor->onLeftButtonClick(event.mouse);
break;
case Common::EVENT_KEYDOWN:
if (event.kbd.keycode == Common::KEYCODE_d)
_director.showBounds = !_director.showBounds;
else _actor->OnKeyboardButtonClick(event.kbd.keycode);
else _actor->onKeyboardButtonClick(event.kbd.keycode);
break;
// don't know why it is used in original
@ -118,10 +124,11 @@ Common::Error Pink::PinkEngine::run() {
}
}
_actor->update();
_director.update();
_director.draw();
_system->delayMillis(50);
_system->delayMillis(5);
}
return Common::kNoError;
@ -135,35 +142,30 @@ void PinkEngine::load(Archive &archive) {
void PinkEngine::initModule(const Common::String &moduleName, bool isLoadingFromSave, const Common::String &pageName) {
if (_module) {
//call module function (smth with unloading)
uint i;
for (i = 0; i < _modules.size(); ++i) {
for (uint i = 0; i < _modules.size(); ++i) {
if (_module == _modules[i]){
_modules[i] = new ModuleProxy(_module->getName());
delete _module;
_module = nullptr;
break;
}
}
_modules[i] = new ModuleProxy(_module->getName());
delete _module;
_module = nullptr;
}
uint i;
for (i = 0; i < _modules.size(); ++i) {
for (uint i = 0; i < _modules.size(); ++i) {
if (_modules[i]->getName() == moduleName) {
loadModule(i);
_module = static_cast<Module*>(_modules[i]);
_module->init(isLoadingFromSave, pageName);
break;
}
}
_module = static_cast<Module*>(_modules[i]);
_module->init(isLoadingFromSave, pageName);
}
void PinkEngine::changeScene(GamePage *page) {
setCursor(kLoadingCursor);
if (!_nextModule.empty() && _nextModule.compareTo(_module->getName())) {
initModule(_nextModule, kLoadingNewGame, _nextPage);
}
@ -198,4 +200,47 @@ void PinkEngine::setVariable(Common::String &variable, Common::String &value) {
_variables[variable] = value;
}
bool PinkEngine::loadCursors() {
Common::PEResources exeResources;
bool isPokus = !strcmp(_desc.gameId, "pokus");
Common::String fileName = isPokus ? _desc.filesDescriptions[1].fileName : _desc.filesDescriptions[2].fileName;
if (!exeResources.loadFromEXE(fileName))
return false;
_cursors.reserve(kCursorsCount);
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusLoadingCursorID));
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusExitForwardCursorID));
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusExitLeftCursorID));
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusExitRightCursorID));
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusClickableFirstCursorID));
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusClickableSecondCursorID));
if (isPokus) {
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusClickableThirdCursorID));
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusNotClickableCursorID));
}
else {
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPerilClickableThirdCursorID));
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPerilNotClickableCursorID));
}
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusHoldingItemCursorID));
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusPDAFirstCursorID));
if (isPokus)
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPokusPDASecondCursorID));
else
_cursors.push_back(Graphics::WinCursorGroup::createCursorGroup(exeResources, kPerilPDASecondCursorID));
return true;
}
void PinkEngine::setCursor(uint cursorIndex) {
Graphics::Cursor *cursor = _cursors[cursorIndex]->cursors[0].cursor;
_system->setCursorPalette(cursor->getPalette(), cursor->getPaletteStartIndex(), cursor->getPaletteCount());
_system->setMouseCursor(cursor->getSurface(), cursor->getWidth(), cursor->getHeight(),
cursor->getHotspotX(), cursor->getHotspotY(), cursor->getKeyColor());
}
}

View File

@ -23,13 +23,14 @@
#ifndef PINK_PINK_H
#define PINK_PINK_H
#include <graphics/wincursor.h>
#include "common/random.h"
#include "engines/engine.h"
#include "gui/EventRecorder.h"
#include "gui/debugger.h"
#include "file.h"
#include "director.h"
#include "constants.h"
/*
* This is the namespace of the Pink engine.
@ -60,11 +61,6 @@ enum {
kPinkDebugSound = 1 << 4
};
enum {
kLoadingSave = 1,
kLoadingNewGame = 0
};
class PinkEngine : public Engine {
public:
PinkEngine(OSystem *system, const ADGameDescription *desc);
@ -87,14 +83,16 @@ public:
void setVariable(Common::String &variable, Common::String &value);
bool checkValueOfVariable(Common::String &variable, Common::String &value);
inline void setCursor(uint cursorIndex);
private:
Common::Error init();
bool loadCursors();
void loadModule(int index);
Console *_console;
Common::RandomSource _rnd;
Common::Array<Graphics::WinCursorGroup*> _cursors;
Common::String _nextModule;
Common::String _nextPage;

View File

@ -23,24 +23,24 @@
#include <audio/audiostream.h>
#include <audio/decoders/wave.h>
#include <audio/decoders/adpcm.h>
#include <common/substream.h>
#include "sound.h"
namespace Pink {
Sound::Sound(Audio::Mixer *mixer, Common::SeekableReadStream *stream)
: _mixer(mixer)
Sound::Sound(Audio::Mixer *mixer, Common::SafeSeekableSubReadStream *stream)
: _mixer(mixer), _fileStream(stream)
{
load(stream);
}
Sound::~Sound() {
stop();
delete _stream;
delete _fileStream;
}
bool Sound::isPlaying() {
return _mixer->isSoundHandleActive(_handle);
}
void Sound::pause() {
@ -56,28 +56,19 @@ void Sound::stop() {
}
void Sound::play(Audio::Mixer::SoundType type, int volume, bool isLoop) {
_mixer->stopHandle(_handle);
if (isLoop) {
//bad impl?
Audio::SeekableAudioStream *seekableStream = dynamic_cast<Audio::SeekableAudioStream*>(_stream);
_stream = Audio::makeLoopingAudioStream(seekableStream, 0, 0, 0);
}
_mixer->playStream(type, &_handle ,_stream, -1 , Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
}
bool Sound::load(Common::SeekableReadStream *stream) {
// Vox files in pink have wave format.
// RIFF (little-endian) data, WAVE audio, Microsoft PCM, 8 bit, mono 22050 Hz
_mixer->stopHandle(_handle);
_stream = Audio::makeWAVStream(stream, DisposeAfterUse::YES);
_fileStream->seek(0);
Audio::AudioStream *audioStream ;
Audio::SeekableAudioStream *wavStream = Audio::makeWAVStream(_fileStream, DisposeAfterUse::NO);
if (isLoop) {
audioStream = Audio::makeLoopingAudioStream(wavStream, 0, 0, 0);
}
else audioStream = wavStream;
return isLoaded();
}
bool Sound::isLoaded() {
return _stream != nullptr;
_mixer->playStream(type, &_handle , audioStream, -1 , Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::YES);
}
void Sound::setBalance(int8 balance) {

View File

@ -36,13 +36,11 @@ namespace Pink {
class Sound {
public:
Sound(Audio::Mixer *mixer, Common::SeekableReadStream *stream);
Sound(Audio::Mixer *mixer, Common::SafeSeekableSubReadStream *stream);
~Sound();
bool load(Common::SeekableReadStream *stream);
void play(Audio::Mixer::SoundType type, int volume, bool isLoop);
bool isLoaded();
bool isPlaying();
void pause();
@ -54,8 +52,8 @@ public:
private:
Audio::Mixer *_mixer;
Audio::AudioStream *_stream;
Audio::SoundHandle _handle;
Common::SafeSeekableSubReadStream *_fileStream;
};
} // End of namespace Pink