mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-14 21:59:17 +00:00
347 lines
11 KiB
C++
347 lines
11 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 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.
|
|
*
|
|
*/
|
|
|
|
#include "common/debug.h"
|
|
#include "common/file.h"
|
|
|
|
#include "pink/objects/condition.h"
|
|
#include "pink/objects/module.h"
|
|
#include "pink/objects/side_effect.h"
|
|
#include "pink/objects/actions/action_hide.h"
|
|
#include "pink/objects/actions/action_play_with_sfx.h"
|
|
#include "pink/objects/actions/action_sound.h"
|
|
#include "pink/objects/actions/action_talk.h"
|
|
#include "pink/objects/actions/action_text.h"
|
|
#include "pink/objects/actions/walk_action.h"
|
|
#include "pink/objects/actors/audio_info_pda_button.h"
|
|
#include "pink/objects/actors/cursor_actor.h"
|
|
#include "pink/objects/actors/inventory_actor.h"
|
|
#include "pink/objects/actors/lead_actor.h"
|
|
#include "pink/objects/actors/pda_button_actor.h"
|
|
#include "pink/objects/actors/supporting_actor.h"
|
|
#include "pink/objects/handlers/handler.h"
|
|
#include "pink/objects/handlers/handler_timer.h"
|
|
#include "pink/objects/pages/game_page.h"
|
|
#include "pink/objects/sequences/seq_timer.h"
|
|
#include "pink/objects/sequences/sequence.h"
|
|
#include "pink/objects/sequences/sequence_item.h"
|
|
#include "pink/objects/walk/walk_location.h"
|
|
|
|
namespace Pink {
|
|
|
|
static const struct RuntimeClass {
|
|
const char *name;
|
|
int id;
|
|
} classMap[] = {
|
|
{"ActionHide", kActionHide},
|
|
{"ActionLoop", kActionLoop},
|
|
{"ActionPlay", kActionPlay},
|
|
{"ActionPlayWithSfx", kActionPlayWithSfx},
|
|
{"ActionSfx", kActionSfx},
|
|
{"ActionSound", kActionSound},
|
|
{"ActionStill", kActionStill},
|
|
{"ActionTalk", kActionTalk},
|
|
{"ActionText", kActionText},
|
|
{"Actor", kActor},
|
|
{"AudioInfoPDAButton", kAudioInfoPDAButton},
|
|
{"ConditionGameVariable", kConditionGameVariable},
|
|
{"ConditionInventoryItemOwner", kConditionInventoryItemOwner},
|
|
{"ConditionModuleVariable", kConditionModuleVariable},
|
|
{"ConditionNotInventoryItemOwner", kConditionNotInventoryItemOwner},
|
|
{"ConditionNotModuleVariable", kConditionNotModuleVariable},
|
|
{"ConditionNotPageVariable", kConditionNotPageVariable},
|
|
{"ConditionPageVariable", kConditionPageVariable},
|
|
{"CursorActor", kCursorActor},
|
|
{"GamePage", kGamePage},
|
|
{"HandlerLeftClick", kHandlerLeftClick},
|
|
{"HandlerStartPage", kHandlerStartPage},
|
|
{"HandlerTimer", kHandlerTimer},
|
|
{"HandlerTimerActions", kHandlerTimerActions},
|
|
{"HandlerTimerSequences", kHandlerTimerSequences},
|
|
{"HandlerUseClick", kHandlerUseClick},
|
|
{"InventoryActor", kInventoryActor},
|
|
{"InventoryItem", kInventoryItem},
|
|
{"LeadActor", kLeadActor},
|
|
{"ModuleProxy", kModuleProxy},
|
|
{"PDAButtonActor", kPDAButtonActor},
|
|
{"ParlSqPink", kParlSqPink},
|
|
{"PubPink", kPubPink},
|
|
{"SeqTimer", kSeqTimer},
|
|
{"Sequence", kSequence},
|
|
{"SequenceAudio", kSequenceAudio},
|
|
{"SequenceItem", kSequenceItem},
|
|
{"SequenceItemDefaultAction", kSequenceItemDefaultAction},
|
|
{"SequenceItemLeader", kSequenceItemLeader},
|
|
{"SequenceItemLeaderAudio", kSequenceItemLeaderAudio},
|
|
{"SideEffectExit", kSideEffectExit},
|
|
{"SideEffectGameVariable", kSideEffectGameVariable},
|
|
{"SideEffectInventoryItemOwner", kSideEffectInventoryItemOwner},
|
|
{"SideEffectLocation", kSideEffectLocation},
|
|
{"SideEffectModuleVariable", kSideEffectModuleVariable},
|
|
{"SideEffectPageVariable", kSideEffectPageVariable},
|
|
{"SideEffectRandomPageVariable", kSideEffectRandomPageVariable},
|
|
{"SupportingActor", kSupportingActor},
|
|
{"WalkAction", kWalkAction},
|
|
{"WalkLocation", kWalkLocation}
|
|
};
|
|
|
|
static Object* createObject(int objectId){
|
|
switch (objectId){
|
|
case kActionHide:
|
|
return new ActionHide;
|
|
case kActionLoop:
|
|
return new ActionLoop;
|
|
case kActionPlay:
|
|
return new ActionPlay;
|
|
case kActionPlayWithSfx:
|
|
return new ActionPlayWithSfx;
|
|
case kActionSfx:
|
|
return new ActionSfx;
|
|
case kActionSound:
|
|
return new ActionSound;
|
|
case kActionStill:
|
|
return new ActionStill;
|
|
case kActionTalk:
|
|
return new ActionTalk;
|
|
case kActionText:
|
|
return new ActionText;
|
|
case kActor:
|
|
return new Actor;
|
|
case kAudioInfoPDAButton:
|
|
return new AudioInfoPDAButton;
|
|
case kConditionGameVariable:
|
|
return new ConditionGameVariable;
|
|
case kConditionInventoryItemOwner:
|
|
return new ConditionInventoryItemOwner;
|
|
case kConditionModuleVariable:
|
|
return new ConditionModuleVariable;
|
|
case kConditionNotInventoryItemOwner:
|
|
return new ConditionNotInventoryItemOwner;
|
|
case kConditionNotModuleVariable:
|
|
return new ConditionNotModuleVariable;
|
|
case kConditionNotPageVariable:
|
|
return new ConditionNotPageVariable;
|
|
case kConditionPageVariable:
|
|
return new ConditionPageVariable;
|
|
case kCursorActor:
|
|
return new CursorActor;
|
|
case kGamePage:
|
|
return new GamePage;
|
|
case kHandlerLeftClick:
|
|
return new HandlerLeftClick;
|
|
case kHandlerStartPage:
|
|
return new HandlerStartPage;
|
|
case kHandlerTimer:
|
|
case kHandlerTimerActions:
|
|
return new HandlerTimerActions; // hack for Peril, but behavior is correct
|
|
case kHandlerTimerSequences:
|
|
return new HandlerTimerSequences;
|
|
case kHandlerUseClick:
|
|
return new HandlerUseClick;
|
|
case kInventoryActor:
|
|
return new InventoryActor;
|
|
case kInventoryItem:
|
|
return new InventoryItem;
|
|
case kLeadActor:
|
|
return new LeadActor;
|
|
case kModuleProxy:
|
|
return new ModuleProxy;
|
|
case kPDAButtonActor:
|
|
return new PDAButtonActor;
|
|
case kParlSqPink:
|
|
return new ParlSqPink;
|
|
case kPubPink:
|
|
return new PubPink;
|
|
case kSeqTimer:
|
|
return new SeqTimer;
|
|
case kSequence:
|
|
return new Sequence;
|
|
case kSequenceAudio:
|
|
return new SequenceAudio;
|
|
case kSequenceItem:
|
|
return new SequenceItem;
|
|
case kSequenceItemDefaultAction:
|
|
return new SequenceItemDefaultAction;
|
|
case kSequenceItemLeader:
|
|
return new SequenceItemLeader;
|
|
case kSequenceItemLeaderAudio:
|
|
return new SequenceItemLeaderAudio;
|
|
case kSideEffectExit:
|
|
return new SideEffectExit;
|
|
case kSideEffectGameVariable:
|
|
return new SideEffectGameVariable;
|
|
case kSideEffectInventoryItemOwner:
|
|
return new SideEffectInventoryItemOwner;
|
|
case kSideEffectLocation:
|
|
return new SideEffectLocation;
|
|
case kSideEffectModuleVariable:
|
|
return new SideEffectModuleVariable;
|
|
case kSideEffectPageVariable:
|
|
return new SideEffectPageVariable;
|
|
case kSideEffectRandomPageVariable:
|
|
return new SideEffectRandomPageVariable;
|
|
case kSupportingActor:
|
|
return new SupportingActor;
|
|
case kWalkAction:
|
|
return new WalkAction;
|
|
case kWalkLocation:
|
|
return new WalkLocation;
|
|
default:
|
|
error("Unknown object id");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
Archive::Archive(Common::SeekableReadStream *stream)
|
|
: _readStream(stream), _writeStream(nullptr)
|
|
{
|
|
_objectMap.push_back(0);
|
|
_objectIdMap.push_back(kNullObject);
|
|
}
|
|
|
|
Archive::Archive(Common::WriteStream *stream)
|
|
: _writeStream(stream), _readStream(nullptr)
|
|
{
|
|
_objectMap.push_back(0);
|
|
_objectIdMap.push_back(kNullObject);
|
|
}
|
|
|
|
Archive::~Archive()
|
|
{}
|
|
|
|
void Archive::mapObject(Object *obj) {
|
|
_objectMap.push_back(obj);
|
|
_objectIdMap.push_back(0);
|
|
}
|
|
|
|
int Archive::readCount() {
|
|
int count = _readStream->readUint16LE();
|
|
|
|
if (count == 0xffff)
|
|
count = _readStream->readUint32LE();
|
|
|
|
return count;
|
|
}
|
|
|
|
Object *Archive::readObject() {
|
|
bool isCopyReturned;
|
|
Object *res = parseObject(isCopyReturned);
|
|
|
|
if (res && !isCopyReturned) {
|
|
res->deserialize(*this);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
Object *Archive::parseObject(bool &isCopyReturned) {
|
|
char className[kMaxClassLength];
|
|
int objectId = 0;
|
|
Object *res = nullptr;
|
|
|
|
uint obTag = _readStream->readUint16LE();
|
|
|
|
if (obTag == 0x0000) {
|
|
return nullptr;
|
|
} else if (obTag == 0xffff) {
|
|
int schema = _readStream->readUint16LE();
|
|
|
|
int size = _readStream->readUint16LE();
|
|
_readStream->read(className, size);
|
|
className[size] = '\0';
|
|
|
|
objectId = findObjectId(className + 1);
|
|
|
|
res = createObject(objectId);
|
|
if (!res) error("Class %s is not implemented", className);
|
|
|
|
_objectMap.push_back(res);
|
|
_objectIdMap.push_back(objectId);
|
|
|
|
_objectMap.push_back(res); // Basically a hack, but behavior is all correct
|
|
_objectIdMap.push_back(objectId);
|
|
|
|
isCopyReturned = false;
|
|
} else if ((obTag & 0x8000) == 0) {
|
|
|
|
res = _objectMap[obTag];
|
|
|
|
isCopyReturned = true;
|
|
} else {
|
|
|
|
obTag &= ~0x8000;
|
|
|
|
objectId = _objectIdMap[obTag];
|
|
|
|
res = createObject(objectId);
|
|
_objectMap.push_back(res);
|
|
_objectIdMap.push_back(objectId);
|
|
|
|
isCopyReturned = false;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
uint Archive::findObjectId(const char *name) {
|
|
RuntimeClass *found = static_cast<RuntimeClass*>
|
|
(bsearch(name, classMap, sizeof(classMap) / sizeof(RuntimeClass) , sizeof(RuntimeClass), [] (const void *a, const void *b) {
|
|
return strcmp((const char *) a, *(const char **) b);
|
|
}));
|
|
|
|
if (!found)
|
|
error("Class %s is not in class Map", name);
|
|
|
|
return found->id;
|
|
}
|
|
|
|
Common::String Archive::readString() {
|
|
char buffer[kMaxStringLength];
|
|
byte len = _readStream->readByte();
|
|
assert(len <= kMaxStringLength);
|
|
_readStream->read(buffer, len);
|
|
return Common::String(buffer, len);
|
|
}
|
|
|
|
uint32 Archive::readDWORD() {
|
|
return _readStream->readUint32LE();
|
|
}
|
|
|
|
uint16 Archive::readWORD() {
|
|
return _readStream->readUint16LE();
|
|
}
|
|
|
|
void Archive::writeDWORD(uint32 val) {
|
|
_writeStream->writeUint32LE(val);
|
|
}
|
|
|
|
void Archive::writeWORD(uint16 val) {
|
|
_writeStream->writeUint16LE(val);
|
|
}
|
|
|
|
void Archive::writeString(const Common::String &string) {
|
|
_writeStream->writeByte(string.size());
|
|
_writeStream->write(string.c_str(), string.size());
|
|
}
|
|
|
|
} // End of namespace Pink
|