Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
/* 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/misc/debugger.h"
#include "ultima/ultima8/usecode/bit_set.h"
namespace Ultima {
namespace Ultima8 {
BitSet::BitSet() : _size(0), _bytes(0), _data(nullptr) {
}
BitSet::BitSet(unsigned int size) : _data(nullptr) {
setSize(size);
}
BitSet::~BitSet() {
delete[] _data;
}
void BitSet::setSize(unsigned int size) {
if (_data) delete[] _data;
_size = size;
_bytes = _size / 8;
if (_size % 8 != 0) _bytes++;
_data = new uint8[_bytes];
for (unsigned int i = 0; i < _bytes; ++i)
_data[i] = 0;
}
uint32 BitSet::getEntries(unsigned int pos, unsigned int n) const {
assert(n <= 32);
assert(pos + n <= _size);
if (n == 0) return 0;
unsigned int firstbyte = pos / 8;
unsigned int lastbyte = (pos + n - 1) / 8;
if (firstbyte == lastbyte) {
return ((_data[firstbyte] >> (pos % 8)) & ((1 << n) - 1));
}
unsigned int firstbits = 8 - (pos % 8);
unsigned int lastbits = ((pos + n - 1) % 8) + 1;
unsigned int firstmask = ((1 << firstbits) - 1) << (8 - firstbits);
unsigned int lastmask = ((1 << lastbits) - 1);
uint32 ret = 0;
ret |= (_data[firstbyte] & firstmask) >> (8 - firstbits);
unsigned int shift = firstbits;
for (unsigned int i = firstbyte + 1; i < lastbyte; ++i) {
ret |= (_data[i] << shift);
shift += 8;
}
ret |= (_data[lastbyte] & lastmask) << shift;
return ret;
}
void BitSet::setEntries(unsigned int pos, unsigned int n, uint32 bits) {
assert(n <= 32);
assert(pos + n <= _size);
if (n == 0) return;
unsigned int firstbyte = pos / 8;
unsigned int lastbyte = (pos + n - 1) / 8;
if (firstbyte == lastbyte) {
_data[firstbyte] &= ~(((1 << n) - 1) << (pos % 8));
_data[firstbyte] |= (bits & ((1 << n) - 1)) << (pos % 8);
return;
}
unsigned int firstbits = 8 - (pos % 8);
unsigned int lastbits = ((pos + n - 1) % 8) + 1;
unsigned int firstmask = ((1 << firstbits) - 1) << (8 - firstbits);
unsigned int lastmask = ((1 << lastbits) - 1);
_data[firstbyte] &= ~firstmask;
_data[firstbyte] |= (bits << (8 - firstbits)) & firstmask;
unsigned int shift = firstbits;
for (unsigned int i = firstbyte + 1; i < lastbyte; ++i) {
_data[i] = (bits >> shift);
shift += 8;
}
_data[lastbyte] &= ~lastmask;
_data[lastbyte] |= (bits >> shift) & lastmask;
}
void BitSet::save(Common::WriteStream *ws) {
ws->writeUint32LE(_size);
ws->write(_data, _bytes);
}
bool BitSet::load(Common::ReadStream *rs, uint32 version) {
uint32 s = rs->readUint32LE();
if (s > 1024 * 1024) {
warning("Improbable globals size %d, corrupt save?", s);
return false;
}
setSize(s);
rs->read(_data, _bytes);
return true;
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,64 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_BITSET_H
#define ULTIMA8_USECODE_BITSET_H
#include "ultima/ultima8/usecode/global_storage.h"
namespace Ultima {
namespace Ultima8 {
class BitSet : public GlobalStorage {
public:
BitSet();
BitSet(unsigned int size);
~BitSet();
//! set the size. The old value is cleared
//! \param size the new size (in bits)
void setSize(unsigned int size) override;
//! get a value
//! \param pos zero-based position (in bits)
//! \param n number of bits (no greater than 32)
//! \return the value these bits represent
uint32 getEntries(unsigned int pos, unsigned int n) const override;
//! set a value
//! \param pos zero-based position (in bits)
//! \param n number of bits (no greater than 32)
//! \param bits the value to set
void setEntries(unsigned int pos, unsigned int n, uint32 bits) override;
void save(Common::WriteStream *ws) override;
bool load(Common::ReadStream *rs, uint32 version) override;
private:
unsigned int _size;
unsigned int _bytes;
uint8 *_data;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,95 @@
/* 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/misc/debugger.h"
#include "ultima/ultima8/usecode/byte_set.h"
namespace Ultima {
namespace Ultima8 {
ByteSet::ByteSet() : _size(0), _data(nullptr) {
}
ByteSet::ByteSet(unsigned int size) : _data(nullptr) {
setSize(size);
}
ByteSet::~ByteSet() {
delete[] _data;
}
void ByteSet::setSize(unsigned int size) {
if (_data) delete[] _data;
_size = size;
_data = new uint8[_size];
for (unsigned int i = 0; i < _size; ++i)
_data[i] = 0;
}
uint32 ByteSet::getEntries(unsigned int pos, unsigned int n) const {
assert(n <= 2);
assert(pos + n <= _size);
if (n == 0) return 0;
if (n == 1) {
return _data[pos];
} else if (n == 2) {
return (_data[pos] << 8) | _data[pos + 1];
}
return 0;
}
void ByteSet::setEntries(unsigned int pos, unsigned int n, uint32 val) {
assert(n <= 2);
assert(pos + n <= _size);
if (n == 0) return;
if (n == 1) {
_data[pos] = static_cast<uint8>(val);
} else if (n == 2) {
_data[pos] = static_cast<uint8>((val & 0xFF00) >> 8);
_data[pos + 1] = static_cast<uint8>(val & 0xFF);
}
}
void ByteSet::save(Common::WriteStream *ws) {
ws->writeUint32LE(_size);
ws->write(_data, _size);
}
bool ByteSet::load(Common::ReadStream *rs, uint32 version) {
uint32 s = rs->readUint32LE();
if (s > 1024 * 1024) {
warning("Improbable globals size %d, corrupt save?", s);
return false;
}
setSize(s);
rs->read(_data, _size);
return true;
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,65 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_BYTESET_H
#define ULTIMA8_USECODE_BYTESET_H
#include "ultima/ultima8/usecode/global_storage.h"
namespace Ultima {
namespace Ultima8 {
// This is a minimal implementation just to support what Crusader needs.
class ByteSet : public GlobalStorage {
public:
ByteSet();
ByteSet(unsigned int size);
~ByteSet();
//! set the size. The old value is cleared
//! \param size the new size (in bytes)
void setSize(unsigned int size) override;
//! get a value
//! \param pos zero-based position (in bytes:)
//! \param n number of bytes (no greater than 2)
//! \return the value these bytes represent
uint32 getEntries(unsigned int pos, unsigned int n) const override;
//! set a value
//! \param pos zero-based position (in bytes)
//! \param n number of bytes (no greater than 2)
//! \param val the value to set
void setEntries(unsigned int pos, unsigned int n, uint32 val) override;
void save(Common::WriteStream *ws) override;
bool load(Common::ReadStream *rs, uint32 version) override;
private:
unsigned int _size;
uint8 *_data;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,57 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_GLOBAL_STORAGE_H
#define ULTIMA8_USECODE_GLOBAL_STORAGE_H
namespace Ultima {
namespace Ultima8 {
/**
* Base class for globals that are accessed by the Usecode.
* In U8 this is a bitfield, in Crusader it's a byte array.
*/
class GlobalStorage {
public:
virtual ~GlobalStorage() {};
virtual void setSize(unsigned int size) = 0;
//! get a value
//! \param pos zero-based position
//! \param n number of entries to read
//! \return the value these entries represent
virtual uint32 getEntries(unsigned int pos, unsigned int n) const = 0;
//! set a value
//! \param pos zero-based position
//! \param n number of entries (no greater than one uint32-worth)
//! \param val the value to set
virtual void setEntries(unsigned int pos, unsigned int n, uint32 val) = 0;
virtual void save(Common::WriteStream *ws) = 0;
virtual bool load(Common::ReadStream *rs, uint32 version) = 0;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,100 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_INTRINSICS_H
#define ULTIMA8_USECODE_INTRINSICS_H
#include "common/scummsys.h"
namespace Ultima {
namespace Ultima8 {
typedef uint32(*Intrinsic)(const uint8 *args, unsigned int argsize);
#define INTRINSIC(x) static uint32 x (const uint8* args, unsigned int argsize)
// TODO: range checking on args
// UINT8s are pushed on the stack as words (see push byte opcodes),
// so we ignore the top byte when popping.
#define ARG_UINT8(x) uint8 x = (*args++); args++;
#define ARG_UINT16(x) uint16 x = (*args++); x += ((*args++) << 8);
#define ARG_UINT32(x) uint32 x = (*args++); x += ((*args++) << 8); \
x+= ((*args++) << 16); x += ((*args++) << 24);
#define ARG_SINT8(x) int8 x = (*args++);
#define ARG_SINT16(x) int16 x = (*args++); x += ((*args++) << 8);
#define ARG_SINT32(x) int32 x = (*args++); x += ((*args++) << 8); \
x+= ((*args++) << 16); x += ((*args++) << 24);
#define ARG_UC_PTR(x) uint32 x = (*args++); x += ((*args++) << 8); \
x+= ((*args++) << 16); x += ((*args++) << 24);
#define ARG_OBJID(x) ObjId x = (*args++); x += ((*args++) << 8);
#define ARG_PROCID(x) ProcId x = (*args++); x += ((*args++) << 8);
#define ARG_OBJECT_FROM_PTR(x) ARG_UC_PTR(ucptr_##x); \
uint16 id_##x = UCMachine::ptrToObject(ucptr_##x); \
Object* x = getObject(id_##x);
#define ARG_OBJECT_FROM_ID(x) ARG_OBJID(id_##x); \
Object* x = getObject(id_##x);
#define ARG_ITEM_FROM_PTR(x) ARG_UC_PTR(ucptr_##x); \
uint16 id_##x = UCMachine::ptrToObject(ucptr_##x); \
Item* x = getItem(id_##x);
#define ARG_ITEM_FROM_ID(x) ARG_OBJID(id_##x); \
Item* x = getItem(id_##x);
#define ARG_CONTAINER_FROM_PTR(x) ARG_UC_PTR(ucptr_##x); \
uint16 id_##x = UCMachine::ptrToObject(ucptr_##x); \
Container* x = getContainer(id_##x);
#define ARG_CONTAINER_FROM_ID(x) ARG_OBJID(id_##x); \
Container* x = getContainer(id_##x);
#define ARG_ACTOR_FROM_PTR(x) ARG_UC_PTR(ucptr_##x); \
uint16 id_##x = UCMachine::ptrToObject(ucptr_##x); \
Actor* x = getActor(id_##x);
#define ARG_ACTOR_FROM_ID(x) ARG_OBJID(id_##x); \
Actor* x = getActor(id_##x);
#define ARG_EGG_FROM_PTR(x) ARG_UC_PTR(ucptr_##x); \
uint16 id_##x = UCMachine::ptrToObject(ucptr_##x); \
Egg* x = dynamic_cast<Egg*>(getObject(id_##x));
#define ARG_EGG_FROM_ID(x) ARG_OBJID(id_##x); \
Egg* x = dynamic_cast<Egg*>(getObject(id_##x));
#define ARG_STRING(x) ARG_UC_PTR(ucptr_##x); \
uint16 id_##x = UCMachine::ptrToObject(ucptr_##x); \
Std::string x = UCMachine::get_instance()->getString(id_##x);
#define ARG_LIST(x) ARG_UINT16(id_##x); \
UCList* x = UCMachine::get_instance()->getList(id_##x);
#define ARG_WORLDPOINT(x) ARG_UC_PTR(ucptr_##x); \
WorldPoint x; \
UCMachine::get_instance()->dereferencePointer(ucptr_##x, x._buf, 5);
// See comment on ARG_UINT8 for why +2 on NULL8
#define ARG_NULL8() args+=2;
#define ARG_NULL16() args+=2;
#define ARG_NULL32() args+=4;
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,337 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_U8INTRINSICS_H
#define ULTIMA8_USECODE_U8INTRINSICS_H
#include "ultima/ultima8/usecode/intrinsics.h"
#include "ultima/ultima8/world/item.h"
#include "ultima/ultima8/usecode/uc_machine.h"
#include "ultima/ultima8/world/container.h"
#include "ultima/ultima8/world/actors/actor.h"
#include "ultima/ultima8/world/actors/main_actor.h"
#include "ultima/ultima8/kernel/kernel.h"
#include "ultima/ultima8/world/camera_process.h"
#include "ultima/ultima8/ultima8.h"
#include "ultima/ultima8/world/egg.h"
#include "ultima/ultima8/world/monster_egg.h"
#include "ultima/ultima8/world/current_map.h"
#include "ultima/ultima8/gfx/palette_fader_process.h"
#include "ultima/ultima8/world/sprite_process.h"
#include "ultima/ultima8/audio/music_process.h"
#include "ultima/ultima8/gumps/scroll_gump.h"
#include "ultima/ultima8/gumps/book_gump.h"
#include "ultima/ultima8/gumps/readable_gump.h"
#include "ultima/ultima8/gumps/target_gump.h"
#include "ultima/ultima8/world/actors/grant_peace_process.h"
#include "ultima/ultima8/world/fireball_process.h"
#include "ultima/ultima8/world/actors/heal_process.h"
#include "ultima/ultima8/gfx/inverter_process.h"
#include "ultima/ultima8/audio/audio_process.h"
#include "ultima/ultima8/games/game.h"
namespace Ultima {
namespace Ultima8 {
// Ultima 8 Intrinsics
const Intrinsic U8Intrinsics[] = {
// 0x000
TargetGump::I_target,
0, //U
Item::I_touch,
Item::I_getX,
Item::I_getY,
Item::I_getZ,
Item::I_getCX,
Item::I_getCY,
Item::I_getCZ,
0, //U
0, //U
0, //U
Item::I_getPoint,
Item::I_getShape,
Item::I_setShape,
Item::I_getFrame,
// 0x010
Item::I_setFrame,
Item::I_getQuality,
Item::I_getUnkEggType,
Item::I_getQuantity,
0, //U
Item::I_getContainer,
Item::I_getRootContainer,
0, //U
0, //U
Item::I_getQ,
Item::I_setQ,
Item::I_setQuality,
0, //U
Item::I_setQuantity,
Item::I_getFamily,
Item::I_getTypeFlag,
// 0x020
Item::I_getStatus,
Item::I_orStatus,
Item::I_andStatus,
Item::I_getFootpadData,
0, //U
Item::I_overlaps,
Item::I_overlapsXY,
Item::I_isOn,
0, //U
0, //U
0, //U
Item::I_ascend,
Item::I_getWeight,
Item::I_getWeightIncludingContents,
Item::I_getSurfaceWeight,
0, //U
// 0x030
0, //U
Item::I_legalCreateAtCoords,
Item::I_create,
Item::I_legalCreateAtPoint,
Item::I_legalCreateInCont,
Item::I_push,
Item::I_popToCoords,
Item::I_popToContainer,
Item::I_pop,
Item::I_popToEnd,
Item::I_destroy,
Container::I_removeContents,
Container::I_destroyContents,
Item::I_isExplosive,
Item::I_move,
0, //U
// 0x040
Item::I_legalMoveToPoint,
Item::I_legalMoveToContainer,
Actor::I_isNPC,
0, //U
Item::I_hurl,
Item::I_shoot,
Item::I_fall,
Item::I_grab,
0, //U
Item::I_bark,
Item::I_ask,
Item::I_getSliderInput,
Item::I_openGump,
Item::I_closeGump,
0, //U
0, //U
// 0x050
Item::I_getMapArray,
0, //U
Item::I_setMapArray,
Item::I_receiveHit,
Item::I_explode,
Item::I_canReach,
Item::I_getRange,
0, //U
Item::I_getDirToCoords,
Item::I_getDirFromCoords,
Item::I_getDirToItem,
Item::I_getDirFromItem,
Item::I_look,
Item::I_use,
0, //U
0, //U
// 0x060
0, //U
Item::I_gotHit,
0, //U
0, //U
0, //U
0, //U
0, //U
Item::I_enterFastArea,
0, //U
0, //U
0, //U
0, //U
0, //U
Item::I_guardianBark,
BookGump::I_readBook,
ScrollGump::I_readScroll,
// 0x070
ReadableGump::I_readGrave,
ReadableGump::I_readPlaque,
Egg::I_getEggXRange,
Egg::I_getEggYRange,
Egg::I_setEggXRange,
Egg::I_setEggYRange,
Egg::I_getEggId,
Egg::I_setEggId,
0, //U
MonsterEgg::I_monsterEggHatch,
MonsterEgg::I_getMonId,
0, //U
0, //U
0, //U
0, //U
0, //U
// 0x080
Actor::I_isBusy,
Actor::I_areEnemiesNear,
Actor::I_isInCombat,
Actor::I_setInCombat,
Actor::I_clrInCombat,
Actor::I_setTarget,
Actor::I_getTarget,
Actor::I_setAlignment,
Actor::I_getAlignment,
Actor::I_setEnemyAlignment,
Actor::I_getEnemyAlignment,
Actor::I_isEnemy,
Actor::I_isDead,
Actor::I_setDead,
Actor::I_clrDead,
Actor::I_isImmortal,
// 0x090
Actor::I_setImmortal,
Actor::I_clrImmortal,
Actor::I_isWithstandDeath,
Actor::I_setWithstandDeath,
Actor::I_clrWithstandDeath,
Actor::I_isFeignDeath,
Actor::I_setFeignDeath,
Actor::I_clrFeignDeath,
0, //U
0, //U
0, //U
0, //U
Actor::I_getDir,
Actor::I_getMap,
Actor::I_teleport,
Actor::I_doAnim,
// 0x0A0
Actor::I_getLastAnimSet,
Actor::I_pathfindToPoint,
Actor::I_pathfindToItem,
Actor::I_getStr,
Actor::I_getInt,
Actor::I_getDex,
Actor::I_getHp,
Actor::I_getMana,
Actor::I_setStr,
Actor::I_setInt,
Actor::I_setDex,
Actor::I_setHp,
Actor::I_setMana,
Actor::I_createActor,
Actor::I_setActivity,
Actor::I_setAirWalkEnabled,
// 0x0B0
Actor::I_getAirWalkEnabled,
Actor::I_schedule,
Actor::I_getEquip,
Actor::I_setEquip,
Ultima8Engine::I_closeItemGumps,
CameraProcess::I_scrollTo,
UCMachine::I_urandom,
UCMachine::I_rndRange,
GrantPeaceProcess::I_castGrantPeace,
UCMachine::I_numToStr,
0, //U
MusicProcess::I_playMusic,
UCMachine::I_getName, //temp
Item::I_igniteChaos,
CameraProcess::I_setCenterOn,
CameraProcess::I_moveTo,
// 0x0C0
0, //U
0, //U
0, //U
0, //U
0, //U
0, //U
CameraProcess::I_startQuake,
CameraProcess::I_stopQuake,
InverterProcess::I_invertScreen,
0, //U
Kernel::I_getNumProcesses,
Kernel::I_resetRef,
MainActor::I_teleportToEgg,
Kernel::I_resetRef,
0, // setRef
Ultima8Engine::I_getAvatarInStasis,
// 0x0D0
Ultima8Engine::I_setAvatarInStasis,
Item::I_getEtherealTop,
Ultima8Engine::I_getCurrentTimerTick,
0, //U (canGetThere)
CurrentMap::I_canExistAt,
SpriteProcess::I_createSprite,
SpriteProcess::I_createSprite,
Item::I_getFamilyOfType,
Ultima8Engine::I_getTimeInGameHours,
Ultima8Engine::I_getTimeInMinutes,
Ultima8Engine::I_getTimeInSeconds,
Ultima8Engine::I_setTimeInGameHours,
0, // U (SetTimeInMinutes)
0, // U (SetTimeInSeconds)
PaletteFaderProcess::I_fadeToBlack,
PaletteFaderProcess::I_fadeFromBlack,
// 0x0E0
PaletteFaderProcess::I_fadeToPaletteTransform,
PaletteFaderProcess::I_lightningBolt,
PaletteFaderProcess::I_fadeToWhite,
PaletteFaderProcess::I_fadeFromWhite,
Game::I_playEndgame,
HealProcess::I_feedAvatar,
MainActor::I_accumulateStrength,
MainActor::I_accumulateIntelligence,
MainActor::I_accumulateDexterity,
MainActor::I_clrAvatarInCombat,
MainActor::I_setAvatarInCombat,
MainActor::I_isAvatarInCombat,
AudioProcess::I_playSFX, // int16
AudioProcess::I_playSFX, // int16 uint8
AudioProcess::I_playSFX, // int16 uint16 ObjID
AudioProcess::I_playAmbientSFX, // int16 Unused (but implemented)
// 0x0F0
AudioProcess::I_playAmbientSFX, // int16 uint8 Unused (but implemented)
AudioProcess::I_playAmbientSFX, // int16 uint16 ObjID
AudioProcess::I_isSFXPlaying,
AudioProcess::I_setVolumeSFX,
AudioProcess::I_stopSFX, // int16
AudioProcess::I_stopSFX, // int16 ObjID
0, //U
0, //U
MusicProcess::I_stopMusic,
0, //U
0, //U
FireballProcess::I_TonysBalls,
Ultima8Engine::I_avatarCanCheat,
Ultima8Engine::I_makeAvatarACheater,
UCMachine::I_true, // isGameRunning
0, //U
// 0x100
0, //U
0 //U
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,139 @@
/* 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/misc/debugger.h"
#include "ultima/ultima8/usecode/uc_list.h"
#include "ultima/ultima8/usecode/uc_machine.h"
namespace Ultima {
namespace Ultima8 {
uint16 UCList::getStringIndex(uint32 index) const {
return _elements[index * 2] + (_elements[index * 2 + 1] << 8);
}
const Std::string &UCList::getString(uint32 index) const {
uint16 sindex = getStringIndex(index);
return UCMachine::get_instance()->getString(sindex);
}
void UCList::freeStrings() {
UCMachine *ucm = UCMachine::get_instance();
for (unsigned int i = 0; i < _size; i++) {
ucm->freeString(getStringIndex(i));
}
free();
}
void UCList::copyStringList(const UCList &l) {
UCMachine *ucm = UCMachine::get_instance();
freeStrings();
for (unsigned int i = 0; i < l._size; i++) {
uint16 s = ucm->duplicateString(l.getStringIndex(i));
uint8 tmp[2]; // ugly...
tmp[0] = static_cast<uint8>(s & 0xFF);
tmp[1] = static_cast<uint8>(s >> 8);
append(tmp);
}
}
void UCList::unionStringList(UCList &l) {
UCMachine *ucm = UCMachine::get_instance();
// take the union of two stringlists
// i.e., append the second to this one, removing any duplicates
for (unsigned int i = 0; i < l._size; i++) {
if (!stringInList(l.getStringIndex(i))) {
append(l[i]);
} else {
// free it if we're not keeping it
ucm->freeString(l.getStringIndex(i));
}
}
l.free(); // NB: do _not_ free the strings in l, since they're in this one
}
void UCList::subtractStringList(const UCList &l) {
for (unsigned int i = 0; i < l._size; i++)
removeString(l.getStringIndex(i));
}
bool UCList::stringInList(uint16 s) const {
Std::string str = UCMachine::get_instance()->getString(s);
for (unsigned int i = 0; i < _size; i++)
if (getString(i) == str)
return true;
return false;
}
void UCList::assignString(uint32 index, uint16 str) {
// assign string str to element index
// free old contents of element index; take ownership of str(?)
UCMachine::get_instance()->freeString(getStringIndex(index));
_elements[index * _elementSize] = static_cast<uint8>(str & 0xFF);
_elements[index * _elementSize + 1] = static_cast<uint8>(str >> 8);
}
void UCList::removeString(uint16 s, bool nodel) {
// do we need to erase all occurrences of str or just the first one?
// (deleting all, currently)
const Std::string &str = UCMachine::get_instance()->getString(s);
for (unsigned int i = 0; i < _size; i++) {
if (getString(i) == str) {
// free string
if (!nodel)
UCMachine::get_instance()->freeString(getStringIndex(i));
// remove string from list
_elements.erase(_elements.begin() + i * _elementSize,
_elements.begin() + (i + 1)*_elementSize);
_size--;
i--; // back up a bit
}
}
}
void UCList::save(Common::WriteStream *ws) const {
ws->writeUint32LE(_elementSize);
ws->writeUint32LE(_size);
if (_size > 0)
ws->write(&(_elements[0]), _size * _elementSize);
}
bool UCList::load(Common::ReadStream *rs, uint32 version) {
_elementSize = rs->readUint32LE();
_size = rs->readUint32LE();
if (_elementSize * _size > 1024 * 1024) {
warning("Improbable UCList size %d x %d, corrupt save?", _elementSize, _size);
return false;
}
_elements.resize(_size * _elementSize);
if (_size > 0)
rs->read(&(_elements[0]), _size * _elementSize);
return true;
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,178 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_UCLIST_H
#define ULTIMA8_USECODE_UCLIST_H
#include "ultima/shared/std/containers.h"
#include "ultima/shared/std/string.h"
namespace Ultima {
namespace Ultima8 {
// stringlists: _elementSize = 2, each element is actually a stringref
// see for example the 0x0E opcode: there is no way to see if the
// created list is a stringlist or not
// the opcodes which do need a distinction have a operand for this.
// Question: how are unionList/subtractList supposed to know what to do?
// their behaviour differs if this is a stringlist
// Question: does subtractList remove _all_ occurrences of elements or only 1?
class UCList {
Std::vector<uint8> _elements;
unsigned int _elementSize;
unsigned int _size;
public:
UCList(unsigned int elementSize, unsigned int capacity = 0) :
_elementSize(elementSize), _size(0) {
if (capacity > 0)
_elements.reserve(_elementSize * capacity);
}
~UCList() {
// Slight problem: we don't know if we're a stringlist.
// So we need to hope something else has ensured any strings
// are already freed.
free();
}
const uint8 *operator[](uint32 index) const {
// check that index isn't out of bounds...
return &(_elements[index * _elementSize]);
}
uint16 getuint16(uint32 index) const {
assert(_elementSize == 2);
uint16 t = _elements[index * _elementSize];
t += _elements[index * _elementSize + 1] << 8;
return t;
}
void append(const uint8 *e) {
_elements.resize((_size + 1) * _elementSize);
for (unsigned int i = 0; i < _elementSize; i++)
_elements[_size * _elementSize + i] = e[i];
_size++;
}
void appenduint16(uint16 val) {
assert(_elementSize == 2);
uint8 buf[2];
buf[0] = static_cast<uint8>(val);
buf[1] = static_cast<uint8>(val >> 8);
append(buf);
}
void remove(const uint8 *e) {
// do we need to erase all occurrences of e or just the first one?
// (deleting all, currently)
for (unsigned int i = 0; i < _size; i++) {
bool equal = true;
for (unsigned int j = 0; j < _elementSize && equal; j++)
equal = equal && (_elements[i * _elementSize + j] == e[j]);
if (equal) {
_elements.erase(_elements.begin() + i * _elementSize,
_elements.begin() + (i + 1)*_elementSize);
_size--;
i--; // back up a bit
}
}
}
bool inList(const uint8 *e) const {
for (unsigned int i = 0; i < _size; i++) {
bool equal = true;
for (unsigned int j = 0; j < _elementSize && equal; j++)
equal = (_elements[i * _elementSize + j] == e[j]);
if (equal)
return true;
}
return false;
}
void appendList(const UCList &l) {
// elementsizes should match...
assert(_elementSize == l.getElementSize());
_elements.reserve(_elementSize * (_size + l._size));
for (unsigned int i = 0; i < l._size; i++)
append(l[i]);
}
void unionList(const UCList &l) { // like append, but remove duplicates
// elementsizes should match...
assert(_elementSize == l.getElementSize());
_elements.reserve(_elementSize * (_size + l._size));
for (unsigned int i = 0; i < l._size; i++)
if (!inList(l[i]))
append(l[i]);
}
void subtractList(const UCList &l) {
// elementsizes should match...
assert(_elementSize == l.getElementSize());
for (unsigned int i = 0; i < l._size; i++)
remove(l[i]);
}
void free() {
_elements.clear();
_size = 0;
}
uint32 getSize() const {
return _size;
}
unsigned int getElementSize() const {
return _elementSize;
}
void assign(uint32 index, const uint8 *e) {
// need to check that index isn't out-of-bounds? (or grow list?)
for (unsigned int i = 0; i < _elementSize; i++)
_elements[index * _elementSize + i] = e[i];
}
void copyList(const UCList &l) { // deep copy for list
free();
appendList(l);
}
void freeStrings();
void copyStringList(const UCList &l) ;
void unionStringList(UCList &l);
void subtractStringList(const UCList &l);
bool stringInList(uint16 str) const;
void assignString(uint32 index, uint16 str);
void removeString(uint16 str, bool nodel = false);
uint16 getStringIndex(uint32 index) const;
void save(Common::WriteStream *ws) const;
bool load(Common::ReadStream *rs, uint32 version);
private:
const Std::string &getString(uint32 index) const;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_UCMACHINE_H
#define ULTIMA8_USECODE_UCMACHINE_H
#include "ultima/ultima8/misc/common_types.h"
#include "ultima/ultima8/misc/set.h"
#include "ultima/shared/std/string.h"
#include "ultima/shared/std/containers.h"
#include "ultima/ultima8/usecode/intrinsics.h"
namespace Ultima {
namespace Ultima8 {
class Debugger;
class Process;
class UCProcess;
class ConvertUsecode;
class GlobalStorage;
class UCList;
class idMan;
class UCMachine {
friend class Debugger;
public:
UCMachine(const Intrinsic *iset, unsigned int icount);
~UCMachine();
static UCMachine *get_instance() {
return _ucMachine;
}
void reset();
void execProcess(UCProcess *proc);
const Std::string &getString(uint16 str) const;
UCList *getList(uint16 l);
void freeString(uint16 s);
void freeStringList(uint16 l);
void freeList(uint16 l);
uint16 duplicateString(uint16 str);
void usecodeStats() const;
static uint32 listToPtr(uint16 l);
static uint32 stringToPtr(uint16 s);
static uint32 stackToPtr(uint16 pid, uint16 offset);
static uint32 globalToPtr(uint16 offset);
static uint32 objectToPtr(uint16 objID);
static uint16 ptrToObject(uint32 ptr);
bool assignPointer(uint32 ptr, const uint8 *data, uint32 size);
bool dereferencePointer(uint32 ptr, uint8 *data, uint32 size);
void saveGlobals(Common::WriteStream *ws) const;
void saveStrings(Common::WriteStream *ws) const;
void saveLists(Common::WriteStream *ws) const;
bool loadGlobals(Common::ReadStream *rs, uint32 version);
bool loadStrings(Common::ReadStream *rs, uint32 version);
bool loadLists(Common::ReadStream *rs, uint32 version);
INTRINSIC(I_true);
INTRINSIC(I_false);
INTRINSIC(I_dummyProcess);
INTRINSIC(I_getName);
INTRINSIC(I_urandom);
INTRINSIC(I_rndRange);
INTRINSIC(I_numToStr);
protected:
void loadIntrinsics(const Intrinsic *i, unsigned int icount);
private:
ConvertUsecode *_convUse;
const Intrinsic *_intrinsics;
unsigned int _intrinsicCount;
GlobalStorage *_globals;
Common::HashMap<uint16, UCList *> _listHeap;
Common::HashMap<uint16, Std::string> _stringHeap;
// Add a string to the list (copies the string)
uint16 assignString(const char *str);
uint16 assignList(UCList *l);
idMan *_listIDs;
idMan *_stringIDs;
static UCMachine *_ucMachine;
// tracing
bool _tracingEnabled;
bool _traceAll;
Set<ObjId> _traceObjIDs;
Set<ProcId> _tracePIDs;
Set<uint16> _traceClasses;
inline bool trace_show(ProcId pid, ObjId objid, uint16 ucclass) {
if (!_tracingEnabled) return false;
if (_traceAll) return true;
if (_traceObjIDs.find(objid) != _traceObjIDs.end()) return true;
if (_tracePIDs.find(pid) != _tracePIDs.end()) return true;
if (_traceClasses.find(ucclass) != _traceClasses.end()) return true;
return false;
}
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,189 @@
/* 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/usecode/uc_process.h"
#include "ultima/ultima8/usecode/uc_machine.h"
#include "ultima/ultima8/usecode/usecode.h"
#include "ultima/ultima8/games/game_data.h"
namespace Ultima {
namespace Ultima8 {
DEFINE_RUNTIME_CLASSTYPE_CODE(UCProcess)
UCProcess::UCProcess() : Process(), _classId(0xFFFF), _ip(0xFFFF),
_bp(0x0000), _temp32(0) { // !! fixme
_usecode = GameData::get_instance()->getMainUsecode();
}
UCProcess::UCProcess(uint16 classid, uint16 offset, uint32 this_ptr,
int thissize, const uint8 *args, int argsize)
: Process(), _classId(0xFFFF), _ip(0xFFFF), _bp(0x0000), _temp32(0) {
_usecode = GameData::get_instance()->getMainUsecode();
load(classid, offset, this_ptr, thissize, args, argsize);
}
UCProcess::~UCProcess() {
}
void UCProcess::load(uint16 classid, uint16 offset, uint32 this_ptr,
int thissize, const uint8 *args, int argsize) {
if (_usecode->get_class_size(classid) == 0)
warning("Class is empty.");
_classId = 0xFFFF;
_ip = 0xFFFF;
_bp = 0x0000;
uint16 thissp = 0;
// first, push the derefenced this pointer
if (this_ptr != 0 && thissize > 0) {
_stack.addSP(-thissize);
UCMachine::get_instance()->
dereferencePointer(this_ptr, _stack.access(), thissize);
thissp = _stack.getSP();
}
// next, push the arguments
_stack.push(args, argsize);
// then, push the new this pointer
if (thissp != 0)
_stack.push4(UCMachine::stackToPtr(_pid, thissp));
// finally, call the specified function
call(classid, offset);
}
void UCProcess::run() {
if (_flags & PROC_SUSPENDED)
return;
// pass to UCMachine for execution
UCMachine::get_instance()->execProcess(this);
}
void UCProcess::call(uint16 classid, uint16 offset) {
_stack.push2(_classId); // BP+04 prev class
_stack.push2(_ip); // BP+02 prev IP
_stack.push2(_bp); // BP+00 prev BP
_classId = classid;
_ip = offset;
_bp = static_cast<uint16>(_stack.getSP()); // TRUNCATES!
}
bool UCProcess::ret() {
_stack.setSP(_bp);
_bp = _stack.pop2();
_ip = _stack.pop2();
_classId = _stack.pop2();
if (_ip == 0xFFFF && _classId == 0xFFFF)
return true;
else
return false;
}
void UCProcess::freeOnTerminate(uint16 index, int type) {
assert(type >= 1 && type <= 3);
Common::Pair<uint16, int> p;
p.first = index;
p.second = type;
_freeOnTerminate.push_back(p);
}
void UCProcess::terminate() {
for (auto &i : _freeOnTerminate) {
uint16 index = i.first;
int typeNum = i.second;
switch (typeNum) {
case 1: // string
UCMachine::get_instance()->freeString(index);
break;
case 2: // stringlist
UCMachine::get_instance()->freeStringList(index);
break;
case 3: // list
UCMachine::get_instance()->freeList(index);
break;
}
}
_freeOnTerminate.clear();
Process::terminate();
}
Common::String UCProcess::dumpInfo() const {
Common::String info = Process::dumpInfo();
if (_classId == 0xFFFF) {
info += ", IP undefined";
} else {
const char *classname = GameData::get_instance()->getMainUsecode()->
get_class_name(_classId);
info += Common::String::format(", classname: %s, IP: %04X:%04X", classname, _classId, _ip);
}
return info;
}
void UCProcess::saveData(Common::WriteStream *ws) {
Process::saveData(ws);
ws->writeUint16LE(_bp);
ws->writeUint16LE(_classId);
ws->writeUint16LE(_ip);
ws->writeUint32LE(_temp32);
ws->writeUint32LE(static_cast<uint32>(_freeOnTerminate.size()));
for (const auto &i : _freeOnTerminate) {
ws->writeUint16LE(i.first);
ws->writeUint32LE(static_cast<uint32>(i.second));
}
_stack.save(ws);
}
bool UCProcess::loadData(Common::ReadStream *rs, uint32 version) {
if (!Process::loadData(rs, version)) return false;
_bp = rs->readUint16LE();
_classId = rs->readUint16LE();
_ip = rs->readUint16LE();
_temp32 = rs->readUint32LE();
uint32 freecount = rs->readUint32LE();
for (unsigned int i = 0; i < freecount; ++i) {
Common::Pair<uint16, int> p;
p.first = rs->readUint16LE();
p.second = static_cast<int>(rs->readUint32LE());
_freeOnTerminate.push_back(p);
}
_stack.load(rs, version);
return true;
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,90 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_UCPROCESS_H
#define ULTIMA8_USECODE_UCPROCESS_H
#include "ultima/shared/std/containers.h"
#include "ultima/ultima8/kernel/process.h"
#include "ultima/ultima8/usecode/uc_stack.h"
namespace Ultima {
namespace Ultima8 {
class Usecode;
// probably won't inherit from Process directly in the future
class UCProcess : public Process {
friend class UCMachine;
friend class Kernel;
public:
UCProcess();
UCProcess(uint16 classid, uint16 offset, uint32 this_ptr = 0,
int thissize = 0, const uint8 *args = 0, int argsize = 0);
~UCProcess() override;
ENABLE_RUNTIME_CLASSTYPE()
void run() override;
void terminate() override;
void freeOnTerminate(uint16 index, int type);
void setReturnValue(uint32 retval) {
_temp32 = retval;
}
uint16 getClassId() const {
return _classId;
}
Common::String dumpInfo() const override;
bool loadData(Common::ReadStream *rs, uint32 version);
void saveData(Common::WriteStream *ws) override;
protected:
void load(uint16 classid, uint16 offset, uint32 this_ptr = 0,
int thissize = 0, const uint8 *args = 0, int argsize = 0);
void call(uint16 classid, uint16 offset);
bool ret();
// stack base pointer
uint16 _bp;
Usecode *_usecode;
uint16 _classId;
uint16 _ip;
uint32 _temp32;
// data stack
UCStack _stack;
// "Free Me" list
Std::list<Common::Pair<uint16, int> > _freeOnTerminate;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,56 @@
/* 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/misc/debugger.h"
#include "ultima/ultima8/usecode/uc_stack.h"
namespace Ultima {
namespace Ultima8 {
void UCStack::save(Common::WriteStream *ws) {
ws->writeUint32LE(_size);
ws->writeUint32LE(getSP());
ws->write(_bufPtr, stacksize());
}
bool UCStack::load(Common::ReadStream *rs, uint32 version) {
_size = rs->readUint32LE();
#ifdef USE_DYNAMIC_UCSTACK
if (_buf) delete[] _buf;
_buf = new uint8[_size];
#else
if (_size > sizeof(_bufArray)) {
warning("UCStack _size mismatch (buf_array too small)");
return false;
}
_buf = _bufArray;
#endif
uint32 sp = rs->readUint32LE();
_bufPtr = _buf + sp;
rs->read(_bufPtr, _size - sp);
return true;
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,191 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_UCSTACK_H
#define ULTIMA8_USECODE_UCSTACK_H
#include "common/scummsys.h"
namespace Ultima {
namespace Ultima8 {
// A little-endian stack for use with usecode
class BaseUCStack {
protected:
uint8 *_buf;
uint8 *_bufPtr;
uint32 _size;
public:
BaseUCStack(uint32 len, uint8 *b) : _buf(b), _size(len) {
// stack grows downward, so start at the end of the buffer
_bufPtr = _buf + _size;
}
virtual ~BaseUCStack() { }
inline uint32 getSize() const {
return _size;
}
inline uint32 stacksize() const {
return _size - (_bufPtr - _buf);
}
inline void addSP(const int32 offset) {
_bufPtr += offset;
}
inline unsigned int getSP() const {
return static_cast<unsigned int>(_bufPtr - _buf);
}
inline void setSP(unsigned int pos) {
_bufPtr = _buf + pos;
}
//
// Push values to the stack
//
inline void push1(uint8 val) {
_bufPtr--;
_bufPtr[0] = val;
}
inline void push2(uint16 val) {
_bufPtr -= 2;
_bufPtr[0] = static_cast<uint8>(val & 0xFF);
_bufPtr[1] = static_cast<uint8>((val >> 8) & 0xFF);
}
inline void push4(uint32 val) {
_bufPtr -= 4;
_bufPtr[0] = static_cast<uint8>(val & 0xFF);
_bufPtr[1] = static_cast<uint8>((val >> 8) & 0xFF);
_bufPtr[2] = static_cast<uint8>((val >> 16) & 0xFF);
_bufPtr[3] = static_cast<uint8>((val >> 24) & 0xFF);
}
// Push an arbitrary number of bytes of 0
inline void push0(const uint32 count) {
_bufPtr -= count;
memset(_bufPtr, 0, count);
}
// Push an arbitrary number of bytes
inline void push(const uint8 *in, const uint32 count) {
_bufPtr -= count;
memcpy(_bufPtr, in, count);
}
//
// Pop values from the stack
//
inline uint16 pop2() {
uint8 b0, b1;
b0 = *_bufPtr++;
b1 = *_bufPtr++;
return (b0 | (b1 << 8));
}
inline uint32 pop4() {
uint8 b0, b1, b2, b3;
b0 = *_bufPtr++;
b1 = *_bufPtr++;
b2 = *_bufPtr++;
b3 = *_bufPtr++;
return (b0 | (b1 << 8) | (b2 << 16) | (b3 << 24));
}
inline void pop(uint8 *out, const uint32 count) {
memcpy(out, _bufPtr, count);
_bufPtr += count;
}
//
// Access a value from a location in the stack
//
inline uint8 access1(const uint32 offset) const {
return _buf[offset];
}
inline uint16 access2(const uint32 offset) const {
return (_buf[offset] | (_buf[offset + 1] << 8));
}
inline uint32 access4(const uint32 offset) const {
return _buf[offset] | (_buf[offset + 1] << 8) |
(_buf[offset + 2] << 16) | (_buf[offset + 3] << 24);
}
inline uint8 *access(const uint32 offset) {
return _buf + offset;
}
inline uint8 *access() {
return _bufPtr;
}
//
// Assign a value to a location in the stack
//
inline void assign1(const uint32 offset, const uint8 val) {
const_cast<uint8 *>(_buf)[offset] = static_cast<uint8>(val & 0xFF);
}
inline void assign2(const uint32 offset, const uint16 val) {
const_cast<uint8 *>(_buf)[offset] = static_cast<uint8>(val & 0xFF);
const_cast<uint8 *>(_buf)[offset + 1] = static_cast<uint8>((val >> 8) & 0xFF);
}
inline void assign4(const uint32 offset, const uint32 val) {
const_cast<uint8 *>(_buf)[offset] = static_cast<uint8>(val & 0xFF);
const_cast<uint8 *>(_buf)[offset + 1] = static_cast<uint8>((val >> 8) & 0xFF);
const_cast<uint8 *>(_buf)[offset + 2] = static_cast<uint8>((val >> 16) & 0xFF);
const_cast<uint8 *>(_buf)[offset + 3] = static_cast<uint8>((val >> 24) & 0xFF);
}
inline void assign(const uint32 offset, const uint8 *in, const uint32 len) {
memcpy(const_cast<uint8 *>(_buf) + offset, in, len);
}
};
class DynamicUCStack : public BaseUCStack {
public:
DynamicUCStack(uint32 len = 0x1000) : BaseUCStack(len, new uint8[len]) { }
~DynamicUCStack() override {
delete [] _buf;
}
#ifdef USE_DYNAMIC_UCSTACK
#define UCStack DynamicUCStack
void save(Common::WriteStream *ws);
bool load(Common::ReadStream *rs, uint32 version);
#endif
};
#ifndef USE_DYNAMIC_UCSTACK
class UCStack : public BaseUCStack {
uint8 _bufArray[0x1000];
public:
UCStack() : BaseUCStack(0x1000, _bufArray) { }
~UCStack() override { }
void save(Common::WriteStream *ws);
bool load(Common::ReadStream *rs, uint32 version);
};
#endif
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,59 @@
/* 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/misc/common_types.h"
#include "ultima/ultima8/usecode/usecode.h"
#include "ultima/ultima8/ultima8.h"
namespace Ultima {
namespace Ultima8 {
uint32 Usecode::get_class_event(uint32 classid, uint32 eventid) {
if (get_class_size(classid) == 0) return 0;
if (eventid >= get_class_event_count(classid)) {
warning("eventid too high: %u >= %u for class %u",
eventid, get_class_event_count(classid), classid);
}
const uint8 *data = get_class(classid);
uint32 offset = 0;
if (GAME_IS_U8) {
offset = data[12 + (eventid * 4) + 0];
offset += data[12 + (eventid * 4) + 1] << 8;
offset += data[12 + (eventid * 4) + 2] << 16;
offset += data[12 + (eventid * 4) + 3] << 24;
} else if (GAME_IS_CRUSADER) {
offset = data[20 + (eventid * 6) + 2];
offset += data[20 + (eventid * 6) + 3] << 8;
offset += data[20 + (eventid * 6) + 4] << 16;
offset += data[20 + (eventid * 6) + 5] << 24;
} else {
warning("Invalid game type.");
}
return offset;
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,49 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_USECODE_H
#define ULTIMA8_USECODE_USECODE_H
namespace Ultima {
namespace Ultima8 {
/**
* Usecode is the main engine code in the U8 engine. It has a simple assembly language
* executed by the UCMachine.
*/
class Usecode {
public:
Usecode() { }
virtual ~Usecode() { }
virtual const uint8 *get_class(uint32 classid) = 0;
virtual uint32 get_class_size(uint32 classid) = 0;
virtual const char *get_class_name(uint32 classid) = 0;
virtual uint32 get_class_base_offset(uint32 classid) = 0;
virtual uint32 get_class_event_count(uint32 classid) = 0;
virtual uint32 get_class_event(uint32 classid, uint32 eventid);
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,82 @@
/* 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/misc/debugger.h"
#include "ultima/ultima8/usecode/usecode_flex.h"
#include "ultima/ultima8/ultima8.h"
namespace Ultima {
namespace Ultima8 {
const uint8 *UsecodeFlex::get_class(uint32 classid) {
const uint8 *obj = get_object_nodel(classid + 2);
return obj;
}
uint32 UsecodeFlex::get_class_size(uint32 classid) {
uint32 size = get_size(classid + 2);
return size;
}
const char *UsecodeFlex::get_class_name(uint32 classid) {
if (get_size(classid + 2) > 0) {
const uint8 *name_object = get_object_nodel(1);
return reinterpret_cast<const char *>(name_object + 4 + (13 * classid));
} else {
return nullptr;
}
}
uint32 UsecodeFlex::get_class_base_offset(uint32 classid) {
if (get_size(classid + 2) == 0) return 0;
if (GAME_IS_U8) {
return 0x0C;
} else if (GAME_IS_CRUSADER) {
const uint8 *obj = get_object_nodel(classid + 2);
uint32 offset = obj[8];
offset += obj[9] << 8;
offset += obj[10] << 16;
offset += obj[11] << 24;
offset--;
return offset;
} else {
warning("Invalid game type.");
return 0;
}
}
uint32 UsecodeFlex::get_class_event_count(uint32 classid) {
if (get_size(classid + 2) == 0) return 0;
if (GAME_IS_U8) {
return 32;
} else if (GAME_IS_CRUSADER) {
return (get_class_base_offset(classid) + 19) / 6;
} else {
warning("Invalid game type.");
return 0;
}
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,46 @@
/* 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/>.
*
*/
#ifndef ULTIMA8_USECODE_USECODEFLEX_H
#define ULTIMA8_USECODE_USECODEFLEX_H
#include "ultima/ultima8/usecode/usecode.h"
#include "ultima/ultima8/filesys/raw_archive.h"
namespace Ultima {
namespace Ultima8 {
class UsecodeFlex : public Usecode, protected RawArchive {
public:
UsecodeFlex(Common::SeekableReadStream *rs) : RawArchive(rs) { }
~UsecodeFlex() override { }
const uint8 *get_class(uint32 classid) override;
uint32 get_class_size(uint32 classid) override;
const char *get_class_name(uint32 classid) override;
uint32 get_class_base_offset(uint32 classid) override;
uint32 get_class_event_count(uint32 classid) override;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif