/* 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 .
*
*/
#ifndef IMMORTAL_H
#define IMMORTAL_H
// Audio is only handled in kernel, therefore it is only needed here
#include "audio/mixer.h"
// Immortal.h is the engine, so it needs the engine headers
#include "engines/engine.h"
#include "engines/savestate.h"
// Theorectically, all graphics should be handled through driver, which is part of kernel, which is in immortal.h
#include "graphics/screen.h"
#include "graphics/surface.h"
// Detection is only needed by the main engine
#include "immortal/detection.h"
#include "common/formats/prodos.h"
#include "common/debug-channels.h"
#include "common/events.h"
#include "common/scummsys.h"
#include "common/system.h"
#include "common/fs.h"
#include "common/hash-str.h"
#include "common/random.h"
#include "common/serializer.h"
#include "common/util.h"
#include "common/platform.h"
// Utilities.h contains many things used by all objects, not just immortal
#include "immortal/utilities.h"
// Room also includes story.h
#include "immortal/room.h"
namespace Immortal {
// Needed by kernel for input
enum InputAction {
kActionNothing,
kActionKey,
kActionRestart, // Key "R" <-- Debug?
kActionSound,
kActionFire,
kActionButton, // Does this just refer to whatever is not the fire button?
kActionDBGStep // Debug key for moving engine forward one frame at a time
};
enum ButtonHeldMask {
kButton0Held = 2,
kButton1Held = 4
};
enum InputDirection {
kDirectionUp,
kDirectionLeft,
kDirectionDown,
kDirectionRight
};
// Needed by kernel for text
enum FadeType {
kTextFadeIn,
kTextDontFadeIn
};
// Needed by kernel for music
enum Song {
kSongNothing,
kSongMaze,
kSongCombat,
kSongText
};
enum Sound {
kSoundSwish = 6,
kSoundAwe,
kSoundHuh,
kSoundClank,
kSoundFireBall,
kSoundDoor
};
// Needed by logic for various things
enum MonsterID {
kPlayerID
};
// Needed by logic for certificate processing
enum CertificateIndex : uint8 {
kCertHits,
kCertLevel,
kCertLoGameFlags,
kCertHiGameFlags,
kCertQuickness,
kCertInvLo,
kCertInvHi,
kCertGoldLo,
kCertGoldHi
};
// Needed by logic for various things
enum GameFlags : uint8 {
kSavedNone,
kSavedKing,
kSavedAna
};
// Needed by level (maybe?)
enum LevelType {
kRoomType,
kMonsterType,
kObjectType
};
// Basically the equivalent of the explosion from a projectile in other games I think
struct Spark {
};
// Generic sprites can be used anywhere, just sort of misc sprites
struct GenericSprite {
};
// Doors are a property of the level, not the room, they define the connections between rooms
struct Door {
uint8 _x = 0;
uint8 _y = 0;
uint8 _fromRoom = 0;
uint8 _toRoom = 0;
uint8 _busyOnRight = 0;
uint8 _on = 0;
};
// Universe is a set of properties for the entire level, nor just the room
struct Univ {
uint16 _rectX = 0;
uint16 _rectY = 0;
uint16 _numAnims = 0;
uint16 _numCols = 0;
uint16 _numRows = 0;
uint16 _numChrs = 0;
uint16 _num2Cols = 0;
uint16 _num2Rows = 0;
uint16 _num2Cells = 0;
uint16 _num2Chrs = 0;
};
struct Chr {
byte *_scanlines[32];
};
struct ImmortalGameDescription;
// Forward declaration because we will need the Disk and Room classes
class ProDosDisk;
class Room;
class ImmortalEngine : public Engine {
private:
Common::RandomSource _randomSource;
protected:
// Engine APIs
Common::Error run() override;
public:
ImmortalEngine(OSystem *syst, const ADGameDescription *gameDesc);
~ImmortalEngine() override;
const ADGameDescription *_gameDescription;
/* Terrible functions because C doesn't like
* bit manipulation enough
*/
uint16 xba(uint16 ab); // This just replicates the XBA command from the 65816, because flipping the byte order is somehow not a common library function???
uint16 rol(uint16 ab, int n); // Rotate bits left by n
uint16 ror(uint16 ab, int n); // Rotate bits right by n
uint16 mult16(uint16 a, uint16 b); // Just avoids using (uint16) everywhere, and is slightly closer to the original
/*
* --- Members ---
*
*/
/*
* Constants
*/
// Misc constants
const int kNumLengths = 21;
const int kNiceTime = 36;
const int kMaxCertificate = 16;
// Screen constants
const int kScreenW__ = 128; // ??? labeled in source as SCREENWIDTH
const int kScreenH__ = 128; // ???
const int kViewPortW = 256;
const int kViewPortH = 128;
const int kScreenSize = (kResH * kResV) * 2; // The size of the screen buffer is (320x200) * 2 byte words
const uint16 kScreenLeft = 32;
const uint16 kScreenTop = 20;
const uint8 kTextLeft = 8;
const uint8 kTextTop = 4;
const uint8 kGaugeX = 0;
const uint8 kGaugeY = static_cast((-13) & 0xff); // ???
const uint16 kScreenBMW = 160; // Screen BitMap Width?
const uint16 kChrW = 64;
const uint16 kChrH = 32;
const uint16 kChrH2 = kChrH * 2;
const uint16 kChrH3 = kChrH * 3;
const uint16 kChrLen = (kChrW / 2) * kChrH;
const uint16 kChrBMW = kChrW / 2;
const uint16 kLCutaway = 4;
const uint16 kLDrawSolid = 32 * ((3 * 16) + 5);
const uint16 kChrDy[19] = {kChr0, kChrH, kChrH2, kChrH, kChrH2,
kChrH2, kChrH, kChrH2, kChrH2, kChr0,
kChr0, kChrH2, kChrH, kChrH2, kChrH2,
kChrH2, kChrH, kChrH2, kChrH2
};
const uint16 kChrMask[19] = {kChr0, kChr0, kChr0, kChr0,
kChrR, kChrL, kChr0, kChrL,
kChrR, kChr0, kChr0, kChrLD,
kChr0, kChrR, kChrLD, kChrRD,
kChr0, kChrRD, kChrL
};
const uint16 kIsBackground[36] = {1, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0
};
// Disk offsets
const int kPaletteOffset = 21205; // This is the byte position of the palette data in the disk
// Sprite constants
const uint16 kMaxSpriteW = 64;
const uint16 kMaxSpriteH = 64;
const uint16 kSpriteDY = 32;
const uint16 kVSX = kMaxSpriteW;
const uint16 kVSY = kSpriteDY;
const uint16 kVSBMW = (kViewPortW + kMaxSpriteW) / 2;
const uint16 kVSLen = kVSBMW * (kViewPortH + kMaxSpriteH);
const uint16 kVSDY = 32; // difference from top of screen to top of viewport in the virtual screen buffer
const uint16 kMySuperBottom = kVSDY + kViewPortH;
const uint16 kSuperBottom = 200;
const uint16 kMySuperTop = kVSDY;
const uint16 kSuperTop = 0;
const uint16 kViewPortSpX = 32;
const uint16 kViewPortSpY = 0;
const uint16 kWizardX = 28; // Common sprite center for some reason
const uint16 kWizardY = 37;
const uint16 kObjectY = 24;
const uint16 kObjectX = 32;
const uint16 kObjectHeight = 48;
const uint16 kObjectWidth = 64;
// Text constants
const uint8 kMaxRows = 5;
const uint8 kMaxCollumns = 26;
const uint16 kYesNoY = 88;
const uint16 kYesNoX1 = 8;
const uint16 kYesNoX2 = 182;
// Asset constants
const char kGaugeOn = 1; // On uses the sprite at index 1 of the font spriteset
const char kGaugeOff = 0; // Off uses the sprite at index 0 of the font spriteset
const char kGaugeStop = 1; // Literally just means the final kGaugeOn char to draw
const char kGaugeStart = 1; // First kGaugeOn char to draw
// Level constants
const int kStoryNull = 5;
const int kMaxFilesPerLevel = 16;
const int kMaxPartInstances = 4;
const int kLevelToMaze[8] = {0, 0, 1, 1, 2, 2, 2, 3};
/*
* 'global' members
*/
// Misc
Common::ErrorCode _err; // If this is not kNoError at any point, the engine will stop
uint8 _certificate[16]; // The certificate (password) is basically the inventory/equipment array
uint8 _lastCertLen = 0;
bool _draw = 0; // Whether the screen should draw this frame
int _zero = 0; // No idea what this is yet
bool _gameOverFlag = false;
uint8 _gameFlags = 0; // Bitflag array of event flags, but only two were used (saving ana and saving the king) <-- why is gameOverFlag not in this? Lol
bool _themePaused = false; // In the source, this is actually considered a bit flag array of 2 bits (b0 and b1). However, it only ever checks for non-zero, so it's effectively only 1 bit.
int _titlesShown = 0;
int _time = 0;
int _promoting = 0; // I think promoting means the title stuff
bool _restart = false;
// Story members
Story _stories[8];
// Level members
int _maxLevels = 0; // This is determined when loading in story files
int _level = 0;
bool _levelOver = false;
int _count = 0;
int _lastLevelLoaded = 0;
int _lastSongLoaded = 0;
int _storyLevel = 0;
int _storyX = 0;
int _loadA = 0;
int _loadY = 0;
uint16 _initialX = 0;
uint16 _initialY = 0;
int _initialBX = 0;
int _initialBY = 0;
int _dRoomNum = 0;
int _initialRoom = 0;
int _currentRoom = 0;
int _lastType = 0;
int _roomCellX = 0;
int _roomCellY = 0;
Room *_rooms[kMaxRooms]; // Rooms within the level
Common::Array _allFlames[kMaxRooms]; // The level needs it's own set of flames so that the flames can be turned on/off permanently. This is technically more like a hashmap in the source, but it could also be seen as a 2d array, just hashed together in the source
// Door members
Common::Array _doors;
uint8 _numDoors = 0;
uint8 _doorRoom = 0;
uint8 _doorToNextLevel = 0;
uint8 _doorCameInFrom = 0;
uint8 _ladders = 0;
uint8 _numLadders = 0;
uint8 _ladderInUse = 0;
uint8 _secretLadder = 0;
uint8 _secretCount = 0;
uint8 _secretDelta = 0;
// Debug members
bool _singleStep = false; // Flag for _singleStep mode
// Input members
int _pressedAction = 0;
int _heldAction = 0;
int _pressedDirection = 0;
int _heldDirection = 0;
// Text printing members
uint8 _slowText = 0;
uint8 _formatted = 0;
uint8 _collumn = 0;
uint8 _row = 0;
uint8 _myButton = 0;
uint8 _lastYes = 0;
// Music members
Song _playing; // Currently playing song
int _themeID = 0; // Not sure yet tbh
int _combatID = 0;
// Asset members
int _numSprites = 0; // This is more accurately actually the index within the sprite array, so _numSprites + 1 is the current number of sprites
DataSprite _dataSprites[kFont + 1]; // All the sprite data, indexed by SpriteName
Sprite _sprites[kMaxSprites]; // All the sprites shown on screen
Cycle _cycles[kMaxCycles];
Common::Array _strPtrs; // Str should really be a char array, but inserting frame values will be stupid so it's just a string instead
Common::Array _motivePtrs;
Common::Array _damagePtrs;
Common::Array