Initial commit
This commit is contained in:
55
engines/ags/shared/ac/audio_clip_type.cpp
Normal file
55
engines/ags/shared/ac/audio_clip_type.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/* 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 "ags/shared/ac/audio_clip_type.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using AGS::Shared::Stream;
|
||||
|
||||
void AudioClipType::ReadFromFile(Stream *in) {
|
||||
id = in->ReadInt32();
|
||||
reservedChannels = in->ReadInt32();
|
||||
volume_reduction_while_speech_playing = in->ReadInt32();
|
||||
crossfadeSpeed = in->ReadInt32();
|
||||
reservedForFuture = in->ReadInt32();
|
||||
}
|
||||
|
||||
void AudioClipType::WriteToFile(Stream *out) {
|
||||
out->WriteInt32(id);
|
||||
out->WriteInt32(reservedChannels);
|
||||
out->WriteInt32(volume_reduction_while_speech_playing);
|
||||
out->WriteInt32(crossfadeSpeed);
|
||||
out->WriteInt32(reservedForFuture);
|
||||
}
|
||||
|
||||
void AudioClipType::ReadFromSavegame(Shared::Stream *in) {
|
||||
volume_reduction_while_speech_playing = in->ReadInt32();
|
||||
crossfadeSpeed = in->ReadInt32();
|
||||
}
|
||||
|
||||
void AudioClipType::WriteToSavegame(Shared::Stream *out) const {
|
||||
out->WriteInt32(volume_reduction_while_speech_playing);
|
||||
out->WriteInt32(crossfadeSpeed);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
52
engines/ags/shared/ac/audio_clip_type.h
Normal file
52
engines/ags/shared/ac/audio_clip_type.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/* 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 AGS_SHARED_AC_AUDIO_CLIP_TYPE_H
|
||||
#define AGS_SHARED_AC_AUDIO_CLIP_TYPE_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// Forward declaration
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
|
||||
#define AUDIO_CLIP_TYPE_SOUND 1
|
||||
struct AudioClipType {
|
||||
int id;
|
||||
int reservedChannels;
|
||||
int volume_reduction_while_speech_playing;
|
||||
int crossfadeSpeed;
|
||||
int reservedForFuture;
|
||||
|
||||
void ReadFromFile(Shared::Stream *in);
|
||||
void WriteToFile(Shared::Stream *out);
|
||||
void ReadFromSavegame(Shared::Stream *in);
|
||||
void WriteToSavegame(Shared::Stream *out) const;
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
214
engines/ags/shared/ac/character_info.cpp
Normal file
214
engines/ags/shared/ac/character_info.cpp
Normal file
@@ -0,0 +1,214 @@
|
||||
/* 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 "common/str.h"
|
||||
#include "ags/shared/ac/character_info.h"
|
||||
#include "ags/shared/ac/game_version.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
#include "ags/shared/util/string_utils.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
void CharacterInfo::ReadBaseFields(Stream *in) {
|
||||
defview = in->ReadInt32();
|
||||
talkview = in->ReadInt32();
|
||||
view = in->ReadInt32();
|
||||
room = in->ReadInt32();
|
||||
prevroom = in->ReadInt32();
|
||||
x = in->ReadInt32();
|
||||
y = in->ReadInt32();
|
||||
wait = in->ReadInt32();
|
||||
flags = in->ReadInt32();
|
||||
following = in->ReadInt16();
|
||||
followinfo = in->ReadInt16();
|
||||
idleview = in->ReadInt32();
|
||||
idletime = in->ReadInt16();
|
||||
idleleft = in->ReadInt16();
|
||||
transparency = in->ReadInt16();
|
||||
baseline = in->ReadInt16();
|
||||
activeinv = in->ReadInt32();
|
||||
talkcolor = in->ReadInt32();
|
||||
thinkview = in->ReadInt32();
|
||||
blinkview = in->ReadInt16();
|
||||
blinkinterval = in->ReadInt16();
|
||||
blinktimer = in->ReadInt16();
|
||||
blinkframe = in->ReadInt16();
|
||||
walkspeed_y = in->ReadInt16();
|
||||
pic_yoffs = in->ReadInt16();
|
||||
z = in->ReadInt32();
|
||||
walkwait = in->ReadInt32();
|
||||
speech_anim_speed = in->ReadInt16();
|
||||
idle_anim_speed = in->ReadInt16();
|
||||
blocking_width = in->ReadInt16();
|
||||
blocking_height = in->ReadInt16();
|
||||
index_id = in->ReadInt32();
|
||||
pic_xoffs = in->ReadInt16();
|
||||
walkwaitcounter = in->ReadInt16();
|
||||
loop = in->ReadInt16();
|
||||
frame = in->ReadInt16();
|
||||
walking = in->ReadInt16();
|
||||
animating = in->ReadInt16();
|
||||
walkspeed = in->ReadInt16();
|
||||
animspeed = in->ReadInt16();
|
||||
in->ReadArrayOfInt16(inv, MAX_INV);
|
||||
actx = in->ReadInt16();
|
||||
acty = in->ReadInt16();
|
||||
}
|
||||
|
||||
void CharacterInfo::WriteBaseFields(Stream *out) const {
|
||||
out->WriteInt32(defview);
|
||||
out->WriteInt32(talkview);
|
||||
out->WriteInt32(view);
|
||||
out->WriteInt32(room);
|
||||
out->WriteInt32(prevroom);
|
||||
out->WriteInt32(x);
|
||||
out->WriteInt32(y);
|
||||
out->WriteInt32(wait);
|
||||
out->WriteInt32(flags);
|
||||
out->WriteInt16(following);
|
||||
out->WriteInt16(followinfo);
|
||||
out->WriteInt32(idleview);
|
||||
out->WriteInt16(idletime);
|
||||
out->WriteInt16(idleleft);
|
||||
out->WriteInt16(transparency);
|
||||
out->WriteInt16(baseline);
|
||||
out->WriteInt32(activeinv);
|
||||
out->WriteInt32(talkcolor);
|
||||
out->WriteInt32(thinkview);
|
||||
out->WriteInt16(blinkview);
|
||||
out->WriteInt16(blinkinterval);
|
||||
out->WriteInt16(blinktimer);
|
||||
out->WriteInt16(blinkframe);
|
||||
out->WriteInt16(walkspeed_y);
|
||||
out->WriteInt16(pic_yoffs);
|
||||
out->WriteInt32(z);
|
||||
out->WriteInt32(walkwait);
|
||||
out->WriteInt16(speech_anim_speed);
|
||||
out->WriteInt16(idle_anim_speed);
|
||||
out->WriteInt16(blocking_width);
|
||||
out->WriteInt16(blocking_height);
|
||||
out->WriteInt32(index_id);
|
||||
out->WriteInt16(pic_xoffs);
|
||||
out->WriteInt16(walkwaitcounter);
|
||||
out->WriteInt16(loop);
|
||||
out->WriteInt16(frame);
|
||||
out->WriteInt16(walking);
|
||||
out->WriteInt16(animating);
|
||||
out->WriteInt16(walkspeed);
|
||||
out->WriteInt16(animspeed);
|
||||
out->WriteArrayOfInt16(inv, MAX_INV);
|
||||
out->WriteInt16(actx);
|
||||
out->WriteInt16(acty);
|
||||
}
|
||||
|
||||
void CharacterInfo::ReadFromFile(Stream *in, CharacterInfo2 &chinfo2, GameDataVersion data_ver) {
|
||||
ReadBaseFields(in);
|
||||
StrUtil::ReadCStrCount(name, in, LEGACY_MAX_CHAR_NAME_LEN);
|
||||
StrUtil::ReadCStrCount(scrname, in, LEGACY_MAX_SCRIPT_NAME_LEN);
|
||||
on = in->ReadInt8();
|
||||
in->ReadInt8(); // alignment padding to int32
|
||||
|
||||
// Upgrade data
|
||||
if (data_ver < kGameVersion_360_16) {
|
||||
idle_anim_speed = animspeed + 5;
|
||||
}
|
||||
// Assign unrestricted names from legacy fields
|
||||
chinfo2.name_new = name;
|
||||
chinfo2.scrname_new = scrname;
|
||||
}
|
||||
|
||||
void CharacterInfo::WriteToFile(Stream *out) const {
|
||||
WriteBaseFields(out);
|
||||
out->Write(name, LEGACY_MAX_CHAR_NAME_LEN);
|
||||
out->Write(scrname, LEGACY_MAX_SCRIPT_NAME_LEN);
|
||||
out->WriteInt8(on);
|
||||
out->WriteInt8(0); // alignment padding to int32
|
||||
}
|
||||
|
||||
void CharacterInfo::ReadFromSavegame(Stream *in, CharacterInfo2 &chinfo2, CharacterSvgVersion save_ver) {
|
||||
ReadBaseFields(in);
|
||||
if (save_ver < kCharSvgVersion_36115) { // Fixed-size name and scriptname
|
||||
chinfo2.name_new.ReadCount(in, LEGACY_MAX_CHAR_NAME_LEN);
|
||||
in->Seek(LEGACY_MAX_SCRIPT_NAME_LEN); // skip legacy scriptname
|
||||
// (don't overwrite static data from save!)
|
||||
} else {
|
||||
chinfo2.name_new = StrUtil::ReadString(in);
|
||||
}
|
||||
on = in->ReadInt8();
|
||||
|
||||
//
|
||||
// Upgrade restored data
|
||||
if (save_ver < kCharSvgVersion_36025) {
|
||||
idle_anim_speed = animspeed + 5;
|
||||
}
|
||||
// Fill legacy name fields, for compatibility with old scripts and plugins
|
||||
snprintf(name, LEGACY_MAX_CHAR_NAME_LEN, "%s", chinfo2.name_new.GetCStr());
|
||||
}
|
||||
|
||||
void CharacterInfo::WriteToSavegame(Stream *out, const CharacterInfo2 &chinfo2) const {
|
||||
WriteBaseFields(out);
|
||||
StrUtil::WriteString(chinfo2.name_new, out); // kCharSvgVersion_36115
|
||||
out->WriteInt8(on);
|
||||
}
|
||||
|
||||
#if defined (OBSOLETE)
|
||||
#define COPY_CHAR_VAR(name) ci->name = oci->name
|
||||
|
||||
void ConvertOldCharacterToNew(OldCharacterInfo *oci, CharacterInfo *ci) {
|
||||
COPY_CHAR_VAR(defview);
|
||||
COPY_CHAR_VAR(talkview);
|
||||
COPY_CHAR_VAR(view);
|
||||
COPY_CHAR_VAR(room);
|
||||
COPY_CHAR_VAR(prevroom);
|
||||
COPY_CHAR_VAR(x);
|
||||
COPY_CHAR_VAR(y);
|
||||
COPY_CHAR_VAR(wait);
|
||||
COPY_CHAR_VAR(flags);
|
||||
COPY_CHAR_VAR(following);
|
||||
COPY_CHAR_VAR(followinfo);
|
||||
COPY_CHAR_VAR(idleview);
|
||||
COPY_CHAR_VAR(idletime);
|
||||
COPY_CHAR_VAR(idleleft);
|
||||
COPY_CHAR_VAR(transparency);
|
||||
COPY_CHAR_VAR(baseline);
|
||||
COPY_CHAR_VAR(activeinv);
|
||||
COPY_CHAR_VAR(loop);
|
||||
COPY_CHAR_VAR(frame);
|
||||
COPY_CHAR_VAR(walking);
|
||||
COPY_CHAR_VAR(animating);
|
||||
COPY_CHAR_VAR(walkspeed);
|
||||
COPY_CHAR_VAR(animspeed);
|
||||
COPY_CHAR_VAR(actx);
|
||||
COPY_CHAR_VAR(acty);
|
||||
COPY_CHAR_VAR(on);
|
||||
snprintf(ci->name, sizeof(CharacterInfo::name), "%s", oci->name);
|
||||
snprintf(ci->scrname, sizeof(CharacterInfo::scrname), "%s", oci->scrname);
|
||||
memcpy(&ci->inv[0], &oci->inv[0], sizeof(short) * 100);
|
||||
// move the talking colour into the struct and remove from flags
|
||||
ci->talkcolor = (oci->flags & OCHF_SPEECHCOL) >> OCHF_SPEECHCOLSHIFT;
|
||||
ci->flags = ci->flags & (~OCHF_SPEECHCOL);
|
||||
}
|
||||
#endif // OBSOLETE
|
||||
|
||||
} // namespace AGS3
|
||||
263
engines/ags/shared/ac/character_info.h
Normal file
263
engines/ags/shared/ac/character_info.h
Normal file
@@ -0,0 +1,263 @@
|
||||
/* 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 AGS_SHARED_AC_CHARACTER_INFO_H
|
||||
#define AGS_SHARED_AC_CHARACTER_INFO_H
|
||||
|
||||
#include "common/std/vector.h"
|
||||
#include "ags/shared/ac/common_defines.h" // constants
|
||||
#include "ags/shared/ac/game_version.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "ags/shared/util/bbop.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
|
||||
#define MAX_INV 301
|
||||
// Character flags
|
||||
#define CHF_MANUALSCALING 1
|
||||
#define CHF_FIXVIEW 2 // between SetCharView and ReleaseCharView
|
||||
#define CHF_NOINTERACT 4
|
||||
#define CHF_NODIAGONAL 8
|
||||
#define CHF_ALWAYSIDLE 0x10
|
||||
#define CHF_NOLIGHTING 0x20
|
||||
#define CHF_NOTURNING 0x40
|
||||
#define CHF_NOWALKBEHINDS 0x80
|
||||
#define CHF_FLIPSPRITE 0x100 // ?? Is this used??
|
||||
#define CHF_NOBLOCKING 0x200
|
||||
#define CHF_SCALEMOVESPEED 0x400
|
||||
#define CHF_NOBLINKANDTHINK 0x800
|
||||
#define CHF_SCALEVOLUME 0x1000
|
||||
#define CHF_HASTINT 0x2000 // engine only
|
||||
#define CHF_BEHINDSHEPHERD 0x4000 // engine only
|
||||
#define CHF_AWAITINGMOVE 0x8000 // engine only
|
||||
#define CHF_MOVENOTWALK 0x10000 // engine only - do not do walk anim
|
||||
#define CHF_ANTIGLIDE 0x20000
|
||||
#define CHF_HASLIGHT 0x40000
|
||||
#define CHF_TINTLIGHTMASK (CHF_NOLIGHTING | CHF_HASTINT | CHF_HASLIGHT)
|
||||
// Speechcol is no longer part of the flags as of v2.5
|
||||
#define OCHF_SPEECHCOL 0xff000000
|
||||
#define OCHF_SPEECHCOLSHIFT 24
|
||||
#define UNIFORM_WALK_SPEED 0
|
||||
#define FOLLOW_ALWAYSONTOP 0x7ffe
|
||||
|
||||
// Character's internal flags, packed in CharacterInfo::animating
|
||||
#define CHANIM_MASK 0xFF
|
||||
#define CHANIM_ON 0x01
|
||||
#define CHANIM_REPEAT 0x02
|
||||
#define CHANIM_BACKWARDS 0x04
|
||||
|
||||
// Converts character flags (CHF_*) to matching RoomObject flags (OBJF_*)
|
||||
inline int CharFlagsToObjFlags(int chflags) {
|
||||
using namespace AGS::Shared;
|
||||
return FlagToFlag(chflags, CHF_NOINTERACT, OBJF_NOINTERACT) |
|
||||
FlagToFlag(chflags, CHF_NOWALKBEHINDS, OBJF_NOWALKBEHINDS) |
|
||||
FlagToFlag(chflags, CHF_HASTINT, OBJF_HASTINT) |
|
||||
FlagToFlag(chflags, CHF_HASLIGHT, OBJF_HASLIGHT) |
|
||||
// following flags are inverse
|
||||
FlagToNoFlag(chflags, CHF_NOLIGHTING, OBJF_USEREGIONTINTS) |
|
||||
FlagToNoFlag(chflags, CHF_MANUALSCALING, OBJF_USEROOMSCALING) |
|
||||
FlagToNoFlag(chflags, CHF_NOBLOCKING, OBJF_SOLID);
|
||||
}
|
||||
|
||||
// Length of deprecated character name field, in bytes
|
||||
#define LEGACY_MAX_CHAR_NAME_LEN 40
|
||||
|
||||
enum CharacterSvgVersion {
|
||||
kCharSvgVersion_Initial = 0, // [UNSUPPORTED] from 3.5.0 pre-alpha
|
||||
kCharSvgVersion_350 = 1, // new movelist format (along with pathfinder)
|
||||
kCharSvgVersion_36025 = 2, // animation volume
|
||||
kCharSvgVersion_36109 = 3, // removed movelists, save externally
|
||||
kCharSvgVersion_36115 = 4, // no limit on character name's length
|
||||
};
|
||||
|
||||
|
||||
// Predeclare a design-time Character extension
|
||||
struct CharacterInfo2;
|
||||
// Predeclare a runtime Character extension (TODO: refactor and remove this from here)
|
||||
struct CharacterExtras;
|
||||
|
||||
// CharacterInfo is a design-time Character data.
|
||||
// Contains original set of character fields.
|
||||
// IMPORTANT: exposed to script API, and plugin API as AGSCharacter!
|
||||
// For older script compatibility the struct also has to maintain its size,
|
||||
// and be stored in a plain array to keep the relative memory address offsets
|
||||
// between the Character objects!
|
||||
// Do not add or change existing fields, unless planning breaking compatibility.
|
||||
// Prefer to use CharacterInfo2 and CharacterExtras structs for any extensions.
|
||||
//
|
||||
// TODO: must refactor, some parts of it should be in a runtime Character class.
|
||||
struct CharacterInfo {
|
||||
int defview;
|
||||
int talkview;
|
||||
int view;
|
||||
int room, prevroom;
|
||||
int x, y, wait;
|
||||
int flags;
|
||||
short following;
|
||||
short followinfo;
|
||||
int idleview; // the loop will be randomly picked
|
||||
short idletime, idleleft; // num seconds idle before playing anim
|
||||
short transparency; // if character is transparent
|
||||
short baseline;
|
||||
int activeinv;
|
||||
int talkcolor;
|
||||
int thinkview;
|
||||
short blinkview, blinkinterval; // design time
|
||||
short blinktimer, blinkframe; // run time
|
||||
short walkspeed_y;
|
||||
short pic_yoffs; // this is fixed in screen coordinates
|
||||
int z; // z-location, for flying etc
|
||||
int walkwait;
|
||||
short speech_anim_speed, idle_anim_speed;
|
||||
short blocking_width, blocking_height;
|
||||
int index_id; // used for object functions to know the id
|
||||
short pic_xoffs; // this is fixed in screen coordinates
|
||||
short walkwaitcounter;
|
||||
uint16_t loop, frame;
|
||||
short walking; // stores movelist index, optionally +TURNING_AROUND
|
||||
short animating; // stores CHANIM_* flags in lower byte and delay in upper byte
|
||||
short walkspeed, animspeed;
|
||||
short inv[MAX_INV];
|
||||
short actx, acty;
|
||||
// These two name fields are deprecated, but must stay here
|
||||
// for compatibility with old scripts and plugin API
|
||||
char name[LEGACY_MAX_CHAR_NAME_LEN];
|
||||
char scrname[LEGACY_MAX_SCRIPT_NAME_LEN];
|
||||
int8 on;
|
||||
|
||||
int get_effective_y() const; // return Y - Z
|
||||
int get_baseline() const; // return baseline, or Y if not set
|
||||
int get_blocking_top() const; // return Y - BlockingHeight/2
|
||||
int get_blocking_bottom() const; // return Y + BlockingHeight/2
|
||||
|
||||
// Returns effective x/y walkspeeds for this character
|
||||
void get_effective_walkspeeds(int &walk_speed_x, int &walk_speed_y) const {
|
||||
walk_speed_x = walkspeed;
|
||||
walk_speed_y = ((walkspeed_y == UNIFORM_WALK_SPEED) ? walkspeed : walkspeed_y);
|
||||
}
|
||||
|
||||
inline bool has_explicit_light() const {
|
||||
return (flags & CHF_HASLIGHT) != 0;
|
||||
}
|
||||
inline bool has_explicit_tint() const {
|
||||
return (flags & CHF_HASTINT) != 0;
|
||||
}
|
||||
inline bool is_animating() const {
|
||||
return (animating & CHANIM_ON) != 0;
|
||||
}
|
||||
inline int get_anim_repeat() const {
|
||||
return (animating & CHANIM_REPEAT) ? ANIM_REPEAT : ANIM_ONCE;
|
||||
}
|
||||
inline bool get_anim_forwards() const {
|
||||
return (animating & CHANIM_BACKWARDS) == 0;
|
||||
}
|
||||
inline int get_anim_delay() const {
|
||||
return (animating >> 8) & 0xFF;
|
||||
}
|
||||
inline void set_animating(bool repeat, bool forwards, int delay) {
|
||||
animating = CHANIM_ON |
|
||||
(CHANIM_REPEAT * repeat) |
|
||||
(CHANIM_BACKWARDS * !forwards) |
|
||||
((delay & 0xFF) << 8);
|
||||
}
|
||||
|
||||
// [IKM] 2012-06-28: I still have to pass char_index to some of those functions
|
||||
// either because they use it to set some variables with it,
|
||||
// or because they pass it further to other functions, that are called from various places
|
||||
// and it would be too much to change them all simultaneously
|
||||
//
|
||||
// [IKM] 2016-08-26: these methods should NOT be in CharacterInfo class,
|
||||
// bit in distinct runtime character class!
|
||||
void UpdateMoveAndAnim(int &char_index, CharacterExtras *chex, std::vector<int> &followingAsSheep);
|
||||
void UpdateFollowingExactlyCharacter();
|
||||
|
||||
int update_character_walkturning(CharacterExtras *chex);
|
||||
void update_character_moving(int &char_index, CharacterExtras *chex, int &doing_nothing);
|
||||
int update_character_animating(int &char_index, int &doing_nothing);
|
||||
void update_character_idle(CharacterExtras *chex, int &doing_nothing);
|
||||
void update_character_follower(int &char_index, std::vector<int> &followingAsSheep, int &doing_nothing);
|
||||
|
||||
void ReadFromFile(Shared::Stream *in, CharacterInfo2 &chinfo2, GameDataVersion data_ver);
|
||||
void WriteToFile(Shared::Stream *out) const;
|
||||
// TODO: move to runtime-only class (?)
|
||||
void ReadFromSavegame(Shared::Stream *in, CharacterInfo2 &chinfo2, CharacterSvgVersion save_ver);
|
||||
void WriteToSavegame(Shared::Stream *out, const CharacterInfo2 &chinfo2) const;
|
||||
|
||||
private:
|
||||
// Fixups loop and frame values, in case any of them are set to a value out of the valid range
|
||||
void FixupCurrentLoopAndFrame();
|
||||
|
||||
// Helper functions that read and write first data fields,
|
||||
// common for both game file and save.
|
||||
void ReadBaseFields(Shared::Stream *in);
|
||||
void WriteBaseFields(Shared::Stream *out) const;
|
||||
};
|
||||
|
||||
|
||||
// Design-time Character extended fields
|
||||
struct CharacterInfo2 {
|
||||
// Unrestricted scriptname and name fields
|
||||
AGS::Shared::String scrname_new;
|
||||
AGS::Shared::String name_new;
|
||||
};
|
||||
|
||||
|
||||
#if defined (OBSOLETE)
|
||||
struct OldCharacterInfo {
|
||||
int defview;
|
||||
int talkview;
|
||||
int view;
|
||||
int room, prevroom;
|
||||
int x, y, wait;
|
||||
int flags;
|
||||
short following;
|
||||
short followinfo;
|
||||
int idleview; // the loop will be randomly picked
|
||||
short idletime, idleleft; // num seconds idle before playing anim
|
||||
short transparency; // if character is transparent
|
||||
short baseline;
|
||||
int activeinv; // this is an INT to support SeeR (no signed shorts)
|
||||
short loop, frame;
|
||||
short walking, animating;
|
||||
short walkspeed, animspeed;
|
||||
short inv[100];
|
||||
short actx, acty;
|
||||
char name[30];
|
||||
char scrname[16];
|
||||
int8 on;
|
||||
};
|
||||
|
||||
void ConvertOldCharacterToNew(OldCharacterInfo *oci, CharacterInfo *ci);
|
||||
#endif // OBSOLETE
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
54
engines/ags/shared/ac/common.cpp
Normal file
54
engines/ags/shared/ac/common.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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 "ags/shared/ac/common.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
void quit(const String &str) {
|
||||
quit(str.GetCStr());
|
||||
}
|
||||
|
||||
void quitprintf(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
String text = String::FromFormatV(fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
// WORKAROUND: In ScummVM we have to make this an error, because
|
||||
// too many places calling it presume it doesn't return,
|
||||
// and will throw a wobbly if does
|
||||
error("%s", text.GetCStr());
|
||||
}
|
||||
|
||||
void set_our_eip(int eip) {
|
||||
_G(our_eip) = eip;
|
||||
}
|
||||
|
||||
int get_our_eip() {
|
||||
return _G(our_eip);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
40
engines/ags/shared/ac/common.h
Normal file
40
engines/ags/shared/ac/common.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/* 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 AGS_SHARED_AC_COMMON_H
|
||||
#define AGS_SHARED_AC_COMMON_H
|
||||
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// These are the project-dependent functions, they are defined both in Engine.App and AGS.Native.
|
||||
void quit(const AGS::Shared::String &str);
|
||||
void quit(const char *);
|
||||
void quitprintf(const char *fmt, ...);
|
||||
void set_our_eip(int eip);
|
||||
int get_our_eip();
|
||||
|
||||
extern const char *game_file_sig;
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
131
engines/ags/shared/ac/common_defines.h
Normal file
131
engines/ags/shared/ac/common_defines.h
Normal file
@@ -0,0 +1,131 @@
|
||||
/* 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 AGS_SHARED_AC_COMMON_DEFINES_H
|
||||
#define AGS_SHARED_AC_COMMON_DEFINES_H
|
||||
|
||||
#include "ags/shared/core/platform.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// Some arbitrary return values, should be replaced with either
|
||||
// simple boolean, or HError
|
||||
#define EXIT_NORMAL 0
|
||||
#define EXIT_CRASH 92
|
||||
#define EXIT_ERROR 93
|
||||
|
||||
// Legacy (UNSUPPORTED!) interaction script constants
|
||||
//
|
||||
// NUMCONDIT : whataction[0]: Char walks off left
|
||||
// [1]: Char walks off right
|
||||
// [2]: Char walks off bottom
|
||||
// [3]: Char walks off top
|
||||
// [4]: First enters screen
|
||||
// [5]: Every time enters screen
|
||||
// [6]: execute every loop
|
||||
// [5]...[19]: Char stands on lookat type
|
||||
// [20]...[35]: Look at type
|
||||
// [36]...[49]: Action on type
|
||||
// [50]...[65]: Use inv on type
|
||||
// [66]...[75]: Look at object
|
||||
// [76]...[85]: Action on object
|
||||
// [86]...[95]: Speak to object
|
||||
// [96]...[105]: Use inv on object
|
||||
// [106]...[124]: Misc conditions 1-20
|
||||
|
||||
// game ver whataction[]=
|
||||
// v1.00 0 : Go to screen
|
||||
// 1 : Don't do anything
|
||||
// 2 : Can't walk
|
||||
// 3 : Man dies
|
||||
// 4 : Run animation
|
||||
// 5 : Display message
|
||||
// 6 : Remove an object (set object.on=0)
|
||||
// 7 : Remove object & add Val2 to inventory
|
||||
// 8 : Add Val1 to inventory (Val2=num times)
|
||||
// 9 : Run a script
|
||||
// v1.00 SR-1 10 : Run graphical script
|
||||
// v1.1 11 : Play sound effect SOUND%d.WAV
|
||||
// v1.12 12 : Play FLI/FLC animation FLIC%d.FLC or FLIC%d.FLI
|
||||
// 13 : Turn object on
|
||||
// v2.00 14 : Run conversation
|
||||
#if defined(OBSOLETE)
|
||||
#define NUM_MISC 20
|
||||
#define NUMOTCON 7 // number of conditions before standing on
|
||||
#define NUM_CONDIT (120 + NUMOTCON)
|
||||
#define MISC_COND (MAX_WALK_BEHINDS * 4 + NUMOTCON + MAX_ROOM_OBJECTS * 4)
|
||||
#define NUMRESPONSE 14
|
||||
#define NUMCOMMANDS 15
|
||||
#define GO_TO_SCREEN 0
|
||||
#define NO_ACTION 1
|
||||
#define NO_WALK 2
|
||||
#define MAN_DIES 3
|
||||
#define RUN_ANIMATE 4
|
||||
#define SHOW_MESSAGE 5
|
||||
#define OBJECT_OFF 6
|
||||
#define OBJECT_INV 7
|
||||
#define ADD_INV 8
|
||||
#define RUNSCRIPT 9
|
||||
#define GRAPHSCRIPT 10
|
||||
#define PLAY_SOUND 11
|
||||
#define PLAY_FLI 12
|
||||
#define OBJECT_ON 13
|
||||
#define RUN_DIALOG 14
|
||||
#endif
|
||||
|
||||
// Script name length limit for some game objects
|
||||
#define LEGACY_MAX_SCRIPT_NAME_LEN 20
|
||||
// Number of state-saved rooms
|
||||
#define MAX_ROOMS 300
|
||||
// Some obsolete room data, likely pre-2.5
|
||||
#define MAX_LEGACY_ROOM_FLAGS 15
|
||||
// Old object name limit
|
||||
#define LEGACY_MAXOBJNAMELEN 30
|
||||
// Max number of sprites in older versions
|
||||
#define LEGACY_MAX_SPRITES_V25 6000
|
||||
#define LEGACY_MAX_SPRITES 30000
|
||||
|
||||
// The game to screen coordinate conversion multiplier, was used in older high-res games
|
||||
#define HIRES_COORD_MULTIPLIER 2
|
||||
|
||||
// Room object flags (currently limited by a byte)
|
||||
#define OBJF_NOINTERACT 0x01 // not clickable
|
||||
#define OBJF_NOWALKBEHINDS 0x02 // ignore walk-behinds
|
||||
#define OBJF_HASTINT 0x04 // the tint_* members are valid
|
||||
#define OBJF_USEREGIONTINTS 0x08 // obey region tints/light areas
|
||||
#define OBJF_USEROOMSCALING 0x10 // obey room scaling areas
|
||||
#define OBJF_SOLID 0x20 // blocks characters from moving
|
||||
#define OBJF_LEGACY_LOCKED 0x40 // object position is locked in the editor (OBSOLETE since 3.5.0)
|
||||
#define OBJF_HASLIGHT 0x80 // the tint_light is valid and treated as brightness
|
||||
#define OBJF_TINTLIGHTMASK (OBJF_HASTINT | OBJF_HASLIGHT | OBJF_USEREGIONTINTS)
|
||||
|
||||
// Animation flow mode
|
||||
// NOTE: had to move to common_defines, because used by CharacterInfo
|
||||
// Animates once and stops at the *last* frame
|
||||
#define ANIM_ONCE 0
|
||||
// Animates infinitely until stopped by command
|
||||
#define ANIM_REPEAT 1
|
||||
// Animates once and stops, resetting to the very first frame
|
||||
#define ANIM_ONCERESET 2
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
48
engines/ags/shared/ac/dialog_topic.cpp
Normal file
48
engines/ags/shared/ac/dialog_topic.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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 "ags/shared/ac/dialog_topic.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using AGS::Shared::Stream;
|
||||
|
||||
void DialogTopic::ReadFromFile(Stream *in) {
|
||||
in->ReadArray(optionnames, 150 * sizeof(char), MAXTOPICOPTIONS);
|
||||
in->ReadArrayOfInt32(optionflags, MAXTOPICOPTIONS);
|
||||
in->ReadInt32(); // optionscripts 32-bit pointer
|
||||
in->ReadArrayOfInt16(entrypoints, MAXTOPICOPTIONS);
|
||||
startupentrypoint = in->ReadInt16();
|
||||
codesize = in->ReadInt16();
|
||||
numoptions = in->ReadInt32();
|
||||
topicFlags = in->ReadInt32();
|
||||
}
|
||||
|
||||
void DialogTopic::ReadFromSavegame(Shared::Stream *in) {
|
||||
in->ReadArrayOfInt32(optionflags, MAXTOPICOPTIONS);
|
||||
}
|
||||
|
||||
void DialogTopic::WriteToSavegame(Shared::Stream *out) const {
|
||||
out->WriteArrayOfInt32(optionflags, MAXTOPICOPTIONS);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
86
engines/ags/shared/ac/dialog_topic.h
Normal file
86
engines/ags/shared/ac/dialog_topic.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/* 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 AGS_SHARED_AC_DIALOG_TOPIC_H
|
||||
#define AGS_SHARED_AC_DIALOG_TOPIC_H
|
||||
|
||||
#include "ags/shared/core/types.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
|
||||
// [IKM] This is *conversation* dialog, not *gui* dialog, mind you!
|
||||
|
||||
#define MAXTOPICOPTIONS 30
|
||||
#define DFLG_ON 1 // currently enabled
|
||||
#define DFLG_OFFPERM 2 // off forever (can't be trurned on)
|
||||
#define DFLG_NOREPEAT 4 // character doesn't repeat it when clicked
|
||||
#define DFLG_HASBEENCHOSEN 8 // dialog option is 'read'
|
||||
#define DTFLG_SHOWPARSER 1 // show parser in this topic
|
||||
#define DCMD_SAY 1
|
||||
#define DCMD_OPTOFF 2
|
||||
#define DCMD_OPTON 3
|
||||
#define DCMD_RETURN 4
|
||||
#define DCMD_STOPDIALOG 5
|
||||
#define DCMD_OPTOFFFOREVER 6
|
||||
#define DCMD_RUNTEXTSCRIPT 7
|
||||
#define DCMD_GOTODIALOG 8
|
||||
#define DCMD_PLAYSOUND 9
|
||||
#define DCMD_ADDINV 10
|
||||
#define DCMD_SETSPCHVIEW 11
|
||||
#define DCMD_NEWROOM 12
|
||||
#define DCMD_SETGLOBALINT 13
|
||||
#define DCMD_GIVESCORE 14
|
||||
#define DCMD_GOTOPREVIOUS 15
|
||||
#define DCMD_LOSEINV 16
|
||||
#define DCMD_ENDSCRIPT 0xff
|
||||
#define DCHAR_NARRATOR 999
|
||||
#define DCHAR_PLAYER 998
|
||||
|
||||
struct DialogTopic {
|
||||
char optionnames[MAXTOPICOPTIONS][150];
|
||||
int32_t optionflags[MAXTOPICOPTIONS];
|
||||
short entrypoints[MAXTOPICOPTIONS];
|
||||
short startupentrypoint;
|
||||
short codesize;
|
||||
int numoptions;
|
||||
int topicFlags;
|
||||
// NOTE: optionscripts is an unknown data from before AGS 2.5
|
||||
#ifdef OBSOLETE
|
||||
std::vector<uint8_t> optionscripts;
|
||||
#endif
|
||||
|
||||
void ReadFromFile(Shared::Stream *in);
|
||||
|
||||
void ReadFromSavegame(Shared::Stream *in);
|
||||
void WriteToSavegame(Shared::Stream *out) const;
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
44
engines/ags/shared/ac/dynobj/script_audio_clip.cpp
Normal file
44
engines/ags/shared/ac/dynobj/script_audio_clip.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/* 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 "ags/shared/ac/dynobj/script_audio_clip.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
void ScriptAudioClip::ReadFromFile(Stream *in) {
|
||||
id = in->ReadInt32();
|
||||
scriptName.ReadCount(in, LEGACY_AUDIOCLIP_SCRIPTNAMELENGTH);
|
||||
fileName.ReadCount(in, LEGACY_AUDIOCLIP_FILENAMELENGTH);
|
||||
bundlingType = static_cast<uint8_t>(in->ReadInt8());
|
||||
type = static_cast<uint8_t>(in->ReadInt8());
|
||||
fileType = static_cast<AudioFileType>(in->ReadInt8());
|
||||
defaultRepeat = in->ReadInt8();
|
||||
in->ReadInt8(); // alignment padding to int16
|
||||
defaultPriority = in->ReadInt16();
|
||||
defaultVolume = in->ReadInt16();
|
||||
in->ReadInt16(); // alignment padding to int32
|
||||
in->ReadInt32(); // reserved
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
68
engines/ags/shared/ac/dynobj/script_audio_clip.h
Normal file
68
engines/ags/shared/ac/dynobj/script_audio_clip.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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 AGS_SHARED_AC_DYNOBJ_SCRIPT_AUDIO_CLIP_H
|
||||
#define AGS_SHARED_AC_DYNOBJ_SCRIPT_AUDIO_CLIP_H
|
||||
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
|
||||
enum AudioFileType {
|
||||
eAudioFileOGG = 1,
|
||||
eAudioFileMP3 = 2,
|
||||
eAudioFileWAV = 3,
|
||||
eAudioFileVOC = 4,
|
||||
eAudioFileMIDI = 5,
|
||||
eAudioFileMOD = 6
|
||||
};
|
||||
|
||||
#define AUCL_BUNDLE_EXE 1
|
||||
#define AUCL_BUNDLE_VOX 2
|
||||
|
||||
#define LEGACY_AUDIOCLIP_SCRIPTNAMELENGTH 30
|
||||
#define LEGACY_AUDIOCLIP_FILENAMELENGTH 15
|
||||
|
||||
struct ScriptAudioClip {
|
||||
int id = 0;
|
||||
Shared::String scriptName;
|
||||
Shared::String fileName;
|
||||
uint8_t bundlingType = AUCL_BUNDLE_EXE;
|
||||
uint8_t type = 0;
|
||||
AudioFileType fileType = eAudioFileOGG;
|
||||
int8 defaultRepeat = 0;
|
||||
short defaultPriority = 50;
|
||||
short defaultVolume = 100;
|
||||
|
||||
void ReadFromFile(Shared::Stream *in);
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
422
engines/ags/shared/ac/game_setup_struct.cpp
Normal file
422
engines/ags/shared/ac/game_setup_struct.cpp
Normal file
@@ -0,0 +1,422 @@
|
||||
/* 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 "ags/shared/ac/audio_clip_type.h"
|
||||
#include "ags/shared/ac/game_setup_struct.h"
|
||||
#include "ags/shared/ac/old_game_setup_struct.h"
|
||||
#include "ags/shared/ac/words_dictionary.h"
|
||||
#include "ags/shared/ac/dynobj/script_audio_clip.h"
|
||||
#include "ags/shared/game/interactions.h"
|
||||
#include "ags/shared/util/string_utils.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
GameSetupStruct::GameSetupStruct()
|
||||
: filever(0)
|
||||
, roomCount(0)
|
||||
, scoreClipID(0) {
|
||||
memset(lipSyncFrameLetters, 0, sizeof(lipSyncFrameLetters));
|
||||
memset(guid, 0, sizeof(guid));
|
||||
memset(saveGameFileExtension, 0, sizeof(saveGameFileExtension));
|
||||
}
|
||||
|
||||
GameSetupStruct::~GameSetupStruct() {
|
||||
Free();
|
||||
}
|
||||
|
||||
void GameSetupStruct::Free() {
|
||||
GameSetupStructBase::Free();
|
||||
|
||||
fonts.clear();
|
||||
mcurs.clear();
|
||||
|
||||
intrChar.clear();
|
||||
charScripts.clear();
|
||||
charProps.clear();
|
||||
|
||||
// TODO: find out if it really needs to begin with 1 here?
|
||||
for (size_t i = 1; i < (size_t)MAX_INV; i++) {
|
||||
intrInv[i].reset();
|
||||
invProps[i].clear();
|
||||
}
|
||||
invScripts.clear();
|
||||
numinvitems = 0;
|
||||
|
||||
viewNames.clear();
|
||||
dialogScriptNames.clear();
|
||||
|
||||
roomNames.clear();
|
||||
roomNumbers.clear();
|
||||
roomCount = 0;
|
||||
|
||||
audioClips.clear();
|
||||
audioClipTypes.clear();
|
||||
|
||||
SpriteInfos.clear();
|
||||
}
|
||||
|
||||
// Assigns font info parameters using legacy flags value read from the game data
|
||||
void SetFontInfoFromLegacyFlags(FontInfo &finfo, const uint8_t data) {
|
||||
finfo.Flags = (data >> 6) & 0xFF;
|
||||
finfo.Size = data & FFLG_LEGACY_SIZEMASK;
|
||||
}
|
||||
|
||||
void AdjustFontInfoUsingFlags(FontInfo &finfo, const uint32_t flags) {
|
||||
finfo.Flags = flags;
|
||||
if ((flags & FFLG_SIZEMULTIPLIER) != 0) {
|
||||
finfo.SizeMultiplier = finfo.Size;
|
||||
finfo.Size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ScriptAudioClip *GetAudioClipForOldStyleNumber(GameSetupStruct &game, bool is_music, int num) {
|
||||
String clip_name;
|
||||
if (is_music)
|
||||
clip_name.Format("aMusic%d", num);
|
||||
else
|
||||
clip_name.Format("aSound%d", num);
|
||||
|
||||
for (size_t i = 0; i < _GP(game).audioClips.size(); ++i) {
|
||||
if (clip_name.CompareNoCase(_GP(game).audioClips[i].scriptName) == 0)
|
||||
return &_GP(game).audioClips[i];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Reading Part 1
|
||||
|
||||
void GameSetupStruct::read_savegame_info(Shared::Stream *in, GameDataVersion data_ver) {
|
||||
if (data_ver > kGameVersion_272) { // only 3.x
|
||||
StrUtil::ReadCStrCount(guid, in, MAX_GUID_LENGTH);
|
||||
StrUtil::ReadCStrCount(saveGameFileExtension, in, MAX_SG_EXT_LENGTH);
|
||||
saveGameFolderName.ReadCount(in, LEGACY_MAX_SG_FOLDER_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
void GameSetupStruct::read_font_infos(Shared::Stream *in, GameDataVersion data_ver) {
|
||||
fonts.resize(numfonts);
|
||||
if (data_ver < kGameVersion_350) {
|
||||
for (int i = 0; i < numfonts; ++i)
|
||||
SetFontInfoFromLegacyFlags(fonts[i], in->ReadInt8());
|
||||
for (int i = 0; i < numfonts; ++i)
|
||||
fonts[i].Outline = in->ReadInt8(); // size of char
|
||||
if (data_ver < kGameVersion_341)
|
||||
return;
|
||||
for (int i = 0; i < numfonts; ++i) {
|
||||
fonts[i].YOffset = in->ReadInt32();
|
||||
if (data_ver >= kGameVersion_341_2)
|
||||
fonts[i].LineSpacing = MAX<int32_t>(0, in->ReadInt32());
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < numfonts; ++i) {
|
||||
uint32_t flags = in->ReadInt32();
|
||||
fonts[i].Size = in->ReadInt32();
|
||||
fonts[i].Outline = in->ReadInt32();
|
||||
fonts[i].YOffset = in->ReadInt32();
|
||||
fonts[i].LineSpacing = MAX<int32_t>(0, in->ReadInt32());
|
||||
AdjustFontInfoUsingFlags(fonts[i], flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameSetupStruct::ReadInvInfo(Stream *in) {
|
||||
for (int i = 0; i < numinvitems; ++i) {
|
||||
invinfo[i].ReadFromFile(in);
|
||||
}
|
||||
}
|
||||
|
||||
void GameSetupStruct::WriteInvInfo(Stream *out) {
|
||||
for (int i = 0; i < numinvitems; ++i) {
|
||||
invinfo[i].WriteToFile(out);
|
||||
}
|
||||
}
|
||||
|
||||
HGameFileError GameSetupStruct::read_cursors(Shared::Stream *in) {
|
||||
mcurs.resize(numcursors);
|
||||
ReadMouseCursors(in);
|
||||
return HGameFileError::None();
|
||||
}
|
||||
|
||||
void GameSetupStruct::read_interaction_scripts(Shared::Stream *in, GameDataVersion data_ver) {
|
||||
_G(numGlobalVars) = 0;
|
||||
|
||||
if (data_ver > kGameVersion_272) { // 3.x
|
||||
charScripts.resize(numcharacters);
|
||||
invScripts.resize(numinvitems);
|
||||
for (size_t i = 0; i < (size_t)numcharacters; ++i)
|
||||
charScripts[i].reset(InteractionScripts::CreateFromStream(in));
|
||||
// NOTE: new inventory items' events are loaded starting from 1 for some reason
|
||||
for (size_t i = 1; i < (size_t)numinvitems; ++i)
|
||||
invScripts[i].reset(InteractionScripts::CreateFromStream(in));
|
||||
} else { // 2.x
|
||||
intrChar.resize(numcharacters);
|
||||
for (size_t i = 0; i < (size_t)numcharacters; ++i)
|
||||
intrChar[i].reset(Interaction::CreateFromStream(in));
|
||||
for (size_t i = 0; i < (size_t)numinvitems; ++i)
|
||||
intrInv[i].reset(Interaction::CreateFromStream(in));
|
||||
|
||||
_G(numGlobalVars) = in->ReadInt32();
|
||||
for (size_t i = 0; i < (size_t)_G(numGlobalVars); ++i)
|
||||
_G(globalvars)[i].Read(in);
|
||||
}
|
||||
}
|
||||
|
||||
void GameSetupStruct::read_words_dictionary(Shared::Stream *in) {
|
||||
dict.reset(new WordsDictionary());
|
||||
read_dictionary(dict.get(), in);
|
||||
}
|
||||
|
||||
void GameSetupStruct::ReadMouseCursors(Stream *in) {
|
||||
for (int i = 0; i < numcursors; ++i) {
|
||||
mcurs[i].ReadFromFile(in);
|
||||
}
|
||||
}
|
||||
|
||||
void GameSetupStruct::WriteMouseCursors(Stream *out) {
|
||||
for (int i = 0; i < numcursors; ++i) {
|
||||
mcurs[i].WriteToFile(out);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Reading Part 2
|
||||
|
||||
void GameSetupStruct::read_characters(Shared::Stream *in) {
|
||||
chars.resize(numcharacters);
|
||||
chars2.resize(numcharacters);
|
||||
ReadCharacters(in);
|
||||
}
|
||||
|
||||
void GameSetupStruct::read_lipsync(Shared::Stream *in, GameDataVersion data_ver) {
|
||||
if (data_ver >= kGameVersion_254) // lip syncing was introduced in 2.54
|
||||
in->ReadArray(&lipSyncFrameLetters[0][0], MAXLIPSYNCFRAMES, 50);
|
||||
}
|
||||
|
||||
void GameSetupStruct::read_messages(Shared::Stream *in, const std::array<int32_t> &load_messages, GameDataVersion data_ver) {
|
||||
char mbuf[GLOBALMESLENGTH];
|
||||
for (int i = 0; i < MAXGLOBALMES; ++i) {
|
||||
if (!load_messages[i])
|
||||
continue;
|
||||
if (data_ver < kGameVersion_261) { // Global messages are not encrypted on < 2.61
|
||||
char *nextchar = mbuf;
|
||||
|
||||
// TODO: probably this is same as fgetstring
|
||||
while (1) {
|
||||
*nextchar = in->ReadInt8();
|
||||
if (*nextchar == 0)
|
||||
break;
|
||||
nextchar++;
|
||||
}
|
||||
} else {
|
||||
read_string_decrypt(in, mbuf, GLOBALMESLENGTH);
|
||||
}
|
||||
messages[i] = mbuf;
|
||||
}
|
||||
}
|
||||
|
||||
void GameSetupStruct::ReadCharacters(Stream *in) {
|
||||
for (int i = 0; i < numcharacters; ++i) {
|
||||
chars[i].ReadFromFile(in, chars2[i], _G(loaded_game_file_version));
|
||||
}
|
||||
}
|
||||
|
||||
void GameSetupStruct::WriteCharacters(Stream *out) {
|
||||
for (int i = 0; i < numcharacters; ++i) {
|
||||
chars[i].WriteToFile(out);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Reading Part 3
|
||||
|
||||
HGameFileError GameSetupStruct::read_customprops(Shared::Stream *in, GameDataVersion data_ver) {
|
||||
dialogScriptNames.resize(numdialog);
|
||||
viewNames.resize(numviews);
|
||||
if (data_ver >= kGameVersion_260) { // >= 2.60
|
||||
if (Properties::ReadSchema(propSchema, in) != kPropertyErr_NoError)
|
||||
return new MainGameFileError(kMGFErr_InvalidPropertySchema);
|
||||
|
||||
int errors = 0;
|
||||
|
||||
charProps.resize(numcharacters);
|
||||
for (int i = 0; i < numcharacters; ++i) {
|
||||
errors += Properties::ReadValues(charProps[i], in);
|
||||
}
|
||||
for (int i = 0; i < numinvitems; ++i) {
|
||||
errors += Properties::ReadValues(invProps[i], in);
|
||||
}
|
||||
|
||||
if (errors > 0)
|
||||
return new MainGameFileError(kMGFErr_InvalidPropertyValues);
|
||||
|
||||
for (int i = 0; i < numviews; ++i)
|
||||
viewNames[i] = String::FromStream(in);
|
||||
|
||||
if (data_ver >= kGameVersion_270) {
|
||||
for (int i = 0; i < numinvitems; ++i)
|
||||
invScriptNames[i] = String::FromStream(in);
|
||||
|
||||
if (data_ver >= kGameVersion_272) {
|
||||
for (int i = 0; i < numdialog; ++i)
|
||||
dialogScriptNames[i] = String::FromStream(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
return HGameFileError::None();
|
||||
}
|
||||
|
||||
HGameFileError GameSetupStruct::read_audio(Shared::Stream *in, GameDataVersion data_ver) {
|
||||
if (data_ver >= kGameVersion_320) {
|
||||
size_t audiotype_count = in->ReadInt32();
|
||||
audioClipTypes.resize(audiotype_count);
|
||||
for (size_t i = 0; i < audiotype_count; ++i) {
|
||||
audioClipTypes[i].ReadFromFile(in);
|
||||
}
|
||||
|
||||
size_t audioclip_count = in->ReadInt32();
|
||||
audioClips.resize(audioclip_count);
|
||||
ReadAudioClips(in, audioclip_count);
|
||||
|
||||
scoreClipID = in->ReadInt32();
|
||||
}
|
||||
return HGameFileError::None();
|
||||
}
|
||||
|
||||
// Temporarily copied this from acruntim.h;
|
||||
// it is unknown if this should be defined for all solution, or only runtime
|
||||
#define STD_BUFFER_SIZE 3000
|
||||
|
||||
void GameSetupStruct::read_room_names(Stream *in, GameDataVersion data_ver) {
|
||||
if ((data_ver >= kGameVersion_301) && (options[OPT_DEBUGMODE] != 0)) {
|
||||
roomCount = in->ReadInt32();
|
||||
roomNumbers.resize(roomCount);
|
||||
roomNames.resize(roomCount);
|
||||
for (int i = 0; i < roomCount; ++i) {
|
||||
roomNumbers[i] = in->ReadInt32();
|
||||
roomNames[i].Read(in);
|
||||
}
|
||||
} else {
|
||||
roomCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void GameSetupStruct::ReadAudioClips(Shared::Stream *in, size_t count) {
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
audioClips[i].ReadFromFile(in);
|
||||
}
|
||||
}
|
||||
|
||||
void GameSetupStruct::ReadFromSaveGame_v321(Stream *in) {
|
||||
// NOTE: the individual object data is read from legacy saves
|
||||
// same way as if it were from a game file
|
||||
ReadInvInfo(in);
|
||||
ReadMouseCursors(in);
|
||||
|
||||
if (_G(loaded_game_file_version) <= kGameVersion_272) {
|
||||
for (int i = 0; i < numinvitems; ++i)
|
||||
intrInv[i]->ReadTimesRunFromSave_v321(in);
|
||||
for (int i = 0; i < numcharacters; ++i)
|
||||
intrChar[i]->ReadTimesRunFromSave_v321(in);
|
||||
}
|
||||
|
||||
in->ReadArrayOfInt32(&options[0], OPT_HIGHESTOPTION_321 + 1);
|
||||
options[OPT_LIPSYNCTEXT] = in->ReadInt8();
|
||||
|
||||
ReadCharacters(in);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
#if defined (OBSOLETE)
|
||||
|
||||
void ConvertOldGameStruct(OldGameSetupStruct *ogss, GameSetupStruct *gss) {
|
||||
snprintf(gss->gamename, sizeof(GameSetupStruct::gamename), "%s", ogss->gamename);
|
||||
for (int i = 0; i < 20; i++)
|
||||
gss->options[i] = ogss->options[i];
|
||||
memcpy(&gss->paluses[0], &ogss->paluses[0], 256);
|
||||
memcpy(&gss->defpal[0], &ogss->defpal[0], 256 * sizeof(RGB));
|
||||
gss->numviews = ogss->numviews;
|
||||
gss->numcharacters = ogss->numcharacters;
|
||||
gss->playercharacter = ogss->playercharacter;
|
||||
gss->totalscore = ogss->totalscore;
|
||||
gss->numinvitems = ogss->numinvitems;
|
||||
gss->numdialog = ogss->numdialog;
|
||||
gss->numdlgmessage = ogss->numdlgmessage;
|
||||
gss->numfonts = ogss->numfonts;
|
||||
gss->color_depth = ogss->color_depth;
|
||||
gss->target_win = ogss->target_win;
|
||||
gss->dialog_bullet = ogss->dialog_bullet;
|
||||
gss->hotdot = ogss->hotdot;
|
||||
gss->hotdotouter = ogss->hotdotouter;
|
||||
gss->uniqueid = ogss->uniqueid;
|
||||
gss->numgui = ogss->numgui;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
SetFontInfoFromLegacyFlags(gss->fonts[i], ogss->fontflags[i]);
|
||||
gss->fonts[i].Outline = ogss->fontoutline[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < LEGACY_MAX_SPRITES_V25; ++i) {
|
||||
gss->SpriteInfos[i].Flags = ogss->spriteflags[i];
|
||||
}
|
||||
|
||||
memcpy(&gss->invinfo[0], &ogss->invinfo[0], 100 * sizeof(InventoryItemInfo));
|
||||
for (int i = 0; i < 10; ++i)
|
||||
gss->mcurs[i] = ogss->mcurs[i];
|
||||
for (int i = 0; i < MAXGLOBALMES; i++)
|
||||
gss->messages[i] = ogss->messages[i];
|
||||
gss->dict = ogss->dict;
|
||||
gss->globalscript = ogss->globalscript;
|
||||
gss->chars = nullptr; //ogss->chars;
|
||||
gss->compiled_script = ogss->compiled_script;
|
||||
gss->numcursors = 10;
|
||||
}
|
||||
#endif // OBSOLETE
|
||||
|
||||
void GameSetupStruct::ReadFromSavegame(Stream *in) {
|
||||
// of GameSetupStruct
|
||||
in->ReadArrayOfInt32(options, OPT_HIGHESTOPTION_321 + 1);
|
||||
options[OPT_LIPSYNCTEXT] = in->ReadInt32();
|
||||
// of GameSetupStructBase
|
||||
playercharacter = in->ReadInt32();
|
||||
dialog_bullet = in->ReadInt32();
|
||||
hotdot = static_cast<uint16_t>(in->ReadInt16());
|
||||
hotdotouter = static_cast<uint16_t>(in->ReadInt16());
|
||||
invhotdotsprite = in->ReadInt32();
|
||||
default_lipsync_frame = in->ReadInt32();
|
||||
}
|
||||
|
||||
void GameSetupStruct::WriteForSavegame(Stream *out) {
|
||||
// of GameSetupStruct
|
||||
out->WriteArrayOfInt32(options, OPT_HIGHESTOPTION_321 + 1);
|
||||
out->WriteInt32(options[OPT_LIPSYNCTEXT]);
|
||||
// of GameSetupStructBase
|
||||
out->WriteInt32(playercharacter);
|
||||
out->WriteInt32(dialog_bullet);
|
||||
out->WriteInt16(static_cast<uint16_t>(hotdot));
|
||||
out->WriteInt16(static_cast<uint16_t>(hotdotouter));
|
||||
out->WriteInt32(invhotdotsprite);
|
||||
out->WriteInt32(default_lipsync_frame);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
189
engines/ags/shared/ac/game_setup_struct.h
Normal file
189
engines/ags/shared/ac/game_setup_struct.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// GameSetupStruct is a contemporary main game data.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_SHARED_AC_GAME_SETUP_STRUCT_H
|
||||
#define AGS_SHARED_AC_GAME_SETUP_STRUCT_H
|
||||
|
||||
#include "common/std/array.h"
|
||||
#include "common/std/vector.h"
|
||||
#include "ags/shared/ac/audio_clip_type.h"
|
||||
#include "ags/shared/ac/character_info.h" // TODO: constants to separate header
|
||||
#include "ags/shared/ac/game_setup_struct_base.h"
|
||||
#include "ags/shared/ac/inventory_item_info.h"
|
||||
#include "ags/shared/ac/mouse_cursor.h"
|
||||
#include "ags/shared/ac/dynobj/script_audio_clip.h"
|
||||
#include "ags/shared/game/custom_properties.h"
|
||||
#include "ags/shared/game/main_game_file.h" // TODO: constants to separate header or split out reading functions
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
struct AssetLibInfo;
|
||||
struct Interaction;
|
||||
struct InteractionScripts;
|
||||
typedef std::shared_ptr<Interaction> PInteraction;
|
||||
typedef std::shared_ptr<InteractionScripts> PInteractionScripts;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using AGS::Shared::PInteraction;
|
||||
using AGS::Shared::PInteractionScripts;
|
||||
using AGS::Shared::HGameFileError;
|
||||
|
||||
|
||||
// TODO: split GameSetupStruct into struct used to hold loaded game data, and actual runtime object
|
||||
struct GameSetupStruct : public GameSetupStructBase {
|
||||
// This array is used only to read data into;
|
||||
// font parameters are then put and queried in the fonts module
|
||||
// TODO: split into installation params (used only when reading) and runtime params
|
||||
std::vector<FontInfo> fonts;
|
||||
InventoryItemInfo invinfo[MAX_INV]{};
|
||||
std::vector<MouseCursor> mcurs;
|
||||
std::vector<PInteraction> intrChar;
|
||||
PInteraction intrInv[MAX_INV];
|
||||
std::vector<PInteractionScripts> charScripts;
|
||||
std::vector<PInteractionScripts> invScripts;
|
||||
// TODO: why we do not use this in the engine instead of
|
||||
// _G(loaded_game_file_version)?
|
||||
int filever; // just used by editor
|
||||
Shared::String compiled_with; // version of AGS this data was created by
|
||||
char lipSyncFrameLetters[MAXLIPSYNCFRAMES][50];
|
||||
AGS::Shared::PropertySchema propSchema;
|
||||
std::vector<AGS::Shared::StringIMap> charProps;
|
||||
AGS::Shared::StringIMap invProps[MAX_INV];
|
||||
// NOTE: although the view names are stored in game data, they are never
|
||||
// used, nor registered as script exports; numeric IDs are used to
|
||||
// reference views instead.
|
||||
std::vector<Shared::String> viewNames;
|
||||
Shared::String invScriptNames[MAX_INV];
|
||||
std::vector<Shared::String> dialogScriptNames;
|
||||
char guid[MAX_GUID_LENGTH];
|
||||
char saveGameFileExtension[MAX_SG_EXT_LENGTH];
|
||||
// NOTE: saveGameFolderName is generally used to create game subdirs in common user directories
|
||||
Shared::String saveGameFolderName;
|
||||
int roomCount;
|
||||
std::vector<int> roomNumbers;
|
||||
std::vector<Shared::String> roomNames;
|
||||
std::vector<ScriptAudioClip> audioClips;
|
||||
std::vector<AudioClipType> audioClipTypes;
|
||||
// A clip to play when player gains score in game
|
||||
// TODO: find out why OPT_SCORESOUND option cannot be used to store this in >=3.2 games
|
||||
int scoreClipID;
|
||||
// number of accessible game audio channels (the ones under direct user control)
|
||||
int numGameChannels = 0;
|
||||
// backward-compatible channel limit that may be exported to script and reserved by audiotypes
|
||||
int numCompatGameChannels = 0;
|
||||
|
||||
// TODO: I converted original array of sprite infos to vector here, because
|
||||
// statistically in most games sprites go in long continious sequences with minimal
|
||||
// gaps, and standard hash-map will have relatively big memory overhead compared.
|
||||
// Of course vector will not behave very well if user has created e.g. only
|
||||
// sprite #1 and sprite #1000000. For that reason I decided to still limit static
|
||||
// sprite count to some reasonable number for the time being. Dynamic sprite IDs are
|
||||
// added in sequence, so there won't be any issue with these.
|
||||
// There could be other collection types, more optimal for this case. For example,
|
||||
// we could use a kind of hash map containing fixed-sized arrays, where size of
|
||||
// array is calculated based on key spread factor.
|
||||
std::vector<SpriteInfo> SpriteInfos;
|
||||
|
||||
// Get game's native color depth (bits per pixel)
|
||||
inline int GetColorDepth() const {
|
||||
return color_depth * 8;
|
||||
}
|
||||
|
||||
|
||||
GameSetupStruct();
|
||||
GameSetupStruct(GameSetupStruct &&gss) = default;
|
||||
~GameSetupStruct();
|
||||
|
||||
GameSetupStruct &operator=(GameSetupStruct &&gss) = default;
|
||||
|
||||
void Free();
|
||||
|
||||
// [IKM] Game struct loading code is moved here from Engine's load_game_file
|
||||
// function; for now it is not supposed to be called by Editor; although it
|
||||
// is possible that eventually will be.
|
||||
//
|
||||
// Since reading game data is made in a bit inconvenient way I had to
|
||||
// a) divide process into three functions (there's some extra stuff
|
||||
// being read between them;
|
||||
// b) use a helper struct to pass some arguments
|
||||
//
|
||||
// I also had to move BuildAudioClipArray from the engine and make it
|
||||
// GameSetupStruct member.
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Do not call these directly
|
||||
//------------------------------
|
||||
// Part 1
|
||||
void read_savegame_info(Shared::Stream *in, GameDataVersion data_ver);
|
||||
void read_font_infos(Shared::Stream *in, GameDataVersion data_ver);
|
||||
HGameFileError read_cursors(Shared::Stream *in);
|
||||
void read_interaction_scripts(Shared::Stream *in, GameDataVersion data_ver);
|
||||
void read_words_dictionary(Shared::Stream *in);
|
||||
|
||||
void ReadInvInfo(Shared::Stream *in);
|
||||
void WriteInvInfo(Shared::Stream *out);
|
||||
void ReadMouseCursors(Shared::Stream *in);
|
||||
void WriteMouseCursors(Shared::Stream *out);
|
||||
//------------------------------
|
||||
// Part 2
|
||||
void read_characters(Shared::Stream *in);
|
||||
void read_lipsync(Shared::Stream *in, GameDataVersion data_ver);
|
||||
void read_messages(Shared::Stream *in, const std::array<int32_t> &load_messages, GameDataVersion data_ver);
|
||||
|
||||
void ReadCharacters(Shared::Stream *in);
|
||||
void WriteCharacters(Shared::Stream *out);
|
||||
//------------------------------
|
||||
// Part 3
|
||||
HGameFileError read_customprops(Shared::Stream *in, GameDataVersion data_ver);
|
||||
HGameFileError read_audio(Shared::Stream *in, GameDataVersion data_ver);
|
||||
void read_room_names(Shared::Stream *in, GameDataVersion data_ver);
|
||||
|
||||
void ReadAudioClips(Shared::Stream *in, size_t count);
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
// Functions for reading and writing appropriate data from/to save game
|
||||
void ReadFromSaveGame_v321(Shared::Stream *in);
|
||||
|
||||
void ReadFromSavegame(Shared::Stream *in);
|
||||
void WriteForSavegame(Shared::Stream *out);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
#if defined (OBSOLETE)
|
||||
struct OldGameSetupStruct;
|
||||
void ConvertOldGameStruct(OldGameSetupStruct *ogss, GameSetupStruct *gss);
|
||||
#endif // OBSOLETE
|
||||
|
||||
// Finds an audio clip using legacy convention index
|
||||
ScriptAudioClip *GetAudioClipForOldStyleNumber(GameSetupStruct &game, bool is_music, int num);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
270
engines/ags/shared/ac/game_setup_struct_base.cpp
Normal file
270
engines/ags/shared/ac/game_setup_struct_base.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
/* 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 "ags/shared/ac/character_info.h"
|
||||
#include "ags/shared/ac/game_setup_struct_base.h"
|
||||
#include "ags/shared/ac/game_setup_struct.h"
|
||||
#include "ags/shared/ac/game_version.h"
|
||||
#include "ags/shared/ac/words_dictionary.h"
|
||||
#include "ags/shared/script/cc_script.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
#include "ags/shared/util/string_utils.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
GameSetupStructBase::GameSetupStructBase()
|
||||
: numviews(0)
|
||||
, numcharacters(0)
|
||||
, playercharacter(-1)
|
||||
, totalscore(0)
|
||||
, numinvitems(0)
|
||||
, numdialog(0)
|
||||
, numdlgmessage(0)
|
||||
, numfonts(0)
|
||||
, color_depth(0)
|
||||
, target_win(0)
|
||||
, dialog_bullet(0)
|
||||
, hotdot(0)
|
||||
, hotdotouter(0)
|
||||
, uniqueid(0)
|
||||
, numgui(0)
|
||||
, numcursors(0)
|
||||
, default_lipsync_frame(0)
|
||||
, invhotdotsprite(0)
|
||||
, dict(nullptr)
|
||||
, _resolutionType(kGameResolution_Undefined)
|
||||
, _dataUpscaleMult(1)
|
||||
, _screenUpscaleMult(1) {
|
||||
memset(options, 0, sizeof(options));
|
||||
memset(paluses, 0, sizeof(paluses));
|
||||
memset(defpal, 0, sizeof(defpal));
|
||||
memset(reserved, 0, sizeof(reserved));
|
||||
}
|
||||
|
||||
GameSetupStructBase::~GameSetupStructBase() {
|
||||
Free();
|
||||
}
|
||||
|
||||
void GameSetupStructBase::Free() {
|
||||
for (int i = 0; i < MAXGLOBALMES; ++i) {
|
||||
messages[i].Free();
|
||||
}
|
||||
dict.reset();
|
||||
chars.clear();
|
||||
|
||||
numcharacters = 0;
|
||||
}
|
||||
|
||||
void GameSetupStructBase::SetDefaultResolution(GameResolutionType type) {
|
||||
SetDefaultResolution(type, Size());
|
||||
}
|
||||
|
||||
void GameSetupStructBase::SetDefaultResolution(Size size) {
|
||||
SetDefaultResolution(kGameResolution_Custom, size);
|
||||
}
|
||||
|
||||
void GameSetupStructBase::SetDefaultResolution(GameResolutionType type, Size size) {
|
||||
// Calculate native res first then remember it
|
||||
SetNativeResolution(type, size);
|
||||
_defGameResolution = _gameResolution;
|
||||
// Setup data resolution according to legacy settings (if set)
|
||||
_dataResolution = _defGameResolution;
|
||||
if (IsLegacyHiRes() && options[OPT_NATIVECOORDINATES] == 0) {
|
||||
_dataResolution = _defGameResolution / HIRES_COORD_MULTIPLIER;
|
||||
}
|
||||
OnResolutionSet();
|
||||
}
|
||||
|
||||
void GameSetupStructBase::SetNativeResolution(GameResolutionType type, Size game_res) {
|
||||
if (type == kGameResolution_Custom) {
|
||||
_resolutionType = kGameResolution_Custom;
|
||||
_gameResolution = game_res;
|
||||
_letterboxSize = _gameResolution;
|
||||
} else {
|
||||
_resolutionType = type;
|
||||
_gameResolution = ResolutionTypeToSize(_resolutionType, IsLegacyLetterbox());
|
||||
_letterboxSize = ResolutionTypeToSize(_resolutionType, false);
|
||||
}
|
||||
}
|
||||
|
||||
void GameSetupStructBase::SetGameResolution(GameResolutionType type) {
|
||||
SetNativeResolution(type, Size());
|
||||
OnResolutionSet();
|
||||
}
|
||||
|
||||
void GameSetupStructBase::SetGameResolution(Size game_res) {
|
||||
SetNativeResolution(kGameResolution_Custom, game_res);
|
||||
OnResolutionSet();
|
||||
}
|
||||
|
||||
void GameSetupStructBase::OnResolutionSet() {
|
||||
// The final data-to-game multiplier is always set after actual game resolution (not default one)
|
||||
if (!_dataResolution.IsNull())
|
||||
_dataUpscaleMult = _gameResolution.Width / _dataResolution.Width;
|
||||
else
|
||||
_dataUpscaleMult = 1;
|
||||
if (!_defGameResolution.IsNull())
|
||||
_screenUpscaleMult = _gameResolution.Width / _defGameResolution.Width;
|
||||
else
|
||||
_screenUpscaleMult = 1;
|
||||
_relativeUIMult = IsLegacyHiRes() ? HIRES_COORD_MULTIPLIER : 1;
|
||||
}
|
||||
|
||||
void GameSetupStructBase::ReadFromFile(Stream *in, GameDataVersion game_ver, SerializeInfo &info) {
|
||||
// NOTE: historically the struct was saved by dumping whole memory
|
||||
// into the file stream, which added padding from memory alignment;
|
||||
// here we mark the padding bytes, as they do not belong to actual data.
|
||||
gamename.ReadCount(in, LEGACY_GAME_NAME_LENGTH);
|
||||
in->ReadInt16(); // alignment padding to int32 (gamename: 50 -> 52 bytes)
|
||||
in->ReadArrayOfInt32(options, MAX_OPTIONS);
|
||||
if (game_ver < kGameVersion_340_4) { // TODO: this should probably be possible to deduce script API level
|
||||
// using game data version and other options like OPT_STRICTSCRIPTING
|
||||
options[OPT_BASESCRIPTAPI] = kScriptAPI_Undefined;
|
||||
options[OPT_SCRIPTCOMPATLEV] = kScriptAPI_Undefined;
|
||||
}
|
||||
in->Read(&paluses[0], sizeof(paluses));
|
||||
// colors are an array of chars
|
||||
in->Read(&defpal[0], sizeof(defpal));
|
||||
numviews = in->ReadInt32();
|
||||
numcharacters = in->ReadInt32();
|
||||
playercharacter = in->ReadInt32();
|
||||
totalscore = in->ReadInt32();
|
||||
numinvitems = in->ReadInt16();
|
||||
in->ReadInt16(); // alignment padding to int32
|
||||
numdialog = in->ReadInt32();
|
||||
numdlgmessage = in->ReadInt32();
|
||||
numfonts = in->ReadInt32();
|
||||
color_depth = in->ReadInt32();
|
||||
target_win = in->ReadInt32();
|
||||
dialog_bullet = in->ReadInt32();
|
||||
hotdot = static_cast<uint16_t>(in->ReadInt16());
|
||||
hotdotouter = static_cast<uint16_t>(in->ReadInt16());
|
||||
uniqueid = in->ReadInt32();
|
||||
numgui = in->ReadInt32();
|
||||
numcursors = in->ReadInt32();
|
||||
GameResolutionType resolution_type = (GameResolutionType)in->ReadInt32();
|
||||
Size game_size;
|
||||
if (resolution_type == kGameResolution_Custom && game_ver >= kGameVersion_330) {
|
||||
game_size.Width = in->ReadInt32();
|
||||
game_size.Height = in->ReadInt32();
|
||||
}
|
||||
SetDefaultResolution(resolution_type, game_size);
|
||||
|
||||
default_lipsync_frame = in->ReadInt32();
|
||||
invhotdotsprite = in->ReadInt32();
|
||||
in->ReadArrayOfInt32(reserved, NUM_INTS_RESERVED);
|
||||
|
||||
info.ExtensionOffset = static_cast<uint32_t>(in->ReadInt32());
|
||||
in->ReadArrayOfInt32(&info.HasMessages.front(), MAXGLOBALMES);
|
||||
|
||||
info.HasWordsDict = in->ReadInt32() != 0;
|
||||
in->ReadInt32(); // globalscript (dummy 32-bit pointer value)
|
||||
in->ReadInt32(); // chars (dummy 32-bit pointer value)
|
||||
info.HasCCScript = in->ReadInt32() != 0;
|
||||
}
|
||||
|
||||
void GameSetupStructBase::WriteToFile(Stream *out, const SerializeInfo &info) const {
|
||||
// NOTE: historically the struct was saved by dumping whole memory
|
||||
// into the file stream, which added padding from memory alignment;
|
||||
// here we mark the padding bytes, as they do not belong to actual data.
|
||||
gamename.WriteCount(out, LEGACY_GAME_NAME_LENGTH);
|
||||
out->WriteInt16(0); // alignment padding to int32
|
||||
out->WriteArrayOfInt32(options, MAX_OPTIONS);
|
||||
out->Write(&paluses[0], sizeof(paluses));
|
||||
// colors are an array of chars
|
||||
out->Write(&defpal[0], sizeof(defpal));
|
||||
out->WriteInt32(numviews);
|
||||
out->WriteInt32(numcharacters);
|
||||
out->WriteInt32(playercharacter);
|
||||
out->WriteInt32(totalscore);
|
||||
out->WriteInt16(numinvitems);
|
||||
out->WriteInt16(0); // alignment padding to int32
|
||||
out->WriteInt32(numdialog);
|
||||
out->WriteInt32(numdlgmessage);
|
||||
out->WriteInt32(numfonts);
|
||||
out->WriteInt32(color_depth);
|
||||
out->WriteInt32(target_win);
|
||||
out->WriteInt32(dialog_bullet);
|
||||
out->WriteInt16(static_cast<uint16_t>(hotdot));
|
||||
out->WriteInt16(static_cast<uint16_t>(hotdotouter));
|
||||
out->WriteInt32(uniqueid);
|
||||
out->WriteInt32(numgui);
|
||||
out->WriteInt32(numcursors);
|
||||
out->WriteInt32(_resolutionType);
|
||||
if (_resolutionType == kGameResolution_Custom) {
|
||||
out->WriteInt32(_defGameResolution.Width);
|
||||
out->WriteInt32(_defGameResolution.Height);
|
||||
}
|
||||
out->WriteInt32(default_lipsync_frame);
|
||||
out->WriteInt32(invhotdotsprite);
|
||||
out->WriteArrayOfInt32(reserved, 17);
|
||||
for (int i = 0; i < MAXGLOBALMES; ++i) {
|
||||
out->WriteInt32(!messages[i].IsEmpty() ? 1 : 0);
|
||||
}
|
||||
out->WriteInt32(dict ? 1 : 0);
|
||||
out->WriteInt32(0); // globalscript (dummy 32-bit pointer value)
|
||||
out->WriteInt32(0); // chars (dummy 32-bit pointer value)
|
||||
out->WriteInt32(info.HasCCScript ? 1 : 0);
|
||||
}
|
||||
|
||||
Size ResolutionTypeToSize(GameResolutionType resolution, bool letterbox) {
|
||||
switch (resolution) {
|
||||
case kGameResolution_Default:
|
||||
case kGameResolution_320x200:
|
||||
return letterbox ? Size(320, 240) : Size(320, 200);
|
||||
case kGameResolution_320x240:
|
||||
return Size(320, 240);
|
||||
case kGameResolution_640x400:
|
||||
return letterbox ? Size(640, 480) : Size(640, 400);
|
||||
case kGameResolution_640x480:
|
||||
return Size(640, 480);
|
||||
case kGameResolution_800x600:
|
||||
return Size(800, 600);
|
||||
case kGameResolution_1024x768:
|
||||
return Size(1024, 768);
|
||||
case kGameResolution_1280x720:
|
||||
return Size(1280, 720);
|
||||
default:
|
||||
return Size();
|
||||
}
|
||||
}
|
||||
|
||||
const char *GetScriptAPIName(ScriptAPIVersion v) {
|
||||
switch (v) {
|
||||
case kScriptAPI_v321: return "v3.2.1";
|
||||
case kScriptAPI_v330: return "v3.3.0";
|
||||
case kScriptAPI_v334: return "v3.3.4";
|
||||
case kScriptAPI_v335: return "v3.3.5";
|
||||
case kScriptAPI_v340: return "v3.4.0";
|
||||
case kScriptAPI_v341: return "v3.4.1";
|
||||
case kScriptAPI_v350: return "v3.5.0-alpha";
|
||||
case kScriptAPI_v3507: return "v3.5.0-final";
|
||||
case kScriptAPI_v351: return "v3.5.1";
|
||||
case kScriptAPI_v360: return "v3.6.0-alpha";
|
||||
case kScriptAPI_v36026: return "v3.6.0-final";
|
||||
case kScriptAPI_v361: return "v3.6.1";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
283
engines/ags/shared/ac/game_setup_struct_base.h
Normal file
283
engines/ags/shared/ac/game_setup_struct_base.h
Normal file
@@ -0,0 +1,283 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
//=============================================================================
|
||||
//
|
||||
// GameSetupStructBase is a base class for main game data.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_SHARED_AC_GAME_SETUP_STRUCT_BASE_H
|
||||
#define AGS_SHARED_AC_GAME_SETUP_STRUCT_BASE_H
|
||||
|
||||
#include "ags/lib/allegro.h" // RGB
|
||||
#include "common/std/array.h"
|
||||
#include "common/std/memory.h"
|
||||
#include "common/std/vector.h"
|
||||
#include "ags/shared/ac/game_version.h"
|
||||
#include "ags/shared/ac/game_struct_defines.h"
|
||||
#include "ags/shared/ac/words_dictionary.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// Forward declaration
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
|
||||
struct CharacterInfo;
|
||||
struct ccScript;
|
||||
|
||||
|
||||
struct GameSetupStructBase {
|
||||
static const int LEGACY_GAME_NAME_LENGTH = 50;
|
||||
static const int MAX_OPTIONS = 100;
|
||||
static const int NUM_INTS_RESERVED = 16;
|
||||
|
||||
Shared::String gamename;
|
||||
int32_t options[MAX_OPTIONS];
|
||||
uint8_t paluses[256];
|
||||
RGB defpal[256];
|
||||
int numviews;
|
||||
int numcharacters;
|
||||
int playercharacter;
|
||||
int totalscore;
|
||||
int numinvitems;
|
||||
int numdialog;
|
||||
int numdlgmessage; // [DEPRECATED]
|
||||
int numfonts;
|
||||
int color_depth; // in bytes per pixel (ie. 1 or 2)
|
||||
int target_win;
|
||||
int dialog_bullet; // 0 for none, otherwise slot num of bullet point
|
||||
int hotdot; // inv cursor hotspot dot color
|
||||
int hotdotouter;
|
||||
int uniqueid; // random key identifying the game
|
||||
int numgui;
|
||||
int numcursors;
|
||||
int default_lipsync_frame; // used for unknown chars
|
||||
int invhotdotsprite;
|
||||
int32_t reserved[NUM_INTS_RESERVED];
|
||||
String messages[MAXGLOBALMES];
|
||||
std::unique_ptr<WordsDictionary> dict;
|
||||
std::vector<CharacterInfo> chars;
|
||||
std::vector<CharacterInfo2> chars2; // extended character fields
|
||||
|
||||
GameSetupStructBase();
|
||||
GameSetupStructBase(GameSetupStructBase &&gss) = default;
|
||||
~GameSetupStructBase();
|
||||
|
||||
GameSetupStructBase &operator=(GameSetupStructBase &&gss) = default;
|
||||
|
||||
void Free();
|
||||
void SetDefaultResolution(GameResolutionType type);
|
||||
void SetDefaultResolution(Size game_res);
|
||||
void SetGameResolution(GameResolutionType type);
|
||||
void SetGameResolution(Size game_res);
|
||||
|
||||
// Tells whether the serialized game data contains certain components
|
||||
struct SerializeInfo {
|
||||
bool HasCCScript = false;
|
||||
bool HasWordsDict = false;
|
||||
std::array<int32_t> HasMessages;
|
||||
// File offset at which game data extensions begin
|
||||
uint32_t ExtensionOffset = 0u;
|
||||
|
||||
SerializeInfo() {
|
||||
HasMessages.resize(MAXGLOBALMES);
|
||||
}
|
||||
};
|
||||
|
||||
void ReadFromFile(Shared::Stream *in, GameDataVersion game_ver, SerializeInfo &info);
|
||||
void WriteToFile(Shared::Stream *out, const SerializeInfo &info) const;
|
||||
|
||||
//
|
||||
// ** On game resolution.
|
||||
//
|
||||
// Game resolution is a size of a native game screen in pixels.
|
||||
// This is the "game resolution" that developer sets up in AGS Editor.
|
||||
// It is in the same units in which sprite and font sizes are defined.
|
||||
//
|
||||
// Graphic renderer may scale and stretch game's frame as requested by
|
||||
// player or system, which will not affect native coordinates in any way.
|
||||
//
|
||||
// ** Legacy upscale mode.
|
||||
//
|
||||
// In the past engine had a separation between logical and native screen
|
||||
// coordinates and supported running games "upscaled". E.g. 320x200 games
|
||||
// could be run as 640x400. This was not done by simply stretching final
|
||||
// game's drawn frame to the larger window, but by multiplying all data
|
||||
// containing coordinates and graphics either on load or real-time.
|
||||
// Games of 640x400 and above were scripted and set up in coordinate units
|
||||
// that were always x2 times smaller than the one developer chose.
|
||||
// For example, choosing a 640x400 resolution would make game draw itself
|
||||
// as 640x400, but all the game logic (object properties, script commands)
|
||||
// would work in 320x200 (this also let run 640x400 downscaled to 320x200).
|
||||
// Ignoring the obvious complications, the known benefit from such approach
|
||||
// was that developers could supply separate sets of fonts and sprites for
|
||||
// low-res and high-res modes.
|
||||
// The 3rd generation of AGS still allows to achieve same effect by using
|
||||
// backwards-compatible option (although it is not recommended except when
|
||||
// importing and continuing old projects).
|
||||
//
|
||||
// In order to support this legacy behavior we have a set of functions for
|
||||
// coordinate conversion. They are required to move from "data" resolution
|
||||
// to "final game" resolution and back.
|
||||
//
|
||||
// Some of the script commands, as well as some internal engine data use
|
||||
// coordinates in "game resolution" instead (this should be documented).
|
||||
// In such case there's another conversion which translates these from
|
||||
// default to actual resolution; e.g. when 320x200 game is run as 640x400
|
||||
// they should be multiplied by 2.
|
||||
//
|
||||
// ** TODO.
|
||||
//
|
||||
// Truth be told, all this is still implemented incorrectly, because no one
|
||||
// found time to rewrite the thing. The correct way would perhaps be:
|
||||
// 1) treat old games as x2 lower resolution than they say.
|
||||
// 2) support drawing particular sprites and texts in x2 higher resolution
|
||||
// (assuming display resolution allows). The latter is potentially enabled
|
||||
// by "sprite batches" system in the engine and will benefit new games too.
|
||||
|
||||
inline GameResolutionType GetResolutionType() const {
|
||||
return _resolutionType;
|
||||
}
|
||||
|
||||
// Get actual game's resolution
|
||||
const Size &GetGameRes() const {
|
||||
return _gameResolution;
|
||||
}
|
||||
// Get default resolution the game was created for;
|
||||
// this is usually equal to GetGameRes except for legacy modes.
|
||||
const Size &GetDefaultRes() const {
|
||||
return _defGameResolution;
|
||||
}
|
||||
// Get data & script resolution;
|
||||
// this is usually equal to GetGameRes except for legacy modes.
|
||||
const Size &GetDataRes() const {
|
||||
return _dataResolution;
|
||||
}
|
||||
// Get game data-->final game resolution coordinate multiplier
|
||||
inline int GetDataUpscaleMult() const {
|
||||
return _dataUpscaleMult;
|
||||
}
|
||||
// Get multiplier for various default UI sizes, meant to keep UI looks
|
||||
// more or less readable in any game resolution.
|
||||
// TODO: find a better solution for UI sizes, perhaps make variables.
|
||||
inline int GetRelativeUIMult() const {
|
||||
return _relativeUIMult;
|
||||
}
|
||||
// Get game default res-->final game resolution coordinate multiplier;
|
||||
// used to convert coordinates from original game res to actual one
|
||||
inline int GetScreenUpscaleMult() const {
|
||||
return _screenUpscaleMult;
|
||||
}
|
||||
// Tells if game allows assets defined in relative resolution;
|
||||
// that is - have to be converted to this game resolution type
|
||||
inline bool AllowRelativeRes() const {
|
||||
return options[OPT_RELATIVEASSETRES] != 0;
|
||||
}
|
||||
// Legacy definition of high and low game resolution.
|
||||
// Used to determine certain hardcoded coordinate conversion logic, but
|
||||
// does not make much sense today when the resolution is arbitrary.
|
||||
inline bool IsLegacyHiRes() const {
|
||||
if (_resolutionType == kGameResolution_Custom)
|
||||
return (_gameResolution.Width * _gameResolution.Height) > (320 * 240);
|
||||
return ::AGS3::IsLegacyHiRes(_resolutionType);
|
||||
}
|
||||
// Tells if data has coordinates in default game resolution
|
||||
inline bool IsDataInNativeCoordinates() const {
|
||||
return options[OPT_NATIVECOORDINATES] != 0;
|
||||
}
|
||||
|
||||
// Tells if game runs in native letterbox mode (legacy option)
|
||||
inline bool IsLegacyLetterbox() const {
|
||||
return options[OPT_LETTERBOX] != 0;
|
||||
}
|
||||
// Get letterboxed frame size
|
||||
const Size &GetLetterboxSize() const {
|
||||
return _letterboxSize;
|
||||
}
|
||||
|
||||
// Room region/hotspot masks are traditionally 1:1 of the room's size in
|
||||
// low-resolution games and 1:2 of the room size in high-resolution games.
|
||||
// This also means that mask relation to data resolution is 1:1 if the
|
||||
// game uses low-res coordinates in script and 1:2 if high-res.
|
||||
|
||||
// Test if the game is built around old audio system
|
||||
inline bool IsLegacyAudioSystem() const {
|
||||
return _G(loaded_game_file_version) < kGameVersion_320;
|
||||
}
|
||||
|
||||
// Returns the expected filename of a digital audio package
|
||||
inline AGS::Shared::String GetAudioVOXName() const {
|
||||
return IsLegacyAudioSystem() ? "music.vox" : "audio.vox";
|
||||
}
|
||||
|
||||
// Returns a list of game options that are forbidden to change at runtime
|
||||
inline static Common::Array<int> GetRestrictedOptions() {
|
||||
return Common::Array<int> {{
|
||||
OPT_DEBUGMODE, OPT_LETTERBOX, OPT_HIRES_FONTS, OPT_SPLITRESOURCES,
|
||||
OPT_STRICTSCRIPTING, OPT_LEFTTORIGHTEVAL, OPT_COMPRESSSPRITES, OPT_STRICTSTRINGS,
|
||||
OPT_NATIVECOORDINATES, OPT_SAFEFILEPATHS, OPT_DIALOGOPTIONSAPI, OPT_BASESCRIPTAPI,
|
||||
OPT_SCRIPTCOMPATLEV, OPT_RELATIVEASSETRES, OPT_GAMETEXTENCODING, OPT_KEYHANDLEAPI,
|
||||
OPT_CUSTOMENGINETAG
|
||||
}};
|
||||
}
|
||||
|
||||
private:
|
||||
void SetDefaultResolution(GameResolutionType type, Size game_res);
|
||||
void SetNativeResolution(GameResolutionType type, Size game_res);
|
||||
void OnResolutionSet();
|
||||
|
||||
// Game's native resolution ID, used to init following values.
|
||||
GameResolutionType _resolutionType;
|
||||
|
||||
// Determines game's default screen resolution. Use for the reference
|
||||
// when comparing with actual screen resolution, which may be modified
|
||||
// by certain overriding game modes.
|
||||
Size _defGameResolution;
|
||||
// Determines game's actual resolution.
|
||||
Size _gameResolution;
|
||||
// Determines resolution in which loaded data and script define coordinates
|
||||
// and sizes (with very little exception).
|
||||
Size _dataResolution;
|
||||
// Letterboxed frame size. Used when old game is run in native letterbox
|
||||
// mode. In all other situations is equal to game's resolution.
|
||||
Size _letterboxSize;
|
||||
|
||||
// Game logic to game resolution coordinate factor
|
||||
int _dataUpscaleMult;
|
||||
// Multiplier for various UI drawin sizes, meant to keep UI elements readable
|
||||
int _relativeUIMult;
|
||||
// Game default resolution to actual game resolution factor
|
||||
int _screenUpscaleMult;
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
296
engines/ags/shared/ac/game_struct_defines.h
Normal file
296
engines/ags/shared/ac/game_struct_defines.h
Normal file
@@ -0,0 +1,296 @@
|
||||
/* 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 AGS_SHARED_AC_GAME_STRUCT_DEFINES_H
|
||||
#define AGS_SHARED_AC_GAME_STRUCT_DEFINES_H
|
||||
|
||||
#include "ags/shared/util/geometry.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#define PAL_GAMEWIDE 0
|
||||
#define PAL_LOCKED 1
|
||||
#define PAL_BACKGROUND 2
|
||||
#define MAXGLOBALMES 500
|
||||
#define GLOBALMESLENGTH 500
|
||||
#define MAXLANGUAGE 5
|
||||
#define LEGACY_MAX_FONTS 30
|
||||
|
||||
// General game options
|
||||
#define OPT_DEBUGMODE 0
|
||||
#define OPT_SCORESOUND 1
|
||||
#define OPT_WALKONLOOK 2
|
||||
#define OPT_DIALOGIFACE 3
|
||||
#define OPT_ANTIGLIDE 4
|
||||
#define OPT_TWCUSTOM 5
|
||||
#define OPT_DIALOGGAP 6
|
||||
#define OPT_NOSKIPTEXT 7
|
||||
#define OPT_DISABLEOFF 8
|
||||
#define OPT_ALWAYSSPCH 9
|
||||
#define OPT_SPEECHTYPE 10
|
||||
#define OPT_PIXPERFECT 11
|
||||
#define OPT_NOWALKMODE 12
|
||||
#define OPT_LETTERBOX 13
|
||||
#define OPT_FIXEDINVCURSOR 14
|
||||
#define OPT_NOLOSEINV 15
|
||||
#define OPT_HIRES_FONTS 16
|
||||
#define OPT_SPLITRESOURCES 17
|
||||
#define OPT_ROTATECHARS 18
|
||||
#define OPT_FADETYPE 19
|
||||
#define OPT_HANDLEINVCLICKS 20
|
||||
#define OPT_MOUSEWHEEL 21
|
||||
#define OPT_DIALOGNUMBERED 22
|
||||
#define OPT_DIALOGUPWARDS 23
|
||||
#define OPT_CROSSFADEMUSIC 24
|
||||
#define OPT_ANTIALIASFONTS 25
|
||||
#define OPT_THOUGHTGUI 26
|
||||
#define OPT_TURNTOFACELOC 27
|
||||
#define OPT_RIGHTLEFTWRITE 28 // right-to-left text writing
|
||||
#define OPT_DUPLICATEINV 29 // if they have 2 of the item, draw it twice
|
||||
#define OPT_SAVESCREENSHOT 30
|
||||
#define OPT_PORTRAITSIDE 31
|
||||
#define OPT_STRICTSCRIPTING 32 // don't allow MoveCharacter-style commands
|
||||
#define OPT_LEFTTORIGHTEVAL 33 // left-to-right operator evaluation
|
||||
#define OPT_COMPRESSSPRITES 34 // sprite compression type (None, RLE, LZW, Deflate)
|
||||
#define OPT_STRICTSTRINGS 35 // don't allow old-style strings, for reference only
|
||||
#define OPT_NEWGUIALPHA 36 // alpha blending method when drawing GUI and controls
|
||||
#define OPT_RUNGAMEDLGOPTS 37
|
||||
#define OPT_NATIVECOORDINATES 38 // defines coordinate relation between game logic and game screen
|
||||
#define OPT_GLOBALTALKANIMSPD 39
|
||||
#define OPT_HIGHESTOPTION_321 39
|
||||
#define OPT_SPRITEALPHA 40 // alpha blending method when drawing images on DrawingSurface
|
||||
#define OPT_SAFEFILEPATHS 41 // restricted file path in script (not writing to the game dir, etc)
|
||||
#define OPT_DIALOGOPTIONSAPI 42 // version of dialog options API (-1 for pre-3.4.0 API)
|
||||
#define OPT_BASESCRIPTAPI 43 // version of the Script API (ScriptAPIVersion) used to compile game script
|
||||
#define OPT_SCRIPTCOMPATLEV 44 // level of API compatibility (ScriptAPIVersion) used to compile game script
|
||||
#define OPT_RENDERATSCREENRES 45 // scale sprites at the (final) screen resolution
|
||||
#define OPT_RELATIVEASSETRES 46 // relative asset resolution mode (where sprites are resized to match game type)
|
||||
#define OPT_WALKSPEEDABSOLUTE 47 // if movement speeds are independent of walkable mask resolution
|
||||
#define OPT_CLIPGUICONTROLS 48 // clip drawn gui control contents to the control's rectangle
|
||||
#define OPT_GAMETEXTENCODING 49 // how the text in the game data should be interpreted
|
||||
#define OPT_KEYHANDLEAPI 50 // key handling mode (old/new)
|
||||
#define OPT_CUSTOMENGINETAG 51 // custom engine tag (for overriding behavior)
|
||||
#define OPT_SCALECHAROFFSETS 52 // apply character scaling to the sprite offsets (z, locked offs)
|
||||
#define OPT_HIGHESTOPTION OPT_SCALECHAROFFSETS
|
||||
#define OPT_NOMODMUSIC 98 // [DEPRECATED]
|
||||
#define OPT_LIPSYNCTEXT 99
|
||||
|
||||
#define CUSTOMENG_NONE 0
|
||||
#define CUSTOMENG_DRACONIAN 1 // Draconian Edition
|
||||
#define CUSTOMENG_CLIFFTOP 2 // Clifftop Games
|
||||
|
||||
// Sierra-style portrait position style
|
||||
#define PORTRAIT_LEFT 0
|
||||
#define PORTRAIT_RIGHT 1
|
||||
#define PORTRAIT_ALTERNATE 2
|
||||
#define PORTRAIT_XPOSITION 3
|
||||
|
||||
// Room transition style
|
||||
#define FADE_NORMAL 0
|
||||
#define FADE_INSTANT 1
|
||||
#define FADE_DISSOLVE 2
|
||||
#define FADE_BOXOUT 3
|
||||
#define FADE_CROSSFADE 4
|
||||
#define FADE_LAST 4 // this should equal the last one
|
||||
|
||||
// Legacy font flags
|
||||
//#define FFLG_LEGACY_NOSCALE 0x01 // TODO: is this from legacy format, ever used?
|
||||
#define FFLG_LEGACY_SIZEMASK 0x3f
|
||||
#define MAX_LEGACY_FONT_SIZE 63
|
||||
// Contemporary font flags
|
||||
#define FFLG_SIZEMULTIPLIER 0x01 // size data means multiplier
|
||||
#define FFLG_DEFLINESPACING 0x02 // linespacing derived from the font height
|
||||
// Font load flags, primarily for backward compatibility:
|
||||
// REPORTNOMINALHEIGHT: get_font_height should return nominal font's height,
|
||||
// eq to "font size" parameter, otherwise returns real pixel height.
|
||||
#define FFLG_REPORTNOMINALHEIGHT 0x04
|
||||
// ASCENDFIXUP: do the TTF ascender fixup, where font's ascender is resized
|
||||
// to the nominal font's height.
|
||||
#define FFLG_ASCENDERFIXUP 0x08
|
||||
// Collection of flags defining fully backward compatible TTF fixup
|
||||
#define FFLG_TTF_BACKCOMPATMASK (FFLG_REPORTNOMINALHEIGHT | FFLG_ASCENDERFIXUP)
|
||||
// Collection of flags defining font's load mode
|
||||
#define FFLG_LOADMODEMASK (FFLG_REPORTNOMINALHEIGHT | FFLG_ASCENDERFIXUP)
|
||||
// Font outline types
|
||||
#define FONT_OUTLINE_NONE -1
|
||||
#define FONT_OUTLINE_AUTO -10
|
||||
|
||||
#define DIALOG_OPTIONS_HIGHLIGHT_COLOR_DEFAULT 14 // Yellow
|
||||
|
||||
// MAXVIEWNAMELENGTH comes from unknown old engine version
|
||||
#define LEGACY_MAXVIEWNAMELENGTH 15
|
||||
#define MAXLIPSYNCFRAMES 20
|
||||
#define MAX_GUID_LENGTH 40
|
||||
#define MAX_SG_EXT_LENGTH 20
|
||||
#define LEGACY_MAX_SG_FOLDER_LEN 50
|
||||
|
||||
enum GameResolutionType {
|
||||
kGameResolution_Undefined = -1,
|
||||
// definition of 320x200 in very old versions of the engine (somewhere pre-2.56)
|
||||
kGameResolution_Default = 0,
|
||||
kGameResolution_320x200 = 1,
|
||||
kGameResolution_320x240 = 2,
|
||||
kGameResolution_640x400 = 3,
|
||||
kGameResolution_640x480 = 4,
|
||||
kGameResolution_800x600 = 5,
|
||||
kGameResolution_1024x768 = 6,
|
||||
kGameResolution_1280x720 = 7,
|
||||
kGameResolution_Custom = 8,
|
||||
kNumGameResolutions,
|
||||
|
||||
kGameResolution_LastLoRes = kGameResolution_320x240,
|
||||
kGameResolution_FirstHiRes = kGameResolution_640x400
|
||||
};
|
||||
|
||||
inline bool IsLegacyHiRes(GameResolutionType resolution) {
|
||||
return resolution > kGameResolution_LastLoRes;
|
||||
}
|
||||
|
||||
Size ResolutionTypeToSize(GameResolutionType resolution, bool letterbox = false);
|
||||
|
||||
// Automatic numbering of dialog options (OPT_DIALOGNUMBERED)
|
||||
enum DialogOptionNumbering {
|
||||
kDlgOptNoNumbering = -1,
|
||||
kDlgOptKeysOnly = 0, // implicit key shortcuts
|
||||
kDlgOptNumbering = 1 // draw option indices and use key shortcuts
|
||||
};
|
||||
|
||||
// Version of the script api (OPT_BASESCRIPTAPI and OPT_SCRIPTCOMPATLEV).
|
||||
// If the existing script function meaning had changed, that may be
|
||||
// possible to find out which implementation to use by checking one of those
|
||||
// two options.
|
||||
// NOTE: please remember that those values are valid only for games made with
|
||||
// 3.4.0 final and above.
|
||||
enum ScriptAPIVersion {
|
||||
kScriptAPI_Undefined = INT32_MIN,
|
||||
kScriptAPI_v321 = 0,
|
||||
kScriptAPI_v330 = 1,
|
||||
kScriptAPI_v334 = 2,
|
||||
kScriptAPI_v335 = 3,
|
||||
kScriptAPI_v340 = 4,
|
||||
kScriptAPI_v341 = 5,
|
||||
kScriptAPI_v350 = 6,
|
||||
kScriptAPI_v3507 = 7,
|
||||
kScriptAPI_v351 = 8,
|
||||
kScriptAPI_v360 = 3060000,
|
||||
kScriptAPI_v36026 = 3060026,
|
||||
kScriptAPI_v361 = 3060100,
|
||||
kScriptAPI_Current = kScriptAPI_v361
|
||||
};
|
||||
|
||||
extern const char *GetScriptAPIName(ScriptAPIVersion v);
|
||||
|
||||
// Determines whether the graphics renderer should scale sprites at the final
|
||||
// screen resolution, as opposed to native resolution
|
||||
enum RenderAtScreenRes {
|
||||
kRenderAtScreenRes_UserDefined = 0,
|
||||
kRenderAtScreenRes_Enabled = 1,
|
||||
kRenderAtScreenRes_Disabled = 2,
|
||||
};
|
||||
|
||||
// Method to use when blending two sprites with alpha channel
|
||||
enum GameSpriteAlphaRenderingStyle {
|
||||
kSpriteAlphaRender_Legacy = 0,
|
||||
kSpriteAlphaRender_Proper
|
||||
};
|
||||
|
||||
// Method to use when blending two GUI elements with alpha channel
|
||||
enum GameGuiAlphaRenderingStyle {
|
||||
kGuiAlphaRender_Legacy = 0,
|
||||
kGuiAlphaRender_AdditiveAlpha,
|
||||
kGuiAlphaRender_Proper
|
||||
};
|
||||
|
||||
// Sprite flags
|
||||
// SERIALIZATION NOTE: serialized as 8-bit in game data and legacy saves
|
||||
// serialized as 32-bit in new saves (for dynamic sprites only).
|
||||
#define SPF_HIRES 0x01 // sized for high native resolution (legacy option)
|
||||
#define SPF_HICOLOR 0x02 // is 16-bit (UNUSED)
|
||||
#define SPF_DYNAMICALLOC 0x04 // created by runtime script
|
||||
#define SPF_TRUECOLOR 0x08 // is 32-bit (UNUSED)
|
||||
#define SPF_ALPHACHANNEL 0x10 // has alpha-channel
|
||||
#define SPF_VAR_RESOLUTION 0x20 // variable resolution (refer to SPF_HIRES)
|
||||
#define SPF_HADALPHACHANNEL 0x80 // the saved sprite on disk has one
|
||||
#define SPF_OBJECTOWNED 0x0100 // owned by a game object (not created in user script)
|
||||
|
||||
// General information about sprite (properties, size)
|
||||
struct SpriteInfo {
|
||||
int Width = 0;
|
||||
int Height = 0;
|
||||
uint32_t Flags = 0u; // SPF_* flags
|
||||
|
||||
SpriteInfo() = default;
|
||||
SpriteInfo(int w, int h, uint32_t flags) : Width(w), Height(h), Flags(flags) {}
|
||||
|
||||
inline Size GetResolution() const { return Size(Width, Height); }
|
||||
// Gets if sprite is created at runtime (by engine, or a script command)
|
||||
inline bool IsDynamicSprite() const { return (Flags & SPF_DYNAMICALLOC) != 0; }
|
||||
|
||||
//
|
||||
// Legacy game support
|
||||
//
|
||||
// Gets if sprite should adjust its base size depending on game's resolution
|
||||
inline bool IsRelativeRes() const {
|
||||
return (Flags & SPF_VAR_RESOLUTION) != 0;
|
||||
}
|
||||
// Gets if sprite belongs to high resolution; hi-res sprites should be
|
||||
// downscaled in low-res games, and low-res sprites should be upscaled
|
||||
// in hi-res games
|
||||
inline bool IsLegacyHiRes() const {
|
||||
return (Flags & SPF_HIRES) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Various font parameters, defining and extending font rendering behavior.
|
||||
// While FontRenderer object's main goal is to render single line of text at
|
||||
// the strictly determined position on canvas, FontInfo may additionally
|
||||
// provide instructions on adjusting drawing position, as well as arranging
|
||||
// multiple lines, and similar cases.
|
||||
struct FontInfo {
|
||||
enum AutoOutlineStyle : int {
|
||||
kSquared = 0,
|
||||
kRounded = 1,
|
||||
};
|
||||
|
||||
// General font's loading and rendering flags
|
||||
uint32_t Flags;
|
||||
// Nominal font import size (in pixels)
|
||||
int Size;
|
||||
// Factor to multiply base font size by
|
||||
int SizeMultiplier;
|
||||
// Outlining font index, or auto-outline flag
|
||||
int Outline;
|
||||
// Custom vertical render offset, used mainly for fixing broken fonts
|
||||
int YOffset;
|
||||
// Custom line spacing between two lines of text (0 = use font height)
|
||||
int LineSpacing;
|
||||
// When automatic outlining, thickness of the outline (0 = no auto outline)
|
||||
int AutoOutlineThickness;
|
||||
// When automatic outlining, style of the outline
|
||||
AutoOutlineStyle AutoOutlineStyle;
|
||||
|
||||
FontInfo();
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
175
engines/ags/shared/ac/game_version.h
Normal file
175
engines/ags/shared/ac/game_version.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Game version constants and information
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_SHARED_AC_GAME_VERSION_H
|
||||
#define AGS_SHARED_AC_GAME_VERSION_H
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
/*
|
||||
|
||||
Game data versions and changes:
|
||||
-------------------------------
|
||||
|
||||
12 : 2.3 + 2.4
|
||||
|
||||
Versions above are incompatible at the moment.
|
||||
|
||||
18 : 2.5.0
|
||||
19 : 2.5.1 + 2.52
|
||||
20 : 2.5.3
|
||||
|
||||
Lip sync data added.
|
||||
21 : 2.5.4
|
||||
22 : 2.5.5
|
||||
|
||||
Variable number of sprites.
|
||||
24 : 2.5.6
|
||||
25 : 2.6.0
|
||||
|
||||
Encrypted global messages and dialogs.
|
||||
26 : 2.6.1
|
||||
|
||||
Wait() must be called with parameter > 0
|
||||
GetRegionAt() clips the input values to the screen size
|
||||
Color 0 now means transparent instead of black for text windows
|
||||
SetPlayerCharacter() does nothing if the new character is already the player character.
|
||||
27 : 2.6.2
|
||||
|
||||
Script modules. Fixes bug in the inventory display.
|
||||
Clickable GUI is selected with regard for the drawing order.
|
||||
Pointer to the "player" variable is now accessed via a dynamic object.
|
||||
31 : 2.7.0
|
||||
32 : 2.7.2
|
||||
|
||||
35 : 3.0.0
|
||||
|
||||
Room names are serialized when game is compiled in "debug" mode.
|
||||
36 : 3.0.1
|
||||
|
||||
Interactions are now scripts. The number for "not set" changed from 0 to -1 for
|
||||
a lot of variables (views, sounds).
|
||||
Deprecated switch between low-res and high-res native coordinates.
|
||||
37 : 3.1.0
|
||||
|
||||
Dialogs are now scripts. New character animation speed.
|
||||
39 : 3.1.1
|
||||
|
||||
Individual character speech animation speed.
|
||||
40 : 3.1.2
|
||||
|
||||
Audio clips
|
||||
41 : 3.2.0
|
||||
42 : 3.2.1
|
||||
|
||||
43 : 3.3.0
|
||||
Added few more game options.
|
||||
|
||||
44 : 3.3.1
|
||||
Added custom dialog option highlight colour.
|
||||
|
||||
45 : 3.4.0.1
|
||||
Support for custom game resolution.
|
||||
|
||||
46 : 3.4.0.2-.3
|
||||
Audio playback speed.
|
||||
Custom dialog option rendering extension.
|
||||
|
||||
47 : 3.4.0.4
|
||||
Custom properties changed at runtime.
|
||||
Ambient lighting
|
||||
|
||||
48 : 3.4.1
|
||||
OPT_RENDERATSCREENRES, extended engine caps check, font vertical offset.
|
||||
|
||||
49 : 3.4.1.2
|
||||
Font custom line spacing.
|
||||
|
||||
50 : 3.5.0.8
|
||||
Sprites have "real" resolution. Expanded FontInfo data format.
|
||||
Option to allow legacy relative asset resolutions.
|
||||
|
||||
3.6.0 :
|
||||
Format value is defined as AGS version represented as NN,NN,NN,NN.
|
||||
Fonts have adjustable outline
|
||||
3.6.0.11:
|
||||
New font load flags, control backward compatible font behavior
|
||||
3.6.0.16:
|
||||
Idle animation speed, modifiable hotspot names, fixed video frame
|
||||
3.6.0.21:
|
||||
Some adjustments to gui text alignment.
|
||||
3.6.1:
|
||||
In RTL mode all text is reversed, not only wrappable (labels etc).
|
||||
3.6.1.10:
|
||||
Disabled automatic SetRestartPoint.
|
||||
3.6.1.14:
|
||||
Extended game object names, resolving hard length limits.
|
||||
*/
|
||||
|
||||
enum GameDataVersion {
|
||||
kGameVersion_Undefined = 0,
|
||||
kGameVersion_230 = 12,
|
||||
kGameVersion_240 = 12,
|
||||
kGameVersion_250 = 18,
|
||||
kGameVersion_251 = 19, // same as 2.52
|
||||
kGameVersion_253 = 20,
|
||||
kGameVersion_254 = 21,
|
||||
kGameVersion_255 = 22,
|
||||
kGameVersion_256 = 24,
|
||||
kGameVersion_260 = 25,
|
||||
kGameVersion_261 = 26,
|
||||
kGameVersion_262 = 27,
|
||||
kGameVersion_270 = 31,
|
||||
kGameVersion_272 = 32,
|
||||
kGameVersion_300 = 35,
|
||||
kGameVersion_301 = 36,
|
||||
kGameVersion_310 = 37,
|
||||
kGameVersion_311 = 39,
|
||||
kGameVersion_312 = 40,
|
||||
kGameVersion_320 = 41,
|
||||
kGameVersion_321 = 42,
|
||||
kGameVersion_330 = 43,
|
||||
kGameVersion_331 = 44,
|
||||
kGameVersion_340_1 = 45,
|
||||
kGameVersion_340_2 = 46,
|
||||
kGameVersion_340_4 = 47,
|
||||
kGameVersion_341 = 48,
|
||||
kGameVersion_341_2 = 49,
|
||||
kGameVersion_350 = 50,
|
||||
kGameVersion_360 = 3060000,
|
||||
kGameVersion_360_11 = 3060011,
|
||||
kGameVersion_360_16 = 3060016,
|
||||
kGameVersion_360_21 = 3060021,
|
||||
kGameVersion_361 = 3060100,
|
||||
kGameVersion_361_10 = 3060110,
|
||||
kGameVersion_361_14 = 3060114,
|
||||
kGameVersion_Current = kGameVersion_361_14
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
47
engines/ags/shared/ac/interface_button.h
Normal file
47
engines/ags/shared/ac/interface_button.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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 AGS_SHARED_AC_INTERFACE_BUTTON_H
|
||||
#define AGS_SHARED_AC_INTERFACE_BUTTON_H
|
||||
|
||||
#include "ags/shared/core/types.h"
|
||||
|
||||
#if defined (OBSOLETE)
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#define MAXBUTTON 20
|
||||
#define IBFLG_ENABLED 1
|
||||
#define IBFLG_INVBOX 2
|
||||
|
||||
struct InterfaceButton {
|
||||
int x, y, pic, overpic, pushpic, leftclick;
|
||||
int rightclick; // if inv, then leftclick = wid, rightclick = hit
|
||||
int reserved_for_future;
|
||||
int8 flags;
|
||||
void set(int xx, int yy, int picc, int overpicc, int actionn);
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif // OBSOLETE
|
||||
|
||||
#endif
|
||||
51
engines/ags/shared/ac/interface_element.h
Normal file
51
engines/ags/shared/ac/interface_element.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* 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 AGS_SHARED_AC_INTERFACE_ELEMENT_H
|
||||
#define AGS_SHARED_AC_INTERFACE_ELEMENT_H
|
||||
|
||||
#if defined (OBSOLETE)
|
||||
|
||||
#include "ags/shared/ac/interface_button.h" // InterfaceButton
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
// this struct should go in a Game struct, not the room structure.
|
||||
struct InterfaceElement {
|
||||
int x, y, x2, y2;
|
||||
int bgcol, fgcol, bordercol;
|
||||
int vtextxp, vtextyp, vtextalign; // X & Y relative to topleft of interface
|
||||
char vtext[40];
|
||||
int numbuttons;
|
||||
InterfaceButton button[MAXBUTTON];
|
||||
int flags;
|
||||
int reserved_for_future;
|
||||
int popupyp; // pops up when _G(mousey) < this
|
||||
int8 popup; // does it pop up? (like sierra icon bar)
|
||||
int8 on;
|
||||
InterfaceElement();
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif // OBSOLETE
|
||||
|
||||
#endif
|
||||
66
engines/ags/shared/ac/inventory_item_info.cpp
Normal file
66
engines/ags/shared/ac/inventory_item_info.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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 "ags/shared/ac/inventory_item_info.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
#include "ags/shared/util/string_utils.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
void InventoryItemInfo::ReadFromFile(Stream *in) {
|
||||
name.ReadCount(in, LEGACY_MAX_INVENTORY_NAME_LENGTH);
|
||||
in->Seek(3); // alignment padding to int32
|
||||
pic = in->ReadInt32();
|
||||
cursorPic = in->ReadInt32();
|
||||
hotx = in->ReadInt32();
|
||||
hoty = in->ReadInt32();
|
||||
in->ReadArrayOfInt32(reserved, 5);
|
||||
flags = in->ReadInt8();
|
||||
in->Seek(3); // alignment padding to int32
|
||||
}
|
||||
|
||||
void InventoryItemInfo::WriteToFile(Stream *out) {
|
||||
name.WriteCount(out, LEGACY_MAX_INVENTORY_NAME_LENGTH);
|
||||
out->WriteByteCount(0, 3); // alignment padding to int32
|
||||
out->WriteInt32(pic);
|
||||
out->WriteInt32(cursorPic);
|
||||
out->WriteInt32(hotx);
|
||||
out->WriteInt32(hoty);
|
||||
out->WriteArrayOfInt32(reserved, 5);
|
||||
out->WriteInt8(flags);
|
||||
out->WriteByteCount(0, 3); // alignment padding to int32
|
||||
}
|
||||
|
||||
void InventoryItemInfo::ReadFromSavegame(Stream *in) {
|
||||
name = StrUtil::ReadString(in);
|
||||
pic = in->ReadInt32();
|
||||
cursorPic = in->ReadInt32();
|
||||
}
|
||||
|
||||
void InventoryItemInfo::WriteToSavegame(Stream *out) const {
|
||||
StrUtil::WriteString(name, out);
|
||||
out->WriteInt32(pic);
|
||||
out->WriteInt32(cursorPic);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
56
engines/ags/shared/ac/inventory_item_info.h
Normal file
56
engines/ags/shared/ac/inventory_item_info.h
Normal 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_SHARED_AC_INVENTORY_ITEM_INFO_H
|
||||
#define AGS_SHARED_AC_INVENTORY_ITEM_INFO_H
|
||||
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
#define IFLG_STARTWITH 1
|
||||
#define LEGACY_MAX_INVENTORY_NAME_LENGTH 25
|
||||
|
||||
struct InventoryItemInfo {
|
||||
String name;
|
||||
int pic;
|
||||
int cursorPic, hotx, hoty;
|
||||
int32_t reserved[5];
|
||||
uint8_t flags; // IFLG_STARTWITH
|
||||
|
||||
void ReadFromFile(Stream *in);
|
||||
void WriteToFile(Stream *out);
|
||||
void ReadFromSavegame(Stream *in);
|
||||
void WriteToSavegame(Stream *out) const;
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
39
engines/ags/shared/ac/keycode.cpp
Normal file
39
engines/ags/shared/ac/keycode.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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 "ags/shared/ac/keycode.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
eAGSKeyCode AGSKeyToScriptKey(eAGSKeyCode keycode) {
|
||||
// Script API requires strictly capital letters, if this is a small letter - capitalize it
|
||||
return (keycode >= 'a' && keycode <= 'z') ?
|
||||
static_cast<eAGSKeyCode>(keycode - 'a' + 'A') : keycode;
|
||||
}
|
||||
|
||||
char AGSKeyToText(eAGSKeyCode keycode) {
|
||||
// support only printable characters (128-255 are chars from extended fonts)
|
||||
if (keycode >= 32 && keycode < 256)
|
||||
return static_cast<char>(keycode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
323
engines/ags/shared/ac/keycode.h
Normal file
323
engines/ags/shared/ac/keycode.h
Normal file
@@ -0,0 +1,323 @@
|
||||
/* 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 AGS_SHARED_AC_KEYCODE_H
|
||||
#define AGS_SHARED_AC_KEYCODE_H
|
||||
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
#define EXTENDED_KEY_CODE ('\0')
|
||||
#define EXTENDED_KEY_CODE_MACOS ('?')
|
||||
|
||||
// Constant used to define Alt+Key codes
|
||||
#define AGS_EXT_KEY_SHIFT 300
|
||||
#define AGS_EXT_KEY_ALPHA(key) (AGS_EXT_KEY_SHIFT + (key - eAGSKeyCodeCtrlA) + 1)
|
||||
|
||||
// These are based on eKeyCode values in AGS Script.
|
||||
// The actual values are based on scan codes of the old backend (allegro 3 and/or 4),
|
||||
// which in turn mostly match ASCII values (at least for ones below 128), including
|
||||
// Ctrl + letter combination codes.
|
||||
// More codes are added at much higher ranges, for example Alt + letter combo codes
|
||||
// are defined as 300 + letter's order.
|
||||
// It should be specifically noted that eAGSKeyCode is directly conversible to ASCII
|
||||
// at the range of 1 - 128, and AGS script makes use of this.
|
||||
// Another important thing to note is that letter codes are always sent into script
|
||||
// callbacks (like "on_key_pressed") in capitalized form, and that's how they are
|
||||
// declared in script API (that's why in these callbacks user would have to check
|
||||
// the Shift key state if they want to know if it's A or Shift + A).
|
||||
enum eAGSKeyCode {
|
||||
eAGSKeyCodeNone = 0,
|
||||
|
||||
eAGSKeyCodeCtrlA = 1,
|
||||
eAGSKeyCodeCtrlB = 2,
|
||||
eAGSKeyCodeCtrlC = 3,
|
||||
eAGSKeyCodeCtrlD = 4,
|
||||
eAGSKeyCodeCtrlE = 5,
|
||||
eAGSKeyCodeCtrlF = 6,
|
||||
eAGSKeyCodeCtrlG = 7,
|
||||
eAGSKeyCodeCtrlH = 8,
|
||||
eAGSKeyCodeCtrlI = 9,
|
||||
eAGSKeyCodeCtrlJ = 10,
|
||||
eAGSKeyCodeCtrlK = 11,
|
||||
eAGSKeyCodeCtrlL = 12,
|
||||
eAGSKeyCodeCtrlM = 13,
|
||||
eAGSKeyCodeCtrlN = 14,
|
||||
eAGSKeyCodeCtrlO = 15,
|
||||
eAGSKeyCodeCtrlP = 16,
|
||||
eAGSKeyCodeCtrlQ = 17,
|
||||
eAGSKeyCodeCtrlR = 18,
|
||||
eAGSKeyCodeCtrlS = 19,
|
||||
eAGSKeyCodeCtrlT = 20,
|
||||
eAGSKeyCodeCtrlU = 21,
|
||||
eAGSKeyCodeCtrlV = 22,
|
||||
eAGSKeyCodeCtrlW = 23,
|
||||
eAGSKeyCodeCtrlX = 24,
|
||||
eAGSKeyCodeCtrlY = 25,
|
||||
eAGSKeyCodeCtrlZ = 26,
|
||||
|
||||
eAGSKeyCodeBackspace = 8, // matches Ctrl + H
|
||||
eAGSKeyCodeTab = 9, // matches Ctrl + I
|
||||
eAGSKeyCodeReturn = 13, // matches Ctrl + M
|
||||
eAGSKeyCodeEscape = 27,
|
||||
|
||||
/* printable chars - from eAGSKeyCodeSpace to eAGSKeyCode_z */
|
||||
eAGSKeyCodeSpace = 32,
|
||||
eAGSKeyCodeExclamationMark = 33,
|
||||
eAGSKeyCodeDoubleQuote = 34,
|
||||
eAGSKeyCodeHash = 35,
|
||||
eAGSKeyCodeDollar = 36,
|
||||
eAGSKeyCodePercent = 37,
|
||||
eAGSKeyCodeAmpersand = 38,
|
||||
eAGSKeyCodeSingleQuote = 39,
|
||||
eAGSKeyCodeOpenParenthesis = 40,
|
||||
eAGSKeyCodeCloseParenthesis = 41,
|
||||
eAGSKeyCodeAsterisk = 42,
|
||||
eAGSKeyCodePlus = 43,
|
||||
eAGSKeyCodeComma = 44,
|
||||
eAGSKeyCodeHyphen = 45,
|
||||
eAGSKeyCodePeriod = 46,
|
||||
eAGSKeyCodeForwardSlash = 47,
|
||||
|
||||
eAGSKeyCode0 = 48,
|
||||
eAGSKeyCode1 = 49,
|
||||
eAGSKeyCode2 = 50,
|
||||
eAGSKeyCode3 = 51,
|
||||
eAGSKeyCode4 = 52,
|
||||
eAGSKeyCode5 = 53,
|
||||
eAGSKeyCode6 = 54,
|
||||
eAGSKeyCode7 = 55,
|
||||
eAGSKeyCode8 = 56,
|
||||
eAGSKeyCode9 = 57,
|
||||
|
||||
eAGSKeyCodeColon = 58,
|
||||
eAGSKeyCodeSemiColon = 59,
|
||||
eAGSKeyCodeLessThan = 60,
|
||||
eAGSKeyCodeEquals = 61,
|
||||
eAGSKeyCodeGreaterThan = 62,
|
||||
eAGSKeyCodeQuestionMark = 63,
|
||||
eAGSKeyCodeAt = 64, // '@'
|
||||
|
||||
/* Notice that default letter codes match capital ASCII letters */
|
||||
eAGSKeyCodeA = 65, // 'A'
|
||||
eAGSKeyCodeB = 66, // 'B', etc
|
||||
eAGSKeyCodeC = 67,
|
||||
eAGSKeyCodeD = 68,
|
||||
eAGSKeyCodeE = 69,
|
||||
eAGSKeyCodeF = 70,
|
||||
eAGSKeyCodeG = 71,
|
||||
eAGSKeyCodeH = 72,
|
||||
eAGSKeyCodeI = 73,
|
||||
eAGSKeyCodeJ = 74,
|
||||
eAGSKeyCodeK = 75,
|
||||
eAGSKeyCodeL = 76,
|
||||
eAGSKeyCodeM = 77,
|
||||
eAGSKeyCodeN = 78,
|
||||
eAGSKeyCodeO = 79,
|
||||
eAGSKeyCodeP = 80,
|
||||
eAGSKeyCodeQ = 81,
|
||||
eAGSKeyCodeR = 82,
|
||||
eAGSKeyCodeS = 83,
|
||||
eAGSKeyCodeT = 84,
|
||||
eAGSKeyCodeU = 85,
|
||||
eAGSKeyCodeV = 86,
|
||||
eAGSKeyCodeW = 87,
|
||||
eAGSKeyCodeX = 88,
|
||||
eAGSKeyCodeY = 89,
|
||||
eAGSKeyCodeZ = 90, // 'Z'
|
||||
|
||||
eAGSKeyCodeOpenBracket = 91,
|
||||
eAGSKeyCodeBackSlash = 92,
|
||||
eAGSKeyCodeCloseBracket = 93,
|
||||
eAGSKeyCodeCaret = 94, // '^'
|
||||
eAGSKeyCodeUnderscore = 95,
|
||||
eAGSKeyCodeBackquote = 96, // '`'
|
||||
|
||||
/* Small ASCII letter codes are declared here for consistency, but unused in script callbacks */
|
||||
eAGSKeyCode_a = 97, // 'a'
|
||||
eAGSKeyCode_b = 98, // 'b', etc
|
||||
eAGSKeyCode_c = 99,
|
||||
eAGSKeyCode_d = 100,
|
||||
eAGSKeyCode_e = 101,
|
||||
eAGSKeyCode_f = 102,
|
||||
eAGSKeyCode_g = 103,
|
||||
eAGSKeyCode_h = 104,
|
||||
eAGSKeyCode_i = 105,
|
||||
eAGSKeyCode_j = 106,
|
||||
eAGSKeyCode_k = 107,
|
||||
eAGSKeyCode_l = 108,
|
||||
eAGSKeyCode_m = 109,
|
||||
eAGSKeyCode_n = 110,
|
||||
eAGSKeyCode_o = 111,
|
||||
eAGSKeyCode_p = 112,
|
||||
eAGSKeyCode_q = 113,
|
||||
eAGSKeyCode_r = 114,
|
||||
eAGSKeyCode_s = 115,
|
||||
eAGSKeyCode_t = 116,
|
||||
eAGSKeyCode_u = 117,
|
||||
eAGSKeyCode_v = 118,
|
||||
eAGSKeyCode_w = 119,
|
||||
eAGSKeyCode_x = 120,
|
||||
eAGSKeyCode_y = 121,
|
||||
eAGSKeyCode_z = 122, // 'z'
|
||||
|
||||
/* extended symbol codes */
|
||||
eAGSKeyCodeF1 = AGS_EXT_KEY_SHIFT + 59,
|
||||
eAGSKeyCodeF2 = AGS_EXT_KEY_SHIFT + 60,
|
||||
eAGSKeyCodeF3 = AGS_EXT_KEY_SHIFT + 61,
|
||||
eAGSKeyCodeF4 = AGS_EXT_KEY_SHIFT + 62,
|
||||
eAGSKeyCodeF5 = AGS_EXT_KEY_SHIFT + 63,
|
||||
eAGSKeyCodeF6 = AGS_EXT_KEY_SHIFT + 64,
|
||||
eAGSKeyCodeF7 = AGS_EXT_KEY_SHIFT + 65,
|
||||
eAGSKeyCodeF8 = AGS_EXT_KEY_SHIFT + 66,
|
||||
eAGSKeyCodeF9 = AGS_EXT_KEY_SHIFT + 67,
|
||||
eAGSKeyCodeF10 = AGS_EXT_KEY_SHIFT + 68,
|
||||
eAGSKeyCodeF11 = AGS_EXT_KEY_SHIFT + 133,
|
||||
eAGSKeyCodeF12 = AGS_EXT_KEY_SHIFT + 134,
|
||||
|
||||
eAGSKeyCodeHome = AGS_EXT_KEY_SHIFT + 71,
|
||||
eAGSKeyCodeUpArrow = AGS_EXT_KEY_SHIFT + 72,
|
||||
eAGSKeyCodePageUp = AGS_EXT_KEY_SHIFT + 73,
|
||||
eAGSKeyCodeLeftArrow = AGS_EXT_KEY_SHIFT + 75,
|
||||
eAGSKeyCodeNumPad5 = AGS_EXT_KEY_SHIFT + 76,
|
||||
eAGSKeyCodeRightArrow = AGS_EXT_KEY_SHIFT + 77,
|
||||
eAGSKeyCodeEnd = AGS_EXT_KEY_SHIFT + 79,
|
||||
eAGSKeyCodeDownArrow = AGS_EXT_KEY_SHIFT + 80,
|
||||
eAGSKeyCodePageDown = AGS_EXT_KEY_SHIFT + 81,
|
||||
eAGSKeyCodeInsert = AGS_EXT_KEY_SHIFT + 82,
|
||||
eAGSKeyCodeDelete = AGS_EXT_KEY_SHIFT + 83,
|
||||
|
||||
// [sonneveld] These are only used by debugging and abort keys.
|
||||
// They're based on allegro4 codes ...
|
||||
eAGSKeyCodeAltV = AGS_EXT_KEY_ALPHA(eAGSKeyCodeV),
|
||||
eAGSKeyCodeAltX = AGS_EXT_KEY_ALPHA(eAGSKeyCodeX),
|
||||
eAGSKeyCodeAltY = AGS_EXT_KEY_ALPHA(eAGSKeyCodeY),
|
||||
eAGSKeyCodeAltZ = AGS_EXT_KEY_ALPHA(eAGSKeyCodeZ),
|
||||
|
||||
// The beginning of "service key list": mod keys and other special keys
|
||||
// not normally intended to affect the default game logic
|
||||
eAGSKeyCode_FirstServiceKey = 391,
|
||||
|
||||
// not certain if necessary anymore (and not certain what was the origin of this value)
|
||||
eAGSKeyCodeAltTab = AGS_EXT_KEY_SHIFT + 99,
|
||||
|
||||
// Mod-key codes
|
||||
// *probably* made-up numbers, not derived from allegro scan codes.
|
||||
eAGSKeyCodeLShift = 403,
|
||||
eAGSKeyCodeRShift = 404,
|
||||
eAGSKeyCodeLCtrl = 405,
|
||||
eAGSKeyCodeRCtrl = 406,
|
||||
eAGSKeyCodeLAlt = 407,
|
||||
|
||||
// [sonneveld]
|
||||
// The following are the AGS_EXT_KEY_SHIFT, derived from applying arithmetic to the original keycodes.
|
||||
// These do not have a corresponding ags key enum, do not appear in the manual and may not be accessible because of OS contraints.
|
||||
eAGSKeyCodeRAlt = 420,
|
||||
// TODO: judging that above works (at least on Win), following might also work,
|
||||
// but idk which ones may be necessary; still keeping here this excerpt from an old code
|
||||
// if they'd want to be restored (also add them to script API then!).
|
||||
// Also see allegro 4's keyboard.h, where these were declared.
|
||||
/*
|
||||
case 392: __allegro_KEY_PRTSCR
|
||||
case 393: __allegro_KEY_PAUSE
|
||||
case 394: __allegro_KEY_ABNT_C1 // The ABNT_C1 (Brazilian) key
|
||||
case 395: __allegro_KEY_YEN)
|
||||
case 396: __allegro_KEY_KANA
|
||||
case 397: __allegro_KEY_CONVERT
|
||||
case 398: __allegro_KEY_NOCONVERT
|
||||
case 400: __allegro_KEY_CIRCUMFLEX
|
||||
case 402: __allegro_KEY_KANJI
|
||||
case 421: __allegro_KEY_LWIN
|
||||
case 422: __allegro_KEY_RWIN
|
||||
case 423: __allegro_KEY_MENU
|
||||
case 424: __allegro_KEY_SCRLOCK
|
||||
case 425: __allegro_KEY_NUMLOCK
|
||||
case 426: __allegro_KEY_CAPSLOCK
|
||||
*/
|
||||
|
||||
// Mask defines the key code position if packed in the int32;
|
||||
// takes only 12 bits, as minimal necessary to accommodate historical codes.
|
||||
eAGSKeyMask = 0x0FFF
|
||||
};
|
||||
|
||||
// AGS key modifiers
|
||||
enum eAGSKeyMod {
|
||||
eAGSModLShift = 0x00010000,
|
||||
eAGSModRShift = 0x00020000,
|
||||
eAGSModLCtrl = 0x00040000,
|
||||
eAGSModRCtrl = 0x00080000,
|
||||
eAGSModLAlt = 0x00100000,
|
||||
eAGSModRAlt = 0x00200000,
|
||||
eAGSModNum = 0x00400000,
|
||||
eAGSModCaps = 0x00800000,
|
||||
|
||||
// Mask defines the key mod position if packed in the int32;
|
||||
// the upper 8 bits are reserved for "input type" codes;
|
||||
// potentially may take 4 bits below (4th pos), as KeyMask takes only 12.
|
||||
eAGSModMask = 0x00FF0000
|
||||
};
|
||||
|
||||
// Combined key code and a textual representation in UTF-8
|
||||
struct KeyInput {
|
||||
const static size_t UTF8_ARR_SIZE = 5;
|
||||
|
||||
eAGSKeyCode Key = eAGSKeyCodeNone; // actual key code
|
||||
eAGSKeyCode CompatKey = eAGSKeyCodeNone; // old-style key code, combined with mods
|
||||
int Mod = 0; // key modifiers
|
||||
int UChar = 0; // full character value (supports unicode)
|
||||
char Text[UTF8_ARR_SIZE]{}; // character in a string format
|
||||
|
||||
KeyInput() = default;
|
||||
};
|
||||
|
||||
// AGS own mouse button codes;
|
||||
// These correspond to MouseButton enum in script and plugin API (sans special values)
|
||||
enum eAGSMouseButton
|
||||
{
|
||||
kMouseNone = 0,
|
||||
kMouseLeft = 1,
|
||||
kMouseRight = 2,
|
||||
kMouseMiddle = 3,
|
||||
kNumMouseButtons
|
||||
};
|
||||
|
||||
// Tells if the AGS keycode refers to the modifier key (ctrl, alt, etc)
|
||||
inline bool IsAGSModKey(eAGSKeyCode keycode) {
|
||||
return (keycode >= eAGSKeyCodeLShift && keycode <= eAGSKeyCodeLAlt) || keycode == eAGSKeyCodeRAlt;
|
||||
}
|
||||
|
||||
// Tells if the AGS keycode refers to the service key (modifier, PrintScreen and similar);
|
||||
// this lets distinct keys that normally should not affect the game
|
||||
inline bool IsAGSServiceKey(eAGSKeyCode keycode) {
|
||||
return keycode >= eAGSKeyCode_FirstServiceKey;
|
||||
}
|
||||
|
||||
// Converts eAGSKeyCode to script API code, for "on_key_press" and similar callbacks
|
||||
eAGSKeyCode AGSKeyToScriptKey(eAGSKeyCode keycode);
|
||||
// Converts eAGSKeyCode to ASCII text representation with the range check; returns 0 on failure
|
||||
// Not unicode compatible.
|
||||
char AGSKeyToText(eAGSKeyCode keycode);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
80
engines/ags/shared/ac/mouse_cursor.cpp
Normal file
80
engines/ags/shared/ac/mouse_cursor.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/* 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 "ags/shared/ac/mouse_cursor.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
#include "ags/shared/util/string_utils.h"
|
||||
#include "common/util.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
void MouseCursor::clear() {
|
||||
pic = 0;
|
||||
hotx = hoty = 0;
|
||||
view = -1;
|
||||
name.Empty();
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
void MouseCursor::ReadFromFile(Stream *in) {
|
||||
pic = in->ReadInt32();
|
||||
hotx = in->ReadInt16();
|
||||
hoty = in->ReadInt16();
|
||||
view = in->ReadInt16();
|
||||
StrUtil::ReadCStrCount(legacy_name, in, LEGACY_MAX_CURSOR_NAME_LENGTH);
|
||||
flags = in->ReadInt8();
|
||||
in->Seek(3); // alignment padding to int32
|
||||
|
||||
name = legacy_name;
|
||||
}
|
||||
|
||||
void MouseCursor::WriteToFile(Stream *out) {
|
||||
out->WriteInt32(pic);
|
||||
out->WriteInt16(hotx);
|
||||
out->WriteInt16(hoty);
|
||||
out->WriteInt16(view);
|
||||
out->Write(legacy_name, LEGACY_MAX_CURSOR_NAME_LENGTH);
|
||||
out->WriteInt8(flags);
|
||||
out->WriteByteCount(0, 3); // alignment padding to int32
|
||||
}
|
||||
|
||||
void MouseCursor::ReadFromSavegame(Stream *in, int cmp_ver) {
|
||||
pic = in->ReadInt32();
|
||||
hotx = static_cast<int16_t>(in->ReadInt32());
|
||||
hoty = static_cast<int16_t>(in->ReadInt32());
|
||||
view = static_cast<int16_t>(in->ReadInt32());
|
||||
flags = static_cast<int8_t>(in->ReadInt32());
|
||||
if (cmp_ver >= kCursorSvgVersion_36016)
|
||||
animdelay = in->ReadInt32();
|
||||
}
|
||||
|
||||
void MouseCursor::WriteToSavegame(Stream *out) const {
|
||||
out->WriteInt32(pic);
|
||||
out->WriteInt32(hotx);
|
||||
out->WriteInt32(hoty);
|
||||
out->WriteInt32(view);
|
||||
out->WriteInt32(flags);
|
||||
out->WriteInt32(animdelay);
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
76
engines/ags/shared/ac/mouse_cursor.h
Normal file
76
engines/ags/shared/ac/mouse_cursor.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* 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 AGS_SHARED_AC_MOUSE_CURSOR_H
|
||||
#define AGS_SHARED_AC_MOUSE_CURSOR_H
|
||||
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
|
||||
#define MCF_ANIMMOVE 1
|
||||
#define MCF_DISABLED 2
|
||||
#define MCF_STANDARD 4
|
||||
#define MCF_HOTSPOT 8 // only animate when over hotspot
|
||||
|
||||
#define LEGACY_MAX_CURSOR_NAME_LENGTH 10
|
||||
|
||||
enum CursorSvgVersion {
|
||||
kCursorSvgVersion_Initial = 0,
|
||||
kCursorSvgVersion_36016 = 1, // animation delay
|
||||
};
|
||||
|
||||
// IMPORTANT: exposed to plugin API as AGSCursor!
|
||||
// do not change topmost fields, unless planning breaking compatibility.
|
||||
struct MouseCursor {
|
||||
int pic = 0;
|
||||
short hotx = 0, hoty = 0;
|
||||
short view = -1;
|
||||
// This is a deprecated name field, but must stay here for compatibility
|
||||
// with the plugin API (unless the plugin interface is reworked)
|
||||
char legacy_name[LEGACY_MAX_CURSOR_NAME_LENGTH]{};
|
||||
char flags = 0;
|
||||
|
||||
// Following fields are not part of the plugin API
|
||||
Shared::String name;
|
||||
int animdelay = 5;
|
||||
|
||||
MouseCursor() {}
|
||||
|
||||
void clear();
|
||||
void ReadFromFile(Shared::Stream *in);
|
||||
void WriteToFile(Shared::Stream *out);
|
||||
void ReadFromSavegame(Shared::Stream *in, int cmp_ver);
|
||||
void WriteToSavegame(Shared::Stream *out) const;
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
88
engines/ags/shared/ac/old_game_setup_struct.h
Normal file
88
engines/ags/shared/ac/old_game_setup_struct.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* 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 AGS_SHARED_AC_OLD_GAME_SETUP_STRUCT_H
|
||||
#define AGS_SHARED_AC_OLD_GAME_SETUP_STRUCT_H
|
||||
|
||||
#if defined (OBSOLETE)
|
||||
|
||||
#include "ags/shared/ac/character_info.h" // OldCharacterInfo, CharacterInfo
|
||||
#include "ags/shared/ac/event_block.h" // EventBlock
|
||||
#include "ags/shared/ac/interface_element.h" // InterfaceElement
|
||||
#include "ags/shared/ac/inventory_item_info.h" // InventoryItemInfo
|
||||
#include "ags/shared/ac/mouse_cursor.h" // MouseCursor
|
||||
#include "ags/shared/ac/words_dictionary.h" // WordsDictionary
|
||||
#include "ags/shared/script/cc_script.h" // ccScript
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
struct OriGameSetupStruct {
|
||||
char gamename[30];
|
||||
int8 options[20];
|
||||
unsigned char paluses[256];
|
||||
RGB defpal[256];
|
||||
InterfaceElement iface[10];
|
||||
int numiface;
|
||||
int numviews;
|
||||
MouseCursor mcurs[10];
|
||||
char *globalscript;
|
||||
int numcharacters;
|
||||
OldCharacterInfo *chars;
|
||||
#if defined (OBSOLETE)
|
||||
EventBlock __charcond[50];
|
||||
EventBlock __invcond[100];
|
||||
#endif
|
||||
ccScript *compiled_script;
|
||||
int playercharacter;
|
||||
unsigned char __old_spriteflags[2100];
|
||||
int totalscore;
|
||||
short numinvitems;
|
||||
InventoryItemInfo invinfo[100];
|
||||
int numdialog, numdlgmessage;
|
||||
int numfonts;
|
||||
int color_depth; // in bytes per pixel (ie. 1 or 2)
|
||||
int target_win;
|
||||
int dialog_bullet; // 0 for none, otherwise slot num of bullet point
|
||||
short hotdot, hotdotouter; // inv cursor hotspot dot
|
||||
int uniqueid; // random key identifying the game
|
||||
int reserved[2];
|
||||
short numlang;
|
||||
char langcodes[MAXLANGUAGE][3];
|
||||
char *messages[MAXGLOBALMES];
|
||||
};
|
||||
|
||||
struct OriGameSetupStruct2 : public OriGameSetupStruct {
|
||||
unsigned char fontflags[10];
|
||||
int8 fontoutline[10];
|
||||
int numgui;
|
||||
WordsDictionary *dict;
|
||||
int reserved2[8];
|
||||
};
|
||||
|
||||
struct OldGameSetupStruct : public OriGameSetupStruct2 {
|
||||
unsigned char spriteflags[LEGACY_MAX_SPRITES_V25];
|
||||
};
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
463
engines/ags/shared/ac/sprite_cache.cpp
Normal file
463
engines/ags/shared/ac/sprite_cache.cpp
Normal file
@@ -0,0 +1,463 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// sprite caching system
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#include "common/system.h"
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
#include "common/std/algorithm.h"
|
||||
#include "ags/shared/ac/sprite_cache.h"
|
||||
#include "ags/shared/ac/game_struct_defines.h"
|
||||
#include "ags/shared/debugging/out.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
// Tells that the sprite is found in the game resources.
|
||||
#define SPRCACHEFLAG_ISASSET 0x01
|
||||
// Tells that the sprite is assigned externally and cannot be autodisposed.
|
||||
#define SPRCACHEFLAG_EXTERNAL 0x02
|
||||
// Tells that the asset sprite failed to load
|
||||
#define SPRCACHEFLAG_ERROR 0x04
|
||||
// Locked sprites are ones that should not be freed when out of cache space.
|
||||
#define SPRCACHEFLAG_LOCKED 0x08
|
||||
|
||||
// High-verbosity sprite cache log
|
||||
#if DEBUG_SPRITECACHE
|
||||
#define SprCacheLog(...) Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Debug, __VA_ARGS__)
|
||||
#else
|
||||
#define SprCacheLog(...)
|
||||
#endif
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
|
||||
SpriteCache::SpriteCache(std::vector<SpriteInfo> &sprInfos, const Callbacks &callbacks)
|
||||
: _sprInfos(sprInfos), _maxCacheSize(DEFAULTCACHESIZE_KB * 1024u),
|
||||
_cacheSize(0u), _lockedSize(0u) {
|
||||
_callbacks.AdjustSize = (callbacks.AdjustSize) ? callbacks.AdjustSize : DummyAdjustSize;
|
||||
_callbacks.InitSprite = (callbacks.InitSprite) ? callbacks.InitSprite : DummyInitSprite;
|
||||
_callbacks.PostInitSprite = (callbacks.PostInitSprite) ? callbacks.PostInitSprite : DummyPostInitSprite;
|
||||
_callbacks.PrewriteSprite = (callbacks.PrewriteSprite) ? callbacks.PrewriteSprite : DummyPrewriteSprite;
|
||||
|
||||
// Generate a placeholder sprite: 1x1 transparent bitmap
|
||||
_placeholder.reset(BitmapHelper::CreateTransparentBitmap(1, 1, 8));
|
||||
}
|
||||
|
||||
size_t SpriteCache::GetCacheSize() const {
|
||||
return _cacheSize;
|
||||
}
|
||||
|
||||
size_t SpriteCache::GetLockedSize() const {
|
||||
return _lockedSize;
|
||||
}
|
||||
|
||||
size_t SpriteCache::GetMaxCacheSize() const {
|
||||
return _maxCacheSize;
|
||||
}
|
||||
|
||||
size_t SpriteCache::GetSpriteSlotCount() const {
|
||||
return _spriteData.size();
|
||||
}
|
||||
|
||||
void SpriteCache::SetMaxCacheSize(size_t size) {
|
||||
FreeMem(size);
|
||||
_maxCacheSize = size;
|
||||
}
|
||||
|
||||
bool SpriteCache::HasFreeSlots() const {
|
||||
return !((_spriteData.size() == SIZE_MAX) || (_spriteData.size() > MAX_SPRITE_INDEX));
|
||||
}
|
||||
|
||||
bool SpriteCache::IsAssetSprite(sprkey_t index) const {
|
||||
return index >= 0 && (size_t)index < _spriteData.size() && // in the valid range
|
||||
_spriteData[index].IsAssetSprite(); // found in the game resources
|
||||
}
|
||||
|
||||
void SpriteCache::Reset() {
|
||||
_file.Close();
|
||||
_spriteData.clear();
|
||||
_mru.clear();
|
||||
_cacheSize = 0;
|
||||
_lockedSize = 0;
|
||||
}
|
||||
|
||||
bool SpriteCache::SetSprite(sprkey_t index, std::unique_ptr<Bitmap> image, int flags) {
|
||||
if (index < 0 || EnlargeTo(index) != index) {
|
||||
Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Error, "SetSprite: unable to use index %d", index);
|
||||
return false;
|
||||
}
|
||||
if (!image || image->GetSize().IsNull() || image->GetColorDepth() <= 0) {
|
||||
DeleteSprite(index); // free previous item in this slot anyway
|
||||
Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Error, "SetSprite: attempt to assign an invalid bitmap to index %d", index);
|
||||
return false;
|
||||
}
|
||||
|
||||
const int spf_flags = flags
|
||||
| (SPF_HICOLOR * image->GetColorDepth() > 8)
|
||||
| (SPF_TRUECOLOR * image->GetColorDepth() > 16);
|
||||
_sprInfos[index] = SpriteInfo(image->GetWidth(), image->GetHeight(), spf_flags);
|
||||
// Assign sprite with 0 size, as it will not be included into the cache size
|
||||
_spriteData[index] = SpriteData(image.release(), 0, SPRCACHEFLAG_EXTERNAL | SPRCACHEFLAG_LOCKED);
|
||||
SprCacheLog("SetSprite: (external) %d", index);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpriteCache::SetEmptySprite(sprkey_t index, bool as_asset) {
|
||||
if (index < 0 || EnlargeTo(index) != index) {
|
||||
Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Error, "SetEmptySprite: unable to use index %d", index);
|
||||
return;
|
||||
}
|
||||
if (as_asset)
|
||||
_spriteData[index].Flags = SPRCACHEFLAG_ISASSET;
|
||||
RemapSpriteToPlaceholder(index);
|
||||
}
|
||||
|
||||
Bitmap *SpriteCache::RemoveSprite(sprkey_t index) {
|
||||
if (index < 0 || (size_t)index >= _spriteData.size())
|
||||
return nullptr;
|
||||
Bitmap *image = _spriteData[index].Image.release();
|
||||
InitNullSprite(index);
|
||||
SprCacheLog("RemoveSprite: %d", index);
|
||||
return image;
|
||||
}
|
||||
|
||||
void SpriteCache::DeleteSprite(sprkey_t index) {
|
||||
assert(index >= 0); // out of positive range indexes are valid to fail
|
||||
if (index < 0 || (size_t)index >= _spriteData.size())
|
||||
return;
|
||||
InitNullSprite(index);
|
||||
SprCacheLog("RemoveAndDispose: %d", index);
|
||||
}
|
||||
|
||||
sprkey_t SpriteCache::EnlargeTo(sprkey_t topmost) {
|
||||
if (topmost < 0 || topmost > MAX_SPRITE_INDEX)
|
||||
return -1;
|
||||
if ((size_t)topmost < _spriteData.size())
|
||||
return topmost;
|
||||
|
||||
size_t newsize = topmost + 1;
|
||||
_sprInfos.resize(newsize);
|
||||
_spriteData.resize(newsize);
|
||||
return topmost;
|
||||
}
|
||||
|
||||
sprkey_t SpriteCache::GetFreeIndex() {
|
||||
// FIXME: inefficient if large number of sprites were created in game;
|
||||
// use "available ids" stack, see managed pool for an example;
|
||||
// NOTE: this is shared with the Editor, which means we cannot rely on the
|
||||
// number of "static" sprites and search for slots after... this may be
|
||||
// resolved by splitting SpriteCache class further on "cache builder" and
|
||||
// "runtime cache".
|
||||
for (size_t i = MIN_SPRITE_INDEX; i < _spriteData.size(); ++i) {
|
||||
// slot empty
|
||||
if (!DoesSpriteExist(i)) {
|
||||
_sprInfos[i] = SpriteInfo();
|
||||
_spriteData[i] = SpriteData();
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// enlarge the sprite bank to find a free slot and return the first new free slot
|
||||
return EnlargeTo(_spriteData.size());
|
||||
}
|
||||
|
||||
bool SpriteCache::SpriteData::DoesSpriteExist() const {
|
||||
return (Image != nullptr) || // HAS loaded bitmap
|
||||
((Flags & SPRCACHEFLAG_ISASSET) != 0); // OR found in the game resources
|
||||
}
|
||||
|
||||
bool SpriteCache::SpriteData::IsAssetSprite() const {
|
||||
return (Flags & SPRCACHEFLAG_ISASSET) != 0;
|
||||
}
|
||||
|
||||
bool SpriteCache::SpriteData::IsError() const {
|
||||
return (Flags & SPRCACHEFLAG_ERROR) != 0;
|
||||
}
|
||||
|
||||
bool SpriteCache::SpriteData::IsExternalSprite() const {
|
||||
return (Flags & SPRCACHEFLAG_EXTERNAL) != 0;
|
||||
}
|
||||
|
||||
bool SpriteCache::SpriteData::IsLocked() const {
|
||||
return (Flags & SPRCACHEFLAG_LOCKED) != 0;
|
||||
}
|
||||
|
||||
bool SpriteCache::DoesSpriteExist(sprkey_t index) const {
|
||||
return (index >= 0 && (size_t)index < _spriteData.size()) && // in the valid range
|
||||
_spriteData[index].IsValid(); // has assigned sprite
|
||||
}
|
||||
|
||||
Size SpriteCache::GetSpriteResolution(sprkey_t index) const {
|
||||
return DoesSpriteExist(index) ? _sprInfos[index].GetResolution() : Size();
|
||||
}
|
||||
|
||||
Bitmap *SpriteCache::operator[](sprkey_t index) {
|
||||
// invalid sprite slot
|
||||
if (!DoesSpriteExist(index) || _spriteData[index].IsError())
|
||||
return _placeholder.get();
|
||||
|
||||
// Externally added sprite or locked sprite, don't put it into MRU list
|
||||
if (_spriteData[index].IsExternalSprite() || _spriteData[index].IsLocked())
|
||||
return _spriteData[index].Image.get();
|
||||
// Either use ready image, or load one from assets
|
||||
if (_spriteData[index].Image) {
|
||||
// Move to the beginning of the MRU list
|
||||
_mru.splice(_mru.begin(), _mru, _spriteData[index].MruIt);
|
||||
return _spriteData[index].Image.get();
|
||||
} else {
|
||||
// Sprite exists in file but is not in mem, load it and add to MRU list
|
||||
if (LoadSprite(index)) {
|
||||
_spriteData[index].MruIt = _mru.insert(_mru.begin(), index);
|
||||
return _spriteData[index].Image.get();
|
||||
}
|
||||
}
|
||||
return _placeholder.get();
|
||||
}
|
||||
|
||||
void SpriteCache::FreeMem(size_t space) {
|
||||
for (int tries = 0; (_mru.size() > 0) && (_cacheSize >= (_maxCacheSize - space)); ++tries) {
|
||||
DisposeOldest();
|
||||
if (tries > 1000) { // ???
|
||||
Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Error, "RUNTIME CACHE ERROR: STUCK IN FREE_UP_MEM; RESETTING CACHE");
|
||||
DisposeAllFreeCached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteCache::DisposeOldest() {
|
||||
assert(_mru.size() > 0);
|
||||
if (_mru.size() == 0)
|
||||
return;
|
||||
auto it = std::prev(_mru.end());
|
||||
const auto sprnum = *it;
|
||||
// Safety check: must be a sprite from resources
|
||||
// TODO: compare with latest upstream
|
||||
// Commented out the assertion, since it triggers for sprites that are in the list but remapped to the placeholder (sprite 0)
|
||||
// Whispers of a Machine is affected by this issue (see TRAC #14730)
|
||||
|
||||
// assert(_spriteData[sprnum].IsAssetSprite());
|
||||
|
||||
if (!_spriteData[sprnum].IsAssetSprite()) {
|
||||
Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Error, "SpriteCache::DisposeOldest: in MRU list sprite %d is external or does not exist", sprnum);
|
||||
_mru.erase(it);
|
||||
// std::list::erase() invalidates iterators to the erased item.
|
||||
// But our implementation does not.
|
||||
_spriteData[sprnum].MruIt._node = nullptr;
|
||||
return;
|
||||
}
|
||||
// Delete the image, unless is locked
|
||||
// NOTE: locked sprites may still occur in MRU list
|
||||
if (!_spriteData[sprnum].IsLocked()) {
|
||||
_cacheSize -= _spriteData[sprnum].Size;
|
||||
_spriteData[sprnum].Image.reset();
|
||||
SprCacheLog("DisposeOldest: disposed %d, size now %d KB", sprnum, _cacheSize / 1024);
|
||||
}
|
||||
// Remove from the mru list
|
||||
_mru.erase(it);
|
||||
// std::list::erase() invalidates iterators to the erased item.
|
||||
// But our implementation does not.
|
||||
_spriteData[sprnum].MruIt._node = nullptr;
|
||||
}
|
||||
|
||||
void SpriteCache::DisposeCached(sprkey_t index) {
|
||||
if (IsAssetSprite(index)) {
|
||||
_spriteData[index].Flags &= ~SPRCACHEFLAG_LOCKED;
|
||||
_spriteData[index].Image.reset();
|
||||
}
|
||||
_cacheSize = _lockedSize;
|
||||
}
|
||||
|
||||
void SpriteCache::DisposeAllFreeCached() {
|
||||
for (size_t i = 0; i < _spriteData.size(); ++i) {
|
||||
if (!_spriteData[i].IsLocked() && // not locked
|
||||
_spriteData[i].IsAssetSprite()) // sprite from game resource
|
||||
{
|
||||
_spriteData[i].Image.reset();
|
||||
}
|
||||
}
|
||||
_cacheSize = _lockedSize;
|
||||
_mru.clear();
|
||||
}
|
||||
|
||||
void SpriteCache::PrecacheSprite(sprkey_t index) {
|
||||
if (index < 0 || (size_t)index >= _spriteData.size())
|
||||
return;
|
||||
if (!_spriteData[index].IsAssetSprite())
|
||||
return; // cannot precache a non-asset sprite
|
||||
|
||||
size_t size = 0;
|
||||
|
||||
if (_spriteData[index].Image == nullptr) {
|
||||
size = LoadSprite(index);
|
||||
} else if (!_spriteData[index].IsLocked()) {
|
||||
size = _spriteData[index].Size;
|
||||
// Remove locked sprite from the MRU list
|
||||
_mru.erase(_spriteData[index].MruIt);
|
||||
// std::list::erase() invalidates iterators to the erased item.
|
||||
// But our implementation does not.
|
||||
_spriteData[index].MruIt._node = nullptr;
|
||||
}
|
||||
|
||||
// make sure locked sprites can't fill the cache
|
||||
_maxCacheSize += size;
|
||||
_lockedSize += size;
|
||||
_spriteData[index].Flags |= SPRCACHEFLAG_LOCKED;
|
||||
SprCacheLog("Precached %d", index);
|
||||
}
|
||||
|
||||
void SpriteCache::LockSprite(sprkey_t index) {
|
||||
assert(index >= 0); // out of positive range indexes are valid to fail
|
||||
if (index < 0 || (size_t)index >= _spriteData.size())
|
||||
return;
|
||||
if (!_spriteData[index].IsAssetSprite())
|
||||
return; // cannot lock a non-asset sprite
|
||||
|
||||
if (_spriteData[index].DoesSpriteExist()) {
|
||||
_spriteData[index].Flags |= SPRCACHEFLAG_LOCKED;
|
||||
} else {
|
||||
LoadSprite(index, true);
|
||||
}
|
||||
SprCacheLog("Locked %d", index);
|
||||
}
|
||||
|
||||
void SpriteCache::UnlockSprite(sprkey_t index) {
|
||||
assert(index >= 0); // out of positive range indexes are valid to fail
|
||||
if (index < 0 || (size_t)index >= _spriteData.size())
|
||||
return;
|
||||
if (!_spriteData[index].IsAssetSprite() ||
|
||||
!_spriteData[index].IsLocked())
|
||||
return; // cannot unlock a non-asset sprite, or non-locked sprite
|
||||
|
||||
_spriteData[index].Flags &= ~SPRCACHEFLAG_LOCKED;
|
||||
SprCacheLog("Unlocked %d", index);
|
||||
}
|
||||
|
||||
size_t SpriteCache::LoadSprite(sprkey_t index, bool lock) {
|
||||
assert((index >= 0) && ((size_t)index < _spriteData.size()));
|
||||
if (index < 0 || (size_t)index >= _spriteData.size())
|
||||
return 0;
|
||||
assert((_spriteData[index].Flags & SPRCACHEFLAG_ISASSET) != 0);
|
||||
|
||||
Bitmap *image;
|
||||
HError err = _file.LoadSprite(index, image);
|
||||
if (!image) {
|
||||
Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Warn,
|
||||
"LoadSprite: failed to load sprite %d:\n%s\n - remapping to placeholder", index,
|
||||
err ? "Sprite does not exist." : err->FullMessage().GetCStr());
|
||||
RemapSpriteToPlaceholder(index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Let the external user convert this sprite's image for their needs
|
||||
image = _callbacks.InitSprite(index, image, _sprInfos[index].Flags);
|
||||
if (!image) {
|
||||
Debug::Printf(kDbgGroup_SprCache, kDbgMsg_Warn,
|
||||
"LoadSprite: failed to initialize sprite %d, remapping to placeholder", index);
|
||||
RemapSpriteToPlaceholder(index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// save the stored sprite info
|
||||
_sprInfos[index].Width = image->GetWidth();
|
||||
_sprInfos[index].Height = image->GetHeight();
|
||||
// Clear up space before adding to cache
|
||||
const size_t size = image->GetWidth() * image->GetHeight() * image->GetBPP();
|
||||
FreeMem(size);
|
||||
// Add to the cache, lock if requested or if it's sprite 0
|
||||
const bool should_lock = lock || (index == 0);
|
||||
_spriteData[index] = SpriteData(image, size, SPRCACHEFLAG_ISASSET);
|
||||
_spriteData[index].Flags |= (SPRCACHEFLAG_LOCKED * should_lock);
|
||||
_cacheSize += size;
|
||||
SprCacheLog("Loaded %d, size now %zu KB", index, _cacheSize / 1024);
|
||||
|
||||
// Let the external user to react to the new sprite;
|
||||
// note that this callback is allowed to modify the sprite's pixels,
|
||||
// but not its size or flags.
|
||||
_callbacks.PostInitSprite(index);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void SpriteCache::RemapSpriteToPlaceholder(sprkey_t index) {
|
||||
assert((index > 0) && ((size_t)index < _spriteData.size()));
|
||||
_sprInfos[index] = SpriteInfo(_placeholder->GetWidth(), _placeholder->GetHeight(), _placeholder->GetColorDepth());
|
||||
_spriteData[index].Flags |= SPRCACHEFLAG_ERROR;
|
||||
SprCacheLog("RemapSpriteToPlaceholder: %d", index);
|
||||
}
|
||||
|
||||
void SpriteCache::InitNullSprite(sprkey_t index) {
|
||||
assert(index >= 0);
|
||||
_sprInfos[index] = SpriteInfo();
|
||||
_spriteData[index] = SpriteData();
|
||||
}
|
||||
|
||||
int SpriteCache::SaveToFile(const String &filename, int store_flags, SpriteCompression compress, SpriteFileIndex &index) {
|
||||
std::vector<std::pair<bool, Bitmap *>> sprites;
|
||||
for (size_t i = 0; i < _spriteData.size(); ++i) {
|
||||
_callbacks.PrewriteSprite(_spriteData[i].Image.get());
|
||||
sprites.push_back(std::make_pair(DoesSpriteExist(i), _spriteData[i].Image.get()));
|
||||
}
|
||||
return SaveSpriteFile(filename, sprites, &_file, store_flags, compress, index);
|
||||
}
|
||||
|
||||
HError SpriteCache::InitFile(const String &filename, const String &sprindex_filename) {
|
||||
Reset();
|
||||
|
||||
std::vector<Size> metrics;
|
||||
HError err = _file.OpenFile(filename, sprindex_filename, metrics);
|
||||
if (!err)
|
||||
return err;
|
||||
|
||||
// Initialize sprite infos
|
||||
size_t newsize = metrics.size();
|
||||
_sprInfos.resize(newsize);
|
||||
_spriteData.resize(newsize);
|
||||
_mru.clear();
|
||||
for (size_t i = 0; i < metrics.size(); ++i) {
|
||||
if (!metrics[i].IsNull()) {
|
||||
// Existing sprite
|
||||
_spriteData[i].Flags = SPRCACHEFLAG_ISASSET;
|
||||
Size newsz = _callbacks.AdjustSize(Size(metrics[i].Width, metrics[i].Height), _sprInfos[i].Flags);
|
||||
_sprInfos[i].Width = newsz.Width;
|
||||
_sprInfos[i].Height = newsz.Height;
|
||||
} else {
|
||||
// Mark as empty slot
|
||||
InitNullSprite(i);
|
||||
}
|
||||
}
|
||||
return HError::None();
|
||||
}
|
||||
|
||||
void SpriteCache::DetachFile() {
|
||||
_file.Close();
|
||||
}
|
||||
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
254
engines/ags/shared/ac/sprite_cache.h
Normal file
254
engines/ags/shared/ac/sprite_cache.h
Normal file
@@ -0,0 +1,254 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//
|
||||
// Sprite caching system.
|
||||
//
|
||||
// SpriteFile handles sprite serialization and streaming.
|
||||
// SpriteCache provides bitmaps by demand; it uses SpriteFile to load sprites
|
||||
// and does MRU (most-recent-use) caching.
|
||||
//
|
||||
// TODO: store sprite data in a specialized container type that is optimized
|
||||
// for having most keys allocated in large continious sequences by default.
|
||||
//
|
||||
// Only for the reference: one of the ideas is for container to have a table
|
||||
// of arrays of fixed size internally. When getting an item the hash would be
|
||||
// first divided on array size to find the array the item resides in, then the
|
||||
// item is taken from item from slot index = (hash - arrsize * arrindex).
|
||||
// TODO: find out if there is already a hash table kind that follows similar
|
||||
// principle.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_SHARED_AC_SPRITE_CACHE_H
|
||||
#define AGS_SHARED_AC_SPRITE_CACHE_H
|
||||
|
||||
#include "common/std/memory.h"
|
||||
#include "common/std/vector.h"
|
||||
#include "common/std/list.h"
|
||||
#include "ags/shared/ac/sprite_file.h"
|
||||
#include "ags/shared/core/platform.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/shared/util/error.h"
|
||||
#include "ags/shared/util/geometry.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class String;
|
||||
class Stream;
|
||||
class Bitmap;
|
||||
} // namespace AGS3
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
typedef AGS::Shared::HError HAGSError;
|
||||
|
||||
struct SpriteInfo;
|
||||
|
||||
// Max size of the sprite cache, in bytes
|
||||
#if AGS_PLATFORM_OS_ANDROID || AGS_PLATFORM_OS_IOS
|
||||
#define DEFAULTCACHESIZE_KB (32 * 1024)
|
||||
#else
|
||||
#define DEFAULTCACHESIZE_KB (128 * 1024)
|
||||
#endif
|
||||
|
||||
struct SpriteInfo;
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
|
||||
class SpriteCache {
|
||||
public:
|
||||
static const sprkey_t MIN_SPRITE_INDEX = 1; // 0 is reserved for "empty sprite"
|
||||
static const sprkey_t MAX_SPRITE_INDEX = INT32_MAX - 1;
|
||||
static const size_t MAX_SPRITE_SLOTS = INT32_MAX;
|
||||
|
||||
typedef Size (*PfnAdjustSpriteSize)(const Size &size, const uint32_t sprite_flags);
|
||||
typedef Bitmap *(*PfnInitSprite)(sprkey_t index, Bitmap *image, uint32_t &sprite_flags);
|
||||
typedef void (*PfnPostInitSprite)(sprkey_t index);
|
||||
typedef void (*PfnPrewriteSprite)(Bitmap *image);
|
||||
|
||||
struct Callbacks {
|
||||
PfnAdjustSpriteSize AdjustSize;
|
||||
PfnInitSprite InitSprite;
|
||||
PfnPostInitSprite PostInitSprite;
|
||||
PfnPrewriteSprite PrewriteSprite;
|
||||
};
|
||||
|
||||
SpriteCache(std::vector<SpriteInfo> &sprInfos, const Callbacks &callbacks);
|
||||
~SpriteCache() = default;
|
||||
|
||||
// Loads sprite reference information and inits sprite stream
|
||||
HError InitFile(const String &filename, const String &sprindex_filename);
|
||||
// Saves current cache contents to the file
|
||||
int SaveToFile(const String &filename, int store_flags, SpriteCompression compress, SpriteFileIndex &index);
|
||||
// Closes an active sprite file stream
|
||||
void DetachFile();
|
||||
|
||||
inline int GetStoreFlags() const {
|
||||
return _file.GetStoreFlags();
|
||||
}
|
||||
inline SpriteCompression GetSpriteCompression() const {
|
||||
return _file.GetSpriteCompression();
|
||||
}
|
||||
|
||||
// Tells if there is a sprite registered for the given index;
|
||||
// this includes sprites that were explicitly assigned but failed to init and were remapped
|
||||
bool DoesSpriteExist(sprkey_t index) const;
|
||||
// Returns sprite's resolution; or empty Size if sprite does not exist
|
||||
Size GetSpriteResolution(sprkey_t index) const;
|
||||
// Makes sure sprite cache has allocated slots for all sprites up to the given inclusive limit;
|
||||
// returns requested index on success, or -1 on failure.
|
||||
sprkey_t EnlargeTo(sprkey_t topmost);
|
||||
// Finds a free slot index, if all slots are occupied enlarges sprite bank; returns index
|
||||
sprkey_t GetFreeIndex();
|
||||
// Returns current size of the cache, in bytes; this includes locked size too!
|
||||
size_t GetCacheSize() const;
|
||||
// Gets the total size of the locked sprites, in bytes
|
||||
size_t GetLockedSize() const;
|
||||
// Returns maximal size limit of the cache, in bytes; this includes locked size too!
|
||||
size_t GetMaxCacheSize() const;
|
||||
// Returns number of sprite slots in the bank (this includes both actual sprites and free slots)
|
||||
size_t GetSpriteSlotCount() const;
|
||||
// Tells if the sprite storage still has unoccupied slots to put new sprites in
|
||||
bool HasFreeSlots() const;
|
||||
// Tells if the given slot is reserved for the asset sprite, that is a "static"
|
||||
// sprite cached from the game assets
|
||||
bool IsAssetSprite(sprkey_t index) const;
|
||||
// Loads sprite using SpriteFile if such index is known,
|
||||
// frees the space if cache size reaches the limit
|
||||
void PrecacheSprite(sprkey_t index);
|
||||
// Locks sprite, preventing it from getting removed by the normal cache limit.
|
||||
// If this is a registered sprite from the game assets, then loads it first.
|
||||
// If this is a sprite with SPRCACHEFLAG_EXTERNAL flag, then does nothing,
|
||||
// as these are always "locked".
|
||||
// If such sprite does not exist, then fails silently.
|
||||
void LockSprite(sprkey_t index);
|
||||
// Unlocks sprite, putting it back into the cache logic,
|
||||
// where it counts towards normal limit may be deleted to free space.
|
||||
// NOTE: sprites with SPRCACHEFLAG_EXTERNAL flag cannot be unlocked,
|
||||
// only explicitly removed.
|
||||
// If such sprite was not present in memory, then fails silently.
|
||||
void UnlockSprite(sprkey_t index);
|
||||
// Unregisters sprite from the bank and returns the bitmap
|
||||
Bitmap *RemoveSprite(sprkey_t index);
|
||||
// Deletes particular sprite, marks slot as unused
|
||||
void DeleteSprite(sprkey_t index);
|
||||
// Deletes a loaded asset image (non-external) from memory, ignoring its
|
||||
// locked status; this keeps an auxiliary sprite information intact,
|
||||
// so that the same sprite can be cached back later.
|
||||
void DisposeCached(sprkey_t index);
|
||||
// Deletes all free cached asset images (non-locked, non-external)
|
||||
// from memory; this keeps all the auxiliary sprite information intact,
|
||||
// so that the same sprite(s) can be cached back later.
|
||||
void DisposeAllFreeCached();
|
||||
// Deletes all data and resets cache to the clear state
|
||||
void Reset();
|
||||
// Assigns new sprite for the given index; this sprite won't be auto disposed.
|
||||
// *Deletes* the previous sprite if one was found at the same index.
|
||||
// "flags" are SPF_* constants that define sprite's behavior in game.
|
||||
bool SetSprite(sprkey_t index, std::unique_ptr<Bitmap> image, int flags = 0);
|
||||
// Assigns new dummy for the given index, silently remapping it to placeholder;
|
||||
// optionally marks it as an asset placeholder.
|
||||
// *Deletes* the previous sprite if one was found at the same index.
|
||||
void SetEmptySprite(sprkey_t index, bool as_asset);
|
||||
// Sets max cache size in bytes
|
||||
void SetMaxCacheSize(size_t size);
|
||||
|
||||
// Loads (if it's not in cache yet) and returns bitmap by the sprite index
|
||||
Bitmap *operator[](sprkey_t index);
|
||||
|
||||
private:
|
||||
// Load sprite from game resource
|
||||
size_t LoadSprite(sprkey_t index, bool lock = false);
|
||||
// Remap the given index to the placeholder
|
||||
void RemapSpriteToPlaceholder(sprkey_t index);
|
||||
// Delete the oldest (least recently used) image in cache
|
||||
void DisposeOldest();
|
||||
// Keep disposing oldest elements until cache has at least the given free space
|
||||
void FreeMem(size_t space);
|
||||
// Initialize the empty sprite slot
|
||||
void InitNullSprite(sprkey_t index);
|
||||
//
|
||||
// Dummy no-op variants for callbacks
|
||||
//
|
||||
static Size DummyAdjustSize(const Size &size, const uint32_t) { return size; }
|
||||
static Bitmap *DummyInitSprite(sprkey_t, Bitmap *image, uint32_t &) { return image; }
|
||||
static void DummyPostInitSprite(sprkey_t) { /* do nothing */ }
|
||||
static void DummyPrewriteSprite(Bitmap *) { /* do nothing */ }
|
||||
|
||||
// Information required for the sprite streaming
|
||||
struct SpriteData {
|
||||
size_t Size = 0; // to track cache size, 0 = means don't track
|
||||
uint32_t Flags = 0; // SPRCACHEFLAG* flags
|
||||
std::unique_ptr<Bitmap> Image; // actual bitmap
|
||||
|
||||
// MRU list reference
|
||||
std::list<sprkey_t>::iterator MruIt;
|
||||
|
||||
SpriteData() = default;
|
||||
SpriteData(SpriteData &&other) = default;
|
||||
SpriteData(Bitmap *image, size_t size, uint32_t flags) : Size(size), Flags(flags), Image(image) {}
|
||||
|
||||
SpriteData &operator=(SpriteData &&other) = default;
|
||||
|
||||
// Tells if this slot has a valid sprite assigned (not empty slot)
|
||||
bool IsValid() const { return Flags != 0u; }
|
||||
// Tells if there actually is a registered sprite in this slot
|
||||
bool DoesSpriteExist() const;
|
||||
// Tells if there's a game resource corresponding to this slot
|
||||
bool IsAssetSprite() const;
|
||||
// Tells if a sprite failed to load from assets, and should not be used
|
||||
bool IsError() const;
|
||||
// Tells if sprite was added externally, not loaded from game resources
|
||||
bool IsExternalSprite() const;
|
||||
// Tells if sprite is locked and should not be disposed by cache logic
|
||||
bool IsLocked() const;
|
||||
};
|
||||
|
||||
// Provided map of sprite infos, to fill in loaded sprite properties
|
||||
std::vector<SpriteInfo> &_sprInfos;
|
||||
// Array of sprite references
|
||||
std::vector<SpriteData> _spriteData;
|
||||
// Placeholder sprite, returned from operator[] for a non-existing sprite
|
||||
std::unique_ptr<Bitmap> _placeholder;
|
||||
|
||||
Callbacks _callbacks;
|
||||
SpriteFile _file;
|
||||
|
||||
size_t _maxCacheSize; // cache size limit
|
||||
size_t _lockedSize; // size in bytes of currently locked images
|
||||
size_t _cacheSize; // size in bytes of currently cached images
|
||||
|
||||
// MRU list: the way to track which sprites were used recently.
|
||||
// When clearing up space for new sprites, cache first deletes the sprites
|
||||
// that were last time used long ago.
|
||||
std::list<sprkey_t> _mru;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
746
engines/ags/shared/ac/sprite_file.cpp
Normal file
746
engines/ags/shared/ac/sprite_file.cpp
Normal file
@@ -0,0 +1,746 @@
|
||||
/* 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 "ags/shared/ac/sprite_file.h"
|
||||
#include "common/std/algorithm.h"
|
||||
#include "ags/shared/core/asset_manager.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/shared/util/compress.h"
|
||||
#include "ags/shared/util/file.h"
|
||||
#include "ags/shared/util/memory_stream.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
|
||||
static const char *spriteFileSig = " Sprite File ";
|
||||
static const char *spindexid = "SPRINDEX";
|
||||
|
||||
// TODO: should not be part of SpriteFile, but rather some asset management class?
|
||||
const char *SpriteFile::DefaultSpriteFileName = "acsprset.spr";
|
||||
const char *SpriteFile::DefaultSpriteIndexName = "sprindex.dat";
|
||||
|
||||
// Image buffer pointer, a helper struct that eases switching
|
||||
// between intermediate buffers when loading, saving or converting an image.
|
||||
template <typename T> struct ImBufferPtrT {
|
||||
T Buf = nullptr;
|
||||
size_t Size = 0;
|
||||
int BPP = 1; // byte per pixel
|
||||
|
||||
ImBufferPtrT() = default;
|
||||
ImBufferPtrT(T buf, size_t sz, int bpp) : Buf(buf), Size(sz), BPP(bpp) {
|
||||
}
|
||||
};
|
||||
typedef ImBufferPtrT<uint8_t *> ImBufferPtr;
|
||||
typedef ImBufferPtrT<const uint8_t *> ImBufferCPtr;
|
||||
|
||||
|
||||
// Finds the given color's index in the palette, or returns SIZE_MAX if such color is not there
|
||||
static size_t lookup_palette(uint32_t col, uint32_t palette[256], uint32_t ncols) {
|
||||
for (size_t i = 0; i < ncols; ++i)
|
||||
if (palette[i] == col) return i;
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
// Converts a 16/32-bit image into the indexed 8-bit pixel data with palette;
|
||||
// NOTE: the palette will contain colors in the same format as the source image.
|
||||
// only succeeds if the total number of colors used in the image is < 257.
|
||||
static bool CreateIndexedBitmap(const Bitmap *image, std::vector<uint8_t> &dst_data,
|
||||
uint32_t palette[256], uint32_t &pal_count) {
|
||||
const int src_bpp = image->GetBPP();
|
||||
if (src_bpp < 2) { assert(0); return false; }
|
||||
const size_t src_size = image->GetWidth() * image->GetHeight() * image->GetBPP();
|
||||
const size_t dst_size = image->GetWidth() * image->GetHeight();
|
||||
dst_data.resize(dst_size);
|
||||
const uint8_t *src = image->GetData(), *src_end = src + src_size;
|
||||
uint8_t *dst = &dst_data[0], *dst_end = dst + dst_size;
|
||||
pal_count = 0;
|
||||
|
||||
for (; src < src_end && dst < dst_end; src += src_bpp) {
|
||||
uint32_t col = 0;
|
||||
size_t pal_n = 0;
|
||||
switch (src_bpp) {
|
||||
case 2:
|
||||
col = *((const uint16_t *)src);
|
||||
pal_n = lookup_palette(col, palette, pal_count);
|
||||
break;
|
||||
case 4:
|
||||
col = *((const uint32_t *)src);
|
||||
pal_n = lookup_palette(col, palette, pal_count);
|
||||
break;
|
||||
default: assert(0); return false;
|
||||
}
|
||||
|
||||
if (pal_n == SIZE_MAX) {
|
||||
if (pal_count == 256) return false;
|
||||
pal_n = pal_count;
|
||||
palette[pal_count++] = col;
|
||||
}
|
||||
*(dst++) = (uint8_t)pal_n;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Unpacks an indexed image's pixel data into the 16/32-bit image;
|
||||
// NOTE: the palette is expected to contain colors in the same format as the destination.
|
||||
static void UnpackIndexedBitmap(Bitmap *image, const uint8_t *data, size_t data_size,
|
||||
uint32_t *palette, uint32_t pal_count) {
|
||||
assert(pal_count > 0);
|
||||
if (pal_count == 0) return; // meaningless
|
||||
const uint8_t bpp = image->GetBPP();
|
||||
const size_t dst_size = image->GetWidth() * image->GetHeight() * image->GetBPP();
|
||||
uint8_t *dst = image->GetDataForWriting(), *dst_end = dst + dst_size;
|
||||
|
||||
switch (bpp) {
|
||||
case 2:
|
||||
for (size_t p = 0; (p < data_size) && (dst < dst_end); ++p, dst += bpp) {
|
||||
uint8_t index = data[p];
|
||||
assert(index < pal_count);
|
||||
uint32_t color = palette[(index < pal_count) ? index : 0];
|
||||
*((uint16_t *)dst) = color;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
for (size_t p = 0; (p < data_size) && (dst < dst_end); ++p, dst += bpp) {
|
||||
uint8_t index = data[p];
|
||||
assert(index < pal_count);
|
||||
uint32_t color = palette[(index < pal_count) ? index : 0];
|
||||
*((uint32_t *)dst) = color;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static inline SpriteFormat PaletteFormatForBPP(int bpp) {
|
||||
switch (bpp) {
|
||||
case 1: return kSprFmt_PaletteRgb888;
|
||||
case 2: return kSprFmt_PaletteRgb565;
|
||||
case 4: return kSprFmt_PaletteArgb8888;
|
||||
default: return kSprFmt_Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint8_t GetPaletteBPP(SpriteFormat fmt) {
|
||||
switch (fmt) {
|
||||
case kSprFmt_PaletteRgb888: return 3;
|
||||
case kSprFmt_PaletteArgb8888: return 4;
|
||||
case kSprFmt_PaletteRgb565: return 2;
|
||||
default: return 0; // means no palette
|
||||
}
|
||||
}
|
||||
|
||||
SpriteFile::SpriteFile() {
|
||||
_curPos = -2;
|
||||
}
|
||||
|
||||
HError SpriteFile::OpenFile(const String &filename, const String &sprindex_filename,
|
||||
std::vector<Size> &metrics) {
|
||||
Close();
|
||||
|
||||
char buff[20];
|
||||
soff_t spr_initial_offs = 0;
|
||||
int spriteFileID = 0;
|
||||
|
||||
_stream.reset(_GP(AssetMgr)->OpenAsset(filename));
|
||||
if (_stream == nullptr)
|
||||
return new Error(String::FromFormat("Failed to open spriteset file '%s'.", filename.GetCStr()));
|
||||
|
||||
spr_initial_offs = _stream->GetPosition();
|
||||
|
||||
_version = (SpriteFileVersion)_stream->ReadInt16();
|
||||
// read the "Sprite File" signature
|
||||
_stream->ReadArray(&buff[0], 13, 1);
|
||||
|
||||
if (_version < kSprfVersion_Uncompressed || _version > kSprfVersion_Current) {
|
||||
_stream.reset();
|
||||
return new Error(String::FromFormat("Unsupported spriteset format (requested %d, supported %d - %d).", _version,
|
||||
kSprfVersion_Uncompressed, kSprfVersion_Current));
|
||||
}
|
||||
|
||||
// unknown version
|
||||
buff[13] = 0;
|
||||
if (strcmp(buff, spriteFileSig)) {
|
||||
_stream.reset();
|
||||
return new Error("Uknown spriteset format.");
|
||||
}
|
||||
|
||||
_storeFlags = 0;
|
||||
if (_version < kSprfVersion_Compressed) {
|
||||
_compress = kSprCompress_None;
|
||||
// skip the palette
|
||||
_stream->Seek(256 * 3); // sizeof(RGB) * 256
|
||||
} else if (_version == kSprfVersion_Compressed) {
|
||||
_compress = kSprCompress_RLE;
|
||||
} else if (_version >= kSprfVersion_Last32bit) {
|
||||
_compress = (SpriteCompression)_stream->ReadInt8();
|
||||
spriteFileID = _stream->ReadInt32();
|
||||
}
|
||||
|
||||
sprkey_t topmost;
|
||||
if (_version < kSprfVersion_HighSpriteLimit)
|
||||
topmost = (uint16_t)_stream->ReadInt16();
|
||||
else
|
||||
topmost = _stream->ReadInt32();
|
||||
if (_version < kSprfVersion_Uncompressed)
|
||||
topmost = 200;
|
||||
|
||||
_spriteData.resize(topmost + 1);
|
||||
metrics.resize(topmost + 1);
|
||||
|
||||
// Version 12+: read global store flags
|
||||
if (_version >= kSprfVersion_StorageFormats) {
|
||||
_storeFlags = _stream->ReadInt8();
|
||||
_stream->ReadInt8(); // reserved
|
||||
_stream->ReadInt8();
|
||||
_stream->ReadInt8();
|
||||
}
|
||||
|
||||
// if there is a sprite index file, use it
|
||||
if (LoadSpriteIndexFile(sprindex_filename, spriteFileID,
|
||||
spr_initial_offs, topmost, metrics)) {
|
||||
// Succeeded
|
||||
return HError::None();
|
||||
}
|
||||
|
||||
// Failed, index file is invalid; index sprites manually
|
||||
return RebuildSpriteIndex(_stream.get(), topmost, metrics);
|
||||
}
|
||||
|
||||
void SpriteFile::Close() {
|
||||
_stream.reset();
|
||||
_spriteData.clear();
|
||||
_version = kSprfVersion_Undefined;
|
||||
_storeFlags = 0;
|
||||
_compress = kSprCompress_None;
|
||||
_curPos = -2;
|
||||
}
|
||||
|
||||
int SpriteFile::GetStoreFlags() const {
|
||||
return _storeFlags;
|
||||
}
|
||||
|
||||
SpriteCompression SpriteFile::GetSpriteCompression() const {
|
||||
return _compress;
|
||||
}
|
||||
|
||||
sprkey_t SpriteFile::GetTopmostSprite() const {
|
||||
return (sprkey_t)_spriteData.size() - 1;
|
||||
}
|
||||
|
||||
bool SpriteFile::LoadSpriteIndexFile(const String &filename, int expectedFileID,
|
||||
soff_t spr_initial_offs, sprkey_t topmost, std::vector<Size> &metrics) {
|
||||
Stream *fidx = _GP(AssetMgr)->OpenAsset(filename);
|
||||
if (fidx == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[9];
|
||||
// check "SPRINDEX" id
|
||||
fidx->ReadArray(&buffer[0], strlen(spindexid), 1);
|
||||
buffer[8] = 0;
|
||||
if (strcmp(buffer, spindexid)) {
|
||||
delete fidx;
|
||||
return false;
|
||||
}
|
||||
// check version
|
||||
SpriteIndexFileVersion vers = (SpriteIndexFileVersion)fidx->ReadInt32();
|
||||
if (vers < kSpridxfVersion_Initial || vers > kSpridxfVersion_Current) {
|
||||
delete fidx;
|
||||
return false;
|
||||
}
|
||||
if (vers >= kSpridxfVersion_Last32bit) {
|
||||
if (fidx->ReadInt32() != expectedFileID) {
|
||||
delete fidx;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sprkey_t topmost_index = fidx->ReadInt32();
|
||||
// end index+1 should be the same as num sprites
|
||||
if (fidx->ReadInt32() != topmost_index + 1) {
|
||||
delete fidx;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (topmost_index != topmost) {
|
||||
delete fidx;
|
||||
return false;
|
||||
}
|
||||
|
||||
sprkey_t numsprits = topmost_index + 1;
|
||||
std::vector<int16_t> rspritewidths; rspritewidths.resize(numsprits);
|
||||
std::vector<int16_t> rspriteheights; rspriteheights.resize(numsprits);
|
||||
std::vector<soff_t> spriteoffs; spriteoffs.resize(numsprits);
|
||||
|
||||
fidx->ReadArrayOfInt16(&rspritewidths[0], numsprits);
|
||||
fidx->ReadArrayOfInt16(&rspriteheights[0], numsprits);
|
||||
if (vers <= kSpridxfVersion_Last32bit) {
|
||||
for (sprkey_t i = 0; i < numsprits; ++i)
|
||||
spriteoffs[i] = fidx->ReadInt32();
|
||||
} else // large file support
|
||||
{
|
||||
fidx->ReadArrayOfInt64(&spriteoffs[0], numsprits);
|
||||
}
|
||||
delete fidx;
|
||||
|
||||
for (sprkey_t i = 0; i <= topmost_index; ++i) {
|
||||
if (spriteoffs[i] != 0) {
|
||||
_spriteData[i].Offset = spriteoffs[i] + spr_initial_offs;
|
||||
metrics[i].Width = rspritewidths[i];
|
||||
metrics[i].Height = rspriteheights[i];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void ReadSprHeader(SpriteDatHeader &hdr, Stream *in,
|
||||
const SpriteFileVersion ver, SpriteCompression gl_compress) {
|
||||
int bpp = in->ReadInt8();
|
||||
SpriteFormat sformat = (SpriteFormat)in->ReadInt8();
|
||||
// note we MUST read first 2 * int8 before skipping rest
|
||||
if (bpp == 0) {
|
||||
hdr = SpriteDatHeader(); return;
|
||||
} // empty slot
|
||||
int pal_count = 0;
|
||||
SpriteCompression compress = gl_compress;
|
||||
if (ver >= kSprfVersion_StorageFormats) {
|
||||
pal_count = (uint8_t)in->ReadInt8() + 1; // saved as (count - 1)
|
||||
compress = (SpriteCompression)in->ReadInt8();
|
||||
}
|
||||
int w = in->ReadInt16();
|
||||
int h = in->ReadInt16();
|
||||
hdr = SpriteDatHeader(bpp, sformat, pal_count, compress, w, h);
|
||||
}
|
||||
|
||||
HError SpriteFile::RebuildSpriteIndex(Stream *in, sprkey_t topmost,
|
||||
std::vector<Size> &metrics) {
|
||||
topmost = MIN(topmost, (sprkey_t)_spriteData.size() - 1);
|
||||
for (sprkey_t i = 0; !in->EOS() && (i <= topmost); ++i) {
|
||||
_spriteData[i].Offset = in->GetPosition();
|
||||
SpriteDatHeader hdr;
|
||||
ReadSprHeader(hdr, _stream.get(), _version, _compress);
|
||||
if (hdr.BPP == 0) continue; // empty slot, this is normal
|
||||
int pal_bpp = GetPaletteBPP(hdr.SFormat);
|
||||
if (pal_bpp > 0) in->Seek(hdr.PalCount * pal_bpp); // skip palette
|
||||
size_t data_sz =
|
||||
((_version >= kSprfVersion_StorageFormats) || _compress != kSprCompress_None) ?
|
||||
(uint32_t)in->ReadInt32() : hdr.Width * hdr.Height * hdr.BPP;
|
||||
in->Seek(data_sz); // skip image data
|
||||
metrics[i].Width = hdr.Width;
|
||||
metrics[i].Height = hdr.Height;
|
||||
}
|
||||
return HError::None();
|
||||
}
|
||||
|
||||
HError SpriteFile::LoadSprite(sprkey_t index, Shared::Bitmap *&sprite) {
|
||||
sprite = nullptr;
|
||||
if (index < 0 || (size_t)index >= _spriteData.size())
|
||||
return new Error(String::FromFormat("LoadSprite: slot index %d out of bounds (%d - %d).",
|
||||
index, 0, _spriteData.size() - 1));
|
||||
|
||||
if (_spriteData[index].Offset == 0)
|
||||
return HError::None(); // sprite is not in file
|
||||
|
||||
SeekToSprite(index);
|
||||
_curPos = -2; // mark undefined pos
|
||||
|
||||
SpriteDatHeader hdr;
|
||||
ReadSprHeader(hdr, _stream.get(), _version, _compress);
|
||||
if (hdr.BPP == 0) return HError::None(); // empty slot, this is normal
|
||||
int bpp = hdr.BPP, w = hdr.Width, h = hdr.Height;
|
||||
std::unique_ptr<Bitmap> image(BitmapHelper::CreateBitmap(w, h, bpp * 8));
|
||||
if (image == nullptr) {
|
||||
return new Error(String::FromFormat("LoadSprite: failed to allocate bitmap %d (%dx%d%d).",
|
||||
index, w, h, bpp * 8));
|
||||
}
|
||||
ImBufferPtr im_data(image->GetDataForWriting(), w * h * bpp, bpp);
|
||||
// (Optional) Handle storage options, reverse
|
||||
std::vector<uint8_t> indexed_buf;
|
||||
uint32_t palette[256];
|
||||
uint32_t pal_bpp = GetPaletteBPP(hdr.SFormat);
|
||||
if (pal_bpp > 0) { // read palette if format assumes one
|
||||
switch (pal_bpp) {
|
||||
case 2: for (uint32_t i = 0; i < hdr.PalCount; ++i) {
|
||||
palette[i] = _stream->ReadInt16();
|
||||
}
|
||||
break;
|
||||
case 4: for (uint32_t i = 0; i < hdr.PalCount; ++i) {
|
||||
palette[i] = _stream->ReadInt32();
|
||||
}
|
||||
break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
indexed_buf.resize(w * h);
|
||||
im_data = ImBufferPtr(&indexed_buf[0], indexed_buf.size(), 1);
|
||||
}
|
||||
// (Optional) Decompress the image data into the temp buffer
|
||||
size_t in_data_size =
|
||||
((_version >= kSprfVersion_StorageFormats) || _compress != kSprCompress_None) ?
|
||||
(uint32_t)_stream->ReadInt32() : (w * h * bpp);
|
||||
if (hdr.Compress != kSprCompress_None) {
|
||||
// TODO: rewrite this to only make a choice once the SpriteFile is initialized
|
||||
// and use either function ptr or a decompressing stream class object
|
||||
if (in_data_size == 0) {
|
||||
return new Error(String::FromFormat("LoadSprite: bad compressed data for sprite %d.", index));
|
||||
}
|
||||
bool result;
|
||||
switch (hdr.Compress) {
|
||||
case kSprCompress_RLE: result = rle_decompress(im_data.Buf, im_data.Size, im_data.BPP, _stream.get());
|
||||
break;
|
||||
case kSprCompress_LZW: result = lzw_decompress(im_data.Buf, im_data.Size, im_data.BPP, _stream.get(), in_data_size);
|
||||
break;
|
||||
case kSprCompress_Deflate: result = inflate_decompress(im_data.Buf, im_data.Size, im_data.BPP, _stream.get(), in_data_size);
|
||||
break;
|
||||
default: assert(!"Unsupported compression type!"); result = false; break;
|
||||
}
|
||||
// TODO: test that not more than data_size was read!
|
||||
if (!result) {
|
||||
return new Error(String::FromFormat("LoadSprite: failed to decompress pixel array for sprite %d.", index));
|
||||
}
|
||||
}
|
||||
// Otherwise (no compression) read directly
|
||||
else {
|
||||
switch (im_data.BPP) {
|
||||
case 1: _stream->Read(im_data.Buf, im_data.Size);
|
||||
break;
|
||||
case 2: _stream->ReadArrayOfInt16(
|
||||
reinterpret_cast<int16_t *>(im_data.Buf), im_data.Size / sizeof(int16_t));
|
||||
break;
|
||||
case 4: _stream->ReadArrayOfInt32(
|
||||
reinterpret_cast<int32_t *>(im_data.Buf), im_data.Size / sizeof(int32_t));
|
||||
break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
}
|
||||
// Finally revert storage options
|
||||
if (pal_bpp > 0) {
|
||||
UnpackIndexedBitmap(image.get(), im_data.Buf, im_data.Size, palette, hdr.PalCount);
|
||||
}
|
||||
|
||||
sprite = image.release(); // FIXME: pass unique_ptr in this function
|
||||
_curPos = index + 1; // mark correct pos
|
||||
return HError::None();
|
||||
}
|
||||
|
||||
HError SpriteFile::LoadRawData(sprkey_t index, SpriteDatHeader &hdr, std::vector<uint8_t> &data) {
|
||||
hdr = SpriteDatHeader();
|
||||
data.resize(0);
|
||||
if (index < 0 || (size_t)index >= _spriteData.size())
|
||||
return new Error(String::FromFormat("LoadSprite: slot index %d out of bounds (%d - %d).",
|
||||
index, 0, _spriteData.size() - 1));
|
||||
|
||||
if (_spriteData[index].Offset == 0)
|
||||
return HError::None(); // sprite is not in file
|
||||
|
||||
SeekToSprite(index);
|
||||
_curPos = -2; // mark undefined pos
|
||||
|
||||
ReadSprHeader(hdr, _stream.get(), _version, _compress);
|
||||
if (hdr.BPP == 0) return HError::None(); // empty slot, this is normal
|
||||
size_t data_size = 0;
|
||||
soff_t data_pos = _stream->GetPosition();
|
||||
// Optional palette
|
||||
size_t pal_size = hdr.PalCount * GetPaletteBPP(hdr.SFormat);
|
||||
data_size += pal_size;
|
||||
_stream->Seek(pal_size);
|
||||
// Pixel data
|
||||
if ((_version >= kSprfVersion_StorageFormats) || _compress != kSprCompress_None)
|
||||
data_size += (uint32_t)_stream->ReadInt32() + sizeof(uint32_t);
|
||||
else
|
||||
data_size += hdr.Width * hdr.Height * hdr.BPP;
|
||||
// Seek back and read all at once
|
||||
data.resize(data_size);
|
||||
_stream->Seek(data_pos, kSeekBegin);
|
||||
_stream->Read(&data[0], data_size);
|
||||
|
||||
_curPos = index + 1; // mark correct pos
|
||||
return HError::None();
|
||||
}
|
||||
|
||||
void SpriteFile::SeekToSprite(sprkey_t index) {
|
||||
// If we didn't just load the previous sprite, seek to it
|
||||
if (index != _curPos) {
|
||||
_stream->Seek(_spriteData[index].Offset, kSeekBegin);
|
||||
_curPos = index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Finds the topmost occupied slot index
|
||||
static sprkey_t FindTopmostSprite(const std::vector<std::pair<bool, Bitmap *>> &sprites) {
|
||||
sprkey_t topmost = -1;
|
||||
for (sprkey_t i = 0; i < static_cast<sprkey_t>(sprites.size()); ++i)
|
||||
if (sprites[i].first)
|
||||
topmost = i;
|
||||
return topmost;
|
||||
}
|
||||
|
||||
int SaveSpriteFile(const String &save_to_file,
|
||||
const std::vector<std::pair<bool, Bitmap *> > &sprites,
|
||||
SpriteFile *read_from_file,
|
||||
int store_flags, SpriteCompression compress, SpriteFileIndex &index) {
|
||||
std::unique_ptr<Stream> output(File::CreateFile(save_to_file));
|
||||
if (output == nullptr)
|
||||
return -1;
|
||||
|
||||
sprkey_t lastslot = FindTopmostSprite(sprites);
|
||||
SpriteFileWriter writer(output);
|
||||
writer.Begin(store_flags, compress, lastslot);
|
||||
|
||||
std::unique_ptr<Bitmap> temp_bmp; // for disposing temp sprites
|
||||
std::vector<uint8_t> membuf; // for loading raw sprite data
|
||||
|
||||
const bool diff_compress =
|
||||
read_from_file &&
|
||||
(read_from_file->GetSpriteCompression() != compress ||
|
||||
read_from_file->GetStoreFlags() != store_flags);
|
||||
|
||||
for (sprkey_t i = 0; i <= lastslot; ++i) {
|
||||
if (!sprites[i].first) { // empty slot
|
||||
writer.WriteEmptySlot();
|
||||
continue;
|
||||
}
|
||||
|
||||
Bitmap *image = sprites[i].second;
|
||||
// if compression setting is different, load the sprite into memory
|
||||
// (otherwise we will be able to simply copy bytes from one file to another
|
||||
if ((image == nullptr) && diff_compress) {
|
||||
read_from_file->LoadSprite(i, image);
|
||||
temp_bmp.reset(image);
|
||||
}
|
||||
|
||||
// if managed to load an image - save it according the new compression settings
|
||||
if (image != nullptr) {
|
||||
writer.WriteBitmap(image);
|
||||
continue;
|
||||
} else if (diff_compress) {
|
||||
// sprite doesn't exist
|
||||
writer.WriteEmptySlot();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not in memory - and same compression option;
|
||||
// Directly copy the sprite bytes from the input file to the output
|
||||
SpriteDatHeader hdr;
|
||||
read_from_file->LoadRawData(i, hdr, membuf);
|
||||
if (hdr.BPP == 0) { // empty slot
|
||||
writer.WriteEmptySlot();
|
||||
continue;
|
||||
}
|
||||
writer.WriteRawData(hdr, &membuf[0], membuf.size());
|
||||
}
|
||||
writer.Finalize();
|
||||
|
||||
index = writer.GetIndex();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveSpriteIndex(const String &filename, const SpriteFileIndex &index) {
|
||||
// write the sprite index file
|
||||
Stream *out = File::CreateFile(filename);
|
||||
if (!out)
|
||||
return -1;
|
||||
// write "SPRINDEX" id
|
||||
out->WriteArray(spindexid, strlen(spindexid), 1);
|
||||
// write version
|
||||
out->WriteInt32(kSpridxfVersion_Current);
|
||||
out->WriteInt32(index.SpriteFileIDCheck);
|
||||
// write last sprite number and num sprites, to verify that
|
||||
// it matches the spr file
|
||||
out->WriteInt32(index.GetLastSlot());
|
||||
out->WriteInt32(index.GetCount());
|
||||
if (index.GetCount() > 0) {
|
||||
out->WriteArrayOfInt16(&index.Widths[0], index.Widths.size());
|
||||
out->WriteArrayOfInt16(&index.Heights[0], index.Heights.size());
|
||||
out->WriteArrayOfInt64(&index.Offsets[0], index.Offsets.size());
|
||||
}
|
||||
delete out;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SpriteFileWriter::SpriteFileWriter(std::unique_ptr<Stream> &out) : _out(out) {
|
||||
}
|
||||
|
||||
void SpriteFileWriter::Begin(int store_flags, SpriteCompression compress, sprkey_t last_slot) {
|
||||
if (!_out) return;
|
||||
_index.SpriteFileIDCheck = g_system->getMillis();
|
||||
_storeFlags = store_flags;
|
||||
_compress = compress;
|
||||
|
||||
// sprite file version
|
||||
_out->WriteInt16(kSprfVersion_Current);
|
||||
_out->WriteArray(spriteFileSig, strlen(spriteFileSig), 1);
|
||||
_out->WriteInt8(_compress ? 1 : 0);
|
||||
_out->WriteInt32(_index.SpriteFileIDCheck);
|
||||
|
||||
// Remember and write provided "last slot" index,
|
||||
// but if it's not set (< 0) then we will have to return back later
|
||||
// and write correct one; this is done in Finalize().
|
||||
_lastSlotPos = _out->GetPosition();
|
||||
_out->WriteInt32(last_slot);
|
||||
|
||||
_out->WriteInt8(_storeFlags);
|
||||
_out->WriteInt8(0); // reserved
|
||||
_out->WriteInt8(0);
|
||||
_out->WriteInt8(0);
|
||||
|
||||
if (last_slot >= 0) { // allocate buffers to store the indexing info
|
||||
sprkey_t numsprits = last_slot + 1;
|
||||
_index.Offsets.reserve(numsprits);
|
||||
_index.Widths.reserve(numsprits);
|
||||
_index.Heights.reserve(numsprits);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteFileWriter::WriteBitmap(Bitmap *image) {
|
||||
if (!_out) return;
|
||||
int bpp = image->GetBPP();
|
||||
int w = image->GetWidth();
|
||||
int h = image->GetHeight();
|
||||
ImBufferCPtr im_data(image->GetData(), w * h * bpp, bpp);
|
||||
|
||||
// (Optional) Handle storage options
|
||||
std::vector<uint8_t> indexed_buf;
|
||||
uint32_t palette[256];
|
||||
uint32_t pal_count = 0;
|
||||
SpriteFormat sformat = kSprFmt_Undefined;
|
||||
|
||||
if ((_storeFlags & kSprStore_OptimizeForSize) != 0 && (image->GetBPP() > 1)) { // Try to store this sprite as an indexed bitmap
|
||||
uint32_t gen_pal_count;
|
||||
if (CreateIndexedBitmap(image, indexed_buf, palette, gen_pal_count) && gen_pal_count > 0) { // Test the resulting size, and switch if the paletted image is less
|
||||
if (im_data.Size > (indexed_buf.size() + gen_pal_count * image->GetBPP())) {
|
||||
im_data = ImBufferCPtr(&indexed_buf[0], indexed_buf.size(), 1);
|
||||
sformat = PaletteFormatForBPP(image->GetBPP());
|
||||
pal_count = gen_pal_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
// (Optional) Compress the image data into the temp buffer
|
||||
SpriteCompression compress = kSprCompress_None;
|
||||
if (_compress != kSprCompress_Deflate)
|
||||
warning("TODO: Deflate not implemented, writing uncompressed BMP");
|
||||
else if (_compress != kSprCompress_None) {
|
||||
// TODO: rewrite this to only make a choice once the SpriteFile is initialized
|
||||
// and use either function ptr or a decompressing stream class object
|
||||
compress = _compress;
|
||||
VectorStream mems(_membuf, kStream_Write);
|
||||
bool result;
|
||||
switch (compress) {
|
||||
case kSprCompress_RLE: result = rle_compress(im_data.Buf, im_data.Size, im_data.BPP, &mems);
|
||||
break;
|
||||
case kSprCompress_LZW: result = lzw_compress(im_data.Buf, im_data.Size, im_data.BPP, &mems);
|
||||
break;
|
||||
case kSprCompress_Deflate: result = deflate_compress(im_data.Buf, im_data.Size, im_data.BPP, &mems);
|
||||
break;
|
||||
default: assert(!"Unsupported compression type!"); result = false; break;
|
||||
}
|
||||
// mark to write as a plain byte array
|
||||
im_data = result ? ImBufferCPtr(&_membuf[0], _membuf.size(), 1) : ImBufferCPtr();
|
||||
}
|
||||
|
||||
// Write the final data
|
||||
SpriteDatHeader hdr(bpp, sformat, pal_count, compress, w, h);
|
||||
WriteSpriteData(hdr, im_data.Buf, im_data.Size, im_data.BPP, palette);
|
||||
_membuf.clear();
|
||||
}
|
||||
|
||||
static inline void WriteSprHeader(const SpriteDatHeader &hdr, Stream *out) {
|
||||
out->WriteInt8(hdr.BPP);
|
||||
out->WriteInt8(hdr.SFormat);
|
||||
out->WriteInt8(hdr.PalCount > 0 ? (uint8_t)(hdr.PalCount - 1) : 0);
|
||||
out->WriteInt8(hdr.Compress);
|
||||
out->WriteInt16(hdr.Width);
|
||||
out->WriteInt16(hdr.Height);
|
||||
}
|
||||
|
||||
void SpriteFileWriter::WriteSpriteData(const SpriteDatHeader &hdr,
|
||||
const uint8_t *im_data, size_t im_data_sz, int im_bpp,
|
||||
const uint32_t palette[256]) {
|
||||
// Add index entry and write resulting data to the stream
|
||||
soff_t sproff = _out->GetPosition();
|
||||
_index.Offsets.push_back(sproff);
|
||||
_index.Widths.push_back(hdr.Width);
|
||||
_index.Heights.push_back(hdr.Height);
|
||||
WriteSprHeader(hdr, _out.get());
|
||||
// write palette, if available
|
||||
int pal_bpp = GetPaletteBPP(hdr.SFormat);
|
||||
if (pal_bpp > 0) {
|
||||
assert(hdr.PalCount > 0);
|
||||
switch (pal_bpp) {
|
||||
case 2: for (uint32_t i = 0; i < hdr.PalCount; ++i) {
|
||||
_out->WriteInt16(palette[i]);
|
||||
}
|
||||
break;
|
||||
case 4: for (uint32_t i = 0; i < hdr.PalCount; ++i) {
|
||||
_out->WriteInt32(palette[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
// write the image pixel data
|
||||
_out->WriteInt32(im_data_sz);
|
||||
switch (im_bpp) {
|
||||
case 1: _out->Write(im_data, im_data_sz);
|
||||
break;
|
||||
case 2: _out->WriteArrayOfInt16(reinterpret_cast<const int16_t *>(im_data),
|
||||
im_data_sz / sizeof(int16_t));
|
||||
break;
|
||||
case 4: _out->WriteArrayOfInt32(reinterpret_cast<const int32_t *>(im_data),
|
||||
im_data_sz / sizeof(int32_t));
|
||||
break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteFileWriter::WriteEmptySlot() {
|
||||
if (!_out) return;
|
||||
soff_t sproff = _out->GetPosition();
|
||||
_out->WriteInt16(0); // write invalid color depth to mark empty slot
|
||||
_index.Offsets.push_back(sproff);
|
||||
_index.Widths.push_back(0);
|
||||
_index.Heights.push_back(0);
|
||||
}
|
||||
|
||||
void SpriteFileWriter::WriteRawData(const SpriteDatHeader &hdr, const uint8_t *data, size_t data_sz) {
|
||||
if (!_out) return;
|
||||
soff_t sproff = _out->GetPosition();
|
||||
_index.Offsets.push_back(sproff);
|
||||
_index.Widths.push_back(hdr.Width);
|
||||
_index.Heights.push_back(hdr.Height);
|
||||
WriteSprHeader(hdr, _out.get());
|
||||
_out->Write(data, data_sz);
|
||||
}
|
||||
|
||||
void SpriteFileWriter::Finalize() {
|
||||
if (!_out || _lastSlotPos < 0) return;
|
||||
_out->Seek(_lastSlotPos, kSeekBegin);
|
||||
_out->WriteInt32(_index.GetLastSlot());
|
||||
_out.reset();
|
||||
}
|
||||
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
237
engines/ags/shared/ac/sprite_file.h
Normal file
237
engines/ags/shared/ac/sprite_file.h
Normal file
@@ -0,0 +1,237 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// SpriteFile class handles sprite file parsing and streaming sprites.
|
||||
// SpriteFileWriter manages writing sprites into the output stream one by one,
|
||||
// accumulating index information, and may therefore be suitable for a variety
|
||||
// of situations.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_SHARED_AC_SPRITE_FILE_H
|
||||
#define AGS_SHARED_AC_SPRITE_FILE_H
|
||||
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "common/std/memory.h"
|
||||
#include "common/std/vector.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
|
||||
class Bitmap;
|
||||
|
||||
// TODO: research old version differences
|
||||
enum SpriteFileVersion {
|
||||
kSprfVersion_Undefined = 0,
|
||||
kSprfVersion_Uncompressed = 4,
|
||||
kSprfVersion_Compressed = 5,
|
||||
kSprfVersion_Last32bit = 6,
|
||||
kSprfVersion_64bit = 10,
|
||||
kSprfVersion_HighSpriteLimit = 11,
|
||||
kSprfVersion_StorageFormats = 12,
|
||||
kSprfVersion_Current = kSprfVersion_StorageFormats
|
||||
};
|
||||
|
||||
enum SpriteIndexFileVersion {
|
||||
kSpridxfVersion_Initial = 1,
|
||||
kSpridxfVersion_Last32bit = 2,
|
||||
kSpridxfVersion_64bit = 10,
|
||||
kSpridxfVersion_HighSpriteLimit = 11,
|
||||
kSpridxfVersion_Current = kSpridxfVersion_HighSpriteLimit
|
||||
};
|
||||
|
||||
// Instructions to how the sprites are allowed to be stored
|
||||
enum SpriteStorage {
|
||||
// When possible convert the sprite into another format for less disk space
|
||||
// e.g. save 16/32-bit images as 8-bit colormaps with palette
|
||||
kSprStore_OptimizeForSize = 0x01
|
||||
};
|
||||
|
||||
// Format in which the sprite's pixel data is stored
|
||||
enum SpriteFormat {
|
||||
kSprFmt_Undefined = 0, // undefined, or keep as-is
|
||||
// Encoded as a 8-bit colormap with palette of 24-bit RGB values
|
||||
kSprFmt_PaletteRgb888 = 32,
|
||||
// Encoded as a 8-bit colormap with palette of 32-bit ARGB values
|
||||
kSprFmt_PaletteArgb8888 = 33,
|
||||
// Encoded as a 8-bit colormap with palette of 16-bit RGB565 values
|
||||
kSprFmt_PaletteRgb565 = 34
|
||||
};
|
||||
|
||||
enum SpriteCompression {
|
||||
kSprCompress_None = 0,
|
||||
kSprCompress_RLE,
|
||||
kSprCompress_LZW,
|
||||
kSprCompress_Deflate
|
||||
};
|
||||
|
||||
typedef int32_t sprkey_t;
|
||||
|
||||
// SpriteFileIndex contains sprite file's table of contents
|
||||
struct SpriteFileIndex {
|
||||
int SpriteFileIDCheck = 0; // tag matching sprite file and index file
|
||||
std::vector<int16_t> Widths;
|
||||
std::vector<int16_t> Heights;
|
||||
std::vector<soff_t> Offsets;
|
||||
|
||||
inline size_t GetCount() const {
|
||||
return Offsets.size();
|
||||
}
|
||||
inline sprkey_t GetLastSlot() const {
|
||||
return (sprkey_t)GetCount() - 1;
|
||||
}
|
||||
};
|
||||
|
||||
// Invidual sprite data header (as read from the file)
|
||||
struct SpriteDatHeader {
|
||||
int BPP = 0; // color depth (bytes per pixel); or input format
|
||||
SpriteFormat SFormat = kSprFmt_Undefined; // storage format
|
||||
uint32_t PalCount = 0; // palette length, if applicable to storage format
|
||||
SpriteCompression Compress = kSprCompress_None; // compression type
|
||||
int Width = 0; // sprite's width
|
||||
int Height = 0; // sprite's height
|
||||
|
||||
SpriteDatHeader() = default;
|
||||
SpriteDatHeader(int bpp, SpriteFormat sformat = kSprFmt_Undefined,
|
||||
uint32_t pal_count = 0, SpriteCompression compress = kSprCompress_None,
|
||||
int w = 0, int h = 0) : BPP(bpp), SFormat(sformat), PalCount(pal_count),
|
||||
Compress(compress), Width(w), Height(h) {
|
||||
}
|
||||
};
|
||||
|
||||
// SpriteFile opens a sprite file for reading, reports general information,
|
||||
// and lets read sprites in any order.
|
||||
class SpriteFile {
|
||||
public:
|
||||
// Standart sprite file and sprite index names
|
||||
static const char *DefaultSpriteFileName;
|
||||
static const char *DefaultSpriteIndexName;
|
||||
|
||||
SpriteFile();
|
||||
// Loads sprite reference information and inits sprite stream
|
||||
HError OpenFile(const String &filename, const String &sprindex_filename,
|
||||
std::vector<Size> &metrics);
|
||||
// Closes stream; no reading will be possible unless opened again
|
||||
void Close();
|
||||
|
||||
int GetStoreFlags() const;
|
||||
// Tells if bitmaps in the file are compressed
|
||||
SpriteCompression GetSpriteCompression() const;
|
||||
// Tells the highest known sprite index
|
||||
sprkey_t GetTopmostSprite() const;
|
||||
|
||||
// Loads sprite index file
|
||||
bool LoadSpriteIndexFile(const String &filename, int expectedFileID,
|
||||
soff_t spr_initial_offs, sprkey_t topmost, std::vector<Size> &metrics);
|
||||
// Rebuilds sprite index from the main sprite file
|
||||
HError RebuildSpriteIndex(Stream *in, sprkey_t topmost,
|
||||
std::vector<Size> &metrics);
|
||||
|
||||
// Loads an image data and creates a ready bitmap
|
||||
HError LoadSprite(sprkey_t index, Bitmap *&sprite);
|
||||
// Loads a raw sprite element data into the buffer, stores header info separately
|
||||
HError LoadRawData(sprkey_t index, SpriteDatHeader &hdr, std::vector<uint8_t> &data);
|
||||
|
||||
private:
|
||||
// Seek stream to sprite
|
||||
void SeekToSprite(sprkey_t index);
|
||||
|
||||
// Internal sprite reference
|
||||
struct SpriteRef {
|
||||
soff_t Offset = 0; // data offset
|
||||
size_t RawSize = 0; // file size of element, in bytes
|
||||
// TODO: RawSize is currently unused, due to incompleteness of spriteindex format
|
||||
};
|
||||
|
||||
// Array of sprite references
|
||||
std::vector<SpriteRef> _spriteData;
|
||||
std::unique_ptr<Stream> _stream; // the sprite stream
|
||||
SpriteFileVersion _version = kSprfVersion_Current;
|
||||
int _storeFlags = 0; // storage flags, specify how sprites may be stored
|
||||
SpriteCompression _compress = kSprCompress_None; // sprite compression typ
|
||||
sprkey_t _curPos; // current stream position (sprite slot)
|
||||
};
|
||||
|
||||
// SpriteFileWriter class writes a sprite file in a requested format.
|
||||
// Start using it by calling Begin, write ready bitmaps or copy raw sprite data
|
||||
// over slot by slot, then call Finalize to let it close the format correctly.
|
||||
class SpriteFileWriter {
|
||||
public:
|
||||
SpriteFileWriter(std::unique_ptr<Stream> &out);
|
||||
~SpriteFileWriter() {
|
||||
}
|
||||
|
||||
// Get the sprite index, accumulated after write
|
||||
const SpriteFileIndex &GetIndex() const {
|
||||
return _index;
|
||||
}
|
||||
|
||||
// Initializes new sprite file format;
|
||||
// store_flags are SpriteStorage;
|
||||
// optionally hint how many sprites will be written.
|
||||
void Begin(int store_flags, SpriteCompression compress, sprkey_t last_slot = -1);
|
||||
// Writes a bitmap into file, compressing if necessary
|
||||
void WriteBitmap(Bitmap *image);
|
||||
// Writes an empty slot marker
|
||||
void WriteEmptySlot();
|
||||
// Writes a raw sprite data without any additional processing
|
||||
void WriteRawData(const SpriteDatHeader &hdr, const uint8_t *data, size_t data_sz);
|
||||
// Finalizes current format; no further writing is possible after this
|
||||
void Finalize();
|
||||
|
||||
private:
|
||||
// Writes prepared image data in a proper file format, following explicit data_bpp rule
|
||||
void WriteSpriteData(const SpriteDatHeader &hdr,
|
||||
const uint8_t *im_data, size_t im_data_sz, int im_bpp,
|
||||
const uint32_t palette[256]);
|
||||
|
||||
std::unique_ptr<Stream> &_out;
|
||||
int _storeFlags = 0;
|
||||
SpriteCompression _compress = kSprCompress_None;
|
||||
soff_t _lastSlotPos = -1; // last slot save position in file
|
||||
// sprite index accumulated on write for reporting back to user
|
||||
SpriteFileIndex _index;
|
||||
// compression buffer
|
||||
std::vector<uint8_t> _membuf;
|
||||
};
|
||||
|
||||
// Saves all sprites to file; fills in index data for external use.
|
||||
// TODO: refactor to be able to save main file and index file separately (separate function for gather data?)
|
||||
// Accepts available sprites as pairs of bool and Bitmap pointer, where boolean value
|
||||
// tells if sprite exists and Bitmap pointer may be null;
|
||||
// If a sprite's bitmap is missing, it will try reading one from the input file stream.
|
||||
int SaveSpriteFile(const String &save_to_file,
|
||||
const std::vector<std::pair<bool, Bitmap *> > &sprites,
|
||||
SpriteFile *read_from_file, // optional file to read missing sprites from
|
||||
int store_flags, SpriteCompression compress, SpriteFileIndex &index);
|
||||
// Saves sprite index table in a separate file
|
||||
extern int SaveSpriteIndex(const String &filename, const SpriteFileIndex &index);
|
||||
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
179
engines/ags/shared/ac/view.cpp
Normal file
179
engines/ags/shared/ac/view.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
/* 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 "ags/shared/ac/view.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using AGS::Shared::Stream;
|
||||
|
||||
ViewFrame::ViewFrame()
|
||||
: pic(0)
|
||||
, xoffs(0)
|
||||
, yoffs(0)
|
||||
, speed(0)
|
||||
, flags(0)
|
||||
, sound(-1)
|
||||
, audioclip(-1) {
|
||||
reserved_for_future[0] = 0;
|
||||
reserved_for_future[1] = 0;
|
||||
}
|
||||
|
||||
void ViewFrame::ReadFromFile(Stream *in) {
|
||||
pic = in->ReadInt32();
|
||||
xoffs = in->ReadInt16();
|
||||
yoffs = in->ReadInt16();
|
||||
speed = in->ReadInt16();
|
||||
in->ReadInt16(); // alignment padding to int32
|
||||
flags = in->ReadInt32();
|
||||
sound = in->ReadInt32();
|
||||
in->ReadInt32(); // reserved 1
|
||||
in->ReadInt32(); // reserved 1
|
||||
}
|
||||
|
||||
void ViewFrame::WriteToFile(Stream *out) {
|
||||
out->WriteInt32(pic);
|
||||
out->WriteInt16(xoffs);
|
||||
out->WriteInt16(yoffs);
|
||||
out->WriteInt16(speed);
|
||||
out->WriteInt16(0); // alignment padding to int32
|
||||
out->WriteInt32(flags);
|
||||
out->WriteInt32(sound);
|
||||
out->WriteInt32(0);
|
||||
out->WriteInt32(0);
|
||||
}
|
||||
|
||||
ViewLoopNew::ViewLoopNew()
|
||||
: numFrames(0)
|
||||
, flags(0) {
|
||||
}
|
||||
|
||||
bool ViewLoopNew::RunNextLoop() {
|
||||
return (flags & LOOPFLAG_RUNNEXTLOOP);
|
||||
}
|
||||
|
||||
void ViewLoopNew::Initialize(int frameCount) {
|
||||
numFrames = frameCount;
|
||||
flags = 0;
|
||||
// an extra frame is allocated to prevent crashes with empty loops
|
||||
frames.resize(numFrames > 0 ? numFrames : 1);
|
||||
}
|
||||
|
||||
void ViewLoopNew::Dispose() {
|
||||
frames.clear();
|
||||
numFrames = 0;
|
||||
}
|
||||
|
||||
void ViewLoopNew::WriteToFile_v321(Stream *out) {
|
||||
out->WriteInt16(static_cast<uint16_t>(numFrames));
|
||||
out->WriteInt32(flags);
|
||||
WriteFrames(out);
|
||||
}
|
||||
|
||||
void ViewLoopNew::WriteFrames(Stream *out) {
|
||||
for (int i = 0; i < numFrames; ++i) {
|
||||
frames[i].WriteToFile(out);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewLoopNew::ReadFromFile_v321(Stream *in) {
|
||||
Initialize(static_cast<uint16_t>(in->ReadInt16()));
|
||||
flags = in->ReadInt32();
|
||||
ReadFrames(in);
|
||||
}
|
||||
|
||||
void ViewLoopNew::ReadFrames(Stream *in) {
|
||||
for (int i = 0; i < numFrames; ++i) {
|
||||
frames[i].ReadFromFile(in);
|
||||
}
|
||||
}
|
||||
|
||||
ViewStruct::ViewStruct()
|
||||
: numLoops(0) {
|
||||
}
|
||||
|
||||
void ViewStruct::Initialize(int loopCount) {
|
||||
numLoops = loopCount;
|
||||
loops.resize(numLoops);
|
||||
}
|
||||
|
||||
void ViewStruct::Dispose() {
|
||||
loops.clear();
|
||||
numLoops = 0;
|
||||
}
|
||||
|
||||
void ViewStruct::WriteToFile(Stream *out) {
|
||||
out->WriteInt16(static_cast<uint16_t>(numLoops));
|
||||
for (int i = 0; i < numLoops; i++) {
|
||||
loops[i].WriteToFile_v321(out);
|
||||
}
|
||||
}
|
||||
|
||||
void ViewStruct::ReadFromFile(Stream *in) {
|
||||
Initialize(static_cast<uint16_t>(in->ReadInt16()));
|
||||
|
||||
for (int i = 0; i < numLoops; i++) {
|
||||
loops[i].ReadFromFile_v321(in);
|
||||
}
|
||||
}
|
||||
|
||||
ViewStruct272::ViewStruct272()
|
||||
: numloops(0) {
|
||||
memset(numframes, 0, sizeof(numframes));
|
||||
memset(loopflags, 0, sizeof(loopflags));
|
||||
}
|
||||
|
||||
void ViewStruct272::ReadFromFile(Stream *in) {
|
||||
numloops = in->ReadInt16();
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
numframes[i] = in->ReadInt16();
|
||||
}
|
||||
in->ReadInt16(); // alignment padding to int32
|
||||
in->ReadArrayOfInt32(loopflags, 16);
|
||||
for (int j = 0; j < 16; ++j) {
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
frames[j][i].ReadFromFile(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Convert272ViewsToNew(const std::vector<ViewStruct272> &oldv, std::vector<ViewStruct> &newv) {
|
||||
for (size_t a = 0; a < oldv.size(); a++) {
|
||||
newv[a].Initialize(oldv[a].numloops);
|
||||
|
||||
for (int b = 0; b < oldv[a].numloops; b++) {
|
||||
newv[a].loops[b].Initialize(oldv[a].numframes[b]);
|
||||
|
||||
if ((oldv[a].numframes[b] > 0) &&
|
||||
(oldv[a].frames[b][oldv[a].numframes[b] - 1].pic == -1)) {
|
||||
newv[a].loops[b].flags = LOOPFLAG_RUNNEXTLOOP;
|
||||
newv[a].loops[b].numFrames--;
|
||||
} else
|
||||
newv[a].loops[b].flags = 0;
|
||||
|
||||
for (int c = 0; c < newv[a].loops[b].numFrames; c++)
|
||||
newv[a].loops[b].frames[c] = oldv[a].frames[b][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
101
engines/ags/shared/ac/view.h
Normal file
101
engines/ags/shared/ac/view.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/* 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 AGS_SHARED_AC_VIEW_H
|
||||
#define AGS_SHARED_AC_VIEW_H
|
||||
|
||||
#include "common/std/vector.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
|
||||
#define VFLG_FLIPSPRITE 1
|
||||
|
||||
struct ViewFrame {
|
||||
int pic;
|
||||
short xoffs, yoffs;
|
||||
short speed;
|
||||
int flags; // VFLG_* flags
|
||||
int sound; // play sound when this frame comes round
|
||||
int reserved_for_future[2]; // kept only for plugin api
|
||||
// not saved, set at runtime only
|
||||
int audioclip; // actual audio clip reference (in case sound is a legacy number)
|
||||
|
||||
ViewFrame();
|
||||
|
||||
void ReadFromFile(Shared::Stream *in);
|
||||
void WriteToFile(Shared::Stream *out);
|
||||
};
|
||||
|
||||
#define LOOPFLAG_RUNNEXTLOOP 1
|
||||
|
||||
struct ViewLoopNew {
|
||||
int numFrames;
|
||||
int flags;
|
||||
std::vector<ViewFrame> frames;
|
||||
// NOTE: we still need numFrames:
|
||||
// as we always allocate at least 1 frame for safety, to avoid crashes,
|
||||
// but have to report "logical" number of frames for the engine API.
|
||||
|
||||
ViewLoopNew();
|
||||
void Initialize(int frameCount);
|
||||
void Dispose();
|
||||
bool RunNextLoop();
|
||||
void WriteToFile_v321(Shared::Stream *out);
|
||||
void ReadFromFile_v321(Shared::Stream *in);
|
||||
void WriteFrames(Shared::Stream *out);
|
||||
void ReadFrames(Shared::Stream *in);
|
||||
};
|
||||
|
||||
struct ViewStruct {
|
||||
int numLoops;
|
||||
std::vector<ViewLoopNew> loops;
|
||||
|
||||
ViewStruct();
|
||||
void Initialize(int loopCount);
|
||||
void Dispose();
|
||||
void WriteToFile(Shared::Stream *out);
|
||||
void ReadFromFile(Shared::Stream *in);
|
||||
};
|
||||
|
||||
struct ViewStruct272 {
|
||||
short numloops;
|
||||
short numframes[16];
|
||||
int32_t loopflags[16];
|
||||
ViewFrame frames[16][20];
|
||||
|
||||
ViewStruct272();
|
||||
void ReadFromFile(Shared::Stream *in);
|
||||
};
|
||||
|
||||
extern void Convert272ViewsToNew(const std::vector<ViewStruct272> &oldv, std::vector<ViewStruct> &newv);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
185
engines/ags/shared/ac/words_dictionary.cpp
Normal file
185
engines/ags/shared/ac/words_dictionary.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
/* 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 "common/std/algorithm.h"
|
||||
#include "ags/shared/ac/words_dictionary.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
#include "ags/shared/util/string_compat.h"
|
||||
#include "ags/globals.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
using namespace AGS::Shared;
|
||||
|
||||
WordsDictionary::WordsDictionary()
|
||||
: num_words(0)
|
||||
, word(nullptr)
|
||||
, wordnum(nullptr) {
|
||||
}
|
||||
|
||||
WordsDictionary::~WordsDictionary() {
|
||||
free_memory();
|
||||
}
|
||||
|
||||
void WordsDictionary::allocate_memory(int wordCount) {
|
||||
num_words = wordCount;
|
||||
if (num_words > 0) {
|
||||
word = new char *[wordCount];
|
||||
word[0] = new char[wordCount * MAX_PARSER_WORD_LENGTH];
|
||||
wordnum = new short[wordCount];
|
||||
for (int i = 1; i < wordCount; i++) {
|
||||
word[i] = word[0] + MAX_PARSER_WORD_LENGTH * i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WordsDictionary::free_memory() {
|
||||
if (num_words > 0) {
|
||||
delete[] word[0];
|
||||
delete[] word;
|
||||
delete[] wordnum;
|
||||
word = nullptr;
|
||||
wordnum = nullptr;
|
||||
num_words = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WordsDictionary::sort() {
|
||||
int aa, bb;
|
||||
for (aa = 0; aa < num_words; aa++) {
|
||||
for (bb = aa + 1; bb < num_words; bb++) {
|
||||
if (((wordnum[aa] == wordnum[bb]) && (ags_stricmp(word[aa], word[bb]) > 0))
|
||||
|| (wordnum[aa] > wordnum[bb])) {
|
||||
short temp = wordnum[aa];
|
||||
char tempst[30];
|
||||
|
||||
wordnum[aa] = wordnum[bb];
|
||||
wordnum[bb] = temp;
|
||||
snprintf(tempst, MAX_PARSER_WORD_LENGTH, "%s", word[aa]);
|
||||
snprintf(word[aa], MAX_PARSER_WORD_LENGTH, "%s", word[bb]);
|
||||
snprintf(word[bb], MAX_PARSER_WORD_LENGTH, "%s", tempst);
|
||||
bb = aa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int WordsDictionary::find_index(const char *wrem) {
|
||||
int aa;
|
||||
for (aa = 0; aa < num_words; aa++) {
|
||||
if (ags_stricmp(wrem, word[aa]) == 0)
|
||||
return aa;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void decrypt_text(char *toenc, size_t buf_sz) {
|
||||
int adx = 0;
|
||||
const char *p_end = toenc + buf_sz;
|
||||
|
||||
while (toenc < p_end) {
|
||||
toenc[0] -= _G(passwencstring)[adx];
|
||||
if (toenc[0] == 0)
|
||||
break;
|
||||
|
||||
adx++;
|
||||
toenc++;
|
||||
|
||||
if (adx > 10)
|
||||
adx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void read_string_decrypt(Stream *in, char *buf, size_t buf_sz) {
|
||||
size_t len = in->ReadInt32();
|
||||
size_t slen = MIN(buf_sz - 1, len);
|
||||
in->Read(buf, slen);
|
||||
if (len > slen)
|
||||
in->Seek(len - slen);
|
||||
decrypt_text(buf, slen);
|
||||
buf[slen] = 0;
|
||||
}
|
||||
|
||||
String read_string_decrypt(Stream *in, std::vector<char> &dec_buf) {
|
||||
size_t len = in->ReadInt32();
|
||||
dec_buf.resize(len + 1);
|
||||
in->Read(dec_buf.data(), len);
|
||||
decrypt_text(dec_buf.data(), len);
|
||||
dec_buf.back() = 0; // null terminate in case read string does not have one
|
||||
return String(dec_buf.data());
|
||||
}
|
||||
|
||||
void read_dictionary(WordsDictionary *dict, Stream *out) {
|
||||
int ii;
|
||||
|
||||
dict->allocate_memory(out->ReadInt32());
|
||||
for (ii = 0; ii < dict->num_words; ii++) {
|
||||
read_string_decrypt(out, dict->word[ii], MAX_PARSER_WORD_LENGTH);
|
||||
dict->wordnum[ii] = out->ReadInt16();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (OBSOLETE)
|
||||
// TODO: not a part of wordsdictionary, move to obsoletes
|
||||
void freadmissout(short *pptr, Stream *in) {
|
||||
in->ReadArrayOfInt16(&pptr[0], 5);
|
||||
in->ReadArrayOfInt16(&pptr[7], NUM_CONDIT - 7);
|
||||
pptr[5] = pptr[6] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void encrypt_text(char *toenc) {
|
||||
int adx = 0, tobreak = 0;
|
||||
|
||||
while (tobreak == 0) {
|
||||
if (toenc[0] == 0)
|
||||
tobreak = 1;
|
||||
|
||||
toenc[0] += _G(passwencstring)[adx];
|
||||
adx++;
|
||||
toenc++;
|
||||
|
||||
if (adx > 10)
|
||||
adx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void write_string_encrypt(Stream *out, const char *s) {
|
||||
int stlent = (int)strlen(s) + 1;
|
||||
|
||||
out->WriteInt32(stlent);
|
||||
char *enc = ags_strdup(s);
|
||||
encrypt_text(enc);
|
||||
out->WriteArray(enc, stlent, 1);
|
||||
free(enc);
|
||||
}
|
||||
|
||||
void write_dictionary(WordsDictionary *dict, Stream *out) {
|
||||
int ii;
|
||||
|
||||
out->WriteInt32(dict->num_words);
|
||||
for (ii = 0; ii < dict->num_words; ii++) {
|
||||
write_string_encrypt(out, dict->word[ii]);
|
||||
out->WriteInt16(dict->wordnum[ii]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AGS3
|
||||
76
engines/ags/shared/ac/words_dictionary.h
Normal file
76
engines/ags/shared/ac/words_dictionary.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* 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 AGS_SHARED_AC_WORDS_DICTIONARY_H
|
||||
#define AGS_SHARED_AC_WORDS_DICTIONARY_H
|
||||
|
||||
#include "common/std/vector.h"
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
class Stream;
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
|
||||
using namespace AGS; // FIXME later
|
||||
|
||||
#define MAX_PARSER_WORD_LENGTH 30
|
||||
#define ANYWORD 29999
|
||||
#define RESTOFLINE 30000
|
||||
|
||||
struct WordsDictionary {
|
||||
int num_words;
|
||||
char **word;
|
||||
short *wordnum;
|
||||
|
||||
WordsDictionary();
|
||||
~WordsDictionary();
|
||||
void allocate_memory(int wordCount);
|
||||
void free_memory();
|
||||
void sort();
|
||||
int find_index(const char *);
|
||||
};
|
||||
|
||||
// Decrypts text found in the given buffer, writes back to the same buffer
|
||||
extern void decrypt_text(char *buf, size_t buf_sz);
|
||||
// Reads an encrypted string from the stream and decrypts into the provided buffer
|
||||
extern void read_string_decrypt(Shared::Stream *in, char *buf, size_t buf_sz);
|
||||
// Reads an encrypted string from the stream and returns as a string;
|
||||
// uses provided vector as a temporary decryption buffer (avoid extra allocs)
|
||||
extern Shared::String read_string_decrypt(Shared::Stream *in, std::vector<char> &dec_buf);
|
||||
extern void read_dictionary(WordsDictionary *dict, Shared::Stream *in);
|
||||
|
||||
#if defined (OBSOLETE)
|
||||
// TODO: not a part of wordsdictionary, move to obsoletes
|
||||
extern void freadmissout(short *pptr, Shared::Stream *in);
|
||||
#endif
|
||||
|
||||
extern void encrypt_text(char *toenc);
|
||||
extern void write_string_encrypt(Shared::Stream *out, const char *s);
|
||||
extern void write_dictionary(WordsDictionary *dict, Shared::Stream *out);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user