scummvm/engines/ags/shared/game/interactions.cpp
Paul Gilbert eb1e337edd AGS: Removed String's "const char*" conversion operator
From upstream 7c426674e7e53bffe9120f8ffc059b77fa03a606
2021-06-13 21:08:59 -07:00

376 lines
10 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
//include <string.h>
#include "ags/shared/ac/common.h" // quit
#include "ags/shared/game/interactions.h"
#include "ags/shared/util/aligned_stream.h"
#include "ags/shared/util/math.h"
namespace AGS3 {
using namespace AGS::Shared;
namespace AGS {
namespace Shared {
InteractionValue::InteractionValue() {
Type = kInterValLiteralInt;
Value = 0;
Extra = 0;
}
void InteractionValue::Read(Stream *in) {
Type = (InterValType)in->ReadInt8();
Value = in->ReadInt32();
Extra = in->ReadInt32();
}
void InteractionValue::Write(Stream *out) const {
out->WriteInt8(Type);
out->WriteInt32(Value);
out->WriteInt32(Extra);
}
//-----------------------------------------------------------------------------
InteractionCommand::InteractionCommand()
: Type(0)
, Parent(nullptr) {
}
InteractionCommand::InteractionCommand(const InteractionCommand &ic) {
*this = ic;
}
void InteractionCommand::Assign(const InteractionCommand &ic, InteractionCommandList *parent) {
Type = ic.Type;
memcpy(Data, ic.Data, sizeof(Data));
Children.reset(ic.Children.get() ? new InteractionCommandList(*ic.Children) : nullptr);
Parent = parent;
}
void InteractionCommand::Reset() {
Type = 0;
memset(Data, 0, sizeof(Data));
Children.reset();
Parent = nullptr;
}
void InteractionCommand::ReadValues_Aligned(Stream *in) {
AlignedStream align_s(in, Shared::kAligned_Read);
for (int i = 0; i < MAX_ACTION_ARGS; ++i) {
Data[i].Read(&align_s);
align_s.Reset();
}
}
void InteractionCommand::Read_v321(Stream *in, bool &has_children) {
in->ReadInt32(); // skip the 32-bit vtbl ptr (the old serialization peculiarity)
Type = in->ReadInt32();
ReadValues_Aligned(in);
has_children = in->ReadInt32() != 0;
in->ReadInt32(); // skip 32-bit Parent pointer
}
void InteractionCommand::WriteValues_Aligned(Stream *out) const {
AlignedStream align_s(out, Shared::kAligned_Write);
for (int i = 0; i < MAX_ACTION_ARGS; ++i) {
Data[i].Write(&align_s);
align_s.Reset();
}
}
void InteractionCommand::Write_v321(Stream *out) const {
out->WriteInt32(0); // write dummy 32-bit vtbl ptr
out->WriteInt32(Type);
WriteValues_Aligned(out);
out->WriteInt32(Children.get() ? 1 : 0);
out->WriteInt32(Parent ? 1 : 0);
}
InteractionCommand &InteractionCommand::operator = (const InteractionCommand &ic) {
Type = ic.Type;
memcpy(Data, ic.Data, sizeof(Data));
Children.reset(ic.Children.get() ? new InteractionCommandList(*ic.Children) : nullptr);
Parent = ic.Parent;
return *this;
}
//-----------------------------------------------------------------------------
InteractionCommandList::InteractionCommandList()
: TimesRun(0) {
}
InteractionCommandList::InteractionCommandList(const InteractionCommandList &icmd_list) {
TimesRun = icmd_list.TimesRun;
Cmds.resize(icmd_list.Cmds.size());
for (size_t i = 0; i < icmd_list.Cmds.size(); ++i) {
Cmds[i].Assign(icmd_list.Cmds[i], this);
}
}
void InteractionCommandList::Reset() {
Cmds.clear();
TimesRun = 0;
}
void InteractionCommandList::Read_Aligned(Stream *in, std::vector<bool> &cmd_children) {
AlignedStream align_s(in, Shared::kAligned_Read);
for (size_t i = 0; i < Cmds.size(); ++i) {
bool has_children;
Cmds[i].Read_v321(&align_s, has_children);
cmd_children[i] = has_children;
align_s.Reset();
}
}
void InteractionCommandList::Read_v321(Stream *in) {
size_t cmd_count = in->ReadInt32();
TimesRun = in->ReadInt32();
std::vector<bool> cmd_children;
Cmds.resize(cmd_count);
cmd_children.resize(cmd_count);
Read_Aligned(in, cmd_children);
for (size_t i = 0; i < cmd_count; ++i) {
if (cmd_children[i]) {
Cmds[i].Children.reset(new InteractionCommandList());
Cmds[i].Children->Read_v321(in);
}
Cmds[i].Parent = this;
}
}
void InteractionCommandList::Write_Aligned(Stream *out) const {
AlignedStream align_s(out, Shared::kAligned_Write);
for (InterCmdVector::const_iterator it = Cmds.begin(); it != Cmds.end(); ++it) {
it->Write_v321(&align_s);
align_s.Reset();
}
}
void InteractionCommandList::Write_v321(Stream *out) const {
size_t cmd_count = Cmds.size();
out->WriteInt32(cmd_count);
out->WriteInt32(TimesRun);
Write_Aligned(out);
for (size_t i = 0; i < cmd_count; ++i) {
if (Cmds[i].Children.get() != nullptr)
Cmds[i].Children->Write_v321(out);
}
}
//-----------------------------------------------------------------------------
InteractionEvent::InteractionEvent()
: Type(0)
, TimesRun(0) {
}
InteractionEvent::InteractionEvent(const InteractionEvent &ie) {
*this = ie;
}
InteractionEvent &InteractionEvent::operator = (const InteractionEvent &ie) {
Type = ie.Type;
TimesRun = ie.TimesRun;
Response.reset(ie.Response.get() ? new InteractionCommandList(*ie.Response) : nullptr);
return *this;
}
//-----------------------------------------------------------------------------
Interaction::Interaction() {
}
Interaction::Interaction(const Interaction &ni) {
*this = ni;
}
Interaction &Interaction::operator =(const Interaction &ni) {
Events.resize(ni.Events.size());
for (size_t i = 0; i < ni.Events.size(); ++i) {
Events[i] = InteractionEvent(ni.Events[i]);
}
return *this;
}
void Interaction::CopyTimesRun(const Interaction &inter) {
assert(Events.size() == inter.Events.size());
size_t count = Math::Min(Events.size(), inter.Events.size());
for (size_t i = 0; i < count; ++i) {
Events[i].TimesRun = inter.Events[i].TimesRun;
}
}
void Interaction::Reset() {
Events.clear();
}
Interaction *Interaction::CreateFromStream(Stream *in) {
if (in->ReadInt32() != kInteractionVersion_Initial)
return nullptr; // unsupported format
const size_t evt_count = in->ReadInt32();
if (evt_count > MAX_NEWINTERACTION_EVENTS)
quit("Can't deserialize interaction: too many events");
int types[MAX_NEWINTERACTION_EVENTS];
int load_response[MAX_NEWINTERACTION_EVENTS];
in->ReadArrayOfInt32(types, evt_count);
in->ReadArrayOfInt32(load_response, evt_count);
Interaction *inter = new Interaction();
inter->Events.resize(evt_count);
for (size_t i = 0; i < evt_count; ++i) {
InteractionEvent &evt = inter->Events[i];
evt.Type = types[i];
if (load_response[i] != 0) {
evt.Response.reset(new InteractionCommandList());
evt.Response->Read_v321(in);
}
}
return inter;
}
void Interaction::Write(Stream *out) const {
out->WriteInt32(kInteractionVersion_Initial); // Version
const size_t evt_count = Events.size();
out->WriteInt32(evt_count);
for (size_t i = 0; i < evt_count; ++i) {
out->WriteInt32(Events[i].Type);
}
// The pointer is only checked against NULL to determine whether the event exists
for (size_t i = 0; i < evt_count; ++i) {
out->WriteInt32(Events[i].Response.get() ? 1 : 0);
}
for (size_t i = 0; i < evt_count; ++i) {
if (Events[i].Response.get())
Events[i].Response->Write_v321(out);
}
}
void Interaction::ReadFromSavedgame_v321(Stream *in) {
const size_t evt_count = in->ReadInt32();
if (evt_count > MAX_NEWINTERACTION_EVENTS)
quit("Can't deserialize interaction: too many events");
Events.resize(evt_count);
for (size_t i = 0; i < evt_count; ++i) {
Events[i].Type = in->ReadInt32();
}
const size_t padding = (MAX_NEWINTERACTION_EVENTS - evt_count);
for (size_t i = 0; i < padding; ++i)
in->ReadInt32(); // cannot skip when reading aligned structs
ReadTimesRunFromSave_v321(in);
// Skip an array of dummy 32-bit pointers
for (size_t i = 0; i < MAX_NEWINTERACTION_EVENTS; ++i)
in->ReadInt32();
}
void Interaction::WriteToSavedgame_v321(Stream *out) const {
const size_t evt_count = Events.size();
out->WriteInt32(evt_count);
for (size_t i = 0; i < evt_count; ++i) {
out->WriteInt32(Events[i].Type);
}
out->WriteByteCount(0, (MAX_NEWINTERACTION_EVENTS - evt_count) * sizeof(int32_t));
WriteTimesRunToSave_v321(out);
// Array of dummy 32-bit pointers
out->WriteByteCount(0, MAX_NEWINTERACTION_EVENTS * sizeof(int32_t));
}
void Interaction::ReadTimesRunFromSave_v321(Stream *in) {
const size_t evt_count = Events.size();
for (size_t i = 0; i < evt_count; ++i) {
Events[i].TimesRun = in->ReadInt32();
}
const size_t padding = (MAX_NEWINTERACTION_EVENTS - evt_count);
for (size_t i = 0; i < padding; ++i)
in->ReadInt32(); // cannot skip when reading aligned structs
}
void Interaction::WriteTimesRunToSave_v321(Stream *out) const {
const size_t evt_count = Events.size();
for (size_t i = 0; i < Events.size(); ++i) {
out->WriteInt32(Events[i].TimesRun);
}
out->WriteByteCount(0, (MAX_NEWINTERACTION_EVENTS - evt_count) * sizeof(int32_t));
}
//-----------------------------------------------------------------------------
#define INTER_VAR_NAME_LENGTH 23
InteractionVariable::InteractionVariable()
: Type(0)
, Value(0) {
}
InteractionVariable::InteractionVariable(const String &name, char type, int val)
: Name(name)
, Type(type)
, Value(val) {
}
void InteractionVariable::Read(Stream *in) {
Name.ReadCount(in, INTER_VAR_NAME_LENGTH);
Type = in->ReadInt8();
Value = in->ReadInt32();
}
void InteractionVariable::Write(Shared::Stream *out) const {
out->Write(Name.GetCStr(), INTER_VAR_NAME_LENGTH);
out->WriteInt8(Type);
out->WriteInt32(Value);
}
//-----------------------------------------------------------------------------
InteractionScripts *InteractionScripts::CreateFromStream(Stream *in) {
const size_t evt_count = in->ReadInt32();
if (evt_count > MAX_NEWINTERACTION_EVENTS) {
quit("Can't deserialize interaction scripts: too many events");
return nullptr;
}
InteractionScripts *scripts = new InteractionScripts();
for (size_t i = 0; i < evt_count; ++i) {
String name = String::FromStream(in);
scripts->ScriptFuncNames.push_back(name);
}
return scripts;
}
} // namespace Shared
} // namespace AGS
} // namespace AGS3