Initial commit

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

View File

@@ -0,0 +1,73 @@
/* 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/>.
*
*/
//=============================================================================
//
// Functions related to finding and opening game assets.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_ASSET_HELPER_H
#define AGS_ENGINE_AC_ASSET_HELPER_H
#include "common/std/memory.h"
#include "common/std/utility.h"
#include "ags/shared/util/string.h"
#include "ags/shared/core/asset_manager.h"
namespace AGS3 {
struct PACKFILE;
namespace AGS {
namespace Shared {
class Stream;
} // namespace Shared
} // namespace AGS
using AGS::Shared::AssetPath;
using AGS::Shared::Stream;
using AGS::Shared::String;
// Looks for valid asset library everywhere and returns path, or empty string if failed
String find_assetlib(const String &filename);
// Returns the path to the audio asset, considering the given bundling type
AssetPath get_audio_clip_assetpath(int bundling_type, const String &filename);
// Returns the path to the voice-over asset
AssetPath get_voice_over_assetpath(const String &filename);
// Custom AGS PACKFILE user object
// TODO: it is preferrable to let our Stream define custom readable window instead,
// keeping this as simple as possible for now (we may require a stream classes overhaul).
struct AGS_PACKFILE_OBJ {
std::unique_ptr<Stream> stream;
size_t asset_size = 0u;
size_t remains = 0u;
};
// Creates PACKFILE stream from AGS asset.
// This function is supposed to be used only when you have to create Allegro
// object, passing PACKFILE stream to constructor.
PACKFILE *PackfileFromAsset(const AssetPath &path);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,333 @@
/* 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/engine/ac/audio_channel.h"
#include "ags/engine/ac/game_state.h"
#include "ags/engine/ac/global_audio.h"
#include "ags/engine/ac/dynobj/cc_audio_clip.h"
#include "ags/engine/debugging/debug_log.h"
#include "ags/shared/game/room_struct.h"
#include "ags/engine/script/runtime_script_value.h"
#include "ags/engine/media/audio/audio_system.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/shared/debugging/out.h"
#include "ags/engine/script/script_api.h"
#include "ags/engine/script/script_runtime.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
int AudioChannel_GetID(ScriptAudioChannel *channel) {
return channel->id;
}
int AudioChannel_GetIsPlaying(ScriptAudioChannel *channel) {
if (_GP(play).fast_forward) {
return 0;
}
return AudioChans::ChannelIsPlaying(channel->id) ? 1 : 0;
}
bool AudioChannel_GetIsPaused(ScriptAudioChannel *channel) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) return ch->is_paused();
return false;
}
int AudioChannel_GetPanning(ScriptAudioChannel *channel) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) {
return ch->get_panning();
}
return 0;
}
void AudioChannel_SetPanning(ScriptAudioChannel *channel, int newPanning) {
if ((newPanning < -100) || (newPanning > 100))
quitprintf("!AudioChannel.Panning: panning value must be between -100 and 100 (passed=%d)", newPanning);
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) {
ch->set_panning(newPanning);
}
}
ScriptAudioClip *AudioChannel_GetPlayingClip(ScriptAudioChannel *channel) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch && ch->_sourceClipID >= 0) {
return &_GP(game).audioClips[ch->_sourceClipID];
}
return nullptr;
}
int AudioChannel_GetPosition(ScriptAudioChannel *channel) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) {
if (_GP(play).fast_forward)
return 999999999;
return ch->get_pos();
}
return 0;
}
int AudioChannel_GetPositionMs(ScriptAudioChannel *channel) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) {
if (_GP(play).fast_forward)
return 999999999;
return ch->get_pos_ms();
}
return 0;
}
int AudioChannel_GetLengthMs(ScriptAudioChannel *channel) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) {
return ch->get_length_ms();
}
return 0;
}
int AudioChannel_GetVolume(ScriptAudioChannel *channel) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) {
return ch->get_volume100();
}
return 0;
}
int AudioChannel_SetVolume(ScriptAudioChannel *channel, int newVolume) {
if ((newVolume < 0) || (newVolume > 100))
quitprintf("!AudioChannel.Volume: new value out of range (supplied: %d, range: 0..100)", newVolume);
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) {
ch->set_volume100(newVolume);
}
return 0;
}
int AudioChannel_GetSpeed(ScriptAudioChannel *channel) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) {
return ch->get_speed();
}
return 0;
}
void AudioChannel_SetSpeed(ScriptAudioChannel *channel, int new_speed) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) {
ch->set_speed(new_speed);
}
}
void AudioChannel_Stop(ScriptAudioChannel *channel) {
if (channel->id == SCHAN_SPEECH && _GP(play).IsNonBlockingVoiceSpeech())
stop_voice_nonblocking();
else
stop_or_fade_out_channel(channel->id, -1, nullptr);
}
void AudioChannel_Pause(ScriptAudioChannel *channel) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) ch->pause();
}
void AudioChannel_Resume(ScriptAudioChannel *channel) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) ch->resume();
}
void AudioChannel_Seek(ScriptAudioChannel *channel, int newPosition) {
if (newPosition < 0)
quitprintf("!AudioChannel.Seek: invalid seek position %d", newPosition);
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch)
ch->seek(newPosition);
}
void AudioChannel_SeekMs(ScriptAudioChannel *channel, int newPosition) {
if (newPosition < 0)
quitprintf("!AudioChannel.SeekMs: invalid seek position %d", newPosition);
auto* ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch)
ch->seek_ms(newPosition);
}
void AudioChannel_SetRoomLocation(ScriptAudioChannel *channel, int xPos, int yPos) {
auto *ch = AudioChans::GetChannelIfPlaying(channel->id);
if (ch) {
int maxDist = ((xPos > _GP(thisroom).Width / 2) ? xPos : (_GP(thisroom).Width - xPos)) - AMBIENCE_FULL_DIST;
ch->_xSource = (xPos > 0) ? xPos : -1;
ch->_ySource = yPos;
ch->_maximumPossibleDistanceAway = maxDist;
if (xPos > 0) {
update_directional_sound_vol();
} else {
ch->apply_directional_modifier(0);
}
}
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
// int | ScriptAudioChannel *channel
RuntimeScriptValue Sc_AudioChannel_GetID(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioChannel, AudioChannel_GetID);
}
// int | ScriptAudioChannel *channel
RuntimeScriptValue Sc_AudioChannel_GetIsPlaying(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioChannel, AudioChannel_GetIsPlaying);
}
// int | ScriptAudioChannel *channel
RuntimeScriptValue Sc_AudioChannel_GetPanning(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioChannel, AudioChannel_GetPanning);
}
// void | ScriptAudioChannel *channel, int newPanning
RuntimeScriptValue Sc_AudioChannel_SetPanning(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptAudioChannel, AudioChannel_SetPanning);
}
// ScriptAudioClip* | ScriptAudioChannel *channel
RuntimeScriptValue Sc_AudioChannel_GetPlayingClip(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJ(ScriptAudioChannel, ScriptAudioClip, _GP(ccDynamicAudioClip), AudioChannel_GetPlayingClip);
}
// int | ScriptAudioChannel *channel
RuntimeScriptValue Sc_AudioChannel_GetPosition(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioChannel, AudioChannel_GetPosition);
}
// int | ScriptAudioChannel *channel
RuntimeScriptValue Sc_AudioChannel_GetPositionMs(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioChannel, AudioChannel_GetPositionMs);
}
// int | ScriptAudioChannel *channel
RuntimeScriptValue Sc_AudioChannel_GetLengthMs(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioChannel, AudioChannel_GetLengthMs);
}
// int | ScriptAudioChannel *channel
RuntimeScriptValue Sc_AudioChannel_GetVolume(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioChannel, AudioChannel_GetVolume);
}
// int | ScriptAudioChannel *channel, int newVolume
RuntimeScriptValue Sc_AudioChannel_SetVolume(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT_PINT(ScriptAudioChannel, AudioChannel_SetVolume);
}
// void | ScriptAudioChannel *channel
RuntimeScriptValue Sc_AudioChannel_Stop(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID(ScriptAudioChannel, AudioChannel_Stop);
}
// void | ScriptAudioChannel *channel, int newPosition
RuntimeScriptValue Sc_AudioChannel_Seek(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptAudioChannel, AudioChannel_Seek);
}
RuntimeScriptValue Sc_AudioChannel_SeekMs(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptAudioChannel, AudioChannel_SeekMs);
}
// void | ScriptAudioChannel *channel, int xPos, int yPos
RuntimeScriptValue Sc_AudioChannel_SetRoomLocation(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT2(ScriptAudioChannel, AudioChannel_SetRoomLocation);
}
RuntimeScriptValue Sc_AudioChannel_GetSpeed(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioChannel, AudioChannel_GetSpeed);
}
RuntimeScriptValue Sc_AudioChannel_SetSpeed(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptAudioChannel, AudioChannel_SetSpeed);
}
RuntimeScriptValue Sc_AudioChannel_Pause(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID(ScriptAudioChannel, AudioChannel_Pause);
}
RuntimeScriptValue Sc_AudioChannel_Resume(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID(ScriptAudioChannel, AudioChannel_Resume);
}
RuntimeScriptValue Sc_AudioChannel_GetIsPaused(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_BOOL(ScriptAudioChannel, AudioChannel_GetIsPaused);
}
void RegisterAudioChannelAPI() {
ScFnRegister audiochan_api[] = {
{"AudioChannel::Pause^0", API_FN_PAIR(AudioChannel_Pause)},
{"AudioChannel::Resume^0", API_FN_PAIR(AudioChannel_Resume)},
{"AudioChannel::Seek^1", API_FN_PAIR(AudioChannel_Seek)},
{"AudioChannel::SeekMs^1", API_FN_PAIR(AudioChannel_SeekMs)},
{"AudioChannel::SetRoomLocation^2", API_FN_PAIR(AudioChannel_SetRoomLocation)},
{"AudioChannel::Stop^0", API_FN_PAIR(AudioChannel_Stop)},
{"AudioChannel::get_ID", API_FN_PAIR(AudioChannel_GetID)},
{"AudioChannel::get_IsPaused", API_FN_PAIR(AudioChannel_GetIsPaused)},
{"AudioChannel::get_IsPlaying", API_FN_PAIR(AudioChannel_GetIsPlaying)},
{"AudioChannel::get_LengthMs", API_FN_PAIR(AudioChannel_GetLengthMs)},
{"AudioChannel::get_Panning", API_FN_PAIR(AudioChannel_GetPanning)},
{"AudioChannel::set_Panning", API_FN_PAIR(AudioChannel_SetPanning)},
{"AudioChannel::get_PlayingClip", API_FN_PAIR(AudioChannel_GetPlayingClip)},
{"AudioChannel::get_Position", API_FN_PAIR(AudioChannel_GetPosition)},
{"AudioChannel::get_PositionMs", API_FN_PAIR(AudioChannel_GetPositionMs)},
{"AudioChannel::get_Volume", API_FN_PAIR(AudioChannel_GetVolume)},
{"AudioChannel::set_Volume", API_FN_PAIR(AudioChannel_SetVolume)},
{"AudioChannel::get_Speed", API_FN_PAIR(AudioChannel_GetSpeed)},
{"AudioChannel::set_Speed", API_FN_PAIR(AudioChannel_SetSpeed)},
// For compatibility with Ahmet Kamil's (aka Gord10) custom engine
{"AudioChannel::SetSpeed^1", API_FN_PAIR(AudioChannel_SetSpeed)},
};
ccAddExternalFunctions361(audiochan_api);
}
} // namespace AGS3

View 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_ENGINE_AC_AUDIO_CHANNEL_H
#define AGS_ENGINE_AC_AUDIO_CHANNEL_H
#include "ags/shared/ac/dynobj/script_audio_clip.h"
#include "ags/engine/ac/dynobj/script_audio_channel.h"
namespace AGS3 {
int AudioChannel_GetID(ScriptAudioChannel *channel);
int AudioChannel_GetIsPlaying(ScriptAudioChannel *channel);
int AudioChannel_GetPanning(ScriptAudioChannel *channel);
void AudioChannel_SetPanning(ScriptAudioChannel *channel, int newPanning);
ScriptAudioClip *AudioChannel_GetPlayingClip(ScriptAudioChannel *channel);
int AudioChannel_GetPosition(ScriptAudioChannel *channel);
int AudioChannel_GetPositionMs(ScriptAudioChannel *channel);
int AudioChannel_GetLengthMs(ScriptAudioChannel *channel);
int AudioChannel_GetVolume(ScriptAudioChannel *channel);
int AudioChannel_SetVolume(ScriptAudioChannel *channel, int newVolume);
void AudioChannel_Stop(ScriptAudioChannel *channel);
void AudioChannel_Seek(ScriptAudioChannel *channel, int newPosition);
void AudioChannel_SeekMs(ScriptAudioChannel *channel, int newPosition);
void AudioChannel_SetRoomLocation(ScriptAudioChannel *channel, int xPos, int yPos);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,173 @@
/* 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/engine/media/audio/audio_system.h"
#include "ags/engine/ac/asset_helper.h"
#include "ags/engine/ac/audio_clip.h"
#include "ags/engine/ac/audio_channel.h"
#include "ags/shared/ac/common.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/engine/ac/string.h"
#include "ags/shared/core/asset_manager.h"
#include "ags/engine/ac/dynobj/cc_audio_channel.h"
#include "ags/engine/ac/dynobj/cc_audio_clip.h"
#include "ags/engine/ac/dynobj/script_string.h"
#include "ags/engine/script/runtime_script_value.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
int AudioClip_GetID(ScriptAudioClip *clip) {
return clip->id;
}
const char *AudioClip_GetScriptName(ScriptAudioClip *clip) {
return CreateNewScriptString(clip->scriptName);
}
int AudioClip_GetFileType(ScriptAudioClip *clip) {
return clip->fileType;
}
int AudioClip_GetType(ScriptAudioClip *clip) {
return clip->type;
}
int AudioClip_GetIsAvailable(ScriptAudioClip *clip) {
return _GP(AssetMgr)->DoesAssetExist(get_audio_clip_assetpath(clip->bundlingType, clip->fileName)) ? 1 : 0;
}
void AudioClip_Stop(ScriptAudioClip *clip) {
for (int i = NUM_SPEECH_CHANS; i < _GP(game).numGameChannels; i++) {
auto *ch = AudioChans::GetChannelIfPlaying(i);
if ((ch != nullptr) && (ch->_sourceClipID == clip->id)) {
AudioChannel_Stop(&_G(scrAudioChannel)[i]);
}
}
}
ScriptAudioChannel *AudioClip_Play(ScriptAudioClip *clip, int priority, int repeat) {
ScriptAudioChannel *sc_ch = play_audio_clip(clip, priority, repeat, 0, false);
return sc_ch;
}
ScriptAudioChannel *AudioClip_PlayFrom(ScriptAudioClip *clip, int position, int priority, int repeat) {
ScriptAudioChannel *sc_ch = play_audio_clip(clip, priority, repeat, position, false);
return sc_ch;
}
ScriptAudioChannel *AudioClip_PlayQueued(ScriptAudioClip *clip, int priority, int repeat) {
ScriptAudioChannel *sc_ch = play_audio_clip(clip, priority, repeat, 0, true);
return sc_ch;
}
ScriptAudioChannel *AudioClip_PlayOnChannel(ScriptAudioClip *clip, int chan, int priority, int repeat) {
if (chan < NUM_SPEECH_CHANS || chan >= _GP(game).numGameChannels)
quitprintf("!AudioClip.PlayOnChannel: invalid channel %d, the range is %d - %d",
chan, NUM_SPEECH_CHANS, _GP(game).numGameChannels - 1);
if (priority == SCR_NO_VALUE)
priority = clip->defaultPriority;
if (repeat == SCR_NO_VALUE)
repeat = clip->defaultRepeat;
return play_audio_clip_on_channel(chan, clip, priority, repeat, 0);
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
ScriptAudioClip *AudioClip_GetByName(const char *name) {
return static_cast<ScriptAudioClip *>(ccGetScriptObjectAddress(name, _GP(ccDynamicAudioClip).GetType()));
}
RuntimeScriptValue Sc_AudioClip_GetByName(const RuntimeScriptValue *params, int32_t param_count) {
API_SCALL_OBJ_POBJ(ScriptAudioClip, _GP(ccDynamicAudioClip), AudioClip_GetByName, const char);
}
RuntimeScriptValue Sc_AudioClip_GetID(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioClip, AudioClip_GetID);
}
RuntimeScriptValue Sc_AudioClip_GetScriptName(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJ(ScriptAudioClip, const char, _GP(myScriptStringImpl), AudioClip_GetScriptName);
}
// int | ScriptAudioClip *clip
RuntimeScriptValue Sc_AudioClip_GetFileType(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioClip, AudioClip_GetFileType);
}
// int | ScriptAudioClip *clip
RuntimeScriptValue Sc_AudioClip_GetType(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioClip, AudioClip_GetType);
}
// int | ScriptAudioClip *clip
RuntimeScriptValue Sc_AudioClip_GetIsAvailable(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptAudioClip, AudioClip_GetIsAvailable);
}
// void | ScriptAudioClip *clip
RuntimeScriptValue Sc_AudioClip_Stop(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID(ScriptAudioClip, AudioClip_Stop);
}
// ScriptAudioChannel* | ScriptAudioClip *clip, int priority, int repeat
RuntimeScriptValue Sc_AudioClip_Play(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJ_PINT2(ScriptAudioClip, ScriptAudioChannel, _GP(ccDynamicAudio), AudioClip_Play);
}
// ScriptAudioChannel* | ScriptAudioClip *clip, int position, int priority, int repeat
RuntimeScriptValue Sc_AudioClip_PlayFrom(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJ_PINT3(ScriptAudioClip, ScriptAudioChannel, _GP(ccDynamicAudio), AudioClip_PlayFrom);
}
// ScriptAudioChannel* | ScriptAudioClip *clip, int priority, int repeat
RuntimeScriptValue Sc_AudioClip_PlayQueued(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJ_PINT2(ScriptAudioClip, ScriptAudioChannel, _GP(ccDynamicAudio), AudioClip_PlayQueued);
}
RuntimeScriptValue Sc_AudioClip_PlayOnChannel(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJ_PINT3(ScriptAudioClip, ScriptAudioChannel, _GP(ccDynamicAudio), AudioClip_PlayOnChannel);
}
void RegisterAudioClipAPI() {
ScFnRegister audioclip_api[] = {
{"AudioClip::GetByName", API_FN_PAIR(AudioClip_GetByName)},
{"AudioClip::Play^2", API_FN_PAIR(AudioClip_Play)},
{"AudioClip::PlayFrom^3", API_FN_PAIR(AudioClip_PlayFrom)},
{"AudioClip::PlayQueued^2", API_FN_PAIR(AudioClip_PlayQueued)},
{"AudioClip::PlayOnChannel^3", API_FN_PAIR(AudioClip_PlayOnChannel)},
{"AudioClip::Stop^0", API_FN_PAIR(AudioClip_Stop)},
{"AudioClip::get_ID", API_FN_PAIR(AudioClip_GetID)},
{"AudioClip::get_FileType", API_FN_PAIR(AudioClip_GetFileType)},
{"AudioClip::get_IsAvailable", API_FN_PAIR(AudioClip_GetIsAvailable)},
{"AudioClip::get_ScriptName", API_FN_PAIR(AudioClip_GetScriptName)},
{"AudioClip::get_Type", API_FN_PAIR(AudioClip_GetType)},
};
ccAddExternalFunctions361(audioclip_api);
}
} // namespace AGS3

View File

@@ -0,0 +1,41 @@
/* 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_ENGINE_AC_AUDIO_CLIP_H
#define AGS_ENGINE_AC_AUDIO_CLIP_H
#include "ags/shared/ac/dynobj/script_audio_clip.h"
#include "ags/engine/ac/dynobj/script_audio_channel.h"
namespace AGS3 {
int AudioClip_GetFileType(ScriptAudioClip *clip);
int AudioClip_GetType(ScriptAudioClip *clip);
int AudioClip_GetIsAvailable(ScriptAudioClip *clip);
void AudioClip_Stop(ScriptAudioClip *clip);
ScriptAudioChannel *AudioClip_Play(ScriptAudioClip *clip, int priority, int repeat);
ScriptAudioChannel *AudioClip_PlayFrom(ScriptAudioClip *clip, int position, int priority, int repeat);
ScriptAudioChannel *AudioClip_PlayQueued(ScriptAudioClip *clip, int priority, int repeat);
ScriptAudioChannel *AudioClip_PlayOnChannel(ScriptAudioClip *clip, int chan, int priority, int repeat);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,455 @@
/* 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/engine/ac/button.h"
#include "ags/shared/ac/common.h"
#include "ags/engine/ac/gui.h"
#include "ags/shared/ac/view.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/engine/ac/global_translation.h"
#include "ags/engine/ac/object.h"
#include "ags/engine/ac/string.h"
#include "ags/engine/ac/view_frame.h"
#include "ags/engine/debugging/debug_log.h"
#include "ags/engine/gui/animating_gui_button.h"
#include "ags/shared/gui/gui_main.h"
#include "ags/shared/debugging/out.h"
#include "ags/engine/script/script_api.h"
#include "ags/engine/script/script_runtime.h"
#include "ags/engine/ac/dynobj/script_string.h"
#include "ags/engine/main/game_run.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// *** BUTTON FUNCTIONS
// Update the actual button's image from the current animation frame
void UpdateButtonState(const AnimatingGUIButton &abtn) {
// Assign view frame as normal image and reset all the rest
_GP(guibuts)[abtn.buttonid].SetImages(_GP(views)[abtn.view].loops[abtn.loop].frames[abtn.frame].pic, 0, 0);
}
void Button_Animate(GUIButton *butt, int view, int loop, int speed, int repeat, int blocking, int direction, int sframe, int volume) {
int guin = butt->ParentId;
int objn = butt->Id;
view--; // convert to internal 0-based view ID
ValidateViewAnimVLF("Button.Animate", view, loop, sframe);
ValidateViewAnimParams("Button.Animate", repeat, blocking, direction);
volume = Math::Clamp(volume, 0, 100);
// if it's already animating, stop it
FindAndRemoveButtonAnimation(guin, objn);
int but_id = _GP(guis)[guin].GetControlID(objn);
AnimatingGUIButton abtn;
abtn.ongui = guin;
abtn.onguibut = objn;
abtn.buttonid = but_id;
abtn.view = view;
abtn.loop = loop;
abtn.speed = speed;
abtn.repeat = (repeat != 0) ? ANIM_REPEAT : ANIM_ONCE; // for now, clamp to supported modes
abtn.blocking = blocking;
abtn.direction = direction;
abtn.frame = SetFirstAnimFrame(view, loop, sframe, direction);
abtn.wait = abtn.speed + _GP(views)[abtn.view].loops[abtn.loop].frames[abtn.frame].speed;
abtn.volume = volume;
_GP(animbuts).push_back(abtn);
// launch into the first frame, and play the first frame's sound
UpdateButtonState(abtn);
CheckViewFrame(abtn.view, abtn.loop, abtn.frame);
// Blocking animate
if (blocking)
GameLoopUntilButAnimEnd(guin, objn);
}
void Button_Animate4(GUIButton *butt, int view, int loop, int speed, int repeat) {
Button_Animate(butt, view, loop, speed, repeat, IN_BACKGROUND, FORWARDS, 0, 100 /* full volume */);
}
void Button_Animate7(GUIButton *butt, int view, int loop, int speed, int repeat, int blocking, int direction, int sframe) {
Button_Animate(butt, view, loop, speed, repeat, blocking, direction, sframe, 100 /* full volume */);
}
const char *Button_GetText_New(GUIButton *butt) {
return CreateNewScriptString(butt->GetText().GetCStr());
}
void Button_GetText(GUIButton *butt, char *buffer) {
snprintf(buffer, MAX_MAXSTRLEN, "%s", butt->GetText().GetCStr());
}
void Button_SetText(GUIButton *butt, const char *newtx) {
newtx = get_translation(newtx);
if (butt->GetText() != newtx) {
butt->SetText(newtx);
}
}
void Button_SetFont(GUIButton *butt, int newFont) {
if ((newFont < 0) || (newFont >= _GP(game).numfonts))
quit("!Button.Font: invalid font number.");
if (butt->Font != newFont) {
butt->Font = newFont;
butt->MarkChanged();
}
}
int Button_GetFont(GUIButton *butt) {
return butt->Font;
}
int Button_GetClipImage(GUIButton *butt) {
return butt->IsClippingImage() ? 1 : 0;
}
void Button_SetClipImage(GUIButton *butt, int newval) {
if (butt->IsClippingImage() != (newval != 0)) {
butt->SetClipImage(newval != 0);
}
}
int Button_GetGraphic(GUIButton *butt) {
// return currently displayed pic
if (butt->GetCurrentImage() < 0)
return butt->GetNormalImage();
return butt->GetCurrentImage();
}
int Button_GetMouseOverGraphic(GUIButton *butt) {
return butt->GetMouseOverImage();
}
void Button_SetMouseOverGraphic(GUIButton *guil, int slotn) {
debug_script_log("GUI %d Button %d mouseover set to slot %d", guil->ParentId, guil->Id, slotn);
slotn = std::max(0, slotn);
guil->SetMouseOverImage(slotn);
FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
}
int Button_GetNormalGraphic(GUIButton *butt) {
return butt->GetNormalImage();
}
void Button_SetNormalGraphic(GUIButton *butt, int slotn) {
debug_script_log("GUI %d Button %d normal set to slot %d", butt->ParentId, butt->Id, slotn);
slotn = std::max(0, slotn);
// NormalGraphic = 0 will turn the Button into a standard colored button
if (slotn == 0) {
butt->SetNormalImage(slotn);
}
// Any other sprite - update the clickable area to the same size as the graphic
else {
const int width = static_cast<size_t>(slotn) < _GP(game).SpriteInfos.size() ? _GP(game).SpriteInfos[slotn].Width : 0;
const int height = static_cast<size_t>(slotn) < _GP(game).SpriteInfos.size() ? _GP(game).SpriteInfos[slotn].Height : 0;
butt->SetNormalImage(slotn);
butt->SetSize(width, height);
}
FindAndRemoveButtonAnimation(butt->ParentId, butt->Id);
}
int Button_GetPushedGraphic(GUIButton *butt) {
return butt->GetPushedImage();
}
void Button_SetPushedGraphic(GUIButton *guil, int slotn) {
debug_script_log("GUI %d Button %d pushed set to slot %d", guil->ParentId, guil->Id, slotn);
slotn = std::max(0, slotn);
guil->SetPushedImage(slotn);
FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
}
int Button_GetTextColor(GUIButton *butt) {
return butt->TextColor;
}
void Button_SetTextColor(GUIButton *butt, int newcol) {
if (butt->TextColor != newcol) {
butt->TextColor = newcol;
butt->MarkChanged();
}
}
// ** start animating buttons code
size_t GetAnimatingButtonCount() {
return _GP(animbuts).size();
}
AnimatingGUIButton *GetAnimatingButtonByIndex(int idxn) {
return idxn >= 0 && (size_t)idxn < _GP(animbuts).size() ?
&_GP(animbuts)[idxn] : nullptr;
}
void AddButtonAnimation(const AnimatingGUIButton &abtn) {
_GP(animbuts).push_back(abtn);
}
// returns 1 if animation finished
bool UpdateAnimatingButton(int bu) {
AnimatingGUIButton &abtn = _GP(animbuts)[bu];
if (abtn.wait > 0) {
abtn.wait--;
return true;
}
if (!CycleViewAnim(abtn.view, abtn.loop, abtn.frame, !abtn.direction, abtn.repeat))
return false;
CheckViewFrame(abtn.view, abtn.loop, abtn.frame, abtn.volume);
abtn.wait = abtn.speed + _GP(views)[abtn.view].loops[abtn.loop].frames[abtn.frame].speed;
UpdateButtonState(abtn);
return true;
}
void StopButtonAnimation(int idxn) {
_GP(animbuts).erase(_GP(animbuts).begin() + idxn);
}
void RemoveAllButtonAnimations() {
_GP(animbuts).clear();
}
// Returns the index of the AnimatingGUIButton object corresponding to the
// given button ID; returns -1 if no such animation exists
int FindButtonAnimation(int guin, int objn) {
for (size_t i = 0; i < _GP(animbuts).size(); ++i) {
if (_GP(animbuts)[i].ongui == guin && _GP(animbuts)[i].onguibut == objn)
return i;
}
return -1;
}
void FindAndRemoveButtonAnimation(int guin, int objn) {
int idx = FindButtonAnimation(guin, objn);
if (idx >= 0)
StopButtonAnimation(idx);
}
// ** end animating buttons code
void Button_Click(GUIButton *butt, int mbut) {
process_interface_click(butt->ParentId, butt->Id, mbut);
}
bool Button_IsAnimating(GUIButton *butt) {
return FindButtonAnimation(butt->ParentId, butt->Id) >= 0;
}
// NOTE: in correspondance to similar functions for Character & Object,
// GetView returns (view index + 1), while GetLoop and GetFrame return
// zero-based index and 0 in case of no animation.
int Button_GetAnimView(GUIButton *butt) {
int idx = FindButtonAnimation(butt->ParentId, butt->Id);
return idx >= 0 ? _GP(animbuts)[idx].view + 1 : 0;
}
int Button_GetAnimLoop(GUIButton *butt) {
int idx = FindButtonAnimation(butt->ParentId, butt->Id);
return idx >= 0 ? _GP(animbuts)[idx].loop : 0;
}
int Button_GetAnimFrame(GUIButton *butt) {
int idx = FindButtonAnimation(butt->ParentId, butt->Id);
return idx >= 0 ? _GP(animbuts)[idx].frame : 0;
}
int Button_GetTextAlignment(GUIButton *butt) {
return butt->TextAlignment;
}
void Button_SetTextAlignment(GUIButton *butt, int align) {
if (butt->TextAlignment != align) {
butt->TextAlignment = (FrameAlignment)align;
butt->MarkChanged();
}
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
// void | GUIButton *butt, int view, int loop, int speed, int repeat
RuntimeScriptValue Sc_Button_Animate4(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT4(GUIButton, Button_Animate4);
}
RuntimeScriptValue Sc_Button_Animate7(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT7(GUIButton, Button_Animate7);
}
RuntimeScriptValue Sc_Button_Animate(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT8(GUIButton, Button_Animate);
}
// const char* | GUIButton *butt
RuntimeScriptValue Sc_Button_GetText_New(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJ(GUIButton, const char, _GP(myScriptStringImpl), Button_GetText_New);
}
// void | GUIButton *butt, char *buffer
RuntimeScriptValue Sc_Button_GetText(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_POBJ(GUIButton, Button_GetText, char);
}
// void | GUIButton *butt, const char *newtx
RuntimeScriptValue Sc_Button_SetText(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_POBJ(GUIButton, Button_SetText, const char);
}
// void | GUIButton *butt, int newFont
RuntimeScriptValue Sc_Button_SetFont(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(GUIButton, Button_SetFont);
}
// int | GUIButton *butt
RuntimeScriptValue Sc_Button_GetFont(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetFont);
}
// int | GUIButton *butt
RuntimeScriptValue Sc_Button_GetClipImage(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetClipImage);
}
// void | GUIButton *butt, int newval
RuntimeScriptValue Sc_Button_SetClipImage(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(GUIButton, Button_SetClipImage);
}
// int | GUIButton *butt
RuntimeScriptValue Sc_Button_GetGraphic(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetGraphic);
}
// int | GUIButton *butt
RuntimeScriptValue Sc_Button_GetMouseOverGraphic(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetMouseOverGraphic);
}
// void | GUIButton *guil, int slotn
RuntimeScriptValue Sc_Button_SetMouseOverGraphic(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(GUIButton, Button_SetMouseOverGraphic);
}
// int | GUIButton *butt
RuntimeScriptValue Sc_Button_GetNormalGraphic(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetNormalGraphic);
}
// void | GUIButton *guil, int slotn
RuntimeScriptValue Sc_Button_SetNormalGraphic(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(GUIButton, Button_SetNormalGraphic);
}
// int | GUIButton *butt
RuntimeScriptValue Sc_Button_GetPushedGraphic(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetPushedGraphic);
}
// void | GUIButton *guil, int slotn
RuntimeScriptValue Sc_Button_SetPushedGraphic(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(GUIButton, Button_SetPushedGraphic);
}
// int | GUIButton *butt
RuntimeScriptValue Sc_Button_GetTextColor(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetTextColor);
}
// void | GUIButton *butt, int newcol
RuntimeScriptValue Sc_Button_SetTextColor(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(GUIButton, Button_SetTextColor);
}
RuntimeScriptValue Sc_Button_Click(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(GUIButton, Button_Click);
}
RuntimeScriptValue Sc_Button_IsAnimating(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_BOOL(GUIButton, Button_IsAnimating);
}
RuntimeScriptValue Sc_Button_GetTextAlignment(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetTextAlignment);
}
RuntimeScriptValue Sc_Button_SetTextAlignment(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(GUIButton, Button_SetTextAlignment);
}
RuntimeScriptValue Sc_Button_GetAnimFrame(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetAnimFrame);
}
RuntimeScriptValue Sc_Button_GetAnimLoop(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetAnimLoop);
}
RuntimeScriptValue Sc_Button_GetAnimView(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(GUIButton, Button_GetAnimView);
}
void RegisterButtonAPI() {
ScFnRegister button_api[] = {
{"Button::Animate^4", API_FN_PAIR(Button_Animate4)},
{"Button::Animate^7", API_FN_PAIR(Button_Animate7)},
{"Button::Animate^8", API_FN_PAIR(Button_Animate)},
{"Button::Click^1", API_FN_PAIR(Button_Click)},
{"Button::GetText^1", API_FN_PAIR(Button_GetText)},
{"Button::SetText^1", API_FN_PAIR(Button_SetText)},
{"Button::get_TextAlignment", API_FN_PAIR(Button_GetTextAlignment)},
{"Button::set_TextAlignment", API_FN_PAIR(Button_SetTextAlignment)},
{"Button::get_Animating", API_FN_PAIR(Button_IsAnimating)},
{"Button::get_ClipImage", API_FN_PAIR(Button_GetClipImage)},
{"Button::set_ClipImage", API_FN_PAIR(Button_SetClipImage)},
{"Button::get_Font", API_FN_PAIR(Button_GetFont)},
{"Button::set_Font", API_FN_PAIR(Button_SetFont)},
{"Button::get_Frame", API_FN_PAIR(Button_GetAnimFrame)},
{"Button::get_Graphic", API_FN_PAIR(Button_GetGraphic)},
{"Button::get_Loop", API_FN_PAIR(Button_GetAnimLoop)},
{"Button::get_MouseOverGraphic", API_FN_PAIR(Button_GetMouseOverGraphic)},
{"Button::set_MouseOverGraphic", API_FN_PAIR(Button_SetMouseOverGraphic)},
{"Button::get_NormalGraphic", API_FN_PAIR(Button_GetNormalGraphic)},
{"Button::set_NormalGraphic", API_FN_PAIR(Button_SetNormalGraphic)},
{"Button::get_PushedGraphic", API_FN_PAIR(Button_GetPushedGraphic)},
{"Button::set_PushedGraphic", API_FN_PAIR(Button_SetPushedGraphic)},
{"Button::get_Text", API_FN_PAIR(Button_GetText_New)},
{"Button::set_Text", API_FN_PAIR(Button_SetText)},
{"Button::get_TextColor", API_FN_PAIR(Button_GetTextColor)},
{"Button::set_TextColor", API_FN_PAIR(Button_SetTextColor)},
{"Button::get_View", API_FN_PAIR(Button_GetAnimView)},
};
ccAddExternalFunctions361(button_api);
}
} // namespace AGS3

View File

@@ -0,0 +1,64 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AGS_ENGINE_AC_BUTTON_H
#define AGS_ENGINE_AC_BUTTON_H
#include "ags/globals.h"
#include "ags/shared/gui/gui_button.h"
namespace AGS3 {
using AGS::Shared::GUIButton;
struct AnimatingGUIButton;
void Button_Animate(GUIButton *butt, int view, int loop, int speed, int repeat, int blocking, int direction, int sframe = 0, int volume = 100);
void Button_Animate4(GUIButton *butt, int view, int loop, int speed, int repeat);
const char *Button_GetText_New(GUIButton *butt);
void Button_GetText(GUIButton *butt, char *buffer);
void Button_SetText(GUIButton *butt, const char *newtx);
void Button_SetFont(GUIButton *butt, int newFont);
int Button_GetFont(GUIButton *butt);
int Button_GetClipImage(GUIButton *butt);
void Button_SetClipImage(GUIButton *butt, int newval);
int Button_GetGraphic(GUIButton *butt);
int Button_GetMouseOverGraphic(GUIButton *butt);
void Button_SetMouseOverGraphic(GUIButton *guil, int slotn);
int Button_GetNormalGraphic(GUIButton *butt);
void Button_SetNormalGraphic(GUIButton *guil, int slotn);
int Button_GetPushedGraphic(GUIButton *butt);
void Button_SetPushedGraphic(GUIButton *guil, int slotn);
int Button_GetTextColor(GUIButton *butt);
void Button_SetTextColor(GUIButton *butt, int newcol);
// Update button's animation, returns whether the animation continues
bool UpdateAnimatingButton(int bu);
size_t GetAnimatingButtonCount();
AnimatingGUIButton *GetAnimatingButtonByIndex(int idxn);
void AddButtonAnimation(const AnimatingGUIButton &abtn);
void StopButtonAnimation(int idxn);
int FindButtonAnimation(int guin, int objn);
void FindAndRemoveButtonAnimation(int guin, int objn);
void RemoveAllButtonAnimations();
} // namespace AGS3
#endif

View 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/engine/ac/cd_audio.h"
#include "ags/engine/platform/base/ags_platform_driver.h"
#include "ags/globals.h"
namespace AGS3 {
int init_cd_player() {
_G(use_cdplayer) = 0;
return _G(platform)->InitializeCDPlayer();
}
int cd_manager(int cmdd, int datt) {
if (!_G(triedToUseCdAudioCommand)) {
_G(triedToUseCdAudioCommand) = true;
init_cd_player();
}
if (cmdd == 0) return _G(use_cdplayer);
if (_G(use_cdplayer) == 0) return 0; // ignore other commands
return _G(platform)->CDPlayerCommand(cmdd, datt);
}
} // namespace AGS3

View 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/>.
*
*/
#ifndef AGS_ENGINE_AC_CDAUDIO_H
#define AGS_ENGINE_AC_CDAUDIO_H
namespace AGS3 {
// CD Player functions
// flags returned with cd_getstatus
#define CDS_DRIVEOPEN 0x0001 // tray is open
#define CDS_DRIVELOCKED 0x0002 // tray locked shut by software
#define CDS_AUDIOSUPPORT 0x0010 // supports audio CDs
#define CDS_DRIVEEMPTY 0x0800 // no CD in drive
int init_cd_player();
int cd_manager(int cmdd, int datt);
} // namespace AGS3
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,247 @@
/* 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_ENGINE_AC_CHARACTER_H
#define AGS_ENGINE_AC_CHARACTER_H
#include "ags/shared/ac/character_info.h"
#include "ags/engine/ac/character_extras.h"
#include "ags/engine/ac/dynobj/script_object.h"
#include "ags/engine/ac/dynobj/script_inv_item.h"
#include "ags/engine/ac/dynobj/script_overlay.h"
#include "ags/engine/game/viewport.h"
#include "ags/shared/util/geometry.h"
namespace AGS3 {
// **** CHARACTER: FUNCTIONS ****
bool is_valid_character(int char_id);
// Asserts the character ID is valid,
// if not then prints a warning to the log; returns assertion result
bool AssertCharacter(const char *apiname, int char_id);
void Character_AddInventory(CharacterInfo *chaa, ScriptInvItem *invi, int addIndex);
void Character_AddWaypoint(CharacterInfo *chaa, int x, int y);
void Character_Animate(CharacterInfo *chaa, int loop, int delay, int repeat, int blocking, int direction, int sframe = 0, int volume = 100);
void Character_Animate5(CharacterInfo *chaa, int loop, int delay, int repeat, int blocking, int direction);
void Character_ChangeRoomAutoPosition(CharacterInfo *chaa, int room, int newPos);
void Character_ChangeRoom(CharacterInfo *chaa, int room, int x, int y);
void Character_ChangeRoomSetLoop(CharacterInfo *chaa, int room, int x, int y, int direction);
void Character_ChangeView(CharacterInfo *chap, int vii);
void Character_FaceDirection(CharacterInfo *char1, int direction, int blockingStyle);
void Character_FaceCharacter(CharacterInfo *char1, CharacterInfo *char2, int blockingStyle);
void Character_FaceLocation(CharacterInfo *char1, int xx, int yy, int blockingStyle);
void Character_FaceObject(CharacterInfo *char1, ScriptObject *obj, int blockingStyle);
void Character_FollowCharacter(CharacterInfo *chaa, CharacterInfo *tofollow, int distaway, int eagerness);
int Character_IsCollidingWithChar(CharacterInfo *char1, CharacterInfo *char2);
int Character_IsCollidingWithObject(CharacterInfo *chin, ScriptObject *objid);
bool Character_IsInteractionAvailable(CharacterInfo *cchar, int mood);
void Character_LockView(CharacterInfo *chap, int vii);
void Character_LockViewEx(CharacterInfo *chap, int vii, int stopMoving);
void Character_LockViewAligned(CharacterInfo *chap, int vii, int loop, int align);
void Character_LockViewAligned_Old(CharacterInfo *chap, int vii, int loop, int align);
void Character_LockViewAlignedEx(CharacterInfo *chap, int vii, int loop, int align, int stopMoving);
void Character_LockViewAlignedEx_Old(CharacterInfo *chap, int vii, int loop, int align, int stopMoving);
void Character_LockViewFrame(CharacterInfo *chaa, int view, int loop, int frame);
void Character_LockViewFrameEx(CharacterInfo *chaa, int view, int loop, int frame, int stopMoving);
void Character_LockViewOffset(CharacterInfo *chap, int vii, int xoffs, int yoffs);
void Character_LockViewOffsetEx(CharacterInfo *chap, int vii, int xoffs, int yoffs, int stopMoving);
void Character_LoseInventory(CharacterInfo *chap, ScriptInvItem *invi);
void Character_PlaceOnWalkableArea(CharacterInfo *chap);
void Character_RemoveTint(CharacterInfo *chaa);
int Character_GetHasExplicitTint(CharacterInfo *chaa);
int Character_GetHasExplicitTint_Old(CharacterInfo *ch);
void Character_Say(CharacterInfo *chaa, const char *text);
void Character_SayAt(CharacterInfo *chaa, int x, int y, int width, const char *texx);
ScriptOverlay *Character_SayBackground(CharacterInfo *chaa, const char *texx);
void Character_SetAsPlayer(CharacterInfo *chaa);
void Character_SetIdleView(CharacterInfo *chaa, int iview, int itime);
void Character_SetOption(CharacterInfo *chaa, int flag, int yesorno);
bool Character_SetProperty(CharacterInfo *chaa, const char *property, int value);
bool Character_SetTextProperty(CharacterInfo *chaa, const char *property, const char *value);
void Character_SetSpeed(CharacterInfo *chaa, int xspeed, int yspeed);
void Character_StopMoving(CharacterInfo *charp);
void Character_Tint(CharacterInfo *chaa, int red, int green, int blue, int opacity, int luminance);
void Character_Think(CharacterInfo *chaa, const char *text);
void Character_UnlockView(CharacterInfo *chaa);
void Character_UnlockViewEx(CharacterInfo *chaa, int stopMoving);
void Character_Walk(CharacterInfo *chaa, int x, int y, int blocking, int direct);
void Character_Move(CharacterInfo *chaa, int x, int y, int blocking, int direct);
void Character_WalkStraight(CharacterInfo *chaa, int xx, int yy, int blocking);
void Character_RunInteraction(CharacterInfo *chaa, int mood);
// **** CHARACTER: PROPERTIES ****
int Character_GetProperty(CharacterInfo *chaa, const char *property);
void Character_GetPropertyText(CharacterInfo *chaa, const char *property, char *bufer);
const char *Character_GetTextProperty(CharacterInfo *chaa, const char *property);
ScriptInvItem *Character_GetActiveInventory(CharacterInfo *chaa);
void Character_SetActiveInventory(CharacterInfo *chaa, ScriptInvItem *iit);
int Character_GetAnimating(CharacterInfo *chaa);
int Character_GetAnimationSpeed(CharacterInfo *chaa);
void Character_SetAnimationSpeed(CharacterInfo *chaa, int newval);
int Character_GetBaseline(CharacterInfo *chaa);
void Character_SetBaseline(CharacterInfo *chaa, int basel);
int Character_GetBlinkInterval(CharacterInfo *chaa);
void Character_SetBlinkInterval(CharacterInfo *chaa, int interval);
int Character_GetBlinkView(CharacterInfo *chaa);
void Character_SetBlinkView(CharacterInfo *chaa, int vii);
int Character_GetBlinkWhileThinking(CharacterInfo *chaa);
void Character_SetBlinkWhileThinking(CharacterInfo *chaa, int yesOrNo);
int Character_GetBlockingHeight(CharacterInfo *chaa);
void Character_SetBlockingHeight(CharacterInfo *chaa, int hit);
int Character_GetBlockingWidth(CharacterInfo *chaa);
void Character_SetBlockingWidth(CharacterInfo *chaa, int wid);
int Character_GetDiagonalWalking(CharacterInfo *chaa);
void Character_SetDiagonalWalking(CharacterInfo *chaa, int yesorno);
int Character_GetClickable(CharacterInfo *chaa);
void Character_SetClickable(CharacterInfo *chaa, int clik);
int Character_GetDestinationX(CharacterInfo *chaa);
int Character_GetDestinationY(CharacterInfo *chaa);
int Character_GetID(CharacterInfo *chaa);
int Character_GetFrame(CharacterInfo *chaa);
void Character_SetFrame(CharacterInfo *chaa, int newval);
int Character_GetIdleView(CharacterInfo *chaa);
int Character_GetIInventoryQuantity(CharacterInfo *chaa, int index);
int Character_HasInventory(CharacterInfo *chaa, ScriptInvItem *invi);
void Character_SetIInventoryQuantity(CharacterInfo *chaa, int index, int quant);
int Character_GetIgnoreLighting(CharacterInfo *chaa);
void Character_SetIgnoreLighting(CharacterInfo *chaa, int yesorno);
int Character_GetIgnoreScaling(CharacterInfo *chaa);
void Character_SetIgnoreScaling(CharacterInfo *chaa, int yesorno);
void Character_SetManualScaling(CharacterInfo *chaa, int yesorno);
int Character_GetIgnoreWalkbehinds(CharacterInfo *chaa);
void Character_SetIgnoreWalkbehinds(CharacterInfo *chaa, int yesorno);
int Character_GetMovementLinkedToAnimation(CharacterInfo *chaa);
void Character_SetMovementLinkedToAnimation(CharacterInfo *chaa, int yesorno);
int Character_GetLoop(CharacterInfo *chaa);
void Character_SetLoop(CharacterInfo *chaa, int newval);
int Character_GetMoving(CharacterInfo *chaa);
const char *Character_GetName(CharacterInfo *chaa);
void Character_SetName(CharacterInfo *chaa, const char *newName);
int Character_GetNormalView(CharacterInfo *chaa);
int Character_GetPreviousRoom(CharacterInfo *chaa);
int Character_GetRoom(CharacterInfo *chaa);
int Character_GetScaleMoveSpeed(CharacterInfo *chaa);
void Character_SetScaleMoveSpeed(CharacterInfo *chaa, int yesorno);
int Character_GetScaleVolume(CharacterInfo *chaa);
void Character_SetScaleVolume(CharacterInfo *chaa, int yesorno);
int Character_GetScaling(CharacterInfo *chaa);
void Character_SetScaling(CharacterInfo *chaa, int zoomlevel);
int Character_GetSolid(CharacterInfo *chaa);
void Character_SetSolid(CharacterInfo *chaa, int yesorno);
int Character_GetSpeaking(CharacterInfo *chaa);
int Character_GetSpeechColor(CharacterInfo *chaa);
void Character_SetSpeechColor(CharacterInfo *chaa, int ncol);
void Character_SetSpeechAnimationDelay(CharacterInfo *chaa, int newDelay);
int Character_GetSpeechView(CharacterInfo *chaa);
void Character_SetSpeechView(CharacterInfo *chaa, int vii);
int Character_GetThinkView(CharacterInfo *chaa);
void Character_SetThinkView(CharacterInfo *chaa, int vii);
int Character_GetTransparency(CharacterInfo *chaa);
void Character_SetTransparency(CharacterInfo *chaa, int trans);
int Character_GetTurnBeforeWalking(CharacterInfo *chaa);
void Character_SetTurnBeforeWalking(CharacterInfo *chaa, int yesorno);
int Character_GetView(CharacterInfo *chaa);
int Character_GetWalkSpeedX(CharacterInfo *chaa);
int Character_GetWalkSpeedY(CharacterInfo *chaa);
int Character_GetX(CharacterInfo *chaa);
void Character_SetX(CharacterInfo *chaa, int newval);
int Character_GetY(CharacterInfo *chaa);
void Character_SetY(CharacterInfo *chaa, int newval);
int Character_GetZ(CharacterInfo *chaa);
void Character_SetZ(CharacterInfo *chaa, int newval);
int Character_GetSpeakingFrame(CharacterInfo *chaa);
//=============================================================================
struct MoveList;
namespace AGS {
namespace Shared {
class Bitmap;
}
}
using namespace AGS; // FIXME later
// Configures and starts character animation.
void animate_character(CharacterInfo *chap, int loopn, int sppd, int rept, int direction = 0, int sframe = 0, int volume = 100);
// Clears up animation parameters
void stop_character_anim(CharacterInfo *chap);
void walk_character(int chac, int tox, int toy, int ignwal, bool autoWalkAnims);
int find_looporder_index(int curloop);
// returns 0 to use diagonal, 1 to not
int useDiagonal(CharacterInfo *char1);
// returns 1 normally, or 0 if they only have horizontal animations
int hasUpDownLoops(CharacterInfo *char1);
void start_character_turning(CharacterInfo *chinf, int useloop, int no_diagonal);
void fix_player_sprite(MoveList *cmls, CharacterInfo *chinf);
// Check whether two characters have walked into each other
int has_hit_another_character(int sourceChar);
int doNextCharMoveStep(CharacterInfo *chi, int &char_index, CharacterExtras *chex);
// Tells if character is currently moving, in eWalkableAreas mode
bool is_char_walking_ndirect(CharacterInfo *chi);
int find_nearest_walkable_area_within(int *xx, int *yy, int range, int step);
void find_nearest_walkable_area(int *xx, int *yy);
void FindReasonableLoopForCharacter(CharacterInfo *chap);
void walk_or_move_character(CharacterInfo *chaa, int x, int y, int blocking, int direct, bool isWalk);
int wantMoveNow(CharacterInfo *chi, CharacterExtras *chex);
void setup_player_character(int charid);
int GetCharacterFrameVolume(CharacterInfo *chi);
Shared::Bitmap *GetCharacterImage(int charid, bool *is_original = nullptr);
CharacterInfo *GetCharacterAtScreen(int xx, int yy);
// Deduces room object's scale, accounting for both manual scaling and the room region effects;
// calculates resulting sprite size.
void update_character_scale(int charid);
CharacterInfo *GetCharacterAtRoom(int x, int y);
// Get character ID at the given room coordinates
int is_pos_on_character(int xx, int yy);
void get_char_blocking_rect(int charid, int *x1, int *y1, int *width, int *y2);
// Check whether the source char is standing inside otherChar's blocking rectangle
int is_char_in_blocking_rect(int sourceChar, int otherChar, int *fromxptr, int *cwidptr);
int my_getpixel(Shared::Bitmap *blk, int x, int y);
int check_click_on_character(int xx, int yy, int mood);
void _DisplaySpeechCore(int chid, const char *displbuf);
void _DisplayThoughtCore(int chid, const char *displbuf);
void _displayspeech(const char *texx, int aschar, int xx, int yy, int widd, int isThought);
int get_character_currently_talking();
void DisplaySpeech(const char *texx, int aschar);
int update_lip_sync(int talkview, int talkloop, int *talkframeptr);
// Recalculate dynamic character properties, e.g. after restoring a game save
void restore_characters();
// Calculates character's bounding box in room coordinates (takes only in-room transform into account)
// use_frame_0 optionally tells to use frame 0 of current loop instead of current frame.
Rect GetCharacterRoomBBox(int charid, bool use_frame_0 = false);
// Find a closest viewport given character is to. Checks viewports in their order in game's array,
// and returns either first viewport character's bounding box intersects with (or rather with its camera),
// or the one that is least far away from its camera; calculated as a perpendicular distance between two AABBs.
PViewport FindNearestViewport(int charid);
// order of loops to turn character in circle from down to down
extern int turnlooporder[8];
} // namespace AGS3
#endif

View File

@@ -0,0 +1,91 @@
/* 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/engine/ac/character_extras.h"
#include "ags/engine/ac/view_frame.h"
#include "ags/shared/util/stream.h"
#include "ags/shared/util/string_utils.h"
namespace AGS3 {
using namespace AGS::Shared;
int CharacterExtras::GetEffectiveY(CharacterInfo *chi) const {
return chi->y - (chi->z * zoom_offs) / 100;
}
int CharacterExtras::GetFrameSoundVolume(CharacterInfo *chi) const {
return AGS3::CalcFrameSoundVolume(
anim_volume, cur_anim_volume,
(chi->flags & CHF_SCALEVOLUME) ? zoom : 100);
}
void CharacterExtras::CheckViewFrame(CharacterInfo *chi) {
AGS3::CheckViewFrame(chi->view, chi->loop, chi->frame, GetFrameSoundVolume(chi));
}
void CharacterExtras::ReadFromSavegame(Stream *in, CharacterSvgVersion save_ver) {
in->ReadArrayOfInt16(invorder, MAX_INVORDER);
invorder_count = in->ReadInt16();
width = in->ReadInt16();
height = in->ReadInt16();
zoom = in->ReadInt16();
xwas = in->ReadInt16();
ywas = in->ReadInt16();
tint_r = in->ReadInt16();
tint_g = in->ReadInt16();
tint_b = in->ReadInt16();
tint_level = in->ReadInt16();
tint_light = in->ReadInt16();
process_idle_this_time = in->ReadInt8();
slow_move_counter = in->ReadInt8();
animwait = in->ReadInt16();
if (save_ver >= kCharSvgVersion_36025) {
anim_volume = static_cast<uint8_t>(in->ReadInt8());
cur_anim_volume = static_cast<uint8_t>(in->ReadInt8());
in->ReadInt8(); // reserved to fill int32
in->ReadInt8();
}
}
void CharacterExtras::WriteToSavegame(Stream *out) const {
out->WriteArrayOfInt16(invorder, MAX_INVORDER);
out->WriteInt16(invorder_count);
out->WriteInt16(width);
out->WriteInt16(height);
out->WriteInt16(zoom);
out->WriteInt16(xwas);
out->WriteInt16(ywas);
out->WriteInt16(tint_r);
out->WriteInt16(tint_g);
out->WriteInt16(tint_b);
out->WriteInt16(tint_level);
out->WriteInt16(tint_light);
out->WriteInt8(process_idle_this_time);
out->WriteInt8(slow_move_counter);
out->WriteInt16(animwait);
out->WriteInt8(static_cast<uint8_t>(anim_volume));
out->WriteInt8(static_cast<uint8_t>(cur_anim_volume));
out->WriteInt8(0); // reserved to fill int32
out->WriteInt8(0);
}
} // namespace AGS3

View File

@@ -0,0 +1,95 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
//=============================================================================
//
// CharacterExtras is a separate runtime character data. Historically it was
// separated from the design-time CharacterInfo, because the latter is exposed
// to script API and plugin API in such way that its memory layout could not
// be changed at all. Although, today this is less of an issue (see comment
// to CharacterInfo).
//
// TODO: in the long run it will be beneficial to remake this into a more
// explicit runtime Character class, while perhaps keeping CharacterInfo only
// to load design-time data.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_CHARACTER_EXTRAS_H
#define AGS_ENGINE_AC_CHARACTER_EXTRAS_H
#include "ags/shared/ac/character_info.h"
#include "ags/engine/ac/runtime_defines.h"
namespace AGS3 {
// Forward declaration
namespace AGS {
namespace Shared {
class Stream;
}
}
using namespace AGS; // FIXME later
// The CharacterInfo struct size is fixed because it's exposed to script
// and plugin API, therefore new stuff has to go here
struct CharacterExtras {
short invorder[MAX_INVORDER] = {};
short invorder_count = 0;
// TODO: implement full AABB and keep updated, so that engine could rely on these cached values all time = 0;
// TODO: consider having both fixed AABB and volatile one that changes with animation frame (unless you change how anims work)
short width = 0;
short height = 0;
short zoom = 100;
short xwas = 0;
short ywas = 0;
short tint_r = 0;
short tint_g = 0;
short tint_b = 0;
short tint_level = 0;
short tint_light = 0;
int8 process_idle_this_time = 0;
int8 slow_move_counter = 0;
short animwait = 0;
int anim_volume = 100; // default animation volume (relative factor)
int cur_anim_volume = 100; // current animation sound volume (relative factor)
// Following fields are deriatives of the above (calculated from these
// and other factors), and hence are not serialized.
//
// zoom factor of sprite offsets, fixed at 100 in backwards compatible mode
int zoom_offs = 100;
int GetEffectiveY(CharacterInfo *chi) const; // return Y - Z
// Calculate wanted frame sound volume based on multiple factors
int GetFrameSoundVolume(CharacterInfo *chi) const;
// Process the current animation frame for the character:
// play linked sounds, and so forth.
void CheckViewFrame(CharacterInfo *chi);
// Read character extra data from saves.
void ReadFromSavegame(Shared::Stream *in, CharacterSvgVersion save_ver);
void WriteToSavegame(Shared::Stream *out) const;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,468 @@
/* 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/common.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/engine/ac/character.h"
#include "ags/engine/ac/character_extras.h"
#include "ags/engine/ac/game_state.h"
#include "ags/engine/ac/global_character.h"
#include "ags/engine/ac/global_game.h"
#include "ags/engine/ac/math.h"
#include "ags/engine/ac/object.h"
#include "ags/engine/ac/view_frame.h"
#include "ags/engine/debugging/debug_log.h"
#include "ags/shared/game/room_struct.h"
#include "ags/engine/main/update.h"
#include "ags/engine/media/audio/audio_system.h"
#include "ags/ags.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
#define Random __Rand
int CharacterInfo::get_baseline() const {
if (baseline < 1)
return y;
return baseline;
}
int CharacterInfo::get_blocking_top() const {
if (blocking_height > 0)
return y - blocking_height / 2;
return y - 2;
}
int CharacterInfo::get_blocking_bottom() const {
// the blocking_bottom should be 1 less than the top + height
// since the code does <= checks on it rather than < checks
if (blocking_height > 0)
return (y + (blocking_height + 1) / 2) - 1;
return y + 3;
}
void CharacterInfo::FixupCurrentLoopAndFrame() {
// If current loop property exceeds number of loops,
// or if selected loop has no frames, then try select any first loop that has frames.
// NOTE: although this may seem like a weird solution to a problem,
// we do so for backwards compatibility; this approximately emulates older games behavior.
if (view >= 0 &&
(loop >= _GP(views)[view].numLoops || _GP(views)[view].loops[loop].numFrames == 0)) {
for (loop = 0;
(loop < _GP(views)[view].numLoops) && (_GP(views)[view].loops[loop].numFrames == 0); ++loop) {
}
if (loop == _GP(views)[view].numLoops) {
// view has no frames?!
// amazingly enough there are old games that allow this to happen...
if (_G(loaded_game_file_version) >= kGameVersion_300)
quitprintf("!Character %s is assigned view %d that has no frames!", scrname, view);
loop = 0;
}
}
// If the last saved frame exceeds a new loop, then switch to frame 1
// (first walking frame) if walking, or frame 0 otherwise or if there's less than 2 frames.
int frames_in_loop = _GP(views)[view].loops[loop].numFrames;
if (frame >= frames_in_loop) {
frame = (walking > 0 && frames_in_loop > 1) ? 1 : 0;
}
}
void CharacterInfo::UpdateMoveAndAnim(int &char_index, CharacterExtras *chex, std::vector<int> &followingAsSheep) {
int res;
if (on != 1)
return;
// Turn around during walk
res = update_character_walkturning(chex);
// Fixup character's loop prior to any further logic updates
FixupCurrentLoopAndFrame();
// FIXME: refactor this nonsense!
// [IKM] Yes, it should return! upon getting RETURN_CONTINUE here
if (res == RETURN_CONTINUE) { // [IKM] now, this is one of those places...
return; // must be careful not to screw things up
}
int doing_nothing = 1;
update_character_moving(char_index, chex, doing_nothing);
// [IKM] 2012-06-28:
// Character index value is used to set up some variables in there, so I cannot just cease using it
res = update_character_animating(char_index, doing_nothing);
// [IKM] Yes, it should return! upon getting RETURN_CONTINUE here
if (res == RETURN_CONTINUE) { // [IKM] now, this is one of those places...
return; // must be careful not to screw things up
}
update_character_follower(char_index, followingAsSheep, doing_nothing);
update_character_idle(chex, doing_nothing);
chex->process_idle_this_time = 0;
}
void CharacterInfo::UpdateFollowingExactlyCharacter() {
x = _GP(game).chars[following].x;
y = _GP(game).chars[following].y;
z = _GP(game).chars[following].z;
room = _GP(game).chars[following].room;
prevroom = _GP(game).chars[following].prevroom;
int usebase = _GP(game).chars[following].get_baseline();
if (flags & CHF_BEHINDSHEPHERD)
baseline = usebase - 1;
else
baseline = usebase + 1;
}
int CharacterInfo::update_character_walkturning(CharacterExtras *chex) {
if (walking >= TURNING_AROUND) {
// Currently rotating to correct direction
if (walkwait > 0) walkwait--;
else {
// Work out which direction is next
int wantloop = find_looporder_index(loop) + 1;
// going anti-clockwise, take one before instead
if (walking >= TURNING_BACKWARDS)
wantloop -= 2;
while (1) {
if (wantloop >= 8)
wantloop = 0;
if (wantloop < 0)
wantloop = 7;
if ((turnlooporder[wantloop] >= _GP(views)[view].numLoops) ||
(_GP(views)[view].loops[turnlooporder[wantloop]].numFrames < 1) ||
((turnlooporder[wantloop] >= 4) && ((flags & CHF_NODIAGONAL) != 0))) {
if (walking >= TURNING_BACKWARDS)
wantloop--;
else
wantloop++;
} else break;
}
loop = turnlooporder[wantloop];
walking -= TURNING_AROUND;
// if still turning, wait for next frame
if (walking % TURNING_BACKWARDS >= TURNING_AROUND)
walkwait = animspeed;
else
walking = walking % TURNING_BACKWARDS;
chex->animwait = 0;
}
return RETURN_CONTINUE;
//continue;
}
return 0;
}
void CharacterInfo::update_character_moving(int &char_index, CharacterExtras *chex, int &doing_nothing) {
if ((walking > 0) && (room == _G(displayed_room))) {
if (walkwait > 0) walkwait--;
else {
flags &= ~CHF_AWAITINGMOVE;
// Move the character
int numSteps = wantMoveNow(this, chex);
if ((numSteps) && (chex->xwas != INVALID_X)) {
// if the zoom level changed mid-move, the walkcounter
// might not have come round properly - so sort it out
x = chex->xwas;
y = chex->ywas;
chex->xwas = INVALID_X;
}
int oldxp = x, oldyp = y;
for (int ff = 0; ff < abs(numSteps); ff++) {
if (doNextCharMoveStep(this, char_index, chex))
break;
if ((walking == 0) || (walking >= TURNING_AROUND))
break;
}
if (numSteps < 0) {
// very small scaling, intersperse the movement
// to stop it being jumpy
chex->xwas = x;
chex->ywas = y;
x = ((x) - oldxp) / 2 + oldxp;
y = ((y) - oldyp) / 2 + oldyp;
} else if (numSteps > 0)
chex->xwas = INVALID_X;
if ((flags & CHF_ANTIGLIDE) == 0)
walkwaitcounter++;
}
// Fixup character's loop, it may be changed when making a walk-move
FixupCurrentLoopAndFrame();
doing_nothing = 0; // still walking?
if (walking < 1) {
// Finished walking, stop and reset state
chex->process_idle_this_time = 1;
doing_nothing = 1;
walkwait = 0;
Character_StopMoving(this);
if ((flags & CHF_MOVENOTWALK) == 0) {
// use standing pic
chex->animwait = 0;
frame = 0;
chex->CheckViewFrame(this);
}
} else if (chex->animwait > 0) {
chex->animwait--;
} else {
if (flags & CHF_ANTIGLIDE)
walkwaitcounter++;
if ((flags & CHF_MOVENOTWALK) == 0) {
frame++;
if (frame >= _GP(views)[view].loops[loop].numFrames) {
// end of loop, so loop back round skipping the standing frame
frame = 1;
if (_GP(views)[view].loops[loop].numFrames < 2)
frame = 0;
}
chex->animwait = _GP(views)[view].loops[loop].frames[frame].speed + animspeed;
if (flags & CHF_ANTIGLIDE)
walkwait = chex->animwait;
else
walkwait = 0;
chex->CheckViewFrame(this);
}
}
}
}
int CharacterInfo::update_character_animating(int &aa, int &doing_nothing) {
CharacterExtras *chex = &_GP(charextra)[index_id];
// not moving, but animating
// idleleft is <0 while idle view is playing (.animating is 0)
if (((animating != 0) || (idleleft < 0)) &&
((walking == 0) || ((flags & CHF_MOVENOTWALK) != 0)) &&
(room == _G(displayed_room))) {
doing_nothing = 0;
// idle anim doesn't count as doing something
if (idleleft < 0)
doing_nothing = 1;
if (wait > 0) wait--;
else if ((_G(char_speaking) == aa) && (_GP(game).options[OPT_LIPSYNCTEXT] != 0)) {
// currently talking with lip-sync speech
int fraa = frame;
wait = update_lip_sync(view, loop, &fraa) - 1;
// closed mouth at end of sentence
// NOTE: standard lip-sync is synchronized with text timer, not voice file
if (_GP(play).speech_in_post_state ||
((_GP(play).messagetime >= 0) && (_GP(play).messagetime < _GP(play).close_mouth_speech_time)))
frame = 0;
if (frame != fraa) {
frame = fraa;
chex->CheckViewFrame(this);
}
//continue;
return RETURN_CONTINUE;
} else {
// Normal view animation
const int oldframe = frame;
bool done_anim = false;
if ((aa == _G(char_speaking)) &&
(_GP(play).speech_in_post_state ||
((!_GP(play).speech_has_voice) &&
(_GP(play).close_mouth_speech_time > 0) &&
(_GP(play).messagetime < _GP(play).close_mouth_speech_time)))) {
// finished talking - stop animation
done_anim = true;
frame = 0;
} else {
if (!CycleViewAnim(view, loop, frame, get_anim_forwards(), get_anim_repeat())) {
done_anim = true; // finished animating
// end of idle anim
if (idleleft < 0) {
// constant anim, reset (need this cos animating==0)
if (idletime == 0)
frame = 0;
// one-off anim, stop
else {
ReleaseCharacterView(aa);
idleleft = idletime;
}
}
}
}
wait = _GP(views)[view].loops[loop].frames[frame].speed;
// idle anim doesn't have speed stored cos animating==0 (TODO: investigate why?)
if (idleleft < 0)
wait += idle_anim_speed;
else
wait += get_anim_delay();
if (frame != oldframe)
chex->CheckViewFrame(this);
if (done_anim)
stop_character_anim(this);
}
}
return 0;
}
void CharacterInfo::update_character_follower(int &aa, std::vector<int> &followingAsSheep, int &doing_nothing) {
if ((following >= 0) && (followinfo == FOLLOW_ALWAYSONTOP)) {
// an always-on-top follow
followingAsSheep.push_back(aa);
}
// not moving, but should be following another character
else if ((following >= 0) && (doing_nothing == 1)) {
short distaway = (followinfo >> 8) & 0x00ff;
// no character in this room
if ((_GP(game).chars[following].on == 0) || (on == 0));
else if (room < 0) {
room++;
if (room == 0) {
// appear in the new room
room = _GP(game).chars[following].room;
x = _GP(play).entered_at_x;
y = _GP(play).entered_at_y;
}
}
// wait a bit, so we're not constantly walking
else if (Random(100) < (followinfo & 0x00ff));
// the followed character has changed room
else if ((room != _GP(game).chars[following].room)
&& (_GP(game).chars[following].on == 0))
; // do nothing if the player isn't visible
else if (room != _GP(game).chars[following].room) {
prevroom = room;
room = _GP(game).chars[following].room;
if (room == _G(displayed_room)) {
// only move to the room-entered position if coming into
// the current room
if (_GP(play).entered_at_x > (_GP(thisroom).Width - 8)) {
x = _GP(thisroom).Width + 8;
y = _GP(play).entered_at_y;
} else if (_GP(play).entered_at_x < 8) {
x = -8;
y = _GP(play).entered_at_y;
} else if (_GP(play).entered_at_y > (_GP(thisroom).Height - 8)) {
y = _GP(thisroom).Height + 8;
x = _GP(play).entered_at_x;
} else if (_GP(play).entered_at_y < _GP(thisroom).Edges.Top + 8) {
y = _GP(thisroom).Edges.Top + 1;
x = _GP(play).entered_at_x;
} else {
// not at one of the edges
// delay for a few seconds to let the player move
room = -_GP(play).follow_change_room_timer;
}
if (room >= 0) {
walk_character(aa, _GP(play).entered_at_x, _GP(play).entered_at_y, 1, true);
doing_nothing = 0;
}
}
} else if (room != _G(displayed_room)) {
// if the character is following another character and
// neither is in the current room, don't try to move
} else if ((abs(_GP(game).chars[following].x - x) > distaway + 30) ||
(abs(_GP(game).chars[following].y - y) > distaway + 30) ||
((followinfo & 0x00ff) == 0)) {
// in same room
int goxoffs = (Random(50) - 25);
// make sure he's not standing on top of the other man
if (goxoffs < 0) goxoffs -= distaway;
else goxoffs += distaway;
walk_character(aa, _GP(game).chars[following].x + goxoffs,
_GP(game).chars[following].y + (Random(50) - 25), 0, true);
doing_nothing = 0;
}
}
}
void CharacterInfo::update_character_idle(CharacterExtras *chex, int &doing_nothing) {
// no idle animation, so skip this bit
if (idleview < 1);
// currently playing idle anim
else if (idleleft < 0);
// not in the current room
else if (room != _G(displayed_room));
// they are moving or animating (or the view is locked), so
// reset idle timeout
else if ((doing_nothing == 0) || ((flags & CHF_FIXVIEW) != 0))
idleleft = idletime;
// count idle time
else if ((_G(loopcounter) % GetGameSpeed() == 0) || (chex->process_idle_this_time == 1)) {
idleleft--;
if (idleleft == -1) {
int useloop = loop;
debug_script_log("%s: Now idle (view %d)", scrname, idleview + 1);
Character_LockView(this, idleview + 1);
// SetCharView resets it to 0
idleleft = -2;
int maxLoops = _GP(views)[idleview].numLoops;
// if the char is set to "no diagonal loops", don't try
// to use diagonal idle loops either
if ((maxLoops > 4) && (useDiagonal(this)))
maxLoops = 4;
// If it's not a "swimming"-type idleanim, choose a random loop
// if there arent enough loops to do the current one.
if ((idletime > 0) && (useloop >= maxLoops)) {
do {
useloop = ::AGS::g_vm->getRandomNumber(maxLoops - 1);
// don't select a loop which is a continuation of a previous one
} while ((useloop > 0) && (_GP(views)[idleview].loops[useloop - 1].RunNextLoop()));
}
// Normal idle anim - just reset to loop 0 if not enough to
// use the current one
else if (useloop >= maxLoops)
useloop = 0;
animate_character(this, useloop, idle_anim_speed, (idletime == 0) ? 1 : 0 /* repeat */);
// don't set Animating while the idle anim plays (TODO: investigate why?)
animating = 0;
}
} // end do idle animation
}
} // namespace AGS3

View File

@@ -0,0 +1,136 @@
/* 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/engine/ac/date_time.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/engine/platform/base/ags_platform_driver.h"
#include "ags/shared/debugging/out.h"
#include "ags/engine/script/script_api.h"
#include "ags/engine/script/script_runtime.h"
#include "ags/globals.h"
namespace AGS3 {
ScriptDateTime *DateTime_Now_Core() {
ScriptDateTime *sdt = new ScriptDateTime();
_G(platform)->GetSystemTime(sdt);
return sdt;
}
ScriptDateTime *DateTime_Now() {
ScriptDateTime *sdt = DateTime_Now_Core();
ccRegisterManagedObject(sdt, sdt);
return sdt;
}
int DateTime_GetYear(ScriptDateTime *sdt) {
return sdt->year;
}
int DateTime_GetMonth(ScriptDateTime *sdt) {
return sdt->month;
}
int DateTime_GetDayOfMonth(ScriptDateTime *sdt) {
return sdt->day;
}
int DateTime_GetHour(ScriptDateTime *sdt) {
return sdt->hour;
}
int DateTime_GetMinute(ScriptDateTime *sdt) {
return sdt->minute;
}
int DateTime_GetSecond(ScriptDateTime *sdt) {
return sdt->second;
}
int DateTime_GetRawTime(ScriptDateTime *sdt) {
return sdt->rawUnixTime;
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
// ScriptDateTime* ()
RuntimeScriptValue Sc_DateTime_Now(const RuntimeScriptValue *params, int32_t param_count) {
API_SCALL_OBJAUTO(ScriptDateTime, DateTime_Now);
}
// int (ScriptDateTime *sdt)
RuntimeScriptValue Sc_DateTime_GetYear(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDateTime, DateTime_GetYear);
}
// int (ScriptDateTime *sdt)
RuntimeScriptValue Sc_DateTime_GetMonth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDateTime, DateTime_GetMonth);
}
// int (ScriptDateTime *sdt)
RuntimeScriptValue Sc_DateTime_GetDayOfMonth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDateTime, DateTime_GetDayOfMonth);
}
// int (ScriptDateTime *sdt)
RuntimeScriptValue Sc_DateTime_GetHour(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDateTime, DateTime_GetHour);
}
// int (ScriptDateTime *sdt)
RuntimeScriptValue Sc_DateTime_GetMinute(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDateTime, DateTime_GetMinute);
}
// int (ScriptDateTime *sdt)
RuntimeScriptValue Sc_DateTime_GetSecond(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDateTime, DateTime_GetSecond);
}
// int (ScriptDateTime *sdt)
RuntimeScriptValue Sc_DateTime_GetRawTime(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDateTime, DateTime_GetRawTime);
}
void RegisterDateTimeAPI() {
ScFnRegister datetime_api[] = {
{"DateTime::get_Now", API_FN_PAIR(DateTime_Now)},
{"DateTime::get_DayOfMonth", API_FN_PAIR(DateTime_GetDayOfMonth)},
{"DateTime::get_Hour", API_FN_PAIR(DateTime_GetHour)},
{"DateTime::get_Minute", API_FN_PAIR(DateTime_GetMinute)},
{"DateTime::get_Month", API_FN_PAIR(DateTime_GetMonth)},
{"DateTime::get_RawTime", API_FN_PAIR(DateTime_GetRawTime)},
{"DateTime::get_Second", API_FN_PAIR(DateTime_GetSecond)},
{"DateTime::get_Year", API_FN_PAIR(DateTime_GetYear)},
};
ccAddExternalFunctions361(datetime_api);
}
} // namespace AGS3

View File

@@ -0,0 +1,41 @@
/* 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_ENGINE_AC_DATETIME_H
#define AGS_ENGINE_AC_DATETIME_H
#include "ags/engine/ac/dynobj/script_date_time.h"
namespace AGS3 {
ScriptDateTime *DateTime_Now_Core();
ScriptDateTime *DateTime_Now();
int DateTime_GetYear(ScriptDateTime *sdt);
int DateTime_GetMonth(ScriptDateTime *sdt);
int DateTime_GetDayOfMonth(ScriptDateTime *sdt);
int DateTime_GetHour(ScriptDateTime *sdt);
int DateTime_GetMinute(ScriptDateTime *sdt);
int DateTime_GetSecond(ScriptDateTime *sdt);
int DateTime_GetRawTime(ScriptDateTime *sdt);
} // namespace AGS3
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,46 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AGS_ENGINE_AC_DIALOG_H
#define AGS_ENGINE_AC_DIALOG_H
#include "common/std/vector.h"
#include "ags/shared/ac/dialog_topic.h"
#include "ags/engine/ac/dynobj/script_dialog.h"
namespace AGS3 {
int Dialog_GetID(ScriptDialog *sd);
int Dialog_GetOptionCount(ScriptDialog *sd);
int Dialog_GetShowTextParser(ScriptDialog *sd);
const char *Dialog_GetOptionText(ScriptDialog *sd, int option);
int Dialog_DisplayOptions(ScriptDialog *sd, int sayChosenOption);
int Dialog_GetOptionState(ScriptDialog *sd, int option);
int Dialog_HasOptionBeenChosen(ScriptDialog *sd, int option);
void Dialog_SetOptionState(ScriptDialog *sd, int option, int newState);
void Dialog_Start(ScriptDialog *sd);
void do_conversation(int dlgnum);
int show_dialog_options(int dlgnum, int sayChosenOption, bool runGameLoopsInBackground);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,277 @@
/* 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/engine/ac/dialog.h"
#include "ags/shared/ac/dialog_topic.h"
#include "ags/engine/ac/dialog_options_rendering.h"
#include "ags/shared/ac/game_struct_defines.h"
#include "ags/engine/debugging/debug_log.h"
#include "ags/engine/script/runtime_script_value.h"
#include "ags/engine/ac/dynobj/cc_dialog.h"
#include "ags/shared/debugging/out.h"
#include "ags/engine/script/script_api.h"
#include "ags/engine/script/script_runtime.h"
#include "ags/globals.h"
namespace AGS3 {
// ** SCRIPT DIALOGOPTIONSRENDERING OBJECT
void DialogOptionsRendering_Update(ScriptDialogOptionsRendering *dlgOptRender) {
dlgOptRender->needRepaint = true;
}
bool DialogOptionsRendering_RunActiveOption(ScriptDialogOptionsRendering *dlgOptRender) {
dlgOptRender->chosenOptionID = dlgOptRender->activeOptionID;
return dlgOptRender->chosenOptionID >= 0;
}
int DialogOptionsRendering_GetX(ScriptDialogOptionsRendering *dlgOptRender) {
return dlgOptRender->x;
}
void DialogOptionsRendering_SetX(ScriptDialogOptionsRendering *dlgOptRender, int newX) {
dlgOptRender->x = newX;
}
int DialogOptionsRendering_GetY(ScriptDialogOptionsRendering *dlgOptRender) {
return dlgOptRender->y;
}
void DialogOptionsRendering_SetY(ScriptDialogOptionsRendering *dlgOptRender, int newY) {
dlgOptRender->y = newY;
}
int DialogOptionsRendering_GetWidth(ScriptDialogOptionsRendering *dlgOptRender) {
return dlgOptRender->width;
}
void DialogOptionsRendering_SetWidth(ScriptDialogOptionsRendering *dlgOptRender, int newWidth) {
dlgOptRender->width = newWidth;
}
int DialogOptionsRendering_GetHeight(ScriptDialogOptionsRendering *dlgOptRender) {
return dlgOptRender->height;
}
void DialogOptionsRendering_SetHeight(ScriptDialogOptionsRendering *dlgOptRender, int newHeight) {
dlgOptRender->height = newHeight;
}
int DialogOptionsRendering_GetHasAlphaChannel(ScriptDialogOptionsRendering *dlgOptRender) {
return dlgOptRender->hasAlphaChannel;
}
void DialogOptionsRendering_SetHasAlphaChannel(ScriptDialogOptionsRendering *dlgOptRender, bool hasAlphaChannel) {
dlgOptRender->hasAlphaChannel = hasAlphaChannel;
}
int DialogOptionsRendering_GetParserTextboxX(ScriptDialogOptionsRendering *dlgOptRender) {
return dlgOptRender->parserTextboxX;
}
void DialogOptionsRendering_SetParserTextboxX(ScriptDialogOptionsRendering *dlgOptRender, int newX) {
dlgOptRender->parserTextboxX = newX;
}
int DialogOptionsRendering_GetParserTextboxY(ScriptDialogOptionsRendering *dlgOptRender) {
return dlgOptRender->parserTextboxY;
}
void DialogOptionsRendering_SetParserTextboxY(ScriptDialogOptionsRendering *dlgOptRender, int newY) {
dlgOptRender->parserTextboxY = newY;
}
int DialogOptionsRendering_GetParserTextboxWidth(ScriptDialogOptionsRendering *dlgOptRender) {
return dlgOptRender->parserTextboxWidth;
}
void DialogOptionsRendering_SetParserTextboxWidth(ScriptDialogOptionsRendering *dlgOptRender, int newWidth) {
dlgOptRender->parserTextboxWidth = newWidth;
}
ScriptDialog *DialogOptionsRendering_GetDialogToRender(ScriptDialogOptionsRendering *dlgOptRender) {
return &_GP(scrDialog)[dlgOptRender->dialogID];
}
ScriptDrawingSurface *DialogOptionsRendering_GetSurface(ScriptDialogOptionsRendering *dlgOptRender) {
dlgOptRender->surfaceAccessed = true;
return dlgOptRender->surfaceToRenderTo;
}
int DialogOptionsRendering_GetActiveOptionID(ScriptDialogOptionsRendering *dlgOptRender) {
return dlgOptRender->activeOptionID + 1;
}
void DialogOptionsRendering_SetActiveOptionID(ScriptDialogOptionsRendering *dlgOptRender, int activeOptionID) {
int optionCount = _G(dialog)[_GP(scrDialog)[dlgOptRender->dialogID].id].numoptions;
if ((activeOptionID < 0) || (activeOptionID > optionCount))
quitprintf("DialogOptionsRenderingInfo.ActiveOptionID: invalid ID specified for this dialog (specified %d, valid range: 1..%d)", activeOptionID, optionCount);
if (dlgOptRender->activeOptionID != activeOptionID - 1) {
dlgOptRender->activeOptionID = activeOptionID - 1;
dlgOptRender->needRepaint = true;
}
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
RuntimeScriptValue Sc_DialogOptionsRendering_Update(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID(ScriptDialogOptionsRendering, DialogOptionsRendering_Update);
}
RuntimeScriptValue Sc_DialogOptionsRendering_RunActiveOption(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_BOOL(ScriptDialogOptionsRendering, DialogOptionsRendering_RunActiveOption);
}
// int (ScriptDialogOptionsRendering *dlgOptRender)
RuntimeScriptValue Sc_DialogOptionsRendering_GetActiveOptionID(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDialogOptionsRendering, DialogOptionsRendering_GetActiveOptionID);
}
// void (ScriptDialogOptionsRendering *dlgOptRender, int activeOptionID)
RuntimeScriptValue Sc_DialogOptionsRendering_SetActiveOptionID(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDialogOptionsRendering, DialogOptionsRendering_SetActiveOptionID);
}
// ScriptDialog* (ScriptDialogOptionsRendering *dlgOptRender)
RuntimeScriptValue Sc_DialogOptionsRendering_GetDialogToRender(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJ(ScriptDialogOptionsRendering, ScriptDialog, _GP(ccDynamicDialog), DialogOptionsRendering_GetDialogToRender);
}
// int (ScriptDialogOptionsRendering *dlgOptRender)
RuntimeScriptValue Sc_DialogOptionsRendering_GetHeight(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDialogOptionsRendering, DialogOptionsRendering_GetHeight);
}
// void (ScriptDialogOptionsRendering *dlgOptRender, int newHeight)
RuntimeScriptValue Sc_DialogOptionsRendering_SetHeight(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDialogOptionsRendering, DialogOptionsRendering_SetHeight);
}
// int (ScriptDialogOptionsRendering *dlgOptRender)
RuntimeScriptValue Sc_DialogOptionsRendering_GetParserTextboxX(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDialogOptionsRendering, DialogOptionsRendering_GetParserTextboxX);
}
// void (ScriptDialogOptionsRendering *dlgOptRender, int newX)
RuntimeScriptValue Sc_DialogOptionsRendering_SetParserTextboxX(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDialogOptionsRendering, DialogOptionsRendering_SetParserTextboxX);
}
// int (ScriptDialogOptionsRendering *dlgOptRender)
RuntimeScriptValue Sc_DialogOptionsRendering_GetParserTextboxY(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDialogOptionsRendering, DialogOptionsRendering_GetParserTextboxY);
}
// void (ScriptDialogOptionsRendering *dlgOptRender, int newY)
RuntimeScriptValue Sc_DialogOptionsRendering_SetParserTextboxY(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDialogOptionsRendering, DialogOptionsRendering_SetParserTextboxY);
}
// int (ScriptDialogOptionsRendering *dlgOptRender)
RuntimeScriptValue Sc_DialogOptionsRendering_GetParserTextboxWidth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDialogOptionsRendering, DialogOptionsRendering_GetParserTextboxWidth);
}
// void (ScriptDialogOptionsRendering *dlgOptRender, int newWidth)
RuntimeScriptValue Sc_DialogOptionsRendering_SetParserTextboxWidth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDialogOptionsRendering, DialogOptionsRendering_SetParserTextboxWidth);
}
// ScriptDrawingSurface* (ScriptDialogOptionsRendering *dlgOptRender)
RuntimeScriptValue Sc_DialogOptionsRendering_GetSurface(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJAUTO(ScriptDialogOptionsRendering, ScriptDrawingSurface, DialogOptionsRendering_GetSurface);
}
// int (ScriptDialogOptionsRendering *dlgOptRender)
RuntimeScriptValue Sc_DialogOptionsRendering_GetWidth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDialogOptionsRendering, DialogOptionsRendering_GetWidth);
}
// void (ScriptDialogOptionsRendering *dlgOptRender, int newWidth)
RuntimeScriptValue Sc_DialogOptionsRendering_SetWidth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDialogOptionsRendering, DialogOptionsRendering_SetWidth);
}
// int (ScriptDialogOptionsRendering *dlgOptRender)
RuntimeScriptValue Sc_DialogOptionsRendering_GetX(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDialogOptionsRendering, DialogOptionsRendering_GetX);
}
// void (ScriptDialogOptionsRendering *dlgOptRender, int newX)
RuntimeScriptValue Sc_DialogOptionsRendering_SetX(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDialogOptionsRendering, DialogOptionsRendering_SetX);
}
// int (ScriptDialogOptionsRendering *dlgOptRender)
RuntimeScriptValue Sc_DialogOptionsRendering_GetY(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDialogOptionsRendering, DialogOptionsRendering_GetY);
}
// void (ScriptDialogOptionsRendering *dlgOptRender, int newY)
RuntimeScriptValue Sc_DialogOptionsRendering_SetY(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDialogOptionsRendering, DialogOptionsRendering_SetY);
}
RuntimeScriptValue Sc_DialogOptionsRendering_GetHasAlphaChannel(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDialogOptionsRendering, DialogOptionsRendering_GetHasAlphaChannel);
}
RuntimeScriptValue Sc_DialogOptionsRendering_SetHasAlphaChannel(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PBOOL(ScriptDialogOptionsRendering, DialogOptionsRendering_SetHasAlphaChannel);
}
void RegisterDialogOptionsRenderingAPI() {
ScFnRegister dialogopt_api[] = {
{"DialogOptionsRenderingInfo::Update^0", API_FN_PAIR(DialogOptionsRendering_Update)},
{"DialogOptionsRenderingInfo::RunActiveOption^0", API_FN_PAIR(DialogOptionsRendering_RunActiveOption)},
{"DialogOptionsRenderingInfo::get_ActiveOptionID", API_FN_PAIR(DialogOptionsRendering_GetActiveOptionID)},
{"DialogOptionsRenderingInfo::set_ActiveOptionID", API_FN_PAIR(DialogOptionsRendering_SetActiveOptionID)},
{"DialogOptionsRenderingInfo::get_DialogToRender", API_FN_PAIR(DialogOptionsRendering_GetDialogToRender)},
{"DialogOptionsRenderingInfo::get_Height", API_FN_PAIR(DialogOptionsRendering_GetHeight)},
{"DialogOptionsRenderingInfo::set_Height", API_FN_PAIR(DialogOptionsRendering_SetHeight)},
{"DialogOptionsRenderingInfo::get_ParserTextBoxX", API_FN_PAIR(DialogOptionsRendering_GetParserTextboxX)},
{"DialogOptionsRenderingInfo::set_ParserTextBoxX", API_FN_PAIR(DialogOptionsRendering_SetParserTextboxX)},
{"DialogOptionsRenderingInfo::get_ParserTextBoxY", API_FN_PAIR(DialogOptionsRendering_GetParserTextboxY)},
{"DialogOptionsRenderingInfo::set_ParserTextBoxY", API_FN_PAIR(DialogOptionsRendering_SetParserTextboxY)},
{"DialogOptionsRenderingInfo::get_ParserTextBoxWidth", API_FN_PAIR(DialogOptionsRendering_GetParserTextboxWidth)},
{"DialogOptionsRenderingInfo::set_ParserTextBoxWidth", API_FN_PAIR(DialogOptionsRendering_SetParserTextboxWidth)},
{"DialogOptionsRenderingInfo::get_Surface", API_FN_PAIR(DialogOptionsRendering_GetSurface)},
{"DialogOptionsRenderingInfo::get_Width", API_FN_PAIR(DialogOptionsRendering_GetWidth)},
{"DialogOptionsRenderingInfo::set_Width", API_FN_PAIR(DialogOptionsRendering_SetWidth)},
{"DialogOptionsRenderingInfo::get_X", API_FN_PAIR(DialogOptionsRendering_GetX)},
{"DialogOptionsRenderingInfo::set_X", API_FN_PAIR(DialogOptionsRendering_SetX)},
{"DialogOptionsRenderingInfo::get_Y", API_FN_PAIR(DialogOptionsRendering_GetY)},
{"DialogOptionsRenderingInfo::set_Y", API_FN_PAIR(DialogOptionsRendering_SetY)},
{"DialogOptionsRenderingInfo::get_HasAlphaChannel", API_FN_PAIR(DialogOptionsRendering_GetHasAlphaChannel)},
{"DialogOptionsRenderingInfo::set_HasAlphaChannel", API_FN_PAIR(DialogOptionsRendering_SetHasAlphaChannel)},
};
ccAddExternalFunctions361(dialogopt_api);
}
} // namespace AGS3

View File

@@ -0,0 +1,53 @@
/* 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_ENGINE_AC_DIALOG_OPTIONS_RENDERING_H
#define AGS_ENGINE_AC_DIALOG_OPTIONS_RENDERING_H
#include "ags/engine/ac/dynobj/script_dialog.h"
#include "ags/engine/ac/dynobj/script_dialog_options_rendering.h"
namespace AGS3 {
int DialogOptionsRendering_GetX(ScriptDialogOptionsRendering *dlgOptRender);
void DialogOptionsRendering_SetX(ScriptDialogOptionsRendering *dlgOptRender, int newX);
int DialogOptionsRendering_GetY(ScriptDialogOptionsRendering *dlgOptRender);
void DialogOptionsRendering_SetY(ScriptDialogOptionsRendering *dlgOptRender, int newY);
int DialogOptionsRendering_GetWidth(ScriptDialogOptionsRendering *dlgOptRender);
void DialogOptionsRendering_SetWidth(ScriptDialogOptionsRendering *dlgOptRender, int newWidth);
int DialogOptionsRendering_GetHeight(ScriptDialogOptionsRendering *dlgOptRender);
void DialogOptionsRendering_SetHeight(ScriptDialogOptionsRendering *dlgOptRender, int newHeight);
int DialogOptionsRendering_GetHasAlphaChannel(ScriptDialogOptionsRendering *dlgOptRender);
void DialogOptionsRendering_SetHasAlphaChannel(ScriptDialogOptionsRendering *dlgOptRender, bool hasAlphaChannel);
int DialogOptionsRendering_GetParserTextboxX(ScriptDialogOptionsRendering *dlgOptRender);
void DialogOptionsRendering_SetParserTextboxX(ScriptDialogOptionsRendering *dlgOptRender, int newX);
int DialogOptionsRendering_GetParserTextboxY(ScriptDialogOptionsRendering *dlgOptRender);
void DialogOptionsRendering_SetParserTextboxY(ScriptDialogOptionsRendering *dlgOptRender, int newY);
int DialogOptionsRendering_GetParserTextboxWidth(ScriptDialogOptionsRendering *dlgOptRender);
void DialogOptionsRendering_SetParserTextboxWidth(ScriptDialogOptionsRendering *dlgOptRender, int newWidth);
ScriptDialog *DialogOptionsRendering_GetDialogToRender(ScriptDialogOptionsRendering *dlgOptRender);
ScriptDrawingSurface *DialogOptionsRendering_GetSurface(ScriptDialogOptionsRendering *dlgOptRender);
int DialogOptionsRendering_GetActiveOptionID(ScriptDialogOptionsRendering *dlgOptRender);
void DialogOptionsRendering_SetActiveOptionID(ScriptDialogOptionsRendering *dlgOptRender, int activeOptionID);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,799 @@
/* 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/config-manager.h"
#include "common/std/algorithm.h"
#include "ags/engine/ac/display.h"
#include "ags/shared/ac/common.h"
#include "ags/shared/font/ags_font_renderer.h"
#include "ags/shared/font/fonts.h"
#include "ags/engine/ac/character.h"
#include "ags/engine/ac/draw.h"
#include "ags/engine/ac/game.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/engine/ac/game_state.h"
#include "ags/engine/ac/global_audio.h"
#include "ags/engine/ac/global_game.h"
#include "ags/engine/ac/gui.h"
#include "ags/engine/ac/mouse.h"
#include "ags/engine/ac/overlay.h"
#include "ags/engine/ac/sys_events.h"
#include "ags/engine/ac/screen_overlay.h"
#include "ags/engine/ac/speech.h"
#include "ags/engine/ac/string.h"
#include "ags/engine/ac/system.h"
#include "ags/engine/ac/top_bar_settings.h"
#include "ags/engine/debugging/debug_log.h"
#include "ags/engine/gfx/blender.h"
#include "ags/shared/gui/gui_button.h"
#include "ags/shared/gui/gui_main.h"
#include "ags/engine/main/game_run.h"
#include "ags/engine/platform/base/ags_platform_driver.h"
#include "ags/shared/ac/sprite_cache.h"
#include "ags/engine/gfx/gfx_util.h"
#include "ags/shared/util/string_utils.h"
#include "ags/engine/ac/mouse.h"
#include "ags/engine/media/audio/audio_system.h"
#include "ags/engine/ac/timer.h"
#include "ags/ags.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
using namespace AGS::Shared::BitmapHelper;
struct DisplayVars {
int linespacing = 0; // font's line spacing
int fulltxtheight = 0; // total height of all the text
} disp;
// Generates a textual image and returns a disposable bitmap
Bitmap *create_textual_image(const char *text, int asspch, int isThought,
int &xx, int &yy, int &adjustedXX, int &adjustedYY, int wii, int usingfont, int allowShrink,
bool &alphaChannel) {
//
// Configure the textual image
//
const bool use_speech_textwindow = (asspch < 0) && (_GP(game).options[OPT_SPEECHTYPE] >= 2);
const bool use_thought_gui = (isThought) && (_GP(game).options[OPT_THOUGHTGUI] > 0);
alphaChannel = false;
int usingGui = -1;
if (use_speech_textwindow)
usingGui = _GP(play).speech_textwindow_gui;
else if (use_thought_gui)
usingGui = _GP(game).options[OPT_THOUGHTGUI];
const int padding = get_textwindow_padding(usingGui);
const int paddingScaled = get_fixed_pixel_size(padding);
// Just in case screen size is not neatly divisible by 320x200
const int paddingDoubledScaled = get_fixed_pixel_size(padding * 2);
// WORKAROUND: Guard Duty specifies a wii of 100,000, which is larger
// than can be supported by ScummVM's surface classes
wii = MIN(wii, 8000);
// Make message copy, because ensure_text_valid_for_font() may modify it
char todis[STD_BUFFER_SIZE];
snprintf(todis, STD_BUFFER_SIZE - 1, "%s", text);
ensure_text_valid_for_font(todis, usingfont);
break_up_text_into_lines(todis, _GP(Lines), wii - 2 * padding, usingfont);
disp.linespacing = get_font_linespacing(usingfont);
disp.fulltxtheight = get_text_lines_surf_height(usingfont, _GP(Lines).Count());
if (_GP(topBar).wantIt) {
// ensure that the window is wide enough to display any top bar text
int topBarWid = get_text_width_outlined(_GP(topBar).text, _GP(topBar).font);
topBarWid += data_to_game_coord(_GP(play).top_bar_borderwidth + 2) * 2;
if (_G(longestline) < topBarWid)
_G(longestline) = topBarWid;
}
const Rect &ui_view = _GP(play).GetUIViewport();
if (xx == OVR_AUTOPLACE);
// centre text in middle of screen
else if (yy < 0) yy = ui_view.GetHeight() / 2 - disp.fulltxtheight / 2 - padding;
// speech, so it wants to be above the character's head
else if (asspch > 0) {
yy -= disp.fulltxtheight;
if (yy < 5) yy = 5;
yy = adjust_y_for_guis(yy);
}
if (_G(longestline) < wii - paddingDoubledScaled) {
// shrink the width of the dialog box to fit the text
int oldWid = wii;
//if ((asspch >= 0) || (allowShrink > 0))
// If it's not speech, or a shrink is allowed, then shrink it
if ((asspch == 0) || (allowShrink > 0))
wii = _G(longestline) + paddingDoubledScaled;
// shift the dialog box right to align it, if necessary
if ((allowShrink == 2) && (xx >= 0))
xx += (oldWid - wii);
}
if (xx < -1) {
xx = (-xx) - wii / 2;
if (xx < 0)
xx = 0;
xx = adjust_x_for_guis(xx, yy);
if (xx + wii >= ui_view.GetWidth())
xx = (ui_view.GetWidth() - wii) - 5;
} else if (xx < 0) xx = ui_view.GetWidth() / 2 - wii / 2;
const int extraHeight = paddingDoubledScaled;
color_t text_color = MakeColor(15);
const int bmp_width = MAX(2, wii);
const int bmp_height = MAX(2, disp.fulltxtheight + extraHeight);
Bitmap *text_window_ds = BitmapHelper::CreateTransparentBitmap(
bmp_width, bmp_height, _GP(game).GetColorDepth());
// inform draw_text_window to free the old bitmap
const bool wantFreeScreenop = true;
//
// Create the textual image (may also adjust some params in the process)
//
// may later change if usingGUI, needed to avoid changing original coordinates
adjustedXX = xx;
adjustedYY = yy;
if ((strlen(todis) < 1) || (strcmp(todis, " ") == 0) || (wii == 0));
// if it's an empty speech line, don't draw anything
else if (asspch) { //text_color = ds->GetCompatibleColor(12);
int ttxleft = 0, ttxtop = paddingScaled, oriwid = wii - padding * 2;
int drawBackground = 0;
if (use_speech_textwindow) {
drawBackground = 1;
} else if (use_thought_gui) {
// make it treat it as drawing inside a window now
if (asspch > 0)
asspch = -asspch;
drawBackground = 1;
}
if (drawBackground) {
draw_text_window_and_bar(&text_window_ds, wantFreeScreenop, &ttxleft, &ttxtop, &adjustedXX, &adjustedYY, &wii, &text_color, 0, usingGui);
if (usingGui > 0) {
alphaChannel = _GP(guis)[usingGui].HasAlphaChannel();
}
} else if ((ShouldAntiAliasText()) && (_GP(game).GetColorDepth() >= 24))
alphaChannel = true;
for (size_t ee = 0; ee < _GP(Lines).Count(); ee++) {
//int ttxp=wii/2 - get_text_width_outlined(lines[ee], usingfont)/2;
int ttyp = ttxtop + ee * disp.linespacing;
// asspch < 0 means that it's inside a text box so don't
// centre the text
if (asspch < 0) {
if ((usingGui >= 0) &&
((_GP(game).options[OPT_SPEECHTYPE] >= 2) || (isThought)))
text_color = text_window_ds->GetCompatibleColor(_GP(guis)[usingGui].FgColor);
else
text_color = text_window_ds->GetCompatibleColor(-asspch);
wouttext_aligned(text_window_ds, ttxleft, ttyp, oriwid, usingfont, text_color, _GP(Lines)[ee].GetCStr(), _GP(play).text_align);
} else {
text_color = text_window_ds->GetCompatibleColor(asspch);
wouttext_aligned(text_window_ds, ttxleft, ttyp, wii, usingfont, text_color, _GP(Lines)[ee].GetCStr(), _GP(play).speech_text_align);
}
}
} else {
int xoffs, yoffs, oriwid = wii - padding * 2;
draw_text_window_and_bar(&text_window_ds, wantFreeScreenop, &xoffs, &yoffs, &adjustedXX, &adjustedYY, &wii, &text_color);
if (_GP(game).options[OPT_TWCUSTOM] > 0) {
alphaChannel = _GP(guis)[_GP(game).options[OPT_TWCUSTOM]].HasAlphaChannel();
}
adjust_y_coordinate_for_text(&yoffs, usingfont);
for (size_t ee = 0; ee < _GP(Lines).Count(); ee++)
wouttext_aligned(text_window_ds, xoffs, yoffs + ee * disp.linespacing, oriwid, usingfont, text_color, _GP(Lines)[ee].GetCStr(), _GP(play).text_align);
}
return text_window_ds;
}
// Pass yy = -1 to find Y co-ord automatically
// allowShrink = 0 for none, 1 for leftwards, 2 for rightwards
// pass blocking=2 to create permanent overlay
ScreenOverlay *display_main(int xx, int yy, int wii, const char *text, int disp_type, int usingfont,
int asspch, int isThought, int allowShrink, bool overlayPositionFixed, bool roomlayer) {
//
// Prepare for the message display
//
// AGS 2.x: If the screen is faded out, fade in again when displaying a message box.
if (!asspch && (_G(loaded_game_file_version) <= kGameVersion_272))
_GP(play).screen_is_faded_out = 0;
// if it's a normal message box and the game was being skipped,
// ensure that the screen is up to date before the message box
// is drawn on top of it
// TODO: is this really necessary anymore?
if ((_GP(play).skip_until_char_stops >= 0) && (disp_type == DISPLAYTEXT_MESSAGEBOX))
render_graphics();
// TODO: should this really be called regardless of message type?
// _display_main may be called even for custom textual overlays
EndSkippingUntilCharStops();
if (_GP(topBar).wantIt) {
// the top bar should behave like DisplaySpeech wrt blocking
disp_type = DISPLAYTEXT_SPEECH;
}
if ((asspch > 0) && (disp_type < DISPLAYTEXT_NORMALOVERLAY)) {
// update the all_buttons_disabled variable in advance
// of the adjust_x/y_for_guis calls
_GP(play).disabled_user_interface++;
update_gui_disabled_status();
_GP(play).disabled_user_interface--;
}
// remove any previous blocking texts if necessary
if (disp_type < DISPLAYTEXT_NORMALOVERLAY)
remove_screen_overlay(_GP(play).text_overlay_on);
// If fast-forwarding, then skip any blocking message immediately
if (_GP(play).fast_forward && (disp_type < DISPLAYTEXT_NORMALOVERLAY)) {
_GP(play).SetWaitSkipResult(SKIP_AUTOTIMER);
post_display_cleanup();
return nullptr;
}
//
// Configure and create an overlay object
//
int ovrtype;
switch (disp_type) {
case DISPLAYTEXT_SPEECH: ovrtype = OVER_TEXTSPEECH; break;
case DISPLAYTEXT_MESSAGEBOX: ovrtype = OVER_TEXTMSG; break;
case DISPLAYTEXT_NORMALOVERLAY: ovrtype = OVER_CUSTOM; break;
default: ovrtype = disp_type; break; // must be precreated overlay id
}
int adjustedXX, adjustedYY;
bool alphaChannel;
Bitmap *text_window_ds = create_textual_image(text, asspch, isThought, xx, yy, adjustedXX, adjustedYY, wii, usingfont, allowShrink, alphaChannel);
size_t nse = add_screen_overlay(roomlayer, xx, yy, ovrtype, text_window_ds, adjustedXX - xx, adjustedYY - yy, alphaChannel);
auto *over = get_overlay(nse); // FIXME: optimize return value
// we should not delete text_window_ds here, because it is now owned by Overlay
// If it's a non-blocking overlay type, then we're done here
if (disp_type >= DISPLAYTEXT_NORMALOVERLAY) {
return over;
}
//
// Wait for the blocking text to timeout or until skipped by another command
//
if (disp_type == DISPLAYTEXT_MESSAGEBOX) {
int countdown = GetTextDisplayTime(text);
int skip_setting = user_to_internal_skip_speech((SkipSpeechStyle)_GP(play).skip_display);
// Loop until skipped
while (true) {
if (SHOULD_QUIT)
return 0;
sys_evt_process_pending();
update_audio_system_on_game_loop();
UpdateCursorAndDrawables();
render_graphics();
eAGSMouseButton mbut;
int mwheelz;
if (run_service_mb_controls(mbut, mwheelz) && mbut > kMouseNone) {
check_skip_cutscene_mclick(mbut);
if (_GP(play).fast_forward)
break;
if (skip_setting & SKIP_MOUSECLICK && !_GP(play).IsIgnoringInput()) {
_GP(play).SetWaitSkipResult(SKIP_MOUSECLICK, mbut);
break;
}
}
bool do_break = false;
while (!_GP(play).fast_forward && !do_break && ags_keyevent_ready()) {
KeyInput ki;
if (run_service_key_controls(ki)) {
check_skip_cutscene_keypress(ki.Key);
if ((skip_setting & SKIP_KEYPRESS) && !_GP(play).IsIgnoringInput() && !IsAGSServiceKey(ki.Key)) {
_GP(play).SetWaitKeySkip(ki);
do_break = true;
}
}
}
if (do_break)
break;
update_polled_stuff();
if (_GP(play).fast_forward == 0) {
WaitForNextFrame();
}
countdown--;
// Special behavior when coupled with a voice-over
if (_GP(play).speech_has_voice) {
// extend life of text if the voice hasn't finished yet
if (AudioChans::ChannelIsPlaying(SCHAN_SPEECH) && (_GP(play).fast_forward == 0)) {
if (countdown <= 1)
countdown = 1;
} else // if the voice has finished, remove the speech
countdown = 0;
}
// Test for the timed auto-skip
if ((countdown < 1) && (skip_setting & SKIP_AUTOTIMER)) {
_GP(play).SetWaitSkipResult(SKIP_AUTOTIMER);
_GP(play).SetIgnoreInput(_GP(play).ignore_user_input_after_text_timeout_ms);
break;
}
// if skipping cutscene, don't get stuck on No Auto Remove text boxes
if ((countdown < 1) && (_GP(play).fast_forward))
break;
}
remove_screen_overlay(OVER_TEXTMSG);
invalidate_screen();
} else {
/* DISPLAYTEXT_SPEECH */
if (!overlayPositionFixed) {
over->SetRoomRelative(true);
VpPoint vpt = _GP(play).GetRoomViewport(0)->ScreenToRoom(over->x, over->y, false);
over->x = vpt.first.X;
over->y = vpt.first.Y;
}
GameLoopUntilNoOverlay();
}
//
// Post-message cleanup
//
post_display_cleanup();
return nullptr;
}
void display_at(int xx, int yy, int wii, const char *text) {
EndSkippingUntilCharStops();
// Start voice-over, if requested by the tokens in speech text
try_auto_play_speech(text, text, _GP(play).narrator_speech);
display_main(xx, yy, wii, text, DISPLAYTEXT_MESSAGEBOX, FONT_NORMAL, 0, 0, 0, false);
// Stop any blocking voice-over, if was started by this function
if (_GP(play).IsBlockingVoiceSpeech())
stop_voice_speech();
}
void post_display_cleanup() {
ags_clear_input_buffer();
_GP(play).messagetime = -1;
_GP(play).speech_in_post_state = false;
}
bool try_auto_play_speech(const char *text, const char *&replace_text, int charid) {
int voice_num;
const char *src = parse_voiceover_token(text, &voice_num);
if (src == text)
return false; // no token
if (voice_num <= 0)
quit("DisplaySpeech: auto-voice symbol '&' not followed by valid integer");
replace_text = src; // skip voice tag
if (play_voice_speech(charid, voice_num)) {
// if Voice Only, then blank out the text
if (_GP(play).speech_mode == kSpeech_VoiceOnly)
replace_text = " ";
return true;
}
return false;
}
int GetTextDisplayLength(const char *text) {
// Skip voice-over token from the length calculation if required
if (_GP(play).unfactor_speech_from_textlength != 0)
text = parse_voiceover_token(text, nullptr);
return static_cast<int>(strlen(text));
}
// Calculates lipsync frame duration (or duration per character) in game loops.
// NOTE: historical formula was this:
// loops_per_character = (((text_len / play.lipsync_speed) + 1) * fps) / text_len;
// But because of a precision loss due integer division this resulted in "jumping" values.
// The new formula uses float division, and coefficent found experimentally to make
// results match the old formula in certain key text lengths, for backwards compatibility.
int CalcLipsyncFrameDuration(int text_len, int fps) {
return static_cast<int>((((static_cast<float>(text_len) / _GP(play).lipsync_speed) + 0.75f) * fps) / text_len);
}
int GetTextDisplayTime(const char *text, int canberel) {
int uselen = 0;
auto fpstimer = ::lround(get_game_fps());
// if it's background speech, make it stay relative to game speed
if ((canberel == 1) && (_GP(play).bgspeech_game_speed == 1))
fpstimer = 40; // NOTE: should be a fixed constant here, not game speed value
if (_G(source_text_length) >= 0) {
// sync to length of original text, to make sure any animations
// and music sync up correctly
uselen = _G(source_text_length);
_G(source_text_length) = -1;
} else {
uselen = GetTextDisplayLength(text);
}
if (uselen <= 0)
return 0;
if (_GP(play).text_speed + _GP(play).text_speed_modifier <= 0)
quit("!Text speed is zero; unable to display text. Check your _GP(game).text_speed settings.");
// Store how many game loops per character of text
_G(loops_per_character) = CalcLipsyncFrameDuration(uselen, fpstimer);
int textDisplayTimeInMS = ((uselen / (_GP(play).text_speed + _GP(play).text_speed_modifier)) + 1) * 1000;
if (textDisplayTimeInMS < _GP(play).text_min_display_time_ms)
textDisplayTimeInMS = _GP(play).text_min_display_time_ms;
return (textDisplayTimeInMS * fpstimer) / 1000;
}
bool ShouldAntiAliasText() {
return (_GP(game).GetColorDepth() >= 24) && (_GP(game).options[OPT_ANTIALIASFONTS] != 0 || ::AGS::g_vm->_forceTextAA);
}
void wouttextxy_AutoOutline(Bitmap *ds, size_t font, int32_t color, const char *texx, int &xxp, int &yyp) {
const FontInfo &finfo = get_fontinfo(font);
int const thickness = finfo.AutoOutlineThickness;
auto const style = finfo.AutoOutlineStyle;
if (thickness <= 0)
return;
// 16-bit games should use 32-bit stencils to keep anti-aliasing working
// because 16-bit blending works correctly if there's an actual color
// on the destination bitmap (and our intermediate bitmaps are transparent).
int const ds_cd = ds->GetColorDepth();
bool const antialias = ds_cd >= 16 && _GP(game).options[OPT_ANTIALIASFONTS] != 0 && !is_bitmap_font(font);
int const stencil_cd = antialias ? 32 : ds_cd;
if (antialias) // This is to make sure TTFs render proper alpha channel in 16-bit games too
color |= makeacol32(0, 0, 0, 0xff);
// WORKAROUND: Clifftop's Spritefont plugin returns a wrong font height for font 2 in Kathy Rain, which causes a partial outline
// for some letters. Unfortunately fixing the value on the plugin side breaks the line spacing, so let's just correct it here.
const int t_width = get_text_width(texx, font);
const auto t_extent = get_font_surface_extent(font);
const int t_height = t_extent.second - t_extent.first + ((strcmp(_GP(game).guid, "{d6795d1c-3cfe-49ec-90a1-85c313bfccaf}") == 0) && (font == 2) ? 1 : 0);
if (t_width == 0 || t_height == 0)
return;
// Prepare stencils
const int t_yoff = t_extent.first;
Bitmap *texx_stencil, *outline_stencil;
alloc_font_outline_buffers(font, &texx_stencil, &outline_stencil,
t_width, t_height, stencil_cd);
texx_stencil->ClearTransparent();
outline_stencil->ClearTransparent();
// Ready text stencil
// Note we are drawing with y off, in case some font's glyphs exceed font's ascender
wouttextxy(texx_stencil, 0, -t_yoff, font, color, texx);
// Anti-aliased TTFs require to be alpha-blended, not blit,
// or the alpha values will be plain copied and final image will be broken.
void(Bitmap:: * pfn_drawstencil)(Bitmap * src, int dst_x, int dst_y);
if (antialias) { // NOTE: we must set out blender AFTER wouttextxy, or it will be overidden
set_argb2any_blender();
pfn_drawstencil = &Bitmap::TransBlendBlt;
} else {
pfn_drawstencil = &Bitmap::MaskedBlit;
}
// move start of text so that the outline doesn't drop off the bitmap
xxp += thickness;
int const outline_y = yyp + t_yoff;
yyp += thickness;
// What we do here: first we paint text onto outline_stencil offsetting vertically;
// then we paint resulting outline_stencil onto final dest offsetting horizontally.
int largest_y_diff_reached_so_far = -1;
for (int x_diff = thickness; x_diff >= 0; x_diff--) {
// Integer arithmetics: In the following, we use terms k*(k + 1) to account for rounding.
// (k + 0.5)^2 == k*k + 2*k*0.5 + 0.5^2 == k*k + k + 0.25 ==approx. k*(k + 1)
int y_term_limit = thickness * (thickness + 1);
if (FontInfo::kRounded == style)
y_term_limit -= x_diff * x_diff;
// Extend the outline stencil to the top and bottom
for (int y_diff = largest_y_diff_reached_so_far + 1;
y_diff <= thickness && y_diff * y_diff <= y_term_limit;
y_diff++) {
(outline_stencil->*pfn_drawstencil)(texx_stencil, 0, thickness - y_diff);
if (y_diff > 0)
(outline_stencil->*pfn_drawstencil)(texx_stencil, 0, thickness + y_diff);
largest_y_diff_reached_so_far = y_diff;
}
// Stamp the outline stencil to the left and right of the text
(ds->*pfn_drawstencil)(outline_stencil, xxp - x_diff, outline_y);
if (x_diff > 0)
(ds->*pfn_drawstencil)(outline_stencil, xxp + x_diff, outline_y);
}
}
// Draw an outline if requested, then draw the text on top
void wouttext_outline(Shared::Bitmap *ds, int xxp, int yyp, int font, color_t text_color, const char *texx) {
size_t const text_font = static_cast<size_t>(font);
// Draw outline (a backdrop) if requested
color_t const outline_color = ds->GetCompatibleColor(_GP(play).speech_text_shadow);
int const outline_font = get_font_outline(font);
if (outline_font >= 0)
wouttextxy(ds, xxp, yyp, static_cast<size_t>(outline_font), outline_color, texx);
else if (outline_font == FONT_OUTLINE_AUTO)
wouttextxy_AutoOutline(ds, text_font, outline_color, texx, xxp, yyp);
else
; // no outline
// Draw text on top
wouttextxy(ds, xxp, yyp, text_font, text_color, texx);
}
void wouttext_aligned(Bitmap *ds, int usexp, int yy, int oriwid, int usingfont, color_t text_color, const char *text, HorAlignment align) {
if (align & kMAlignHCenter)
usexp = usexp + (oriwid / 2) - (get_text_width_outlined(text, usingfont) / 2);
else if (align & kMAlignRight)
usexp = usexp + (oriwid - get_text_width_outlined(text, usingfont));
wouttext_outline(ds, usexp, yy, usingfont, text_color, text);
}
int get_font_outline_padding(int font) {
if (get_font_outline(font) == FONT_OUTLINE_AUTO) {
// scaled up bitmap font, push outline further out
if (is_bitmap_font(font) && get_font_scaling_mul(font) > 1)
return get_fixed_pixel_size(2); // FIXME: should be 2 + get_fixed_pixel_size(2)?
// otherwise, just push outline by 1 pixel
else
return 2;
}
return 0;
}
void do_corner(Bitmap *ds, int sprn, int x, int y, int offx, int offy) {
if (sprn < 0) return;
if (!_GP(spriteset).DoesSpriteExist(sprn)) {
sprn = 0;
}
x = x + offx * _GP(game).SpriteInfos[sprn].Width;
y = y + offy * _GP(game).SpriteInfos[sprn].Height;
draw_gui_sprite_v330(ds, sprn, x, y);
}
int get_but_pic(GUIMain *guo, int indx) {
int butid = guo->GetControlID(indx);
return butid >= 0 ? _GP(guibuts)[butid].GetNormalImage() : 0;
}
void draw_button_background(Bitmap *ds, int xx1, int yy1, int xx2, int yy2, GUIMain *iep) {
color_t draw_color;
if (iep == nullptr) { // standard window
draw_color = ds->GetCompatibleColor(15);
ds->FillRect(Rect(xx1, yy1, xx2, yy2), draw_color);
draw_color = ds->GetCompatibleColor(16);
ds->DrawRect(Rect(xx1, yy1, xx2, yy2), draw_color);
} else {
if (_G(loaded_game_file_version) < kGameVersion_262) {
// In pre-2.62 color 0 should be treated as "black" instead of "transparent";
// this was an unintended effect in older versions (see 2.62 changelog fixes).
if (iep->BgColor == 0)
iep->BgColor = 16;
}
if (iep->BgColor >= 0) draw_color = ds->GetCompatibleColor(iep->BgColor);
else draw_color = ds->GetCompatibleColor(0); // black backrgnd behind picture
if (iep->BgColor > 0)
ds->FillRect(Rect(xx1, yy1, xx2, yy2), draw_color);
const int leftRightWidth = _GP(game).SpriteInfos[get_but_pic(iep, 4)].Width;
const int topBottomHeight = _GP(game).SpriteInfos[get_but_pic(iep, 6)].Height;
// GUI middle space
if (iep->BgImage > 0) {
{
// offset the background image and clip it so that it is drawn
// such that the border graphics can have a transparent outside
// edge
int bgoffsx = xx1 - leftRightWidth / 2;
int bgoffsy = yy1 - topBottomHeight / 2;
ds->SetClip(Rect(bgoffsx, bgoffsy, xx2 + leftRightWidth / 2, yy2 + topBottomHeight / 2));
int bgfinishx = xx2;
int bgfinishy = yy2;
int bgoffsyStart = bgoffsy;
while (bgoffsx <= bgfinishx) {
bgoffsy = bgoffsyStart;
while (bgoffsy <= bgfinishy) {
draw_gui_sprite_v330(ds, iep->BgImage, bgoffsx, bgoffsy);
bgoffsy += _GP(game).SpriteInfos[iep->BgImage].Height;
}
bgoffsx += _GP(game).SpriteInfos[iep->BgImage].Width;
}
// return to normal clipping rectangle
ds->ResetClip();
}
}
// Vertical borders
ds->SetClip(Rect(xx1 - leftRightWidth, yy1, xx2 + 1 + leftRightWidth, yy2));
for (int uu = yy1; uu <= yy2; uu += _GP(game).SpriteInfos[get_but_pic(iep, 4)].Height) {
do_corner(ds, get_but_pic(iep, 4), xx1, uu, -1, 0); // left side
do_corner(ds, get_but_pic(iep, 5), xx2 + 1, uu, 0, 0); // right side
}
// Horizontal borders
ds->SetClip(Rect(xx1, yy1 - topBottomHeight, xx2, yy2 + 1 + topBottomHeight));
for (int uu = xx1; uu <= xx2; uu += _GP(game).SpriteInfos[get_but_pic(iep, 6)].Width) {
do_corner(ds, get_but_pic(iep, 6), uu, yy1, 0, -1); // top side
do_corner(ds, get_but_pic(iep, 7), uu, yy2 + 1, 0, 0); // bottom side
}
ds->ResetClip();
// Four corners
do_corner(ds, get_but_pic(iep, 0), xx1, yy1, -1, -1); // top left
do_corner(ds, get_but_pic(iep, 1), xx1, yy2 + 1, -1, 0); // bottom left
do_corner(ds, get_but_pic(iep, 2), xx2 + 1, yy1, 0, -1); // top right
do_corner(ds, get_but_pic(iep, 3), xx2 + 1, yy2 + 1, 0, 0); // bottom right
}
}
// Calculate the width that the left and right border of the textwindow
// GUI take up
int get_textwindow_border_width(int twgui) {
if (twgui < 0)
return 0;
if (!_GP(guis)[twgui].IsTextWindow())
quit("!GUI set as text window but is not actually a text window GUI");
int borwid = _GP(game).SpriteInfos[get_but_pic(&_GP(guis)[twgui], 4)].Width +
_GP(game).SpriteInfos[get_but_pic(&_GP(guis)[twgui], 5)].Width;
return borwid;
}
// get the hegiht of the text window's top border
int get_textwindow_top_border_height(int twgui) {
if (twgui < 0)
return 0;
if (!_GP(guis)[twgui].IsTextWindow())
quit("!GUI set as text window but is not actually a text window GUI");
return _GP(game).SpriteInfos[get_but_pic(&_GP(guis)[twgui], 6)].Height;
}
// Get the padding for a text window
// -1 for the game's custom text window
int get_textwindow_padding(int ifnum) {
int result;
if (ifnum < 0)
ifnum = _GP(game).options[OPT_TWCUSTOM];
if (ifnum > 0 && ifnum < _GP(game).numgui)
result = _GP(guis)[ifnum].Padding;
else
result = TEXTWINDOW_PADDING_DEFAULT;
return result;
}
void draw_text_window(Bitmap **text_window_ds, bool should_free_ds,
int *xins, int *yins, int *xx, int *yy, int *wii, color_t *set_text_color, int ovrheight, int ifnum) {
assert(text_window_ds);
Bitmap *ds = *text_window_ds;
if (ifnum < 0)
ifnum = _GP(game).options[OPT_TWCUSTOM];
if (ifnum <= 0) {
if (ovrheight)
quit("!Cannot use QFG4 style options without custom text window");
draw_button_background(ds, 0, 0, ds->GetWidth() - 1, ds->GetHeight() - 1, nullptr);
if (set_text_color)
*set_text_color = ds->GetCompatibleColor(16);
xins[0] = 3;
yins[0] = 3;
} else {
if (ifnum >= _GP(game).numgui)
quitprintf("!Invalid GUI %d specified as text window (total GUIs: %d)", ifnum, _GP(game).numgui);
if (!_GP(guis)[ifnum].IsTextWindow())
quit("!GUI set as text window but is not actually a text window GUI");
int tbnum = get_but_pic(&_GP(guis)[ifnum], 0);
wii[0] += get_textwindow_border_width(ifnum);
xx[0] -= _GP(game).SpriteInfos[tbnum].Width;
yy[0] -= _GP(game).SpriteInfos[tbnum].Height;
if (ovrheight == 0)
ovrheight = disp.fulltxtheight;
if (should_free_ds)
delete *text_window_ds;
int padding = get_textwindow_padding(ifnum);
*text_window_ds = BitmapHelper::CreateTransparentBitmap(wii[0], ovrheight + (padding * 2) + _GP(game).SpriteInfos[tbnum].Height * 2, _GP(game).GetColorDepth());
ds = *text_window_ds;
int xoffs = _GP(game).SpriteInfos[tbnum].Width, yoffs = _GP(game).SpriteInfos[tbnum].Height;
draw_button_background(ds, xoffs, yoffs, (ds->GetWidth() - xoffs) - 1, (ds->GetHeight() - yoffs) - 1, &_GP(guis)[ifnum]);
if (set_text_color)
*set_text_color = ds->GetCompatibleColor(_GP(guis)[ifnum].FgColor);
xins[0] = xoffs + padding;
yins[0] = yoffs + padding;
}
}
void draw_text_window_and_bar(Bitmap **text_window_ds, bool should_free_ds,
int *xins, int *yins, int *xx, int *yy, int *wii, color_t *set_text_color, int ovrheight, int ifnum) {
assert(text_window_ds);
draw_text_window(text_window_ds, should_free_ds, xins, yins, xx, yy, wii, set_text_color, ovrheight, ifnum);
if ((_GP(topBar).wantIt) && (text_window_ds && *text_window_ds)) {
// top bar on the dialog window with character's name
// create an enlarged window, then free the old one
Bitmap *ds = *text_window_ds;
Bitmap *newScreenop = BitmapHelper::CreateBitmap(ds->GetWidth(), ds->GetHeight() + _GP(topBar).height, _GP(game).GetColorDepth());
newScreenop->Blit(ds, 0, 0, 0, _GP(topBar).height, ds->GetWidth(), ds->GetHeight());
delete *text_window_ds;
*text_window_ds = newScreenop;
ds = *text_window_ds;
// draw the top bar
color_t draw_color = ds->GetCompatibleColor(_GP(play).top_bar_backcolor);
ds->FillRect(Rect(0, 0, ds->GetWidth() - 1, _GP(topBar).height - 1), draw_color);
if (_GP(play).top_bar_backcolor != _GP(play).top_bar_bordercolor) {
// draw the border
draw_color = ds->GetCompatibleColor(_GP(play).top_bar_bordercolor);
for (int j = 0; j < data_to_game_coord(_GP(play).top_bar_borderwidth); j++)
ds->DrawRect(Rect(j, j, ds->GetWidth() - (j + 1), _GP(topBar).height - (j + 1)), draw_color);
}
// draw the text
int textx = (ds->GetWidth() / 2) - get_text_width_outlined(_GP(topBar).text, _GP(topBar).font) / 2;
color_t text_color = ds->GetCompatibleColor(_GP(play).top_bar_textcolor);
wouttext_outline(ds, textx, _GP(play).top_bar_borderwidth + get_fixed_pixel_size(1), _GP(topBar).font, text_color, _GP(topBar).text);
// don't draw it next time
_GP(topBar).wantIt = 0;
// adjust the text Y position
yins[0] += _GP(topBar).height;
} else if (_GP(topBar).wantIt)
_GP(topBar).wantIt = 0;
}
} // namespace AGS3

View File

@@ -0,0 +1,87 @@
/* 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_ENGINE_AC_DISPLAY_H
#define AGS_ENGINE_AC_DISPLAY_H
#include "ags/shared/gui/gui_main.h"
namespace AGS3 {
using AGS::Shared::GUIMain;
// options for 'disp_type' parameter
// blocking speech
#define DISPLAYTEXT_SPEECH 0
// super-blocking message box
#define DISPLAYTEXT_MESSAGEBOX 1
// regular non-blocking overlay
#define DISPLAYTEXT_NORMALOVERLAY 2
// also accepts explicit overlay ID >= OVER_CUSTOM
struct ScreenOverlay;
Shared::Bitmap *create_textual_image(const char *text, int asspch, int isThought,
int &xx, int &yy, int &adjustedXX, int &adjustedYY, int wii, int usingfont, int allowShrink,
bool &alphaChannel);
// Creates a textual overlay using the given parameters;
// Pass yy = -1 to find Y co-ord automatically
// allowShrink = 0 for none, 1 for leftwards, 2 for rightwards
// pass blocking=2 to create permanent overlay
ScreenOverlay *display_main(int xx, int yy, int wii, const char *text, int disp_type, int usingfont,
int asspch, int isThought, int allowShrink, bool overlayPositionFixed, bool roomlayer = false);
// Displays a standard blocking message box at a given position
void display_at(int xx, int yy, int wii, const char *text);
// Cleans up display message state
void post_display_cleanup();
// Tests the given string for the voice-over tags and plays cue clip for the given character;
// will assign replacement string, which will be blank string if game is in "voice-only" mode
// and clip was started, or string cleaned from voice-over tags which is safe to display on screen.
// Returns whether voice-over clip was started successfully.
bool try_auto_play_speech(const char *text, const char *&replace_text, int charid);
// Calculates meaningful length of the displayed text
int GetTextDisplayLength(const char *text);
// Calculates number of game loops for displaying a text on screen
int GetTextDisplayTime(const char *text, int canberel = 0);
// Draw an outline if requested, then draw the text on top
void wouttext_outline(Shared::Bitmap *ds, int xxp, int yyp, int usingfont, color_t text_color, const char *texx);
void wouttext_aligned(Shared::Bitmap *ds, int usexp, int yy, int oriwid, int usingfont, color_t text_color, const char *text, HorAlignment align);
void do_corner(Shared::Bitmap *ds, int sprn, int xx1, int yy1, int typx, int typy);
// Returns the image of a button control on the GUI under given child index
int get_but_pic(GUIMain *guo, int indx);
void draw_button_background(Shared::Bitmap *ds, int xx1, int yy1, int xx2, int yy2, GUIMain *iep);
// Calculate the width that the left and right border of the textwindow
// GUI take up
int get_textwindow_border_width(int twgui);
// get the hegiht of the text window's top border
int get_textwindow_top_border_height(int twgui);
// draw_text_window: draws the normal or custom text window
// create a new bitmap the size of the window before calling, and
// point text_window_ds to it
// returns text start x & y pos in parameters
// Warning!: draw_text_window() and draw_text_window_and_bar() can create new text_window_ds
void draw_text_window(Shared::Bitmap **text_window_ds, bool should_free_ds, int *xins, int *yins, int *xx, int *yy, int *wii, color_t *set_text_color, int ovrheight, int ifnum);
void draw_text_window_and_bar(Shared::Bitmap **text_window_ds, bool should_free_ds,
int *xins, int *yins, int *xx, int *yy, int *wii, color_t *set_text_color, int ovrheight = 0, int ifnum = -1);
int get_textwindow_padding(int ifnum);
} // namespace AGS3
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,322 @@
/* 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_ENGINE_AC_DRAW_H
#define AGS_ENGINE_AC_DRAW_H
#include "common/std/memory.h"
#include "ags/shared/core/types.h"
#include "ags/shared/ac/common_defines.h"
#include "ags/shared/gfx/gfx_def.h"
#include "ags/shared/gfx/allegro_bitmap.h"
#include "ags/shared/gfx/bitmap.h"
#include "ags/shared/game/room_struct.h"
#include "ags/engine/ac/runtime_defines.h"
#include "ags/engine/ac/walk_behind.h"
namespace AGS3 {
namespace AGS {
namespace Shared {
typedef std::shared_ptr<Shared::Bitmap> PBitmap;
} // namespace Shared
namespace Engine {
class IDriverDependantBitmap;
} // namespace Engine
} // namespace AGS
using namespace AGS; // FIXME later
#define IS_ANTIALIAS_SPRITES _GP(usetup).enable_antialiasing && (_GP(play).disable_antialiasing == 0)
// Render stage flags, for filtering out certain elements
// during room transitions, capturing screenshots, etc.
// NOTE: these values are internal and purely arbitrary atm.
#define RENDER_BATCH_ENGINE_OVERLAY 0x0001
#define RENDER_BATCH_MOUSE_CURSOR 0x0002
#define RENDER_SHOT_SKIP_ON_FADE (RENDER_BATCH_ENGINE_OVERLAY | RENDER_BATCH_MOUSE_CURSOR)
/**
* Buffer and info flags for viewport/camera pairs rendering in software mode
*/
struct RoomCameraDrawData {
// Intermediate bitmap for the software drawing method.
// We use this bitmap in case room camera has scaling enabled, we draw dirty room rects on it,
// and then pass to software renderer which draws sprite on top and then either blits or stretch-blits
// to the virtual screen.
// For more details see comment in ALSoftwareGraphicsDriver::RenderToBackBuffer().
AGS::Shared::PBitmap Buffer; // this is the actual bitmap
AGS::Shared::PBitmap Frame; // this is either same bitmap reference or sub-bitmap of virtual screen
bool IsOffscreen; // whether room viewport was offscreen (cannot use sub-bitmap)
bool IsOverlap; // whether room viewport overlaps any others (marking dirty rects is complicated)
};
typedef int32_t sprkey_t;
// TODO: refactor the draw unit into a virtual interface with
// two implementations: for software and video-texture render,
// instead of checking whether the current method is "software".
struct DrawState {
// Whether we should use software rendering methods
// (aka raw draw), as opposed to video texture transform & fx
bool SoftwareRender = false;
// Whether we should redraw whole game screen each frame
bool FullFrameRedraw = false;
// Walk-behinds representation
WalkBehindMethodEnum WalkBehindMethod = DrawAsSeparateSprite;
// Whether there are currently remnants of a on-screen effect
bool ScreenIsDirty = false;
// A map of shared "control blocks" per each sprite used
// when preparing object textures. "Control block" is currently just
// an integer which lets to check whether the object texture is in sync
// with the sprite. When the dynamic sprite is updated or deleted,
// the control block is marked as invalid and removed from the map;
// but certain objects may keep the shared ptr to the old block with
// "invalid" mark, thus they know that they must reset their texture.
//
// TODO: investigate an alternative of having a equivalent of
// "shared texture" with sprite ID ref in Software renderer too,
// which would allow to use same method of testing DDB ID for both
// kinds of renderers, thus saving on 1 extra notification mechanism.
std::unordered_map<sprkey_t, std::shared_ptr<uint32_t> >
SpriteNotifyMap;
};
// ObjTexture is a helper struct that pairs a raw bitmap with
// a renderer's texture and an optional position
struct ObjTexture {
// Sprite ID
uint32_t SpriteID = UINT32_MAX;
// Raw bitmap; used for software render mode,
// or when particular object types require generated image.
std::unique_ptr<Shared::Bitmap> Bmp;
// Corresponding texture, created by renderer
Engine::IDriverDependantBitmap *Ddb = nullptr;
// Sprite notification block: becomes invalid to notify an updated
// or deleted sprtie
std::shared_ptr<uint32_t> SpriteNotify;
// Sprite's position
Point Pos;
// Texture's offset, *relative* to the logical sprite's position;
// may be used in case the texture's size is different for any reason
Point Off;
ObjTexture() = default;
ObjTexture(uint32_t sprite_id, Shared::Bitmap *bmp, Engine::IDriverDependantBitmap *ddb, int x, int y, int xoff = 0, int yoff = 0)
: SpriteID(sprite_id), Bmp(bmp), Ddb(ddb), Pos(x, y), Off(xoff, yoff) {
}
ObjTexture(ObjTexture &&o);
~ObjTexture();
ObjTexture &operator =(ObjTexture &&o);
// Tests if the sprite change was notified
inline bool IsChangeNotified() const {
return SpriteNotify && (*SpriteNotify != SpriteID);
}
};
// ObjectCache stores cached object data, used to determine
// if active sprite / texture should be reconstructed
struct ObjectCache {
std::unique_ptr<AGS::Shared::Bitmap> image;
bool in_use = false; // CHECKME: possibly may be removed
int sppic = 0;
short tintr = 0, tintg = 0, tintb = 0, tintamnt = 0, tintlight = 0;
short lightlev = 0, zoom = 0;
bool mirrored = 0;
int x = 0, y = 0;
ObjectCache() = default;
ObjectCache(int pic_, int tintr_, int tintg_, int tintb_, int tint_amnt_, int tint_light_,
int light_, int zoom_, bool mirror_, int posx_, int posy_)
: sppic(pic_), tintr(tintr_), tintg(tintg_), tintb(tintb_), tintamnt(tint_amnt_), tintlight(tint_light_)
, lightlev(light_), zoom(zoom_), mirrored(mirror_), x(posx_), y(posy_) {}
};
struct DrawFPS {
Engine::IDriverDependantBitmap *ddb = nullptr;
std::unique_ptr<Shared::Bitmap> bmp;
int font = -1; // in case normal font changes at runtime
};
// Converts AGS color index to the actual bitmap color using game's color depth
int MakeColor(int color_index);
class Viewport;
class Camera;
// Initializes drawing methods and optimisation
void init_draw_method();
// Initializes global game drawing resources
void init_game_drawdata();
// Initializes drawing resources upon entering new room
void init_room_drawdata();
// Disposes resources related to the current drawing methods
void dispose_draw_method();
// Disposes global game drawing resources
void dispose_game_drawdata();
// Disposes any temporary resources on leaving current room
void dispose_room_drawdata();
// Releases all the cached textures of game objects
void clear_drawobj_cache();
// Updates drawing settings depending on main viewport's size and position on screen
void on_mainviewport_changed();
// Notifies that a new room viewport was created
void on_roomviewport_created(int index);
// Notifies that a new room viewport was deleted
void on_roomviewport_deleted(int index);
// Updates drawing settings if room viewport's position or size has changed
void on_roomviewport_changed(Viewport *view);
// Detects overlapping viewports, starting from the given index in z-sorted array
void detect_roomviewport_overlaps(size_t z_index);
// Updates drawing settings if room camera's size has changed
void on_roomcamera_changed(Camera *cam);
// Marks particular object as need to update the texture
void mark_object_changed(int objid);
// TODO: write a generic drawable/objcache system where each object
// allocates a drawable for itself, and disposes one if being removed.
void reset_drawobj_for_overlay(int objnum);
// Marks all game objects which reference this sprite for redraw
void notify_sprite_changed(int sprnum, bool deleted);
// whether there are currently remnants of a DisplaySpeech
void mark_screen_dirty();
bool is_screen_dirty();
// marks whole screen as needing a redraw
void invalidate_screen();
// marks all the camera frame as needing a redraw
void invalidate_camera_frame(int index);
// marks certain rectangle on screen as needing a redraw
// in_room flag tells how to interpret the coordinates: as in-room coords or screen viewport coordinates.
void invalidate_rect(int x1, int y1, int x2, int y2, bool in_room);
void mark_current_background_dirty();
// Avoid freeing and reallocating the memory if possible
Shared::Bitmap *recycle_bitmap(Shared::Bitmap *bimp, int coldep, int wid, int hit, bool make_transparent = false);
void recycle_bitmap(std::unique_ptr<Shared::Bitmap> &bimp, int coldep, int wid, int hit, bool make_transparent = false);
Engine::IDriverDependantBitmap* recycle_ddb_sprite(Engine::IDriverDependantBitmap *ddb, uint32_t sprite_id, Shared::Bitmap *source, bool has_alpha = false, bool opaque = false);
inline Engine::IDriverDependantBitmap* recycle_ddb_bitmap(Engine::IDriverDependantBitmap *ddb, Shared::Bitmap *source, bool has_alpha = false, bool opaque = false) {
return recycle_ddb_sprite(ddb, UINT32_MAX, source, has_alpha, opaque);
}
// Draw everything
void render_graphics(Engine::IDriverDependantBitmap *extraBitmap = nullptr, int extraX = 0, int extraY = 0);
// Construct game scene, scheduling drawing list for the renderer
void construct_game_scene(bool full_redraw = false);
// Construct final game screen elements; updates and draws mouse cursor
void construct_game_screen_overlay(bool draw_mouse = true);
// Construct engine overlay with debugging tools (fps, console)
void construct_engine_overlay();
// Clears black game borders in legacy letterbox mode
void clear_letterbox_borders();
void debug_draw_room_mask(RoomAreaMask mask);
void debug_draw_movelist(int charnum);
void update_room_debug();
void tint_image(Shared::Bitmap *g, Shared::Bitmap *source, int red, int grn, int blu, int light_level, int luminance = 255);
void draw_sprite_support_alpha(Shared::Bitmap *ds, bool ds_has_alpha, int xpos, int ypos, Shared::Bitmap *image, bool src_has_alpha,
Shared::BlendMode blend_mode = Shared::kBlendMode_Alpha, int alpha = 0xFF);
void draw_sprite_slot_support_alpha(Shared::Bitmap *ds, bool ds_has_alpha, int xpos, int ypos, int src_slot,
Shared::BlendMode blend_mode = Shared::kBlendMode_Alpha, int alpha = 0xFF);
void draw_gui_sprite(Shared::Bitmap *ds, int pic, int x, int y, bool use_alpha = true, Shared::BlendMode blend_mode = Shared::kBlendMode_Alpha);
void draw_gui_sprite_v330(Shared::Bitmap *ds, int pic, int x, int y, bool use_alpha = true, Shared::BlendMode blend_mode = Shared::kBlendMode_Alpha);
void draw_gui_sprite(Shared::Bitmap *ds, bool use_alpha, int xpos, int ypos,
Shared::Bitmap *image, bool src_has_alpha, Shared::BlendMode blend_mode = Shared::kBlendMode_Alpha, int alpha = 0xFF);
// Puts a pixel of certain color, scales it if running in upscaled resolution (legacy feature)
void putpixel_scaled(Shared::Bitmap *ds, int x, int y, int col);
// Render game on screen
void render_to_screen();
// Callbacks for the graphics driver
void draw_game_screen_callback();
void GfxDriverOnInitCallback(void *data);
bool GfxDriverSpriteEvtCallback(int evt, int data);
// Create the actsps[objid] image with the object drawn correctly.
// Returns true if nothing at all has changed and actsps is still
// intact from last time; false otherwise.
// Hardware-accelerated do not require altering the raw bitmap itself,
// so they only detect whether the sprite ID itself has changed.
// Software renderers modify the cached bitmap whenever any visual
// effect changes (scaling, tint, etc).
// * force_software option forces HW renderers to construct the image
// in software mode as well.
bool construct_object_gfx(int objid, bool force_software);
bool construct_char_gfx(int charid, bool force_software);
// Returns a cached character image prepared for the render
Shared::Bitmap *get_cached_character_image(int charid);
// Returns a cached object image prepared for the render
Shared::Bitmap *get_cached_object_image(int objid);
// Adds a walk-behind sprite to the list for the given slot
// (reuses existing texture if possible)
void add_walkbehind_image(size_t index, Shared::Bitmap *bmp, int x, int y);
void draw_and_invalidate_text(Shared::Bitmap *ds, int x1, int y1, int font, color_t text_color, const char *text);
void setpal();
// These functions are converting coordinates between data resolution and
// game resolution units. The first are units used by game data and script,
// and second define the game's screen resolution, sprite and font sizes.
// This conversion is done before anything else (like moving from room to
// viewport on screen, or scaling game further in the window by the graphic
// renderer).
int get_fixed_pixel_size(int pixels);
// coordinate conversion data,script ---> final game resolution
extern int data_to_game_coord(int coord);
extern void data_to_game_coords(int *x, int *y);
extern void data_to_game_round_up(int *x, int *y);
// coordinate conversion final game resolution ---> data,script
extern int game_to_data_coord(int coord);
extern void game_to_data_coords(int &x, int &y);
extern int game_to_data_round_up(int coord);
// convert contextual data coordinates to final game resolution
extern void ctx_data_to_game_coord(int &x, int &y, bool hires_ctx);
extern void ctx_data_to_game_size(int &x, int &y, bool hires_ctx);
extern int ctx_data_to_game_size(int size, bool hires_ctx);
extern int game_to_ctx_data_size(int size, bool hires_ctx);
// This function converts game coordinates coming from script to the actual game resolution.
extern void defgame_to_finalgame_coords(int &x, int &y);
// Creates bitmap of a format compatible with the gfxdriver;
// if col_depth is 0, uses game's native color depth.
Shared::Bitmap *CreateCompatBitmap(int width, int height, int col_depth = 0);
// Checks if the bitmap is compatible with the gfxdriver;
// returns same bitmap or its copy of a compatible format.
Shared::Bitmap *ReplaceBitmapWithSupportedFormat(Shared::Bitmap *bitmap);
// Checks if the bitmap needs any kind of adjustments before it may be used
// in AGS sprite operations. Also handles number of certain special cases
// (old systems or uncommon gfx modes, and similar stuff).
// Original bitmap **gets deleted** if a new bitmap had to be created.
Shared::Bitmap *PrepareSpriteForUse(Shared::Bitmap *bitmap, bool has_alpha);
// Same as above, but compatible for std::shared_ptr.
Shared::PBitmap PrepareSpriteForUse(Shared::PBitmap bitmap, bool has_alpha);
// Makes a screenshot corresponding to the last screen render and returns it as a bitmap
// of the requested width and height and game's native color depth.
Shared::Bitmap *CopyScreenIntoBitmap(int width, int height, const Rect *src_rect = nullptr,
bool at_native_res = false, uint32_t batch_skip_filter = 0u);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,409 @@
/* 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/>.
*
*/
//=============================================================================
//
// Software drawing component. Optimizes drawing for software renderer using
// dirty rectangles technique.
//
// TODO: do research/profiling to find out if this dirty rectangles thing
// is still giving ANY notable performance boost at all.
//
// TODO: would that give any benefit to reorganize the code and move dirty
// rectangles into SoftwareGraphicDriver?
// Alternatively: we could pass dirty rects struct pointer and room background
// DDB when calling BeginSpriteBatch(). Driver itself could be calling
// update_invalid_region(). That will keep gfx driver's changes to minimum.
//
// NOTE: this code, including structs and functions, has underwent several
// iterations of changes. Originally it was meant to perform full transform
// of dirty rects right away, but later I realized it won't work that way
// because a) Allegro does not support scaling bitmaps over destination with
// different colour depth (which may be a case when running 16-bit game),
// and b) Allegro does not support scaling and rotating of sprites with
// blending and lighting at the same time which means that room objects have
// to be drawn upon non-scaled background first. Possibly some of the code
// below may be therefore simplified.
//
//=============================================================================
#include "common/std/vector.h"
#include "ags/engine/ac/draw_software.h"
#include "ags/shared/gfx/bitmap.h"
#include "ags/shared/util/scaling.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
using namespace AGS::Engine;
IRSpan::IRSpan()
: x1(0), x2(0) {
}
IRRow::IRRow()
: numSpans(0) {
}
int IRSpan::mergeSpan(int tx1, int tx2) {
if ((tx1 > x2) || (tx2 < x1))
return 0;
// overlapping, increase the span
if (tx1 < x1)
x1 = tx1;
if (tx2 > x2)
x2 = tx2;
return 1;
}
DirtyRects::DirtyRects()
: NumDirtyRegions(0) {
}
bool DirtyRects::IsInit() const {
return DirtyRows.size() > 0;
}
void DirtyRects::Init(const Size &surf_size, const Rect &viewport) {
int height = surf_size.Height;
if (SurfaceSize != surf_size) {
Destroy();
SurfaceSize = surf_size;
DirtyRows.resize(height);
NumDirtyRegions = WHOLESCREENDIRTY;
for (int i = 0; i < height; ++i)
DirtyRows[i].numSpans = 0;
}
Viewport = viewport;
Room2Screen.Init(surf_size, viewport);
Screen2DirtySurf.Init(viewport, RectWH(0, 0, surf_size.Width, surf_size.Height));
}
void DirtyRects::SetSurfaceOffsets(int x, int y) {
Room2Screen.SetSrcOffsets(x, y);
}
void DirtyRects::Destroy() {
DirtyRows.clear();
NumDirtyRegions = 0;
}
void DirtyRects::Reset() {
NumDirtyRegions = 0;
for (size_t i = 0; i < DirtyRows.size(); ++i)
DirtyRows[i].numSpans = 0;
}
void dispose_invalid_regions(bool /* room_only */) {
_GP(RoomCamRects).clear();
_GP(RoomCamPositions).clear();
}
void set_invalidrects_globaloffs(int x, int y) {
_GP(GlobalOffs) = Point(x, y);
}
void init_invalid_regions(int view_index, const Size &surf_size, const Rect &viewport) {
if (view_index < 0) {
_GP(BlackRects).Init(surf_size, viewport);
} else {
if (_GP(RoomCamRects).size() <= (size_t)view_index) {
_GP(RoomCamRects).resize(view_index + 1);
_GP(RoomCamPositions).resize(view_index + 1);
}
_GP(RoomCamRects)[view_index].Init(surf_size, viewport);
_GP(RoomCamPositions)[view_index] = std::make_pair(-1000, -1000);
}
}
void delete_invalid_regions(int view_index) {
if (view_index >= 0) {
_GP(RoomCamRects).erase(_GP(RoomCamRects).begin() + view_index);
_GP(RoomCamPositions).erase(_GP(RoomCamPositions).begin() + view_index);
}
}
void set_invalidrects_cameraoffs(int view_index, int x, int y) {
if (view_index < 0) {
_GP(BlackRects).SetSurfaceOffsets(x, y);
return;
} else {
_GP(RoomCamRects)[view_index].SetSurfaceOffsets(x, y);
}
int &posxwas = _GP(RoomCamPositions)[view_index].first;
int &posywas = _GP(RoomCamPositions)[view_index].second;
if ((x != posxwas) || (y != posywas)) {
invalidate_all_camera_rects(view_index);
posxwas = x;
posywas = y;
}
}
void invalidate_all_rects() {
for (auto &rects : _GP(RoomCamRects)) {
if (!IsRectInsideRect(rects.Viewport, _GP(BlackRects).Viewport))
_GP(BlackRects).NumDirtyRegions = WHOLESCREENDIRTY;
rects.NumDirtyRegions = WHOLESCREENDIRTY;
}
}
void invalidate_all_camera_rects(int view_index) {
if (view_index < 0)
return;
_GP(RoomCamRects)[view_index].NumDirtyRegions = WHOLESCREENDIRTY;
}
void invalidate_rect_on_surf(int x1, int y1, int x2, int y2, DirtyRects &rects) {
if (rects.DirtyRows.size() == 0)
return;
if (rects.NumDirtyRegions >= MAXDIRTYREGIONS) {
// too many invalid rectangles, just mark the whole thing dirty
rects.NumDirtyRegions = WHOLESCREENDIRTY;
return;
}
if (x1 > x2 || y1 > y2)
return;
int a;
const Size &surfsz = rects.SurfaceSize;
if (x1 >= surfsz.Width || y1 >= surfsz.Height || x2 < 0 || y2 < 0)
return;
if (x2 >= surfsz.Width) x2 = surfsz.Width - 1;
if (y2 >= surfsz.Height) y2 = surfsz.Height - 1;
if (x1 < 0) x1 = 0;
if (y1 < 0) y1 = 0;
rects.NumDirtyRegions++;
// ** Span code
std::vector<IRRow> &dirtyRow = rects.DirtyRows;
int s, foundOne;
// add this rect to the list for this row
for (a = y1; a <= y2; a++) {
foundOne = 0;
for (s = 0; s < dirtyRow[a].numSpans; s++) {
if (dirtyRow[a].span[s].mergeSpan(x1, x2)) {
foundOne = 1;
break;
}
}
if (foundOne) {
// we were merged into a span, so we're ok
int t;
// check whether now two of the spans overlap each other
// in which case merge them
for (s = 0; s < dirtyRow[a].numSpans; s++) {
for (t = s + 1; t < dirtyRow[a].numSpans; t++) {
if (dirtyRow[a].span[s].mergeSpan(dirtyRow[a].span[t].x1, dirtyRow[a].span[t].x2)) {
dirtyRow[a].numSpans--;
for (int u = t; u < dirtyRow[a].numSpans; u++)
dirtyRow[a].span[u] = dirtyRow[a].span[u + 1];
break;
}
}
}
} else if (dirtyRow[a].numSpans < MAX_SPANS_PER_ROW) {
dirtyRow[a].span[dirtyRow[a].numSpans].x1 = x1;
dirtyRow[a].span[dirtyRow[a].numSpans].x2 = x2;
dirtyRow[a].numSpans++;
} else {
// didn't fit in an existing span, and there are none spare
int nearestDist = 99999, nearestWas = -1, extendLeft = 0;
// find the nearest span, and enlarge that to include this rect
for (s = 0; s < dirtyRow[a].numSpans; s++) {
int tleft = dirtyRow[a].span[s].x1 - x2;
if ((tleft > 0) && (tleft < nearestDist)) {
nearestDist = tleft;
nearestWas = s;
extendLeft = 1;
}
int tright = x1 - dirtyRow[a].span[s].x2;
if ((tright > 0) && (tright < nearestDist)) {
nearestDist = tright;
nearestWas = s;
extendLeft = 0;
}
}
assert(nearestWas >= 0);
if (extendLeft)
dirtyRow[a].span[nearestWas].x1 = x1;
else
dirtyRow[a].span[nearestWas].x2 = x2;
}
}
// ** End span code
//}
}
void invalidate_rect_ds(DirtyRects &rects, int x1, int y1, int x2, int y2, bool in_room) {
if (!in_room) {
// TODO: for most opimisation (esp. with multiple viewports) should perhaps
// split/cut parts of the original rectangle which overlap room viewport(s).
Rect r(x1, y1, x2, y2);
// If overlay is NOT completely over the room, then invalidate black rect
if (!IsRectInsideRect(rects.Viewport, r))
invalidate_rect_on_surf(x1, y1, x2, y2, _GP(BlackRects));
// If overlay is NOT intersecting room viewport at all, then stop
if (!AreRectsIntersecting(rects.Viewport, r))
return;
// Transform from screen to room coordinates through the known viewport
x1 = rects.Screen2DirtySurf.X.ScalePt(x1);
x2 = rects.Screen2DirtySurf.X.ScalePt(x2);
y1 = rects.Screen2DirtySurf.Y.ScalePt(y1);
y2 = rects.Screen2DirtySurf.Y.ScalePt(y2);
} else {
// Transform only from camera pos to room background
x1 -= rects.Room2Screen.X.GetSrcOffset();
y1 -= rects.Room2Screen.Y.GetSrcOffset();
x2 -= rects.Room2Screen.X.GetSrcOffset();
y2 -= rects.Room2Screen.Y.GetSrcOffset();
}
invalidate_rect_on_surf(x1, y1, x2, y2, rects);
}
void invalidate_rect_ds(int x1, int y1, int x2, int y2, bool in_room) {
if (!in_room) { // convert from game viewport to global screen coords
x1 += _GP(GlobalOffs).X;
x2 += _GP(GlobalOffs).X;
y1 += _GP(GlobalOffs).Y;
y2 += _GP(GlobalOffs).Y;
}
for (auto &rects : _GP(RoomCamRects))
invalidate_rect_ds(rects, x1, y1, x2, y2, in_room);
}
void invalidate_rect_global(int x1, int y1, int x2, int y2) {
for (auto &rects : _GP(RoomCamRects))
invalidate_rect_ds(rects, x1, y1, x2, y2, false);
}
// Note that this function is denied to perform any kind of scaling or other transformation
// other than blitting with offset. This is mainly because destination could be a 32-bit virtual screen
// while room background was 16-bit and Allegro lib does not support stretching between colour depths.
// The no_transform flag here means essentially "no offset", and indicates that the function
// must blit src on ds at 0;0. Otherwise, actual Viewport offset is used.
void update_invalid_region(Bitmap *ds, Bitmap *src, const DirtyRects &rects, bool no_transform) {
if (rects.NumDirtyRegions == 0)
return;
if (!no_transform)
ds->SetClip(rects.Viewport);
const int src_x = rects.Room2Screen.X.GetSrcOffset();
const int src_y = rects.Room2Screen.Y.GetSrcOffset();
const int dst_x = no_transform ? 0 : rects.Viewport.Left;
const int dst_y = no_transform ? 0 : rects.Viewport.Top;
if (rects.NumDirtyRegions == WHOLESCREENDIRTY) {
ds->Blit(src, src_x, src_y, dst_x, dst_y, rects.SurfaceSize.Width, rects.SurfaceSize.Height);
} else {
const std::vector<IRRow> &dirtyRow = rects.DirtyRows;
const int surf_height = rects.SurfaceSize.Height;
// TODO: is this IsMemoryBitmap check is still relevant?
// If bitmaps properties match and no transform required other than linear offset
if (src->GetColorDepth() == ds->GetColorDepth()) {
const int bypp = src->GetBPP();
// do the fast memory copy
for (int i = 0; i < surf_height; i++) {
const uint8_t *src_scanline = src->GetScanLine(i + src_y);
uint8_t *dst_scanline = ds->GetScanLineForWriting(i + dst_y);
const IRRow &dirty_row = dirtyRow[i];
for (int k = 0; k < dirty_row.numSpans; k++) {
int tx1 = dirty_row.span[k].x1;
int tx2 = dirty_row.span[k].x2;
memcpy(&dst_scanline[(tx1 + dst_x) * bypp], &src_scanline[(tx1 + src_x) * bypp], ((tx2 - tx1) + 1) * bypp);
}
}
}
// If has to use Blit, but still must draw with no transform but offset
else {
// do fast copy without transform
for (int i = 0, rowsInOne = 1; i < surf_height; i += rowsInOne, rowsInOne = 1) {
// if there are rows with identical masks, do them all in one go
// TODO: what is this for? may this be done at the invalidate_rect merge step?
while ((i + rowsInOne < surf_height) && (memcmp(&dirtyRow[i], &dirtyRow[i + rowsInOne], sizeof(IRRow)) == 0))
rowsInOne++;
const IRRow &dirty_row = dirtyRow[i];
for (int k = 0; k < dirty_row.numSpans; k++) {
int tx1 = dirty_row.span[k].x1;
int tx2 = dirty_row.span[k].x2;
ds->Blit(src, tx1 + src_x, i + src_y, tx1 + dst_x, i + dst_y, (tx2 - tx1) + 1, rowsInOne);
}
}
}
}
}
void update_invalid_region(Bitmap *ds, color_t fill_color, const DirtyRects &rects) {
ds->SetClip(rects.Viewport);
if (rects.NumDirtyRegions == WHOLESCREENDIRTY) {
ds->FillRect(rects.Viewport, fill_color);
} else {
const std::vector<IRRow> &dirtyRow = rects.DirtyRows;
const int surf_height = rects.SurfaceSize.Height;
{
const AGS::Shared::PlaneScaling &tf = rects.Room2Screen;
for (int i = 0, rowsInOne = 1; i < surf_height; i += rowsInOne, rowsInOne = 1) {
// if there are rows with identical masks, do them all in one go
// TODO: what is this for? may this be done at the invalidate_rect merge step?
while ((i + rowsInOne < surf_height) && (memcmp(&dirtyRow[i], &dirtyRow[i + rowsInOne], sizeof(IRRow)) == 0))
rowsInOne++;
const IRRow &dirty_row = dirtyRow[i];
for (int k = 0; k < dirty_row.numSpans; k++) {
Rect src_r(dirty_row.span[k].x1, i, dirty_row.span[k].x2, i + rowsInOne - 1);
Rect dst_r = tf.ScaleRange(src_r);
ds->FillRect(dst_r, fill_color);
}
}
}
}
}
void update_black_invreg_and_reset(Bitmap *ds) {
if (!_GP(BlackRects).IsInit())
return;
update_invalid_region(ds, (color_t)0, _GP(BlackRects));
_GP(BlackRects).Reset();
}
void update_room_invreg_and_reset(int view_index, Bitmap *ds, Bitmap *src, bool no_transform) {
if (view_index < 0 || _GP(RoomCamRects).size() == 0)
return;
update_invalid_region(ds, src, _GP(RoomCamRects)[view_index], no_transform);
_GP(RoomCamRects)[view_index].Reset();
}
} // namespace AGS3

View File

@@ -0,0 +1,116 @@
/* 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/>.
*
*/
//=============================================================================
//
// Software drawing component. Optimizes drawing for software renderer using
// dirty rectangles technique.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_DRAW_SOFTWARE_H
#define AGS_ENGINE_AC_DRAW_SOFTWARE_H
#include "ags/shared/gfx/bitmap.h"
#include "ags/engine/gfx/ddb.h"
#include "ags/shared/util/geometry.h"
#include "ags/shared/util/scaling.h"
namespace AGS3 {
using AGS::Shared::PlaneScaling;
// TODO: choose these values depending on game resolution?
#define MAXDIRTYREGIONS 25
#define WHOLESCREENDIRTY (MAXDIRTYREGIONS + 5)
#define MAX_SPANS_PER_ROW 4
// Dirty rects store coordinate values in the coordinate system of a camera surface,
// where coords always span from 0,0 to surface width,height.
// Converting from room to dirty rects would require subtracting room camera offsets.
struct IRSpan {
int x1, x2;
int mergeSpan(int tx1, int tx2);
IRSpan();
};
struct IRRow {
IRSpan span[MAX_SPANS_PER_ROW];
int numSpans;
IRRow();
};
struct DirtyRects {
// Size of the surface managed by this dirty rects object
Size SurfaceSize;
// Where the surface is rendered on screen
Rect Viewport;
// Room -> screen coordinate transformation
PlaneScaling Room2Screen;
// Screen -> dirty surface rect
// The dirty rects are saved in coordinates limited to (0,0)->(camera size) rather than room or screen coords
PlaneScaling Screen2DirtySurf;
std::vector<IRRow> DirtyRows;
Rect DirtyRegions[MAXDIRTYREGIONS];
size_t NumDirtyRegions;
DirtyRects();
bool IsInit() const;
// Initialize dirty rects for the given surface size
void Init(const Size &surf_size, const Rect &viewport);
void SetSurfaceOffsets(int x, int y);
// Delete dirty rects
void Destroy();
// Mark all surface as tidy
void Reset();
};
// Sets global viewport offset (used for legacy letterbox)
void set_invalidrects_globaloffs(int x, int y);
// Inits dirty rects array for the given room camera/viewport pair
// View_index indicates the room viewport (>= 0) or the main viewport (-1)
void init_invalid_regions(int view_index, const Size &surf_size, const Rect &viewport);
// Deletes dirty rects for particular index
void delete_invalid_regions(int view_index);
// Disposes dirty rects arrays
void dispose_invalid_regions(bool room_only);
// Update the coordinate transformation for the particular dirty rects object
void set_invalidrects_cameraoffs(int view_index, int x, int y);
// Mark the whole screen dirty
void invalidate_all_rects();
// Mark the whole camera surface dirty
void invalidate_all_camera_rects(int view_index);
// Mark certain rectangle dirty; in_room tells if coordinates are room viewport or screen coords
void invalidate_rect_ds(int x1, int y1, int x2, int y2, bool in_room);
// Mark rectangle dirty, treat pos as global screen coords (not offset by legacy letterbox mode)
void invalidate_rect_global(int x1, int y1, int x2, int y2);
// Paints the black screen background in the regions marked as dirty
void update_black_invreg_and_reset(AGS::Shared::Bitmap *ds);
// Copies the room regions marked as dirty from source (src) to destination (ds) with the given offset (x, y)
// no_transform flag tells the system that the regions should be plain copied to the ds.
void update_room_invreg_and_reset(int view_index, AGS::Shared::Bitmap *ds, AGS::Shared::Bitmap *src, bool no_transform);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,590 @@
/* 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/engine/ac/draw.h"
#include "ags/engine/ac/drawing_surface.h"
#include "ags/shared/ac/common.h"
#include "ags/engine/ac/display.h"
#include "ags/engine/ac/game.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/engine/ac/game_state.h"
#include "ags/engine/ac/global_translation.h"
#include "ags/engine/ac/room_object.h"
#include "ags/engine/ac/room_status.h"
#include "ags/engine/ac/string.h"
#include "ags/engine/ac/walk_behind.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/engine/debugging/debug_log.h"
#include "ags/shared/font/fonts.h"
#include "ags/shared/gui/gui_main.h"
#include "ags/shared/ac/sprite_cache.h"
#include "ags/engine/script/runtime_script_value.h"
#include "ags/shared/gfx/gfx_def.h"
#include "ags/shared/debugging/out.h"
#include "ags/engine/script/script_api.h"
#include "ags/engine/script/script_runtime.h"
#include "ags/engine/gfx/gfx_util.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
using namespace AGS::Engine;
// ** SCRIPT DRAWINGSURFACE OBJECT
void DrawingSurface_Release(ScriptDrawingSurface *sds) {
if (sds->roomBackgroundNumber >= 0) {
if (sds->modified) {
if (sds->roomBackgroundNumber == _GP(play).bg_frame) {
invalidate_screen();
mark_current_background_dirty();
}
_GP(play).raw_modified[sds->roomBackgroundNumber] = 1;
}
sds->roomBackgroundNumber = -1;
}
if (sds->roomMaskType > kRoomAreaNone) {
if (sds->roomMaskType == kRoomAreaWalkBehind) {
walkbehinds_recalc();
}
sds->roomMaskType = kRoomAreaNone;
}
if (sds->dynamicSpriteNumber >= 0) {
if (sds->modified) {
game_sprite_updated(sds->dynamicSpriteNumber);
}
sds->dynamicSpriteNumber = -1;
}
if (sds->dynamicSurfaceNumber >= 0) {
_G(dynamicallyCreatedSurfaces)[sds->dynamicSurfaceNumber].reset();
sds->dynamicSurfaceNumber = -1;
}
sds->modified = 0;
}
void ScriptDrawingSurface::PointToGameResolution(int *xcoord, int *ycoord) {
ctx_data_to_game_coord(*xcoord, *ycoord, highResCoordinates != 0);
}
void ScriptDrawingSurface::SizeToGameResolution(int *width, int *height) {
ctx_data_to_game_size(*width, *height, highResCoordinates != 0);
}
void ScriptDrawingSurface::SizeToGameResolution(int *valueToAdjust) {
*valueToAdjust = ctx_data_to_game_size(*valueToAdjust, highResCoordinates != 0);
}
// convert actual co-ordinate back to what the script is expecting
void ScriptDrawingSurface::SizeToDataResolution(int *valueToAdjust) {
*valueToAdjust = game_to_ctx_data_size(*valueToAdjust, highResCoordinates != 0);
}
ScriptDrawingSurface *DrawingSurface_CreateCopy(ScriptDrawingSurface *sds) {
Bitmap *sourceBitmap = sds->GetBitmapSurface();
for (int i = 0; i < MAX_DYNAMIC_SURFACES; i++) {
if (_G(dynamicallyCreatedSurfaces)[i] == nullptr) {
_G(dynamicallyCreatedSurfaces)[i].reset(BitmapHelper::CreateBitmapCopy(sourceBitmap));
ScriptDrawingSurface *newSurface = new ScriptDrawingSurface();
newSurface->dynamicSurfaceNumber = i;
newSurface->hasAlphaChannel = sds->hasAlphaChannel;
ccRegisterManagedObject(newSurface, newSurface);
return newSurface;
}
}
quit("!DrawingSurface.CreateCopy: too many copied surfaces created");
return nullptr;
}
void DrawingSurface_DrawImageImpl(ScriptDrawingSurface *sds, Bitmap *src,
int dst_x, int dst_y, int trans, int dst_width, int dst_height,
int src_x, int src_y, int src_width, int src_height, int sprite_id, bool src_has_alpha) {
Bitmap *ds = sds->GetBitmapSurface();
if (src == ds) {
} // ignore for now; bitmap lib supports, and may be used for effects
/* debug_script_warn("DrawingSurface.DrawImage: drawing onto itself"); */
if (src->GetColorDepth() != ds->GetColorDepth()) {
if (sprite_id >= 0)
debug_script_warn("DrawImage: Sprite %d colour depth %d-bit not same as destination depth %d-bit", sprite_id, src->GetColorDepth(), ds->GetColorDepth());
else
debug_script_warn("DrawImage: Source image colour depth %d-bit not same as destination depth %d-bit", src->GetColorDepth(), ds->GetColorDepth());
}
if ((trans < 0) || (trans > 100))
debug_script_warn("DrawingSurface.DrawImage: invalid transparency %d, range is %d - %d", trans, 0, 100);
trans = Math::Clamp(trans, 0, 100);
if (trans == 100)
return; // fully transparent
if (dst_width < 1 || dst_height < 1 || src_width < 1 || src_height < 1)
return; // invalid src or dest rectangles
// Setup uninitialized arguments; convert coordinates for legacy script mode
if (dst_width == SCR_NO_VALUE) {
dst_width = src->GetWidth();
} else {
sds->SizeToGameResolution(&dst_width);
}
if (dst_height == SCR_NO_VALUE) {
dst_height = src->GetHeight();
} else {
sds->SizeToGameResolution(&dst_height);
}
if (src_x == SCR_NO_VALUE) {
src_x = 0;
}
if (src_y == SCR_NO_VALUE) {
src_y = 0;
}
sds->PointToGameResolution(&src_x, &src_y);
if (src_width == SCR_NO_VALUE) {
src_width = src->GetWidth();
} else {
sds->SizeToGameResolution(&src_width);
}
if (src_height == SCR_NO_VALUE) {
src_height = src->GetHeight();
} else {
sds->SizeToGameResolution(&src_height);
}
sds->PointToGameResolution(&dst_x, &dst_y);
if (dst_x >= ds->GetWidth() || dst_x + dst_width <= 0 || dst_y >= ds->GetHeight() || dst_y + dst_height <= 0 ||
src_x >= src->GetWidth() || src_x + src_width <= 0 || src_y >= src->GetHeight() || src_y + src_height <= 0)
return; // source or destination rects lie completely off surface
// Clamp the source rect to the valid limits to prevent exceptions (ignore dest, bitmap drawing deals with that)
Math::ClampLength(src_x, src_width, 0, src->GetWidth());
Math::ClampLength(src_y, src_height, 0, src->GetHeight());
// TODO: possibly optimize by not making a stretched intermediate bitmap
// if simpler blit/draw_sprite could be called (no translucency with alpha channel).
std::unique_ptr<Bitmap> conv_src;
if (dst_width != src->GetWidth() || dst_height != src->GetHeight() ||
src_width != src->GetWidth() || src_height != src->GetHeight()) {
// Resize and/or partial copy specified
conv_src.reset(BitmapHelper::CreateBitmap(dst_width, dst_height, src->GetColorDepth()));
conv_src->StretchBlt(src,
RectWH(src_x, src_y, src_width, src_height),
RectWH(0, 0, dst_width, dst_height));
src = conv_src.get();
}
ds = sds->StartDrawing();
draw_sprite_support_alpha(ds, sds->hasAlphaChannel != 0, dst_x, dst_y, src, src_has_alpha,
kBlendMode_Alpha, GfxDef::Trans100ToAlpha255(trans));
sds->FinishedDrawing();
}
void DrawingSurface_DrawImage(ScriptDrawingSurface *sds,
int dst_x, int dst_y, int slot, int trans,
int dst_width, int dst_height,
int src_x, int src_y, int src_width, int src_height) {
if ((slot < 0) || (!_GP(spriteset).DoesSpriteExist(slot)))
quit("!DrawingSurface.DrawImage: invalid sprite slot number specified");
DrawingSurface_DrawImageImpl(sds, _GP(spriteset)[slot], dst_x, dst_y, trans, dst_width, dst_height,
src_x, src_y, src_width, src_height, slot, (_GP(game).SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0);
}
void DrawingSurface_DrawImage6(ScriptDrawingSurface *sds, int xx, int yy, int slot, int trans, int width, int height) {
DrawingSurface_DrawImage(sds, xx, yy, slot, trans, width, height, 0, 0, SCR_NO_VALUE, SCR_NO_VALUE);
}
void DrawingSurface_DrawSurface(ScriptDrawingSurface *target, ScriptDrawingSurface *source, int trans,
int dst_x, int dst_y, int dst_width, int dst_height,
int src_x, int src_y, int src_width, int src_height) {
DrawingSurface_DrawImageImpl(target, source->GetBitmapSurface(), dst_x, dst_y, trans, dst_width, dst_height,
src_x, src_y, src_width, src_height, -1, source->hasAlphaChannel != 0);
}
void DrawingSurface_DrawSurface2(ScriptDrawingSurface *target, ScriptDrawingSurface *source, int trans) {
DrawingSurface_DrawSurface(target, source, trans, 0, 0, SCR_NO_VALUE, SCR_NO_VALUE, 0, 0, SCR_NO_VALUE, SCR_NO_VALUE);
}
void DrawingSurface_SetDrawingColor(ScriptDrawingSurface *sds, int newColour) {
sds->currentColourScript = newColour;
// StartDrawing to set up ds to set the colour at the appropriate
// depth for the background
Bitmap *ds = sds->StartDrawing();
if (newColour == SCR_COLOR_TRANSPARENT) {
sds->currentColour = ds->GetMaskColor();
} else {
sds->currentColour = ds->GetCompatibleColor(newColour);
}
sds->FinishedDrawingReadOnly();
}
int DrawingSurface_GetDrawingColor(ScriptDrawingSurface *sds) {
return sds->currentColourScript;
}
void DrawingSurface_SetUseHighResCoordinates(ScriptDrawingSurface *sds, int highRes) {
if (_GP(game).AllowRelativeRes())
sds->highResCoordinates = (highRes) ? 1 : 0;
}
int DrawingSurface_GetUseHighResCoordinates(ScriptDrawingSurface *sds) {
return sds->highResCoordinates;
}
int DrawingSurface_GetHeight(ScriptDrawingSurface *sds) {
Bitmap *ds = sds->StartDrawing();
int height = ds->GetHeight();
sds->FinishedDrawingReadOnly();
sds->SizeToGameResolution(&height);
return height;
}
int DrawingSurface_GetWidth(ScriptDrawingSurface *sds) {
Bitmap *ds = sds->StartDrawing();
int width = ds->GetWidth();
sds->FinishedDrawingReadOnly();
sds->SizeToGameResolution(&width);
return width;
}
void DrawingSurface_Clear(ScriptDrawingSurface *sds, int colour) {
Bitmap *ds = sds->StartDrawing();
int allegroColor;
if ((colour == -SCR_NO_VALUE) || (colour == SCR_COLOR_TRANSPARENT)) {
allegroColor = ds->GetMaskColor();
} else {
allegroColor = ds->GetCompatibleColor(colour);
}
ds->Fill(allegroColor);
sds->FinishedDrawing();
}
void DrawingSurface_DrawCircle(ScriptDrawingSurface *sds, int x, int y, int radius) {
sds->PointToGameResolution(&x, &y);
sds->SizeToGameResolution(&radius);
Bitmap *ds = sds->StartDrawing();
ds->FillCircle(Circle(x, y, radius), sds->currentColour);
sds->FinishedDrawing();
}
void DrawingSurface_DrawRectangle(ScriptDrawingSurface *sds, int x1, int y1, int x2, int y2) {
sds->PointToGameResolution(&x1, &y1);
sds->PointToGameResolution(&x2, &y2);
Bitmap *ds = sds->StartDrawing();
ds->FillRect(Rect(x1, y1, x2, y2), sds->currentColour);
sds->FinishedDrawing();
}
void DrawingSurface_DrawTriangle(ScriptDrawingSurface *sds, int x1, int y1, int x2, int y2, int x3, int y3) {
sds->PointToGameResolution(&x1, &y1);
sds->PointToGameResolution(&x2, &y2);
sds->PointToGameResolution(&x3, &y3);
Bitmap *ds = sds->StartDrawing();
ds->DrawTriangle(Triangle(x1, y1, x2, y2, x3, y3), sds->currentColour);
sds->FinishedDrawing();
}
void DrawingSurface_DrawString(ScriptDrawingSurface *sds, int xx, int yy, int font, const char *text) {
sds->PointToGameResolution(&xx, &yy);
Bitmap *ds = sds->StartDrawing();
// don't use wtextcolor because it will do a 16->32 conversion
color_t text_color = sds->currentColour;
if ((ds->GetColorDepth() <= 8) && (_GP(play).raw_color > 255)) {
text_color = ds->GetCompatibleColor(1);
debug_script_warn("RawPrint: Attempted to use hi-color on 256-col background");
}
String res_str = GUI::ApplyTextDirection(text);
wouttext_outline(ds, xx, yy, font, text_color, res_str.GetCStr());
sds->FinishedDrawing();
}
void DrawingSurface_DrawStringWrapped_Old(ScriptDrawingSurface *sds, int xx, int yy, int wid, int font, int alignment, const char *msg) {
DrawingSurface_DrawStringWrapped(sds, xx, yy, wid, font, ConvertLegacyScriptAlignment((LegacyScriptAlignment)alignment), msg);
}
void DrawingSurface_DrawStringWrapped(ScriptDrawingSurface *sds, int xx, int yy, int wid, int font, int alignment, const char *msg) {
int linespacing = get_font_linespacing(font);
sds->PointToGameResolution(&xx, &yy);
sds->SizeToGameResolution(&wid);
if (break_up_text_into_lines(msg, _GP(Lines), wid, font) == 0)
return;
Bitmap *ds = sds->StartDrawing();
color_t text_color = sds->currentColour;
for (size_t i = 0; i < _GP(Lines).Count(); i++) {
GUI::DrawTextAlignedHor(ds, _GP(Lines)[i].GetCStr(), font, text_color,
xx, xx + wid - 1, yy + linespacing * i, (FrameAlignment)alignment);
}
sds->FinishedDrawing();
}
void DrawingSurface_DrawMessageWrapped(ScriptDrawingSurface *sds, int xx, int yy, int wid, int font, int msgm) {
char displbuf[3000];
get_message_text(msgm, displbuf);
// it's probably too late but check anyway
if (strlen(displbuf) > 2899)
quit("!RawPrintMessageWrapped: message too long");
DrawingSurface_DrawStringWrapped_Old(sds, xx, yy, wid, font, kLegacyScAlignLeft, displbuf);
}
void DrawingSurface_DrawLine(ScriptDrawingSurface *sds, int fromx, int fromy, int tox, int toy, int thickness) {
sds->PointToGameResolution(&fromx, &fromy);
sds->PointToGameResolution(&tox, &toy);
sds->SizeToGameResolution(&thickness);
int ii, jj, xx, yy;
Bitmap *ds = sds->StartDrawing();
// draw several lines to simulate the thickness
color_t draw_color = sds->currentColour;
for (ii = 0; ii < thickness; ii++) {
xx = (ii - (thickness / 2));
for (jj = 0; jj < thickness; jj++) {
yy = (jj - (thickness / 2));
ds->DrawLine(Line(fromx + xx, fromy + yy, tox + xx, toy + yy), draw_color);
}
}
sds->FinishedDrawing();
}
void DrawingSurface_DrawPixel(ScriptDrawingSurface *sds, int x, int y) {
sds->PointToGameResolution(&x, &y);
int thickness = 1;
sds->SizeToGameResolution(&thickness);
int ii, jj;
Bitmap *ds = sds->StartDrawing();
// draw several pixels to simulate the thickness
color_t draw_color = sds->currentColour;
for (ii = 0; ii < thickness; ii++) {
for (jj = 0; jj < thickness; jj++) {
ds->PutPixel(x + ii, y + jj, draw_color);
}
}
sds->FinishedDrawing();
}
int DrawingSurface_GetPixel(ScriptDrawingSurface *sds, int x, int y) {
sds->PointToGameResolution(&x, &y);
Bitmap *ds = sds->StartDrawing();
int rawPixel = ds->GetPixel(x, y);
int maskColor = ds->GetMaskColor();
int colDepth = ds->GetColorDepth();
if (rawPixel == maskColor) {
rawPixel = (unsigned int)SCR_COLOR_TRANSPARENT;
} else if (colDepth > 8) {
int r = getr_depth(colDepth, rawPixel);
int g = getg_depth(colDepth, rawPixel);
int b = getb_depth(colDepth, rawPixel);
rawPixel = Game_GetColorFromRGB(r, g, b);
}
sds->FinishedDrawingReadOnly();
return rawPixel;
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
// void (ScriptDrawingSurface *sds, int colour)
RuntimeScriptValue Sc_DrawingSurface_Clear(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDrawingSurface, DrawingSurface_Clear);
}
// ScriptDrawingSurface* (ScriptDrawingSurface *sds)
RuntimeScriptValue Sc_DrawingSurface_CreateCopy(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJAUTO(ScriptDrawingSurface, ScriptDrawingSurface, DrawingSurface_CreateCopy);
}
// void (ScriptDrawingSurface *sds, int x, int y, int radius)
RuntimeScriptValue Sc_DrawingSurface_DrawCircle(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT3(ScriptDrawingSurface, DrawingSurface_DrawCircle);
}
// void (ScriptDrawingSurface* sds, int xx, int yy, int slot, int trans, int width, int height)
RuntimeScriptValue Sc_DrawingSurface_DrawImage6(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT6(ScriptDrawingSurface, DrawingSurface_DrawImage6);
}
RuntimeScriptValue Sc_DrawingSurface_DrawImage(void *self, const RuntimeScriptValue *params, int32_t param_count) {
ASSERT_OBJ_PARAM_COUNT(METHOD, 10);
DrawingSurface_DrawImage((ScriptDrawingSurface *)self, params[0].IValue, params[1].IValue, params[2].IValue, params[3].IValue, params[4].IValue, params[5].IValue,
params[6].IValue, params[7].IValue, params[8].IValue, params[9].IValue);
return RuntimeScriptValue((int32_t)0);
}
// void (ScriptDrawingSurface *sds, int fromx, int fromy, int tox, int toy, int thickness)
RuntimeScriptValue Sc_DrawingSurface_DrawLine(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT5(ScriptDrawingSurface, DrawingSurface_DrawLine);
}
// void (ScriptDrawingSurface *sds, int xx, int yy, int wid, int font, int msgm)
RuntimeScriptValue Sc_DrawingSurface_DrawMessageWrapped(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT5(ScriptDrawingSurface, DrawingSurface_DrawMessageWrapped);
}
// void (ScriptDrawingSurface *sds, int x, int y)
RuntimeScriptValue Sc_DrawingSurface_DrawPixel(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT2(ScriptDrawingSurface, DrawingSurface_DrawPixel);
}
// void (ScriptDrawingSurface *sds, int x1, int y1, int x2, int y2)
RuntimeScriptValue Sc_DrawingSurface_DrawRectangle(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT4(ScriptDrawingSurface, DrawingSurface_DrawRectangle);
}
// void (ScriptDrawingSurface *sds, int xx, int yy, int font, const char* texx, ...)
RuntimeScriptValue Sc_DrawingSurface_DrawString(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_SCRIPT_SPRINTF(DrawingSurface_DrawString, 4);
DrawingSurface_DrawString((ScriptDrawingSurface *)self, params[0].IValue, params[1].IValue, params[2].IValue, scsf_buffer);
return RuntimeScriptValue((int32_t)0);
}
// void (ScriptDrawingSurface *sds, int xx, int yy, int wid, int font, int alignment, const char *msg)
RuntimeScriptValue Sc_DrawingSurface_DrawStringWrapped_Old(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT5_POBJ(ScriptDrawingSurface, DrawingSurface_DrawStringWrapped_Old, const char);
}
RuntimeScriptValue Sc_DrawingSurface_DrawStringWrapped(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_SCRIPT_SPRINTF(DrawingSurface_DrawString, 6);
DrawingSurface_DrawStringWrapped((ScriptDrawingSurface *)self, params[0].IValue, params[1].IValue, params[2].IValue,
params[3].IValue, params[4].IValue, scsf_buffer);
return RuntimeScriptValue((int32_t)0);
}
// void (ScriptDrawingSurface* target, ScriptDrawingSurface* source, int translev)
RuntimeScriptValue Sc_DrawingSurface_DrawSurface2(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_POBJ_PINT(ScriptDrawingSurface, DrawingSurface_DrawSurface2, ScriptDrawingSurface);
}
RuntimeScriptValue Sc_DrawingSurface_DrawSurface(void *self, const RuntimeScriptValue *params, int32_t param_count) {
ASSERT_OBJ_PARAM_COUNT(METHOD, 10);
DrawingSurface_DrawSurface((ScriptDrawingSurface *)self, (ScriptDrawingSurface *)params[0].Ptr,
params[1].IValue, params[2].IValue, params[3].IValue, params[4].IValue, params[5].IValue,
params[6].IValue, params[7].IValue, params[8].IValue, params[9].IValue);
return RuntimeScriptValue((int32_t)0);
}
// void (ScriptDrawingSurface *sds, int x1, int y1, int x2, int y2, int x3, int y3)
RuntimeScriptValue Sc_DrawingSurface_DrawTriangle(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT6(ScriptDrawingSurface, DrawingSurface_DrawTriangle);
}
// int (ScriptDrawingSurface *sds, int x, int y)
RuntimeScriptValue Sc_DrawingSurface_GetPixel(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT_PINT2(ScriptDrawingSurface, DrawingSurface_GetPixel);
}
// void (ScriptDrawingSurface* sds)
RuntimeScriptValue Sc_DrawingSurface_Release(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID(ScriptDrawingSurface, DrawingSurface_Release);
}
// int (ScriptDrawingSurface *sds)
RuntimeScriptValue Sc_DrawingSurface_GetDrawingColor(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDrawingSurface, DrawingSurface_GetDrawingColor);
}
// void (ScriptDrawingSurface *sds, int newColour)
RuntimeScriptValue Sc_DrawingSurface_SetDrawingColor(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDrawingSurface, DrawingSurface_SetDrawingColor);
}
// int (ScriptDrawingSurface *sds)
RuntimeScriptValue Sc_DrawingSurface_GetHeight(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDrawingSurface, DrawingSurface_GetHeight);
}
// int (ScriptDrawingSurface *sds)
RuntimeScriptValue Sc_DrawingSurface_GetUseHighResCoordinates(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDrawingSurface, DrawingSurface_GetUseHighResCoordinates);
}
// void (ScriptDrawingSurface *sds, int highRes)
RuntimeScriptValue Sc_DrawingSurface_SetUseHighResCoordinates(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDrawingSurface, DrawingSurface_SetUseHighResCoordinates);
}
// int (ScriptDrawingSurface *sds)
RuntimeScriptValue Sc_DrawingSurface_GetWidth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDrawingSurface, DrawingSurface_GetWidth);
}
//=============================================================================
//
// Exclusive variadic API implementation for Plugins
//
//=============================================================================
void ScPl_DrawingSurface_DrawStringWrapped(ScriptDrawingSurface *sds, int xx, int yy, int wid, int font, int alignment, const char *msg, ...) {
API_PLUGIN_SCRIPT_SPRINTF(msg);
DrawingSurface_DrawStringWrapped(sds, xx, yy, wid, font, alignment, scsf_buffer);
}
void RegisterDrawingSurfaceAPI(ScriptAPIVersion base_api, ScriptAPIVersion /*compat_api */) {
ScFnRegister drawsurf_api[] = {
{"DrawingSurface::Clear^1", API_FN_PAIR(DrawingSurface_Clear)},
{"DrawingSurface::CreateCopy^0", API_FN_PAIR(DrawingSurface_CreateCopy)},
{"DrawingSurface::DrawCircle^3", API_FN_PAIR(DrawingSurface_DrawCircle)},
{"DrawingSurface::DrawImage^6", API_FN_PAIR(DrawingSurface_DrawImage6)},
{"DrawingSurface::DrawImage^10", API_FN_PAIR(DrawingSurface_DrawImage)},
{"DrawingSurface::DrawLine^5", API_FN_PAIR(DrawingSurface_DrawLine)},
{"DrawingSurface::DrawMessageWrapped^5", API_FN_PAIR(DrawingSurface_DrawMessageWrapped)},
{"DrawingSurface::DrawPixel^2", API_FN_PAIR(DrawingSurface_DrawPixel)},
{"DrawingSurface::DrawRectangle^4", API_FN_PAIR(DrawingSurface_DrawRectangle)},
{"DrawingSurface::DrawString^104", Sc_DrawingSurface_DrawString},
{"DrawingSurface::DrawSurface^2", API_FN_PAIR(DrawingSurface_DrawSurface2)},
{"DrawingSurface::DrawSurface^10", API_FN_PAIR(DrawingSurface_DrawSurface)},
{"DrawingSurface::DrawTriangle^6", API_FN_PAIR(DrawingSurface_DrawTriangle)},
{"DrawingSurface::GetPixel^2", API_FN_PAIR(DrawingSurface_GetPixel)},
{"DrawingSurface::Release^0", API_FN_PAIR(DrawingSurface_Release)},
{"DrawingSurface::get_DrawingColor", API_FN_PAIR(DrawingSurface_GetDrawingColor)},
{"DrawingSurface::set_DrawingColor", API_FN_PAIR(DrawingSurface_SetDrawingColor)},
{"DrawingSurface::get_Height", API_FN_PAIR(DrawingSurface_GetHeight)},
{"DrawingSurface::get_UseHighResCoordinates", API_FN_PAIR(DrawingSurface_GetUseHighResCoordinates)},
{"DrawingSurface::set_UseHighResCoordinates", API_FN_PAIR(DrawingSurface_SetUseHighResCoordinates)},
{"DrawingSurface::get_Width", API_FN_PAIR(DrawingSurface_GetWidth)},
};
ccAddExternalFunctions361(drawsurf_api);
// Few functions have to be selected based on API level
if (base_api < kScriptAPI_v350) {
ccAddExternalObjectFunction361("DrawingSurface::DrawStringWrapped^6", API_FN_PAIR(DrawingSurface_DrawStringWrapped_Old));
}
else { // old non-variadic and new variadic variants
ccAddExternalObjectFunction361("DrawingSurface::DrawStringWrapped^6", API_FN_PAIR(DrawingSurface_DrawStringWrapped));
ccAddExternalObjectFunction361("DrawingSurface::DrawStringWrapped^106", Sc_DrawingSurface_DrawStringWrapped, (void *)ScPl_DrawingSurface_DrawStringWrapped);
}
}
} // namespace AGS3

View File

@@ -0,0 +1,57 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AGS_ENGINE_AC_DRAWING_SURFACE_H
#define AGS_ENGINE_AC_DRAWING_SURFACE_H
#include "ags/engine/ac/dynobj/script_drawing_surface.h"
namespace AGS3 {
void DrawingSurface_Release(ScriptDrawingSurface *sds);
// convert actual co-ordinate back to what the script is expecting
ScriptDrawingSurface *DrawingSurface_CreateCopy(ScriptDrawingSurface *sds);
void DrawingSurface_DrawSurface(ScriptDrawingSurface *target, ScriptDrawingSurface *source, int trans,
int dst_x, int dst_y, int dst_width, int dst_height,
int src_x, int src_y, int src_width, int src_height);
void DrawingSurface_DrawSurface2(ScriptDrawingSurface *target, ScriptDrawingSurface *source, int trans);
void DrawingSurface_DrawImage6(ScriptDrawingSurface *sds, int xx, int yy, int slot, int trans, int width, int height);
void DrawingSurface_SetDrawingColor(ScriptDrawingSurface *sds, int newColour);
int DrawingSurface_GetDrawingColor(ScriptDrawingSurface *sds);
void DrawingSurface_SetUseHighResCoordinates(ScriptDrawingSurface *sds, int highRes);
int DrawingSurface_GetUseHighResCoordinates(ScriptDrawingSurface *sds);
int DrawingSurface_GetHeight(ScriptDrawingSurface *sds);
int DrawingSurface_GetWidth(ScriptDrawingSurface *sds);
void DrawingSurface_Clear(ScriptDrawingSurface *sds, int colour);
void DrawingSurface_DrawCircle(ScriptDrawingSurface *sds, int x, int y, int radius);
void DrawingSurface_DrawRectangle(ScriptDrawingSurface *sds, int x1, int y1, int x2, int y2);
void DrawingSurface_DrawTriangle(ScriptDrawingSurface *sds, int x1, int y1, int x2, int y2, int x3, int y3);
void DrawingSurface_DrawString(ScriptDrawingSurface *sds, int xx, int yy, int font, const char *text);
void DrawingSurface_DrawStringWrapped(ScriptDrawingSurface *sds, int xx, int yy, int wid, int font, int alignment, const char *msg);
void DrawingSurface_DrawStringWrapped_Old(ScriptDrawingSurface *sds, int xx, int yy, int wid, int font, int alignment, const char *msg);
void DrawingSurface_DrawMessageWrapped(ScriptDrawingSurface *sds, int xx, int yy, int wid, int font, int msgm);
void DrawingSurface_DrawLine(ScriptDrawingSurface *sds, int fromx, int fromy, int tox, int toy, int thickness);
void DrawingSurface_DrawPixel(ScriptDrawingSurface *sds, int x, int y);
int DrawingSurface_GetPixel(ScriptDrawingSurface *sds, int x, int y);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,609 @@
/* 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/engine/ac/dynamic_sprite.h"
#include "ags/shared/ac/common.h"
#include "ags/engine/ac/draw.h"
#include "ags/engine/ac/game.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/engine/ac/game_state.h"
#include "ags/engine/ac/global_dynamic_sprite.h"
#include "ags/engine/ac/global_game.h"
#include "ags/engine/ac/math.h" // M_PI
#include "ags/engine/ac/path_helper.h"
#include "ags/engine/ac/room_object.h"
#include "ags/engine/ac/room_status.h"
#include "ags/engine/ac/system.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/engine/debugging/debug_log.h"
#include "ags/shared/game/room_struct.h"
#include "ags/shared/gui/gui_button.h"
#include "ags/shared/ac/sprite_cache.h"
#include "ags/engine/gfx/graphics_driver.h"
#include "ags/engine/script/runtime_script_value.h"
#include "ags/shared/debugging/out.h"
#include "ags/engine/script/script_api.h"
#include "ags/engine/script/script_runtime.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace Shared;
using namespace Engine;
// ** SCRIPT DYNAMIC SPRITE
void DynamicSprite_Delete(ScriptDynamicSprite *sds) {
if (sds->slot) {
free_dynamic_sprite(sds->slot);
sds->slot = 0;
}
}
ScriptDrawingSurface *DynamicSprite_GetDrawingSurface(ScriptDynamicSprite *dss) {
ScriptDrawingSurface *surface = new ScriptDrawingSurface();
surface->dynamicSpriteNumber = dss->slot;
if ((_GP(game).SpriteInfos[dss->slot].Flags & SPF_ALPHACHANNEL) != 0)
surface->hasAlphaChannel = true;
ccRegisterManagedObject(surface, surface);
return surface;
}
int DynamicSprite_GetGraphic(ScriptDynamicSprite *sds) {
if (sds->slot == 0)
quit("!DynamicSprite.Graphic: Cannot get graphic, sprite has been deleted");
return sds->slot;
}
int DynamicSprite_GetWidth(ScriptDynamicSprite *sds) {
return game_to_data_coord(_GP(game).SpriteInfos[sds->slot].Width);
}
int DynamicSprite_GetHeight(ScriptDynamicSprite *sds) {
return game_to_data_coord(_GP(game).SpriteInfos[sds->slot].Height);
}
int DynamicSprite_GetColorDepth(ScriptDynamicSprite *sds) {
// Dynamic sprite ensures the sprite exists always
int depth = _GP(spriteset)[sds->slot]->GetColorDepth();
if (depth == 15)
depth = 16;
if (depth == 24)
depth = 32;
return depth;
}
void DynamicSprite_Resize(ScriptDynamicSprite *sds, int width, int height) {
if ((width < 1) || (height < 1))
quit("!DynamicSprite.Resize: width and height must be greater than zero");
if (sds->slot == 0)
quit("!DynamicSprite.Resize: sprite has been deleted");
data_to_game_coords(&width, &height);
if (width * height >= 25000000)
quitprintf("!DynamicSprite.Resize: new size is too large: %d x %d", width, height);
// resize the sprite to the requested size
Bitmap *sprite = _GP(spriteset)[sds->slot];
std::unique_ptr<Bitmap> new_pic(BitmapHelper::CreateBitmap(width, height, sprite->GetColorDepth()));
new_pic->StretchBlt(sprite,
RectWH(0, 0, _GP(game).SpriteInfos[sds->slot].Width, _GP(game).SpriteInfos[sds->slot].Height),
RectWH(0, 0, width, height));
add_dynamic_sprite(sds->slot, std::move(new_pic), (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
}
void DynamicSprite_Flip(ScriptDynamicSprite *sds, int direction) {
if ((direction < 1) || (direction > 3))
quit("!DynamicSprite.Flip: invalid direction");
if (sds->slot == 0)
quit("!DynamicSprite.Flip: sprite has been deleted");
// resize the sprite to the requested size
Bitmap *sprite = _GP(spriteset)[sds->slot];
std::unique_ptr<Bitmap> new_pic(BitmapHelper::CreateTransparentBitmap(sprite->GetWidth(), sprite->GetHeight(), sprite->GetColorDepth()));
// AGS script FlipDirection corresponds to internal GraphicFlip
new_pic->FlipBlt(sprite, 0, 0, static_cast<GraphicFlip>(direction));
add_dynamic_sprite(sds->slot, std::move(new_pic), (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
}
void DynamicSprite_CopyTransparencyMask(ScriptDynamicSprite *sds, int sourceSprite) {
if (sds->slot == 0)
quit("!DynamicSprite.CopyTransparencyMask: sprite has been deleted");
if ((_GP(game).SpriteInfos[sds->slot].Width != _GP(game).SpriteInfos[sourceSprite].Width) ||
(_GP(game).SpriteInfos[sds->slot].Height != _GP(game).SpriteInfos[sourceSprite].Height)) {
quit("!DynamicSprite.CopyTransparencyMask: sprites are not the same size");
}
Bitmap *target = _GP(spriteset)[sds->slot];
Bitmap *source = _GP(spriteset)[sourceSprite];
if (target->GetColorDepth() != source->GetColorDepth()) {
quit("!DynamicSprite.CopyTransparencyMask: sprites are not the same colour depth");
}
// set the target's alpha channel depending on the source
bool dst_has_alpha = (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0;
bool src_has_alpha = (_GP(game).SpriteInfos[sourceSprite].Flags & SPF_ALPHACHANNEL) != 0;
_GP(game).SpriteInfos[sds->slot].Flags &= ~SPF_ALPHACHANNEL;
if (src_has_alpha) {
_GP(game).SpriteInfos[sds->slot].Flags |= SPF_ALPHACHANNEL;
}
BitmapHelper::CopyTransparency(target, source, dst_has_alpha, src_has_alpha);
}
void DynamicSprite_ChangeCanvasSize(ScriptDynamicSprite *sds, int width, int height, int x, int y) {
if (sds->slot == 0)
quit("!DynamicSprite.ChangeCanvasSize: sprite has been deleted");
if ((width < 1) || (height < 1))
quit("!DynamicSprite.ChangeCanvasSize: new size is too small");
data_to_game_coords(&x, &y);
data_to_game_coords(&width, &height);
Bitmap *sprite = _GP(spriteset)[sds->slot];
std::unique_ptr<Bitmap> new_pic(BitmapHelper::CreateTransparentBitmap(width, height, sprite->GetColorDepth()));
// blit it into the enlarged image
new_pic->Blit(sprite, 0, 0, x, y, sprite->GetWidth(), sprite->GetHeight());
// replace the bitmap in the sprite set
add_dynamic_sprite(sds->slot, std::move(new_pic), (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
}
void DynamicSprite_Crop(ScriptDynamicSprite *sds, int x1, int y1, int width, int height) {
if ((width < 1) || (height < 1))
quit("!DynamicSprite.Crop: co-ordinates do not make sense");
if (sds->slot == 0)
quit("!DynamicSprite.Crop: sprite has been deleted");
data_to_game_coords(&x1, &y1);
data_to_game_coords(&width, &height);
if ((width > _GP(game).SpriteInfos[sds->slot].Width) || (height > _GP(game).SpriteInfos[sds->slot].Height))
quit("!DynamicSprite.Crop: requested to crop an area larger than the source");
Bitmap *sprite = _GP(spriteset)[sds->slot];
std::unique_ptr<Bitmap> new_pic(BitmapHelper::CreateBitmap(width, height, sprite->GetColorDepth()));
// blit it cropped
new_pic->Blit(sprite, x1, y1, 0, 0, new_pic->GetWidth(), new_pic->GetHeight());
// replace the bitmap in the sprite set
add_dynamic_sprite(sds->slot, std::move(new_pic), (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
}
void DynamicSprite_Rotate(ScriptDynamicSprite *sds, int angle, int width, int height) {
if ((angle < 1) || (angle > 359))
quit("!DynamicSprite.Rotate: invalid angle (must be 1-359)");
if (sds->slot == 0)
quit("!DynamicSprite.Rotate: sprite has been deleted");
if ((width == SCR_NO_VALUE) || (height == SCR_NO_VALUE)) {
// calculate the new image size automatically
// 1 degree = 181 degrees in terms of x/y size, so % 180
int useAngle = angle % 180;
// and 0..90 is the same as 180..90
if (useAngle > 90)
useAngle = 180 - useAngle;
// useAngle is now between 0 and 90 (otherwise the sin/cos stuff doesn't work)
double angleInRadians = (double)useAngle * (M_PI / 180.0);
double sinVal = sin(angleInRadians);
double cosVal = cos(angleInRadians);
width = (cosVal * (double)_GP(game).SpriteInfos[sds->slot].Width + sinVal * (double)_GP(game).SpriteInfos[sds->slot].Height);
height = (sinVal * (double)_GP(game).SpriteInfos[sds->slot].Width + cosVal * (double)_GP(game).SpriteInfos[sds->slot].Height);
} else {
data_to_game_coords(&width, &height);
}
// convert to allegro angle
angle = (angle * 256) / 360;
// resize the sprite to the requested size
Bitmap *sprite = _GP(spriteset)[sds->slot];
std::unique_ptr<Bitmap> new_pic(BitmapHelper::CreateTransparentBitmap(width, height, sprite->GetColorDepth()));
// rotate the sprite about its centre
// (+ width%2 fixes one pixel offset problem)
new_pic->RotateBlt(sprite, width / 2 + width % 2, height / 2,
sprite->GetWidth() / 2, sprite->GetHeight() / 2, itofix(angle));
// replace the bitmap in the sprite set
add_dynamic_sprite(sds->slot, std::move(new_pic), (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
}
void DynamicSprite_Tint(ScriptDynamicSprite *sds, int red, int green, int blue, int saturation, int luminance) {
Bitmap *source = _GP(spriteset)[sds->slot];
std::unique_ptr<Bitmap> new_pic(BitmapHelper::CreateBitmap(source->GetWidth(), source->GetHeight(), source->GetColorDepth()));
tint_image(new_pic.get(), source, red, green, blue, saturation, (luminance * 25) / 10);
add_dynamic_sprite(sds->slot, std::move(new_pic), (_GP(game).SpriteInfos[sds->slot].Flags & SPF_ALPHACHANNEL) != 0);
}
int DynamicSprite_SaveToFile(ScriptDynamicSprite *sds, const char *namm) {
if (sds->slot == 0)
quit("!DynamicSprite.SaveToFile: sprite has been deleted");
auto filename = String(namm);
if (filename.FindChar('.') == String::NoIndex)
filename.Append(".bmp");
ResolvedPath rp;
if (!ResolveWritePathAndCreateDirs(filename, rp))
return 0;
return _GP(spriteset)[sds->slot]->SaveToFile(rp.FullPath, _G(palette)) ? 1 : 0;
}
ScriptDynamicSprite *DynamicSprite_CreateFromSaveGame(int sgslot, int width, int height) {
int slotnum = LoadSaveSlotScreenshot(sgslot, width, height);
if (slotnum) {
ScriptDynamicSprite *new_spr = new ScriptDynamicSprite(slotnum);
return new_spr;
}
return nullptr;
}
ScriptDynamicSprite *DynamicSprite_CreateFromFile(const char *filename) {
int slotnum = LoadImageFile(filename);
if (slotnum) {
ScriptDynamicSprite *new_spr = new ScriptDynamicSprite(slotnum);
return new_spr;
}
return nullptr;
}
ScriptDynamicSprite *DynamicSprite_CreateFromScreenShot(int width, int height) {
// TODO: refactor and merge with create_savegame_screenshot()
if (!_GP(spriteset).HasFreeSlots())
return nullptr;
// NOTE: be aware that by the historical logic AGS makes a screenshot
// of a "main viewport", that may be smaller in legacy "letterbox" mode.
const Rect &viewport = _GP(play).GetMainViewport();
if (width <= 0)
width = viewport.GetWidth();
else
width = data_to_game_coord(width);
if (height <= 0)
height = viewport.GetHeight();
else
height = data_to_game_coord(height);
std::unique_ptr<Bitmap> new_pic(CopyScreenIntoBitmap(width, height, &viewport));
// replace the bitmap in the sprite set
int new_slot = add_dynamic_sprite(std::move(new_pic));
return new ScriptDynamicSprite(new_slot);
}
ScriptDynamicSprite *DynamicSprite_CreateFromExistingSprite(int slot, int preserveAlphaChannel) {
if (!_GP(spriteset).HasFreeSlots())
return nullptr;
if (!_GP(spriteset).DoesSpriteExist(slot))
quitprintf("DynamicSprite.CreateFromExistingSprite: sprite %d does not exist", slot);
// create a new sprite as a copy of the existing one
std::unique_ptr<Bitmap> new_pic(BitmapHelper::CreateBitmapCopy(_GP(spriteset)[slot]));
if (!new_pic)
return nullptr;
bool hasAlpha = (preserveAlphaChannel) && ((_GP(game).SpriteInfos[slot].Flags & SPF_ALPHACHANNEL) != 0);
int new_slot = add_dynamic_sprite(std::move(new_pic), hasAlpha);
return new ScriptDynamicSprite(new_slot);
}
ScriptDynamicSprite *DynamicSprite_CreateFromDrawingSurface(ScriptDrawingSurface *sds, int x, int y, int width, int height) {
if (!_GP(spriteset).HasFreeSlots())
return nullptr;
if (width <= 0 || height <= 0) {
debug_script_warn("WARNING: DynamicSprite.CreateFromDrawingSurface: invalid size %d x %d, will adjust", width, height);
width = std::max(1, width);
height = std::max(1, height);
}
// use DrawingSurface resolution
sds->PointToGameResolution(&x, &y);
sds->SizeToGameResolution(&width, &height);
Bitmap *ds = sds->StartDrawing();
if ((x < 0) || (y < 0) || (x + width > ds->GetWidth()) || (y + height > ds->GetHeight()))
quit("!DynamicSprite.CreateFromDrawingSurface: requested area is outside the surface");
std::unique_ptr<Bitmap> new_pic(BitmapHelper::CreateBitmap(width, height, ds->GetColorDepth()));
if (!new_pic)
return nullptr;
new_pic->Blit(ds, x, y, 0, 0, width, height);
sds->FinishedDrawingReadOnly();
int new_slot = add_dynamic_sprite(std::move(new_pic), (sds->hasAlphaChannel != 0));
return new ScriptDynamicSprite(new_slot);
}
ScriptDynamicSprite *DynamicSprite_Create(int width, int height, int alphaChannel) {
if (width <= 0 || height <= 0) {
debug_script_warn("WARNING: DynamicSprite.Create: invalid size %d x %d, will adjust", width, height);
width = MAX(1, width);
height = MAX(1, height);
}
data_to_game_coords(&width, &height);
if (!_GP(spriteset).HasFreeSlots())
return nullptr;
std::unique_ptr<Bitmap> new_pic(CreateCompatBitmap(width, height));
if (!new_pic)
return nullptr;
new_pic->ClearTransparent();
if ((alphaChannel) && (_GP(game).GetColorDepth() < 32))
alphaChannel = false;
int new_slot = add_dynamic_sprite(std::move(new_pic), alphaChannel != 0);
return new ScriptDynamicSprite(new_slot);
}
ScriptDynamicSprite *DynamicSprite_CreateFromExistingSprite_Old(int slot) {
return DynamicSprite_CreateFromExistingSprite(slot, 0);
}
ScriptDynamicSprite *DynamicSprite_CreateFromBackground(int frame, int x1, int y1, int width, int height) {
if (frame == SCR_NO_VALUE) {
frame = _GP(play).bg_frame;
} else if ((frame < 0) || ((size_t)frame >= _GP(thisroom).BgFrameCount))
quit("!DynamicSprite.CreateFromBackground: invalid frame specified");
if (x1 == SCR_NO_VALUE)
x1 = 0;
if (y1 == SCR_NO_VALUE)
y1 = 0;
if (width == SCR_NO_VALUE)
width = _GP(play).room_width;
if (height == SCR_NO_VALUE)
height = _GP(play).room_height;
if (width <= 0 || height <= 0) {
debug_script_warn("WARNING: DynamicSprite.CreateFromBackground: invalid size %d x %d, will adjust", width, height);
width = std::max(1, width);
height = std::max(1, height);
}
if ((x1 < 0) || (y1 < 0) || (x1 + width > _GP(play).room_width) || (y1 + height > _GP(play).room_height))
quit("!DynamicSprite.CreateFromBackground: invalid co-ordinates specified");
data_to_game_coords(&x1, &y1);
data_to_game_coords(&width, &height);
if (!_GP(spriteset).HasFreeSlots())
return nullptr;
// create a new sprite as a copy of the existing one
std::unique_ptr<Bitmap> new_pic(BitmapHelper::CreateBitmap(width, height, _GP(thisroom).BgFrames[frame].Graphic->GetColorDepth()));
if (!new_pic)
return nullptr;
new_pic->Blit(_GP(thisroom).BgFrames[frame].Graphic.get(), x1, y1, 0, 0, width, height);
int new_slot = add_dynamic_sprite(std::move(new_pic));
return new ScriptDynamicSprite(new_slot);
}
//=============================================================================
int add_dynamic_sprite(std::unique_ptr<Bitmap> image, bool has_alpha, uint32_t extra_flags) {
int slot = _GP(spriteset).GetFreeIndex();
if (slot <= 0)
return 0;
return add_dynamic_sprite(slot, std::move(image), has_alpha, extra_flags);
}
int add_dynamic_sprite(int slot, std::unique_ptr<Bitmap> image, bool has_alpha, uint32_t extra_flags) {
assert(slot > 0 && !_GP(spriteset).IsAssetSprite(slot));
if (slot <= 0 || _GP(spriteset).IsAssetSprite(slot))
return 0; // invalid slot, or reserved for the static sprite
uint32_t flags = SPF_DYNAMICALLOC | (SPF_ALPHACHANNEL * has_alpha) | extra_flags;
if(!_GP(spriteset).SetSprite(slot, std::move(image), flags))
return 0; // failed to add the sprite, bad image or realloc failed
// Notify a new (normal) dynamic sprite in case some objects
// have this number assigned to their Graphic property
if ((extra_flags & SPF_OBJECTOWNED) == 0)
game_sprite_updated(slot);
return slot;
}
void free_dynamic_sprite(int slot, bool notify_all) {
assert((slot > 0) && (static_cast<size_t>(slot) < _GP(game).SpriteInfos.size()) &&
(_GP(game).SpriteInfos[slot].Flags & SPF_DYNAMICALLOC));
if ((slot <= 0) || (static_cast<size_t>(slot) >= _GP(game).SpriteInfos.size()) ||
(_GP(game).SpriteInfos[slot].Flags & SPF_DYNAMICALLOC) == 0)
return;
_GP(spriteset).DeleteSprite(slot);
if (notify_all)
game_sprite_updated(slot, true);
}
//=============================================================================
//
// Script API Functions
//
//=============================================================================
// void (ScriptDynamicSprite *sds, int width, int height, int x, int y)
RuntimeScriptValue Sc_DynamicSprite_ChangeCanvasSize(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT4(ScriptDynamicSprite, DynamicSprite_ChangeCanvasSize);
}
// void (ScriptDynamicSprite *sds, int sourceSprite)
RuntimeScriptValue Sc_DynamicSprite_CopyTransparencyMask(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDynamicSprite, DynamicSprite_CopyTransparencyMask);
}
// void (ScriptDynamicSprite *sds, int x1, int y1, int width, int height)
RuntimeScriptValue Sc_DynamicSprite_Crop(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT4(ScriptDynamicSprite, DynamicSprite_Crop);
}
// void (ScriptDynamicSprite *sds)
RuntimeScriptValue Sc_DynamicSprite_Delete(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID(ScriptDynamicSprite, DynamicSprite_Delete);
}
// void (ScriptDynamicSprite *sds, int direction)
RuntimeScriptValue Sc_DynamicSprite_Flip(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT(ScriptDynamicSprite, DynamicSprite_Flip);
}
// ScriptDrawingSurface* (ScriptDynamicSprite *dss)
RuntimeScriptValue Sc_DynamicSprite_GetDrawingSurface(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_OBJAUTO(ScriptDynamicSprite, ScriptDrawingSurface, DynamicSprite_GetDrawingSurface);
}
// void (ScriptDynamicSprite *sds, int width, int height)
RuntimeScriptValue Sc_DynamicSprite_Resize(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT2(ScriptDynamicSprite, DynamicSprite_Resize);
}
// void (ScriptDynamicSprite *sds, int angle, int width, int height)
RuntimeScriptValue Sc_DynamicSprite_Rotate(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT3(ScriptDynamicSprite, DynamicSprite_Rotate);
}
// int (ScriptDynamicSprite *sds, const char* namm)
RuntimeScriptValue Sc_DynamicSprite_SaveToFile(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT_POBJ(ScriptDynamicSprite, DynamicSprite_SaveToFile, const char);
}
// void (ScriptDynamicSprite *sds, int red, int green, int blue, int saturation, int luminance)
RuntimeScriptValue Sc_DynamicSprite_Tint(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_VOID_PINT5(ScriptDynamicSprite, DynamicSprite_Tint);
}
// int (ScriptDynamicSprite *sds)
RuntimeScriptValue Sc_DynamicSprite_GetColorDepth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDynamicSprite, DynamicSprite_GetColorDepth);
}
// int (ScriptDynamicSprite *sds)
RuntimeScriptValue Sc_DynamicSprite_GetGraphic(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDynamicSprite, DynamicSprite_GetGraphic);
}
// int (ScriptDynamicSprite *sds)
RuntimeScriptValue Sc_DynamicSprite_GetHeight(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDynamicSprite, DynamicSprite_GetHeight);
}
// int (ScriptDynamicSprite *sds)
RuntimeScriptValue Sc_DynamicSprite_GetWidth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptDynamicSprite, DynamicSprite_GetWidth);
}
// ScriptDynamicSprite* (int width, int height, int alphaChannel)
RuntimeScriptValue Sc_DynamicSprite_Create(const RuntimeScriptValue *params, int32_t param_count) {
API_SCALL_OBJAUTO_PINT3(ScriptDynamicSprite, DynamicSprite_Create);
}
// ScriptDynamicSprite* (int frame, int x1, int y1, int width, int height)
RuntimeScriptValue Sc_DynamicSprite_CreateFromBackground(const RuntimeScriptValue *params, int32_t param_count) {
API_SCALL_OBJAUTO_PINT5(ScriptDynamicSprite, DynamicSprite_CreateFromBackground);
}
// ScriptDynamicSprite* (ScriptDrawingSurface *sds, int x, int y, int width, int height)
RuntimeScriptValue Sc_DynamicSprite_CreateFromDrawingSurface(const RuntimeScriptValue *params, int32_t param_count) {
API_SCALL_OBJAUTO_POBJ_PINT4(ScriptDynamicSprite, DynamicSprite_CreateFromDrawingSurface, ScriptDrawingSurface);
}
// ScriptDynamicSprite* (int slot)
RuntimeScriptValue Sc_DynamicSprite_CreateFromExistingSprite_Old(const RuntimeScriptValue *params, int32_t param_count) {
API_SCALL_OBJAUTO_PINT(ScriptDynamicSprite, DynamicSprite_CreateFromExistingSprite_Old);
}
// ScriptDynamicSprite* (int slot, int preserveAlphaChannel)
RuntimeScriptValue Sc_DynamicSprite_CreateFromExistingSprite(const RuntimeScriptValue *params, int32_t param_count) {
API_SCALL_OBJAUTO_PINT2(ScriptDynamicSprite, DynamicSprite_CreateFromExistingSprite);
}
// ScriptDynamicSprite* (const char *filename)
RuntimeScriptValue Sc_DynamicSprite_CreateFromFile(const RuntimeScriptValue *params, int32_t param_count) {
API_SCALL_OBJAUTO_POBJ(ScriptDynamicSprite, DynamicSprite_CreateFromFile, const char);
}
// ScriptDynamicSprite* (int sgslot, int width, int height)
RuntimeScriptValue Sc_DynamicSprite_CreateFromSaveGame(const RuntimeScriptValue *params, int32_t param_count) {
API_SCALL_OBJAUTO_PINT3(ScriptDynamicSprite, DynamicSprite_CreateFromSaveGame);
}
// ScriptDynamicSprite* (int width, int height)
RuntimeScriptValue Sc_DynamicSprite_CreateFromScreenShot(const RuntimeScriptValue *params, int32_t param_count) {
API_SCALL_OBJAUTO_PINT2(ScriptDynamicSprite, DynamicSprite_CreateFromScreenShot);
}
void RegisterDynamicSpriteAPI() {
ScFnRegister dynsprite_api[] = {
{"DynamicSprite::Create^3", API_FN_PAIR(DynamicSprite_Create)},
{"DynamicSprite::CreateFromBackground", API_FN_PAIR(DynamicSprite_CreateFromBackground)},
{"DynamicSprite::CreateFromDrawingSurface^5", API_FN_PAIR(DynamicSprite_CreateFromDrawingSurface)},
{"DynamicSprite::CreateFromExistingSprite^1", API_FN_PAIR(DynamicSprite_CreateFromExistingSprite_Old)},
{"DynamicSprite::CreateFromExistingSprite^2", API_FN_PAIR(DynamicSprite_CreateFromExistingSprite)},
{"DynamicSprite::CreateFromFile", API_FN_PAIR(DynamicSprite_CreateFromFile)},
{"DynamicSprite::CreateFromSaveGame", API_FN_PAIR(DynamicSprite_CreateFromSaveGame)},
{"DynamicSprite::CreateFromScreenShot", API_FN_PAIR(DynamicSprite_CreateFromScreenShot)},
{"DynamicSprite::ChangeCanvasSize^4", API_FN_PAIR(DynamicSprite_ChangeCanvasSize)},
{"DynamicSprite::CopyTransparencyMask^1", API_FN_PAIR(DynamicSprite_CopyTransparencyMask)},
{"DynamicSprite::Crop^4", API_FN_PAIR(DynamicSprite_Crop)},
{"DynamicSprite::Delete", API_FN_PAIR(DynamicSprite_Delete)},
{"DynamicSprite::Flip^1", API_FN_PAIR(DynamicSprite_Flip)},
{"DynamicSprite::GetDrawingSurface^0", API_FN_PAIR(DynamicSprite_GetDrawingSurface)},
{"DynamicSprite::Resize^2", API_FN_PAIR(DynamicSprite_Resize)},
{"DynamicSprite::Rotate^3", API_FN_PAIR(DynamicSprite_Rotate)},
{"DynamicSprite::SaveToFile^1", API_FN_PAIR(DynamicSprite_SaveToFile)},
{"DynamicSprite::Tint^5", API_FN_PAIR(DynamicSprite_Tint)},
{"DynamicSprite::get_ColorDepth", API_FN_PAIR(DynamicSprite_GetColorDepth)},
{"DynamicSprite::get_Graphic", API_FN_PAIR(DynamicSprite_GetGraphic)},
{"DynamicSprite::get_Height", API_FN_PAIR(DynamicSprite_GetHeight)},
{"DynamicSprite::get_Width", API_FN_PAIR(DynamicSprite_GetWidth)},
};
ccAddExternalFunctions361(dynsprite_api);
}
} // namespace AGS3

View File

@@ -0,0 +1,67 @@
/* 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_ENGINE_AC_DYNAMICSPRITE_H
#define AGS_ENGINE_AC_DYNAMICSPRITE_H
#include "ags/engine/ac/dynobj/script_dynamic_sprite.h"
#include "ags/engine/ac/dynobj/script_drawing_surface.h"
namespace AGS3 {
void DynamicSprite_Delete(ScriptDynamicSprite *sds);
ScriptDrawingSurface *DynamicSprite_GetDrawingSurface(ScriptDynamicSprite *dss);
int DynamicSprite_GetGraphic(ScriptDynamicSprite *sds);
int DynamicSprite_GetWidth(ScriptDynamicSprite *sds);
int DynamicSprite_GetHeight(ScriptDynamicSprite *sds);
int DynamicSprite_GetColorDepth(ScriptDynamicSprite *sds);
void DynamicSprite_Resize(ScriptDynamicSprite *sds, int width, int height);
void DynamicSprite_Flip(ScriptDynamicSprite *sds, int direction);
void DynamicSprite_CopyTransparencyMask(ScriptDynamicSprite *sds, int sourceSprite);
void DynamicSprite_ChangeCanvasSize(ScriptDynamicSprite *sds, int width, int height, int x, int y);
void DynamicSprite_Crop(ScriptDynamicSprite *sds, int x1, int y1, int width, int height);
void DynamicSprite_Rotate(ScriptDynamicSprite *sds, int angle, int width, int height);
void DynamicSprite_Tint(ScriptDynamicSprite *sds, int red, int green, int blue, int saturation, int luminance);
int DynamicSprite_SaveToFile(ScriptDynamicSprite *sds, const char *namm);
ScriptDynamicSprite *DynamicSprite_CreateFromSaveGame(int sgslot, int width, int height);
ScriptDynamicSprite *DynamicSprite_CreateFromFile(const char *filename);
ScriptDynamicSprite *DynamicSprite_CreateFromScreenShot(int width, int height);
ScriptDynamicSprite *DynamicSprite_CreateFromExistingSprite(int slot, int preserveAlphaChannel);
ScriptDynamicSprite *DynamicSprite_CreateFromDrawingSurface(ScriptDrawingSurface *sds, int x, int y, int width, int height);
ScriptDynamicSprite *DynamicSprite_Create(int width, int height, int alphaChannel);
ScriptDynamicSprite *DynamicSprite_CreateFromExistingSprite_Old(int slot);
ScriptDynamicSprite *DynamicSprite_CreateFromBackground(int frame, int x1, int y1, int width, int height);
// Registers a new dynamic sprite, and returns a slot number;
// returns 0 if no free slot could be found or allocated.
// Updates game.SpriteInfos[].
int add_dynamic_sprite(std::unique_ptr<AGS::Shared::Bitmap> image, bool has_alpha = false, uint32_t extra_flags = 0u);
// Registers a new dynamic sprite in the given slot number,
// previous bitmap on this slot (if any) will be deleted.
// Returns same slot number on success, or 0 if there was an error.
// Updates game.SpriteInfos[].
int add_dynamic_sprite(int slot, std::unique_ptr<AGS::Shared::Bitmap> image, bool hasAlpha = false, uint32_t extra_flags = 0u);
// Disposes a dynamic sprite, and frees the slot
void free_dynamic_sprite(int slot, bool notify_all = true);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,38 @@
/* 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_ENGINE_AC_DYNOBJ_ALL_DYNAMIC_CLASSES_H
#define AGS_ENGINE_AC_DYNOBJ_ALL_DYNAMIC_CLASSES_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
#include "ags/engine/ac/dynobj/cc_audio_channel.h"
#include "ags/engine/ac/dynobj/cc_audio_clip.h"
#include "ags/engine/ac/dynobj/cc_character.h"
#include "ags/engine/ac/dynobj/cc_dialog.h"
#include "ags/engine/ac/dynobj/cc_gui.h"
#include "ags/engine/ac/dynobj/cc_gui_object.h"
#include "ags/engine/ac/dynobj/cc_hotspot.h"
#include "ags/engine/ac/dynobj/cc_inventory.h"
#include "ags/engine/ac/dynobj/cc_object.h"
#include "ags/engine/ac/dynobj/cc_region.h"
#include "ags/engine/ac/dynobj/cc_serializer.h"
#endif

View File

@@ -0,0 +1,41 @@
/* 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_ENGINE_AC_DYNOBJ_ALL_SCRIPT_CLASSES_H
#define AGS_ENGINE_AC_DYNOBJ_ALL_SCRIPT_CLASSES_H
#include "ags/engine/ac/dynobj/script_date_time.h"
#include "ags/engine/ac/dynobj/script_dialog.h"
#include "ags/engine/ac/dynobj/script_dialog_options_rendering.h"
#include "ags/engine/ac/dynobj/script_drawing_surface.h"
#include "ags/engine/ac/dynobj/script_dynamic_sprite.h"
#include "ags/engine/ac/dynobj/script_gui.h"
#include "ags/engine/ac/dynobj/script_hotspot.h"
#include "ags/engine/ac/dynobj/script_inv_item.h"
#include "ags/engine/ac/dynobj/script_mouse.h"
#include "ags/engine/ac/dynobj/script_object.h"
#include "ags/engine/ac/dynobj/script_overlay.h"
#include "ags/engine/ac/dynobj/script_region.h"
#include "ags/engine/ac/dynobj/script_string.h"
#include "ags/engine/ac/dynobj/script_system.h"
#include "ags/engine/ac/dynobj/script_view_frame.h"
#endif

View File

@@ -0,0 +1,95 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ags/shared/core/types.h"
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
#include "ags/shared/util/memory_stream.h"
namespace AGS3 {
using namespace AGS::Shared;
int CCBasicObject::Dispose(void * /*address*/, bool /*force*/) {
return 0; // cannot be removed from memory
}
int CCBasicObject::Serialize(void * /*address*/, uint8_t * /*buffer*/, int /*bufsize*/) {
return 0; // does not save data
}
void *CCBasicObject::GetFieldPtr(void *address, intptr_t offset) {
return static_cast<uint8_t *>(address) + offset;
}
void CCBasicObject::Read(void *address, intptr_t offset, uint8_t *dest, size_t size) {
memcpy(dest, static_cast<uint8_t *>(address) + offset, size);
}
uint8_t CCBasicObject::ReadInt8(void *address, intptr_t offset) {
return *(uint8_t *)(static_cast<uint8_t *>(address) + offset);
}
int16_t CCBasicObject::ReadInt16(void *address, intptr_t offset) {
return *(int16_t *)(static_cast<uint8_t *>(address) + offset);
}
int32_t CCBasicObject::ReadInt32(void *address, intptr_t offset) {
return *(int32_t *)(static_cast<uint8_t *>(address) + offset);
}
float CCBasicObject::ReadFloat(void *address, intptr_t offset) {
return *(float *)(static_cast<uint8_t *>(address) + offset);
}
void CCBasicObject::Write(void *address, intptr_t offset, const uint8_t *src, size_t size) {
memcpy(static_cast<uint8_t *>(address) + offset, src, size);
}
void CCBasicObject::WriteInt8(void *address, intptr_t offset, uint8_t val) {
*(uint8_t *)(static_cast<uint8_t *>(address) + offset) = val;
}
void CCBasicObject::WriteInt16(void *address, intptr_t offset, int16_t val) {
*(int16_t *)(static_cast<uint8_t *>(address) + offset) = val;
}
void CCBasicObject::WriteInt32(void *address, intptr_t offset, int32_t val) {
*(int32_t *)(static_cast<uint8_t *>(address) + offset) = val;
}
void CCBasicObject::WriteFloat(void *address, intptr_t offset, float val) {
*(float *)(static_cast<uint8_t *>(address) + offset) = val;
}
int AGSCCDynamicObject::Serialize(void *address, uint8_t *buffer, int bufsize) {
// If the required space is larger than the provided buffer,
// then return negated required space, notifying the caller that a larger buffer is necessary
size_t req_size = CalcSerializeSize(address);
assert(req_size <= INT32_MAX); // dynamic object API does not support size > int32
if (bufsize < 0 || req_size > static_cast<size_t>(bufsize))
return -(static_cast<int32_t>(req_size));
MemoryStream mems(reinterpret_cast<uint8_t *>(buffer), bufsize, kStream_Write);
Serialize(address, &mems);
return static_cast<int32_t>(mems.GetPosition());
}
} // namespace AGS3

View File

@@ -0,0 +1,117 @@
/* 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/>.
*
*/
//=============================================================================
//
// This is a collection of common implementations of the IScriptObject
// interface. Intended to be used as parent classes for majority of the
// script object managers.
//
// CCBasicObject: parent for managers that treat object contents as raw
// byte buffer.
//
// AGSCCDynamicObject, extends CCBasicObject: parent for built-in dynamic
// object managers; provides simpler serialization methods working with
// streams instead of a raw memory buffer.
//
// AGSCCStaticObject, extends CCBasicObject: a formal stub, intended as
// a parent for built-in static object managers.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_DYNOBJ_CCDYNAMIC_OBJECT_H
#define AGS_ENGINE_AC_DYNOBJ_CCDYNAMIC_OBJECT_H
#include "ags/engine/ac/dynobj/cc_script_object.h"
namespace AGS3 {
namespace AGS { namespace Shared { class Stream; } }
// CCBasicObject: basic implementation of the script object interface,
// intended to be used as a parent for object/manager classes that do not
// require specific implementation.
// * Dispose ignored, never deletes any data on its own;
// * Serialization skipped, does not save or load anything;
// * Provides default implementation for reading and writing data fields,
// treats the contents of an object as a raw byte buffer.
struct CCBasicObject : public IScriptObject {
public:
virtual ~CCBasicObject() = default;
// Dispose the object
int Dispose(void * /*address*/, bool /*force*/) override;
// Serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
int Serialize(void * /*address*/, uint8_t * /*buffer*/, int /*bufsize*/) override;
//
// Legacy support for reading and writing object fields by their relative offset
//
void *GetFieldPtr(void *address, intptr_t offset) override;
void Read(void *address, intptr_t offset, uint8_t *dest, size_t size) override;
uint8_t ReadInt8(void *address, intptr_t offset) override;
int16_t ReadInt16(void *address, intptr_t offset) override;
int32_t ReadInt32(void *address, intptr_t offset) override;
float ReadFloat(void *address, intptr_t offset) override;
void Write(void *address, intptr_t offset, const uint8_t *src, size_t size) override;
void WriteInt8(void *address, intptr_t offset, uint8_t val) override;
void WriteInt16(void *address, intptr_t offset, int16_t val) override;
void WriteInt32(void *address, intptr_t offset, int32_t val) override;
void WriteFloat(void *address, intptr_t offset, float val) override;
};
// AGSCCDynamicObject: standard parent implementation for the built-in
// script objects/manager.
// * Serialization from a raw buffer; provides a virtual function that
// accepts Stream, to be implemented in children instead.
// * Provides Unserialize interface that accepts Stream.
struct AGSCCDynamicObject : public CCBasicObject {
public:
virtual ~AGSCCDynamicObject() = default;
// TODO: pass savegame format version
int Serialize(void *address, uint8_t *buffer, int bufsize) override;
// Try unserializing the object from the given input stream
virtual void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) = 0;
protected:
// Savegame serialization
// Calculate and return required space for serialization, in bytes
virtual size_t CalcSerializeSize(const void *address) = 0;
// Write object data into the provided stream
virtual void Serialize(const void *address, AGS::Shared::Stream *out) = 0;
};
// CCStaticObject is a base class for managing static global objects in script.
// The static objects can never be disposed, and do not support serialization
// through IScriptObject interface.
struct AGSCCStaticObject : public CCBasicObject {
public:
virtual ~AGSCCStaticObject() = default;
const char *GetType() override { return "StaticObject"; }
};
} // namespace AGS3
#endif

View 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/>.
*
*/
#include "ags/shared/util/stream.h"
#include "ags/engine/ac/dynobj/cc_audio_channel.h"
#include "ags/engine/ac/dynobj/script_audio_channel.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/engine/media/audio/audio_system.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
const char *CCAudioChannel::GetType() {
return "AudioChannel";
}
size_t CCAudioChannel::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
void CCAudioChannel::Serialize(const void *address, Stream *out) {
const ScriptAudioChannel *ach = static_cast<const ScriptAudioChannel *>(address);
out->WriteInt32(ach->id);
}
void CCAudioChannel::Unserialize(int index, Stream *in, size_t data_sz) {
int id = in->ReadInt32();
ccRegisterUnserializedObject(index, &_G(scrAudioChannel)[id], this);
}
} // namespace AGS3

View File

@@ -0,0 +1,41 @@
/* 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_ENGINE_DYNOBJ_CC_AUDIO_CHANNEL_H
#define AGS_ENGINE_DYNOBJ_CC_AUDIO_CHANNEL_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCAudioChannel final : AGSCCDynamicObject {
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,50 @@
/* 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/engine/ac/dynobj/cc_audio_clip.h"
#include "ags/shared/ac/dynobj/script_audio_clip.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/shared/util/stream.h"
namespace AGS3 {
using namespace AGS::Shared;
const char *CCAudioClip::GetType() {
return "AudioClip";
}
size_t CCAudioClip::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
void CCAudioClip::Serialize(const void *address, Stream *out) {
const ScriptAudioClip *ach = static_cast<const ScriptAudioClip *>(address);
out->WriteInt32(ach->id);
}
void CCAudioClip::Unserialize(int index, Stream *in, size_t data_sz) {
int id = in->ReadInt32();
ccRegisterUnserializedObject(index, &_GP(game).audioClips[id], this);
}
} // namespace AGS3

View File

@@ -0,0 +1,41 @@
/* 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_ENGINE_DYNOBJ_CC_AUDIO_CLIP_H
#define AGS_ENGINE_DYNOBJ_CC_AUDIO_CLIP_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCAudioClip final : AGSCCDynamicObject {
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,370 @@
/* 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/engine/ac/dynobj/cc_character.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/ac/character_info.h"
#include "ags/engine/ac/global_character.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/shared/script/cc_common.h" // cc_error
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// return the type name of the object
const char *CCCharacter::GetType() {
return "Character";
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
size_t CCCharacter::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
void CCCharacter::Serialize(const void *address, Stream *out) {
const CharacterInfo *chaa = static_cast<const CharacterInfo *>(address);
out->WriteInt32(chaa->index_id);
}
void CCCharacter::Unserialize(int index, Stream *in, size_t data_sz) {
int num = in->ReadInt32();
ccRegisterUnserializedObject(index, &_GP(game).chars[num], this);
}
uint8_t CCCharacter::ReadInt8(void *address, intptr_t offset) {
const CharacterInfo *ci = static_cast<CharacterInfo *>(address);
const int on_offset = 28 * sizeof(int32_t) /* first var group */
+ 301 * sizeof(int16_t) /* inventory */ + sizeof(int16_t) * 2 /* two shorts */ + 40 /* name */ + 20 /* scrname */;
if (offset == on_offset)
return ci->on;
cc_error("ScriptCharacter: unsupported 'char' variable offset %d", offset);
return 0;
}
void CCCharacter::WriteInt8(void *address, intptr_t offset, uint8_t val) {
CharacterInfo *ci = static_cast<CharacterInfo *>(address);
const int on_offset = 28 * sizeof(int32_t) /* first var group */
+ 301 * sizeof(int16_t) /* inventory */ + sizeof(int16_t) * 2 /* two shorts */ + 40 /* name */ + 20 /* scrname */;
if (offset == on_offset)
ci->on = val;
else
cc_error("ScriptCharacter: unsupported 'char' variable offset %d", offset);
}
int16_t CCCharacter::ReadInt16(void *address, intptr_t offset) {
const CharacterInfo *ci = static_cast<CharacterInfo *>(address);
// Handle inventory fields
const int invoffset = 112;
if (offset >= invoffset && offset < (uint)(invoffset + MAX_INV * sizeof(short))) {
return ci->inv[(offset - invoffset) / sizeof(short)];
}
switch (offset) {
// +9 int32 = 36
case 36:
return ci->following;
case 38:
return ci->followinfo;
// 40 +1 int32 = 44
case 44:
return ci->idletime;
case 46:
return ci->idleleft;
case 48:
return ci->transparency;
case 50:
return ci->baseline;
// 52 +3 int32 = 64
case 64:
return ci->blinkview;
case 66:
return ci->blinkinterval;
case 68:
return ci->blinktimer;
case 70:
return ci->blinkframe;
case 72:
return ci->walkspeed_y;
case 74:
return ci->pic_yoffs;
// 76 +2 int32 = 84
case 84:
return ci->speech_anim_speed;
case 86:
return ci->idle_anim_speed;
case 88:
return ci->blocking_width;
case 90:
return ci->blocking_height;
// 92 +1 int32 = 96
case 96:
return ci->pic_xoffs;
case 98:
return ci->walkwaitcounter;
case 100:
return ci->loop;
case 102:
return ci->frame;
case 104:
return ci->walking;
case 106:
return ci->animating;
case 108:
return ci->walkspeed;
case 110:
return ci->animspeed;
// 112 +301 int16 = 714 (skip inventory)
case 714:
return ci->actx;
case 716:
return ci->acty;
default:
cc_error("ScriptCharacter: unsupported 'short' variable offset %d", offset);
return 0;
}
}
void CCCharacter::WriteInt16(void *address, intptr_t offset, int16_t val) {
CharacterInfo *ci = static_cast<CharacterInfo *>(address);
// Detect when a game directly modifies the inventory, which causes the displayed
// and actual inventory to diverge since 2.70. Force an update of the displayed
// inventory for older games that rely on this behaviour.
const int invoffset = 112;
if (offset >= invoffset && offset < (uint)(invoffset + MAX_INV * sizeof(short))) {
ci->inv[(offset - invoffset) / sizeof(short)] = val;
update_invorder();
return;
}
// TODO: for safety, find out which of the following fields
// must be readonly, and add assertions for them, i.e.:
// cc_error("ScriptCharacter: attempt to write readonly 'short' variable at offset %d", offset);
switch (offset) {
// +9 int32 = 36
case 36:
ci->following = val;
break;
case 38:
ci->followinfo = val;
break;
// 40 +1 int32 = 44
case 44:
ci->idletime = val;
break;
case 46:
ci->idleleft = val;
break;
case 48:
ci->transparency = val;
break;
case 50:
ci->baseline = val;
break;
// 52 +3 int32 = 64
case 64:
ci->blinkview = val;
break;
case 66:
ci->blinkinterval = val;
break;
case 68:
ci->blinktimer = val;
break;
case 70:
ci->blinkframe = val;
break;
case 72:
ci->walkspeed_y = val;
break;
case 74:
ci->pic_yoffs = val;
break;
// 76 +2 int32 = 84
case 84:
ci->speech_anim_speed = val;
break;
case 86:
ci->idle_anim_speed = val;
break;
case 88:
ci->blocking_width = val;
break;
case 90:
ci->blocking_height = val;
break;
// 92 +1 int32 = 96
case 96:
ci->pic_xoffs = val;
break;
case 98:
ci->walkwaitcounter = val;
break;
case 100:
ci->loop = val;
break;
case 102:
ci->frame = val;
break;
case 104:
ci->walking = val;
break;
case 106:
ci->animating = val;
break;
case 108:
ci->walkspeed = val;
break;
case 110:
ci->animspeed = val;
break;
// 112 +301 int16 = 714 (skip inventory)
case 714:
ci->actx = val;
break;
case 716:
ci->acty = val;
break;
default:
cc_error("ScriptCharacter: unsupported 'short' variable offset %d", offset);
break;
}
}
int32_t CCCharacter::ReadInt32(void *address, intptr_t offset) {
const CharacterInfo *ci = static_cast<CharacterInfo *>(address);
switch (offset) {
case 0:
return ci->defview;
case 4:
return ci->talkview;
case 8:
return ci->view;
case 12:
return ci->room;
case 16:
return ci->prevroom;
case 20:
return ci->x;
case 24:
return ci->y;
case 28:
return ci->wait;
case 32:
return ci->flags;
// 36 +2 int16 = 40
case 40:
return ci->idleview;
// 44 +4 int16 = 52
case 52:
return ci->activeinv;
case 56:
return ci->talkcolor;
case 60:
return ci->thinkview;
// 64 +6 int16 = 76
case 76:
return ci->z;
case 80:
return ci->walkwait;
// 84 +4 int16 = 100
case 92:
return ci->index_id;
default:
cc_error("ScriptCharacter: unsupported 'int' variable offset %d", offset);
return 0;
}
}
void CCCharacter::WriteInt32(void *address, intptr_t offset, int32_t val) {
CharacterInfo *ci = static_cast<CharacterInfo *>(address);
// TODO: for safety, find out which of the following fields
// must be readonly, and add assertions for them, i.e.:
// cc_error("ScriptCharacter: attempt to write readonly 'int' variable at offset %d", offset);
switch (offset) {
case 0:
ci->defview = val;
break;
case 4:
ci->talkview = val;
break;
case 8:
ci->view = val;
break;
case 12:
ci->room = val;
break;
case 16:
ci->prevroom = val;
break;
case 20:
ci->x = val;
break;
case 24:
ci->y = val;
break;
case 28:
ci->wait = val;
break;
case 32:
ci->flags = val;
break;
// 36 +2 int16 = 40
case 40:
ci->idleview = val;
break;
// 44 +4 int16 = 52
case 52:
ci->activeinv = val;
break;
case 56:
ci->talkcolor = val;
break;
case 60:
ci->thinkview = val;
break;
// 64 +6 int16 = 76
case 76:
ci->z = val;
break;
case 80:
ci->walkwait = val;
break;
// 84 +4 int16 = 100
case 92:
ci->index_id = val;
break;
default:
cc_error("ScriptCharacter: unsupported 'int' variable offset %d", offset);
break;
}
}
} // namespace AGS3

View File

@@ -0,0 +1,58 @@
/* 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/>.
*
*/
//=============================================================================
//
// Wrapper around script "Character" struct, managing access to its variables.
// Assumes object data contains CharacterInfo object.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_DYNOBJ_CC_CHARACTER_H
#define AGS_ENGINE_AC_DYNOBJ_CC_CHARACTER_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCCharacter final : AGSCCDynamicObject {
public:
// return the type name of the object
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
uint8_t ReadInt8(void *address, intptr_t offset) override;
int16_t ReadInt16(void *address, intptr_t offset) override;
int32_t ReadInt32(void *address, intptr_t offset) override;
void WriteInt8(void *address, intptr_t offset, uint8_t val) override;
void WriteInt16(void *address, intptr_t offset, int16_t val) override;
void WriteInt32(void *address, intptr_t offset, int32_t val) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View 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/engine/ac/dynobj/cc_dialog.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/engine/ac/dialog.h"
#include "ags/shared/ac/dialog_topic.h"
#include "ags/shared/ac/game_struct_defines.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// return the type name of the object
const char *CCDialog::GetType() {
return "Dialog";
}
size_t CCDialog::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
void CCDialog::Serialize(const void *address, Stream *out) {
const ScriptDialog *shh = static_cast<const ScriptDialog *>(address);
out->WriteInt32(shh->id);
}
void CCDialog::Unserialize(int index, Stream *in, size_t data_sz) {
int num = in->ReadInt32();
ccRegisterUnserializedObject(index, &_GP(scrDialog)[num], this);
}
} // namespace AGS3

View 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/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_CC_DIALOG_H
#define AGS_ENGINE_AC_DYNOBJ_CC_DIALOG_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCDialog final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,114 @@
/* 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/engine/ac/dynobj/cc_dynamic_array.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/engine/ac/dynobj/script_string.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
const char *CCDynamicArray::TypeName = "CCDynamicArray";
// return the type name of the object
const char *CCDynamicArray::GetType() {
return TypeName;
}
int CCDynamicArray::Dispose(void *address, bool force) {
// If it's an array of managed objects, release their ref counts;
// except if this array is forcefully removed from the managed pool,
// in which case just ignore these.
if (!force) {
const Header &hdr = GetHeader(address);
bool is_managed = (hdr.ElemCount & ARRAY_MANAGED_TYPE_FLAG) != 0;
const uint32_t el_count = hdr.ElemCount & (~ARRAY_MANAGED_TYPE_FLAG);
if (is_managed) { // Dynamic array of managed pointers: subref them directly
const uint32_t *handles = reinterpret_cast<const uint32_t *>(address);
for (uint32_t i = 0; i < el_count; ++i) {
if (handles[i] > 0)
ccReleaseObjectReference(handles[i]);
}
}
}
delete[] (static_cast<uint8_t *>(address) - MemHeaderSz);
return 1;
}
size_t CCDynamicArray::CalcSerializeSize(const void *address) {
const Header &hdr = GetHeader(address);
return hdr.TotalSize + FileHeaderSz;
}
void CCDynamicArray::Serialize(const void *address, Stream *out) {
const Header &hdr = GetHeader(address);
out->WriteInt32(hdr.ElemCount);
out->WriteInt32(hdr.TotalSize);
out->Write(address, hdr.TotalSize); // elements
}
void CCDynamicArray::Unserialize(int index, Stream *in, size_t data_sz) {
uint8_t *new_arr = new uint8_t[(data_sz - FileHeaderSz) + MemHeaderSz];
Header &hdr = reinterpret_cast<Header &>(*new_arr);
hdr.ElemCount = in->ReadInt32();
hdr.TotalSize = in->ReadInt32();
in->Read(new_arr + MemHeaderSz, data_sz - FileHeaderSz);
ccRegisterUnserializedObject(index, &new_arr[MemHeaderSz], this);
}
/* static */ DynObjectRef CCDynamicArray::Create(int numElements, int elementSize, bool isManagedType) {
uint8_t *new_arr = new uint8_t[numElements * elementSize + MemHeaderSz];
memset(new_arr, 0, numElements * elementSize + MemHeaderSz);
Header &hdr = reinterpret_cast<Header &>(*new_arr);
hdr.ElemCount = numElements | (ARRAY_MANAGED_TYPE_FLAG * isManagedType);
hdr.TotalSize = elementSize * numElements;
void *obj_ptr = &new_arr[MemHeaderSz];
int32_t handle = ccRegisterManagedObject(obj_ptr, &_GP(globalDynamicArray));
if (handle == 0) {
delete[] new_arr;
return DynObjectRef();
}
return DynObjectRef(handle, obj_ptr, &_GP(globalDynamicArray));
}
DynObjectRef DynamicArrayHelpers::CreateStringArray(const std::vector<const char *> items) {
// NOTE: we need element size of "handle" for array of managed pointers
DynObjectRef arr = _GP(globalDynamicArray).Create(items.size(), sizeof(int32_t), true);
if (!arr.Obj)
return arr;
// Create script strings and put handles into array
int32_t *slots = static_cast<int32_t *>(arr.Obj);
for (auto s : items) {
DynObjectRef str = ScriptString::Create(s);
// We must add reference count, because the string is going to be saved
// within another object (array), not returned to script directly
ccAddObjectReference(str.Handle);
*(slots++) = str.Handle;
}
return arr;
}
} // namespace AGS3

View 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/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_CC_DYNAMICARRAY_H
#define AGS_ENGINE_AC_DYNOBJ_CC_DYNAMICARRAY_H
#include "common/std/vector.h"
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
#include "ags/shared/util/stream.h"
namespace AGS3 {
#define ARRAY_MANAGED_TYPE_FLAG 0x80000000
struct CCDynamicArray final : AGSCCDynamicObject {
public:
static const char *TypeName;
struct Header {
// May contain ARRAY_MANAGED_TYPE_FLAG
uint32_t ElemCount = 0u;
// TODO: refactor and store "elem size" instead
uint32_t TotalSize = 0u;
};
CCDynamicArray() = default;
~CCDynamicArray() = default;
inline static const Header &GetHeader(const void *address) {
return reinterpret_cast<const Header &>(*(static_cast<const uint8_t *>(address) - MemHeaderSz));
}
// Create managed array object and return a pointer to the beginning of a buffer
static DynObjectRef Create(int numElements, int elementSize, bool isManagedType);
// return the type name of the object
const char *GetType() override;
int Dispose(void *address, bool force) override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
private:
// The size of the array's header in memory, prepended to the element data
static const size_t MemHeaderSz = sizeof(Header);
// The size of the serialized header
static const size_t FileHeaderSz = sizeof(uint32_t) * 2;
// Savegame serialization
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
// Helper functions for setting up dynamic arrays.
namespace DynamicArrayHelpers {
// Create array of managed strings
DynObjectRef CreateStringArray(const std::vector<const char *>);
} // namespace DynamicArrayHelpers
} // namespace AGS3
#endif

View File

@@ -0,0 +1,53 @@
/* 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/engine/ac/dynobj/cc_gui.h"
#include "ags/engine/ac/dynobj/script_gui.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// return the type name of the object
const char *CCGUI::GetType() {
return "GUI";
}
size_t CCGUI::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
void CCGUI::Serialize(const void *address, Stream *out) {
const ScriptGUI *shh = static_cast<const ScriptGUI *>(address);
out->WriteInt32(shh->id);
}
void CCGUI::Unserialize(int index, Stream *in, size_t data_sz) {
int num = in->ReadInt32();
ccRegisterUnserializedObject(index, &_GP(scrGui)[num], this);
}
} // namespace AGS3

View 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/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_CCGUI_H
#define AGS_ENGINE_AC_DYNOBJ_CCGUI_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCGUI final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,57 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ags/engine/ac/dynobj/cc_gui_object.h"
#include "ags/engine/ac/dynobj/script_gui.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/gui/gui_main.h"
#include "ags/shared/gui/gui_object.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// return the type name of the object
const char *CCGUIObject::GetType() {
return "GUIObject";
}
size_t CCGUIObject::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t) * 2;
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
void CCGUIObject::Serialize(const void *address, Stream *out) {
const GUIObject *guio = static_cast<const GUIObject *>(address);
out->WriteInt32(guio->ParentId);
out->WriteInt32(guio->Id);
}
void CCGUIObject::Unserialize(int index, Stream *in, size_t data_sz) {
int guinum = in->ReadInt32();
int objnum = in->ReadInt32();
ccRegisterUnserializedObject(index, _GP(guis)[guinum].GetControl(objnum), this);
}
} // namespace AGS3

View 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/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_CC_GUI_OBJECT_H
#define AGS_ENGINE_AC_DYNOBJ_CC_GUI_OBJECT_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCGUIObject final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View 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/engine/ac/dynobj/cc_hotspot.h"
#include "ags/engine/ac/dynobj/script_hotspot.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/ac/common_defines.h"
#include "ags/shared/game/room_struct.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// return the type name of the object
const char *CCHotspot::GetType() {
return "Hotspot";
}
size_t CCHotspot::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
void CCHotspot::Serialize(const void *address, Stream *out) {
const ScriptHotspot *shh = static_cast<const ScriptHotspot *>(address);
out->WriteInt32(shh->id);
}
void CCHotspot::Unserialize(int index, Stream *in, size_t data_sz) {
int num = in->ReadInt32();
ccRegisterUnserializedObject(index, &_G(scrHotspot)[num], this);
}
} // namespace AGS3

View 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/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_CC_HOTSPOT_H
#define AGS_ENGINE_AC_DYNOBJ_CC_HOTSPOT_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCHotspot final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View 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/engine/ac/dynobj/cc_inventory.h"
#include "ags/engine/ac/dynobj/script_inv_item.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/ac/character_info.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// return the type name of the object
const char *CCInventory::GetType() {
return "Inventory";
}
size_t CCInventory::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
void CCInventory::Serialize(const void *address, Stream *out) {
const ScriptInvItem *shh = static_cast<const ScriptInvItem *>(address);
out->WriteInt32(shh->id);
}
void CCInventory::Unserialize(int index, Stream *in, size_t data_sz) {
int num = in->ReadInt32();
ccRegisterUnserializedObject(index, &_G(scrInv)[num], this);
}
} // namespace AGS3

View 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/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_CCINVENTORY_H
#define AGS_ENGINE_AC_DYNOBJ_CCINVENTORY_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCInventory final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View 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/engine/ac/dynobj/cc_object.h"
#include "ags/engine/ac/dynobj/script_object.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/ac/common_defines.h"
#include "ags/shared/game/room_struct.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// return the type name of the object
const char *CCObject::GetType() {
return "Object";
}
size_t CCObject::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
void CCObject::Serialize(const void *address, Stream *out) {
const ScriptObject *shh = static_cast<const ScriptObject *>(address);
out->WriteInt32(shh->id);
}
void CCObject::Unserialize(int index, Stream *in, size_t data_sz) {
int num = in->ReadInt32();
ccRegisterUnserializedObject(index, &_G(scrObj)[num], this);
}
} // namespace AGS3

View 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/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_CCOBJECT_H
#define AGS_ENGINE_AC_DYNOBJ_CCOBJECT_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCObject final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View 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/engine/ac/dynobj/cc_region.h"
#include "ags/engine/ac/dynobj/script_region.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/ac/common_defines.h"
#include "ags/shared/game/room_struct.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// return the type name of the object
const char *CCRegion::GetType() {
return "Region";
}
size_t CCRegion::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
void CCRegion::Serialize(const void *address, Stream *out) {
const ScriptRegion *shh = static_cast<const ScriptRegion *>(address);
out->WriteInt32(shh->id);
}
void CCRegion::Unserialize(int index, Stream *in, size_t data_sz) {
int num = in->ReadInt32();
ccRegisterUnserializedObject(index, &_G(scrRegion)[num], this);
}
} // namespace AGS3

View 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/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_CCREGION_H
#define AGS_ENGINE_AC_DYNOBJ_CCREGION_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCRegion final : AGSCCDynamicObject {
// return the type name of the object
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,128 @@
/* 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/>.
*
*/
//=============================================================================
//
// IScriptObject: script managed object interface.
// Provides interaction with a object which allocation and lifetime is
// managed by the engine and/or the managed pool rather than the script VM.
// These may be both static objects existing throughout the game, and
// dynamic objects allocated by the script command.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_DYNOBJ_CC_SCRIPT_OBJECT_H
#define AGS_ENGINE_AC_DYNOBJ_CC_SCRIPT_OBJECT_H
#include "common/std/utility.h"
#include "ags/shared/core/types.h"
namespace AGS3 {
// Forward declaration
namespace AGS {
namespace Shared {
class Stream;
} // namespace Shared
} // namespace AGS
struct IScriptObject;
// A convenience struct for grouping handle and dynamic object
struct DynObjectRef {
const int Handle = 0;
void *const Obj = nullptr;
IScriptObject *const Mgr = nullptr;
DynObjectRef() = default;
DynObjectRef(int handle, void *obj, IScriptObject *mgr)
: Handle(handle), Obj(obj), Mgr(mgr) {}
};
struct IScriptObject {
// WARNING: The first section of this interface is also a part of the AGS plugin API!
// when a ref count reaches 0, this is called with the address
// of the object. Return 1 to remove the object from memory, 0 to
// leave it
// The "force" flag tells system to detach the object, breaking any links and references
// to other managed objects or game resources (instead of disposing these too).
// TODO: it might be better to rewrite the managed pool and remove this flag at all,
// because it makes the use of this interface prone to mistakes.
virtual int Dispose(void *address, bool force = false) = 0;
// return the type name of the object
virtual const char *GetType() = 0;
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
// TODO: pass savegame format version
virtual int Serialize(void *address, uint8_t *buffer, int bufsize) = 0;
// WARNING: following section is not a part of plugin API, therefore these methods
// should **never** be called for kScValPluginObject script objects!
// Legacy support for reading and writing object values by their relative offset.
// These methods allow to "remap" script struct field access, by taking the
// legacy offset, and using it rather as a field ID than an address, for example.
// Consequently these also let trigger side-effects, such as updating an object
// after a field value is written to.
// RE: GetFieldPtr() -
// According to AGS script specification, when the old-string pointer or char array is passed
// as an argument, the byte-code does not include any specific command for the member variable
// retrieval and instructs to pass an address of the object itself with certain offset.
// This results in functions like StrCopy writing directly over object address.
// There may be other implementations, but the big question is: how to detect when this is
// necessary, because byte-code does not contain any distinct operation for this case.
// The worst thing here is that with the current byte-code structure we can never tell whether
// offset 0 means getting pointer to whole object or a pointer to its first field.
virtual void *GetFieldPtr(void *address, intptr_t offset) = 0;
virtual void Read(void *address, intptr_t offset, uint8_t *dest, size_t size) = 0;
virtual uint8_t ReadInt8(void *address, intptr_t offset) = 0;
virtual int16_t ReadInt16(void *address, intptr_t offset) = 0;
virtual int32_t ReadInt32(void *address, intptr_t offset) = 0;
virtual float ReadFloat(void *address, intptr_t offset) = 0;
virtual void Write(void *address, intptr_t offset, const uint8_t *src, size_t size) = 0;
virtual void WriteInt8(void *address, intptr_t offset, uint8_t val) = 0;
virtual void WriteInt16(void *address, intptr_t offset, int16_t val) = 0;
virtual void WriteInt32(void *address, intptr_t offset, int32_t val) = 0;
virtual void WriteFloat(void *address, intptr_t offset, float val) = 0;
protected:
IScriptObject() {}
virtual ~IScriptObject() {}
};
// The interface of a script objects deserializer that handles multiple types.
struct ICCObjectCollectionReader {
virtual ~ICCObjectCollectionReader() {}
// TODO: pass savegame format version
virtual void Unserialize(int32_t handle, const char *objectType, const char *serializedData, int dataSize) = 0;
};
// The interface of a script objects deserializer that handles a single type.
// WARNING: a part of the plugin API.
struct ICCObjectReader {
virtual ~ICCObjectReader() {}
virtual void Unserialize(int32_t handle, const char *serializedData, int dataSize) = 0;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,140 @@
/* 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/util/memory_stream.h"
#include "ags/engine/ac/dynobj/cc_serializer.h"
#include "ags/engine/ac/dynobj/all_dynamic_classes.h"
#include "ags/engine/ac/dynobj/all_script_classes.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/engine/ac/dynobj/cc_dynamic_array.h"
#include "ags/engine/ac/dynobj/script_user_object.h"
#include "ags/engine/ac/dynobj/script_camera.h"
#include "ags/engine/ac/dynobj/script_containers.h"
#include "ags/engine/ac/dynobj/script_file.h"
#include "ags/engine/ac/dynobj/script_viewport.h"
#include "ags/engine/ac/game.h"
#include "ags/engine/debugging/debug_log.h"
#include "ags/plugins/plugin_engine.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// *** De-serialization of script objects
void AGSDeSerializer::Unserialize(int32_t index, const char *objectType, const char *serializedData, int dataSize) {
if (dataSize < 0) {
quitprintf("Unserialise: invalid data size (%d) for object type '%s'", dataSize, objectType);
return; // TODO: don't quit, return error
}
// Note that while our builtin classes may accept Stream object,
// classes registered by plugin cannot, because streams are not (yet)
// part of the plugin API.
size_t data_sz = static_cast<size_t>(dataSize);
assert(data_sz <= INT32_MAX); // dynamic object API does not support size > int32
MemoryStream mems(reinterpret_cast<const uint8_t *>(serializedData), dataSize);
// TODO: consider this: there are object types that are part of the
// script's foundation, because they are created by the bytecode ops:
// such as DynamicArray and UserObject. *Maybe* these should be moved
// to certain "base serializer" class which guarantees their restoration.
//
// TODO: should we support older save versions here (DynArray, UserObj)?
// might have to use older class names to distinguish save formats
if (strcmp(objectType, CCDynamicArray::TypeName) == 0) {
_GP(globalDynamicArray).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, ScriptUserObject::TypeName) == 0) {
ScriptUserObject *suo = new ScriptUserObject();
suo->Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "GUIObject") == 0) {
_GP(ccDynamicGUIObject).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "Character") == 0) {
_GP(ccDynamicCharacter).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "Hotspot") == 0) {
_GP(ccDynamicHotspot).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "Region") == 0) {
_GP(ccDynamicRegion).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "Inventory") == 0) {
_GP(ccDynamicInv).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "Dialog") == 0) {
_GP(ccDynamicDialog).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "GUI") == 0) {
_GP(ccDynamicGUI).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "Object") == 0) {
_GP(ccDynamicObject).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "String") == 0) {
_GP(myScriptStringImpl).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "File") == 0) {
// files cannot be restored properly -- so just recreate
// the object; attempting any operations on it will fail
sc_File *scf = new sc_File();
ccRegisterUnserializedObject(index, scf, scf);
} else if (strcmp(objectType, "Overlay") == 0) {
ScriptOverlay *scf = new ScriptOverlay();
scf->Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "DateTime") == 0) {
ScriptDateTime *scf = new ScriptDateTime();
scf->Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "ViewFrame") == 0) {
ScriptViewFrame *scf = new ScriptViewFrame();
scf->Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "DynamicSprite") == 0) {
ScriptDynamicSprite *scf = new ScriptDynamicSprite();
scf->Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "DrawingSurface") == 0) {
ScriptDrawingSurface *sds = new ScriptDrawingSurface();
sds->Unserialize(index, &mems, data_sz);
if (sds->isLinkedBitmapOnly) {
_G(dialogOptionsRenderingSurface) = sds;
}
} else if (strcmp(objectType, "DialogOptionsRendering") == 0) {
_GP(ccDialogOptionsRendering).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "StringDictionary") == 0) {
Dict_Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "StringSet") == 0) {
Set_Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "Viewport2") == 0) {
Viewport_Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "Camera2") == 0) {
Camera_Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "AudioChannel") == 0) {
_GP(ccDynamicAudio).Unserialize(index, &mems, data_sz);
} else if (strcmp(objectType, "AudioClip") == 0) {
_GP(ccDynamicAudioClip).Unserialize(index, &mems, data_sz);
} else {
// check if the type is read by a plugin
for (const auto &pr : _GP(pluginReaders)) {
if (pr.Type == objectType) {
if (dataSize == 0) { // avoid unserializing stubbed plugins
debug(0, "Skipping %s plugin unserialization (dataSize = 0)", objectType);
return;
}
pr.Reader->Unserialize(index, serializedData, dataSize);
return;
}
}
quitprintf("Unserialise: unknown object type: '%s'", objectType);
}
}
} // namespace AGS3

View File

@@ -0,0 +1,35 @@
/* 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_ENGINE_AC_DYNOBJ_SERIALIZER_H
#define AGS_ENGINE_AC_DYNOBJ_SERIALIZER_H
#include "ags/engine/ac/dynobj/cc_script_object.h"
namespace AGS3 {
struct AGSDeSerializer : ICCObjectCollectionReader {
void Unserialize(int32_t index, const char *objectType, const char *serializedData, int dataSize) override;
};
} // namespace AGS3
#endif

View 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/>.
*
*/
#include "ags/engine/ac/dynobj/cc_static_array.h"
#include "ags/engine/ac/dynobj/cc_script_object.h"
namespace AGS3 {
void CCStaticArray::Create(IScriptObject *mgr, size_t elem_script_size, size_t elem_mem_size, size_t elem_count) {
_mgr = mgr;
_elemScriptSize = elem_script_size;
_elemMemSize = elem_mem_size;
_elemCount = elem_count;
}
void *CCStaticArray::GetFieldPtr(void *address, intptr_t offset) {
return GetElementPtr(address, offset);
}
void CCStaticArray::Read(void *address, intptr_t offset, uint8_t *dest, size_t size) {
void *el_ptr = GetElementPtr(address, offset);
return _mgr->Read(el_ptr, offset % _elemScriptSize, dest, size);
}
uint8_t CCStaticArray::ReadInt8(void *address, intptr_t offset) {
void *el_ptr = GetElementPtr(address, offset);
return _mgr->ReadInt8(el_ptr, offset % _elemScriptSize);
}
int16_t CCStaticArray::ReadInt16(void *address, intptr_t offset) {
void *el_ptr = GetElementPtr(address, offset);
return _mgr->ReadInt16(el_ptr, offset % _elemScriptSize);
}
int32_t CCStaticArray::ReadInt32(void *address, intptr_t offset) {
void *el_ptr = GetElementPtr(address, offset);
return _mgr->ReadInt32(el_ptr, offset % _elemScriptSize);
}
float CCStaticArray::ReadFloat(void *address, intptr_t offset) {
void *el_ptr = GetElementPtr(address, offset);
return _mgr->ReadFloat(el_ptr, offset % _elemScriptSize);
}
void CCStaticArray::Write(void *address, intptr_t offset, const uint8_t *src, size_t size) {
void *el_ptr = GetElementPtr(address, offset);
return _mgr->Write(el_ptr, offset % _elemScriptSize, src, size);
}
void CCStaticArray::WriteInt8(void *address, intptr_t offset, uint8_t val) {
void *el_ptr = GetElementPtr(address, offset);
return _mgr->WriteInt8(el_ptr, offset % _elemScriptSize, val);
}
void CCStaticArray::WriteInt16(void *address, intptr_t offset, int16_t val) {
void *el_ptr = GetElementPtr(address, offset);
return _mgr->WriteInt16(el_ptr, offset % _elemScriptSize, val);
}
void CCStaticArray::WriteInt32(void *address, intptr_t offset, int32_t val) {
void *el_ptr = GetElementPtr(address, offset);
return _mgr->WriteInt32(el_ptr, offset % _elemScriptSize, val);
}
void CCStaticArray::WriteFloat(void *address, intptr_t offset, float val) {
void *el_ptr = GetElementPtr(address, offset);
return _mgr->WriteFloat(el_ptr, offset % _elemScriptSize, val);
}
} // namespace AGS3

View File

@@ -0,0 +1,96 @@
/* 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/>.
*
*/
//=============================================================================
//
// CCStaticArray manages access to an array of script objects,
// where an element's size counted by script's bytecode may differ from the
// real element size in the engine's memory.
// The purpose of this is to remove size restriction from the engine's structs
// exposed to scripts.
//
// FIXME: [ivan-mogilko] the above was meant to work, but in reality it doesn't
// and won't, at least not without some extra workarounds.
// The problem that I missed here is following:
// when the script compiler is told to get an Nth element of a global struct
// array, such as character[n], it calculates the memory address as
// array address + sizeof(Character) * n.
// If this address is used for the read/write operations, these ops can be
// intercepted by interpreter and remapped into the real fields
// (see IScriptObject::ReadN, WriteN interface)
// But if this address is used IN POINTER COMPARISON, then we cannot do
// anything. And if our real struct in the engine is stored on a different
// relative memory offset than one expected by compiler, then this pointer
// comparison will fail, e.g. script expression like
// if (player == character[n])
//
// NOTE: on the other hand, similar effect could be achieved by separating
// object data into two or more structs, where "base" structs are stored in
// the exposed arrays (part of API), while extending structs are stored
// separately. This is more an issue of engine data design.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_DYNOBJ_STATIC_ARRAY_H
#define AGS_ENGINE_AC_DYNOBJ_STATIC_ARRAY_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCStaticArray : public AGSCCStaticObject {
public:
~CCStaticArray() override {}
void Create(IScriptObject *mgr, size_t elem_script_size, size_t elem_mem_size, size_t elem_count = SIZE_MAX /*unknown*/);
inline IScriptObject *GetObjectManager() const {
return _mgr;
}
// Legacy support for reading and writing object values by their relative offset
inline void *GetElementPtr(void *address, intptr_t legacy_offset) {
return static_cast<uint8_t *>(address) + (legacy_offset / _elemScriptSize) * _elemMemSize;
}
void *GetFieldPtr(void *address, intptr_t offset) override;
void Read(void *address, intptr_t offset, uint8_t *dest, size_t size) override;
uint8_t ReadInt8(void *address, intptr_t offset) override;
int16_t ReadInt16(void *address, intptr_t offset) override;
int32_t ReadInt32(void *address, intptr_t offset) override;
float ReadFloat(void *address, intptr_t offset) override;
void Write(void *address, intptr_t offset, const uint8_t *src, size_t size) override;
void WriteInt8(void *address, intptr_t offset, uint8_t val) override;
void WriteInt16(void *address, intptr_t offset, int16_t val) override;
void WriteInt32(void *address, intptr_t offset, int32_t val) override;
void WriteFloat(void *address, intptr_t offset, float val) override;
private:
IScriptObject *_mgr = nullptr;
size_t _elemScriptSize = 0u;
size_t _elemMemSize = 0u;
size_t _elemCount = 0u;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,154 @@
/* 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/>.
*
*/
//=============================================================================
//
// C-Script run-time interpreter (c) 2001 Chris Jones
//
// You must DISABLE OPTIMIZATIONS AND REGISTER VARIABLES in your compiler
// when compiling this, or strange results can happen.
//
// There is a problem with importing functions on 16-bit compilers: the
// script system assumes that all parameters are passed as 4 bytes, which
// ints are not on 16-bit systems. Be sure to define all parameters as longs,
// or join the 21st century and switch to DJGPP or Visual C++.
//
//=============================================================================
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/core/platform.h"
#include "ags/engine/ac/dynobj/managed_object_pool.h"
#include "ags/shared/debugging/out.h"
#include "ags/shared/script/cc_common.h"
#include "ags/shared/script/cc_internal.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
// register a memory handle for the object and allow script
// pointers to point to it
int32_t ccRegisterManagedObject(void *object, IScriptObject *callback, ScriptValueType obj_type) {
int32_t handl = _GP(pool).AddObject(object, callback, obj_type);
ManagedObjectLog("Register managed object type '%s' handle=%d addr=%08X",
((callback == NULL) ? "(unknown)" : callback->GetType()), handl, object);
return handl;
}
// register a de-serialized object
int32_t ccRegisterUnserializedObject(int index, void *object, IScriptObject *callback, ScriptValueType obj_type) {
return _GP(pool).AddUnserializedObject(object, callback, obj_type, index);
}
// unregister a particular object
int ccUnRegisterManagedObject(void *object) {
return _GP(pool).RemoveObject(object);
}
// remove all registered objects
void ccUnregisterAllObjects() {
_GP(pool).reset();
}
// serialize all objects to disk
void ccSerializeAllObjects(Stream *out) {
_GP(pool).WriteToDisk(out);
}
// un-serialise all objects (will remove all currently registered ones)
int ccUnserializeAllObjects(Stream *in, ICCObjectCollectionReader *callback) {
return _GP(pool).ReadFromDisk(in, callback);
}
// dispose the object if RefCount==0
void ccAttemptDisposeObject(int32_t handle) {
_GP(pool).CheckDispose(handle);
}
// translate between object handles and memory addresses
int32_t ccGetObjectHandleFromAddress(void *address) {
// set to null
if (address == nullptr)
return 0;
int32_t handl = _GP(pool).AddressToHandle(address);
ManagedObjectLog("Line %d WritePtr: %08X to %d", _G(currentline), address, handl);
if (handl == 0) {
cc_error("Pointer cast failure: the object being pointed to is not in the managed object pool");
return -1;
}
return handl;
}
void *ccGetObjectAddressFromHandle(int32_t handle) {
if (handle == 0) {
return nullptr;
}
void *addr = _GP(pool).HandleToAddress(handle);
ManagedObjectLog("Line %d ReadPtr: %d to %08X", _G(currentline), handle, addr);
if (addr == nullptr) {
cc_error("Error retrieving pointer: invalid handle %d", handle);
return nullptr;
}
return addr;
}
ScriptValueType ccGetObjectAddressAndManagerFromHandle(int32_t handle, void *&object, IScriptObject *&manager) {
if (handle == 0) {
object = nullptr;
manager = nullptr;
return kScValUndefined;
}
ScriptValueType obj_type = _GP(pool).HandleToAddressAndManager(handle, object, manager);
if (obj_type == kScValUndefined) {
cc_error("Error retrieving pointer: invalid handle %d", handle);
}
return obj_type;
}
int ccAddObjectReference(int32_t handle) {
if (handle == 0)
return 0;
return _GP(pool).AddRef(handle);
}
int ccReleaseObjectReference(int32_t handle) {
if (handle == 0)
return 0;
if (_GP(pool).HandleToAddress(handle) == nullptr) {
cc_error("Error releasing pointer: invalid handle %d", handle);
return -1;
}
return _GP(pool).SubRef(handle);
}
} // namespace AGS3

View File

@@ -0,0 +1,73 @@
/* 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/>.
*
*/
//=============================================================================
//
// Dynamic object management utilities.
// TODO: frankly, many of these functions could be factored out by a direct
// use of ManagedPool class.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_DYNOBJ_MANAGER_H
#define AGS_ENGINE_AC_DYNOBJ_MANAGER_H
#include "ags/shared/core/types.h"
#include "ags/engine/script/runtime_script_value.h"
#include "ags/engine/ac/dynobj/cc_script_object.h"
namespace AGS3 {
// Forward declaration
namespace AGS {
namespace Shared {
class Stream;
} // namespace Shared
} // namespace AGS
using namespace AGS; // FIXME later
// register a memory handle for the object and allow script
// pointers to point to it
extern int32_t ccRegisterManagedObject(void *object, IScriptObject *, ScriptValueType obj_type = kScValScriptObject);
// register a de-serialized object
extern int32_t ccRegisterUnserializedObject(int index, void *object, IScriptObject *, ScriptValueType obj_type = kScValScriptObject);
// unregister a particular object
extern int ccUnRegisterManagedObject(void *object);
// remove all registered objects
extern void ccUnregisterAllObjects();
// serialize all objects to disk
extern void ccSerializeAllObjects(Shared::Stream *out);
// un-serialise all objects (will remove all currently registered ones)
extern int ccUnserializeAllObjects(Shared::Stream *in, ICCObjectCollectionReader *callback);
// dispose the object if RefCount==0
extern void ccAttemptDisposeObject(int32_t handle);
// translate between object handles and memory addresses
extern int32_t ccGetObjectHandleFromAddress(void *address);
extern void *ccGetObjectAddressFromHandle(int32_t handle);
extern ScriptValueType ccGetObjectAddressAndManagerFromHandle(int32_t handle, void *&object, IScriptObject *&manager);
extern int ccAddObjectReference(int32_t handle);
extern int ccReleaseObjectReference(int32_t handle);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,347 @@
/* 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/vector.h"
#include "ags/engine/ac/dynobj/managed_object_pool.h"
#include "ags/shared/debugging/out.h"
#include "ags/shared/util/string_utils.h" // fputstring, etc
#include "ags/shared/script/cc_common.h"
#include "ags/shared/script/cc_internal.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
const auto OBJECT_CACHE_MAGIC_NUMBER = 0xa30b;
const auto SERIALIZE_BUFFER_SIZE = 10240;
const auto GARBAGE_COLLECTION_INTERVAL = 1024;
const auto RESERVED_SIZE = 2048;
int ManagedObjectPool::Remove(ManagedObject &o, bool force) {
const bool can_remove = o.callback->Dispose(o.addr, force) != 0;
if (!(can_remove || force))
return 0;
available_ids.push(o.handle);
handleByAddress.erase(o.addr);
ManagedObjectLog("Line %d Disposed managed object handle=%d", currentline, o.handle);
o = ManagedObject();
return 1;
}
int32_t ManagedObjectPool::AddRef(int32_t handle) {
if (handle < 1 || (size_t)handle >= objects.size())
return 0;
auto &o = objects[handle];
if (!o.isUsed())
return 0;
o.refCount++;
ManagedObjectLog("Line %d AddRef: handle=%d new refcount=%d", _G(currentline), o.handle, o.refCount);
return o.refCount;
}
int ManagedObjectPool::CheckDispose(int32_t handle) {
if (handle < 1 || (size_t)handle >= objects.size())
return 1;
auto &o = objects[handle];
if (!o.isUsed()) {
return 1;
}
if (o.refCount >= 1) {
return 0;
}
return Remove(o);
}
int32_t ManagedObjectPool::SubRef(int32_t handle) {
if (handle < 1 || (size_t)handle >= objects.size()) {
return 0;
}
auto &o = objects[handle];
if (!o.isUsed()) {
return 0;
}
o.refCount--;
const auto newRefCount = o.refCount;
const auto canBeDisposed = (o.addr != disableDisposeForObject);
if (canBeDisposed && o.refCount <= 0) {
Remove(o);
}
// object could be removed at this point, don't use any values.
ManagedObjectLog("Line %d SubRef: handle=%d new refcount=%d canBeDisposed=%d", _G(currentline), handle, newRefCount, canBeDisposed);
return newRefCount;
}
int32_t ManagedObjectPool::AddressToHandle(void *addr) {
if (addr == nullptr) {
return 0;
}
auto it = handleByAddress.find(addr);
if (it == handleByAddress.end()) {
return 0;
}
return it->_value;
}
// this function is called often (whenever a pointer is used)
void *ManagedObjectPool::HandleToAddress(int32_t handle) {
if (handle < 1 || (size_t)handle >= objects.size()) {
return nullptr;
}
auto &o = objects[handle];
if (!o.isUsed()) {
return nullptr;
}
return o.addr;
}
// this function is called often (whenever a pointer is used)
ScriptValueType ManagedObjectPool::HandleToAddressAndManager(int32_t handle, void *&object, IScriptObject *&manager) {
if ((handle < 1 || (size_t)handle >= objects.size()) || !objects[handle].isUsed()) {
object = nullptr;
manager = nullptr;
return kScValUndefined;
}
auto &o = objects[handle];
object = (void *)(o.addr); // WARNING: This strips the const from the char* pointer.
manager = o.callback;
return o.obj_type;
}
int ManagedObjectPool::RemoveObject(void *address) {
if (address == nullptr) {
return 0;
}
auto it = handleByAddress.find(address);
if (it == handleByAddress.end()) {
return 0;
}
auto &o = objects[it->_value];
return Remove(o, true);
}
void ManagedObjectPool::RunGarbageCollectionIfAppropriate() {
if (objectCreationCounter <= GARBAGE_COLLECTION_INTERVAL) {
return;
}
RunGarbageCollection();
objectCreationCounter = 0;
}
void ManagedObjectPool::RunGarbageCollection() {
for (int i = 1; i < nextHandle; i++) {
auto &o = objects[i];
if (!o.isUsed()) {
continue;
}
if (o.refCount < 1) {
Remove(o);
}
}
ManagedObjectLog("Ran garbage collection");
}
int ManagedObjectPool::Add(int handle, void *address, IScriptObject *callback, ScriptValueType obj_type)
{
auto &o = objects[handle];
assert(!o.isUsed());
o = ManagedObject(obj_type, handle, address, callback);
handleByAddress.insert({address, handle});
ManagedObjectLog("Allocated managed object type=%s, handle=%d, addr=%08X", callback->GetType(), handle, address);
return handle;
}
int ManagedObjectPool::AddObject(void *address, IScriptObject *callback, ScriptValueType obj_type) {
int32_t handle;
if (!available_ids.empty()) {
handle = available_ids.front();
available_ids.pop();
} else {
handle = nextHandle++;
if ((size_t)handle >= objects.size()) {
objects.resize(handle + 1024, ManagedObject());
}
}
objectCreationCounter++;
return Add(handle, address, callback, obj_type);
}
int ManagedObjectPool::AddUnserializedObject(void *address, IScriptObject *callback, ScriptValueType obj_type, int handle) {
if (handle < 1) {
cc_error("Attempt to assign invalid handle: %d", handle);
return 0;
}
if ((size_t)handle >= objects.size()) {
objects.resize(handle + 1024, ManagedObject());
}
return Add(handle, address, callback, obj_type);
}
void ManagedObjectPool::WriteToDisk(Stream *out) {
// use this opportunity to clean up any non-referenced pointers
RunGarbageCollection();
std::vector<uint8_t> serializeBuffer;
serializeBuffer.resize(SERIALIZE_BUFFER_SIZE);
out->WriteInt32(OBJECT_CACHE_MAGIC_NUMBER);
out->WriteInt32(2); // version
int size = 0;
for (int i = 1; i < nextHandle; i++) {
auto const &o = objects[i];
if (o.isUsed()) {
size += 1;
}
}
out->WriteInt32(size);
for (int i = 1; i < nextHandle; i++) {
auto const &o = objects[i];
if (!o.isUsed()) {
continue;
}
// handle
out->WriteInt32(o.handle);
// write the type of the object
StrUtil::WriteCStr(o.callback->GetType(), out);
// now write the object data
int bytesWritten = o.callback->Serialize(o.addr, &serializeBuffer.front(), serializeBuffer.size());
if ((bytesWritten < 0) && ((size_t)(-bytesWritten) > serializeBuffer.size())) {
// buffer not big enough, re-allocate with requested size
serializeBuffer.resize(-bytesWritten);
bytesWritten = o.callback->Serialize(o.addr, &serializeBuffer.front(), serializeBuffer.size());
}
assert(bytesWritten >= 0);
out->WriteInt32(bytesWritten);
out->Write(&serializeBuffer.front(), bytesWritten);
out->WriteInt32(o.refCount);
ManagedObjectLog("Wrote handle = %d", o.handle);
}
}
int ManagedObjectPool::ReadFromDisk(Stream *in, ICCObjectCollectionReader *reader) {
if (in->ReadInt32() != OBJECT_CACHE_MAGIC_NUMBER) {
cc_error("Data was not written by ccSeralize");
return -1;
}
char typeNameBuffer[200];
std::vector<char> serializeBuffer;
serializeBuffer.resize(SERIALIZE_BUFFER_SIZE);
auto version = in->ReadInt32();
switch (version) {
case 1: {
// IMPORTANT: numObjs is "nextHandleId", which is why we iterate from 1 to numObjs-1
int numObjs = in->ReadInt32();
for (int i = 1; i < numObjs; i++) {
StrUtil::ReadCStr(typeNameBuffer, in, sizeof(typeNameBuffer));
if (typeNameBuffer[0] != 0) {
size_t numBytes = in->ReadInt32();
if (numBytes > serializeBuffer.size()) {
serializeBuffer.resize(numBytes);
}
in->Read(&serializeBuffer.front(), numBytes);
// Delegate work to ICCObjectReader
reader->Unserialize(i, typeNameBuffer, &serializeBuffer.front(), numBytes);
objects[i].refCount = in->ReadInt32();
ManagedObjectLog("Read handle = %d", objects[i].handle);
}
}
}
break;
case 2: {
// This is actually number of objects written.
int objectsSize = in->ReadInt32();
for (int i = 0; i < objectsSize; i++) {
auto handle = in->ReadInt32();
assert(handle >= 1);
StrUtil::ReadCStr(typeNameBuffer, in, sizeof(typeNameBuffer));
assert(typeNameBuffer[0] != 0);
size_t numBytes = in->ReadInt32();
if (numBytes > serializeBuffer.size()) {
serializeBuffer.resize(numBytes);
}
in->Read(&serializeBuffer.front(), numBytes);
// Delegate work to ICCObjectReader
reader->Unserialize(handle, typeNameBuffer, &serializeBuffer.front(), numBytes);
objects[handle].refCount = in->ReadInt32();
ManagedObjectLog("Read handle = %d", objects[i].handle);
}
}
break;
default:
cc_error("Invalid data version: %d", version);
return -1;
}
// re-adjust next handles. (in case saved in random order)
available_ids = std::queue<int32_t>();
nextHandle = 1;
for (const auto &o : objects) {
if (o.isUsed()) {
nextHandle = o.handle + 1;
}
}
for (int i = 1; i < nextHandle; i++) {
if (!objects[i].isUsed()) {
available_ids.push(i);
}
}
return 0;
}
// de-allocate all objects
void ManagedObjectPool::reset() {
for (int i = 1; i < nextHandle; i++) {
auto &o = objects[i];
if (!o.isUsed()) {
continue;
}
Remove(o, true);
}
available_ids = std::queue<int32_t>();
nextHandle = 1;
}
ManagedObjectPool::ManagedObjectPool() : objectCreationCounter(0), nextHandle(1), available_ids(), objects(RESERVED_SIZE, ManagedObject()), handleByAddress() {
handleByAddress.reserve(RESERVED_SIZE);
}
} // namespace AGS3

View File

@@ -0,0 +1,113 @@
/* 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_ENGINE_AC_DYNOBJ_CC_MANAGED_OBJECT_POOL_H
#define AGS_ENGINE_AC_DYNOBJ_CC_MANAGED_OBJECT_POOL_H
#include "common/std/vector.h"
#include "common/std/queue.h"
#include "common/std/map.h"
#include "ags/shared/core/platform.h"
#include "ags/engine/script/runtime_script_value.h"
#include "ags/engine/ac/dynobj/cc_script_object.h" // IScriptObject
namespace AGS3 {
namespace AGS {
namespace Shared {
class Stream;
} // namespace Shared
} // namespace AGS
using namespace AGS; // FIXME later
struct Pointer_Hash {
uint operator()(void *v) const {
return static_cast<uint>(reinterpret_cast<uintptr>(v));
}
};
struct ManagedObjectPool final {
private:
// TODO: find out if we can make handle size_t
struct ManagedObject {
ScriptValueType obj_type;
int32_t handle;
void *addr;
IScriptObject *callback;
int refCount;
bool isUsed() const {
return obj_type != kScValUndefined;
}
ManagedObject() : obj_type(kScValUndefined), handle(0), addr(nullptr),
callback(nullptr), refCount(0) {}
ManagedObject(ScriptValueType theType, int32_t theHandle,
void *theAddr, IScriptObject *theCallback)
: obj_type(theType), handle(theHandle), addr(theAddr),
callback(theCallback), refCount(0) {
}
};
int objectCreationCounter; // used to do garbage collection every so often
int32_t nextHandle{}; // TODO: manage nextHandle's going over INT32_MAX !
std::queue<int32_t> available_ids;
std::vector<ManagedObject> objects;
std::unordered_map<void *, int32_t, Pointer_Hash> handleByAddress;
int Add(int handle, void *address, IScriptObject *callback, ScriptValueType obj_type);
int Remove(ManagedObject &o, bool force = false);
void RunGarbageCollection();
public:
int32_t AddRef(int32_t handle);
int CheckDispose(int32_t handle);
int32_t SubRef(int32_t handle);
int32_t AddressToHandle(void *addr);
void *HandleToAddress(int32_t handle);
ScriptValueType HandleToAddressAndManager(int32_t handle, void *&object, IScriptObject *&manager);
int RemoveObject(void *address);
void RunGarbageCollectionIfAppropriate();
int AddObject(void *address, IScriptObject *callback, ScriptValueType obj_type);
int AddUnserializedObject(void *address, IScriptObject *callback, ScriptValueType obj_type, int handle);
void WriteToDisk(Shared::Stream *out);
int ReadFromDisk(Shared::Stream *in, ICCObjectCollectionReader *reader);
void reset();
ManagedObjectPool();
void *disableDisposeForObject{ nullptr };
};
// Extreme(!!) verbosity managed memory pool log
#if DEBUG_MANAGED_OBJECTS
#define ManagedObjectLog(...) Debug::Printf(kDbgGroup_ManObj, kDbgMsg_Debug, __VA_ARGS__)
#else
#define ManagedObjectLog(...)
#endif
} // namespace AGS3
#endif

View File

@@ -0,0 +1,34 @@
/* 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_ENGINE_DYNOBJ__SCRIPTAUDIOCHANNEL_H
#define AGS_ENGINE_DYNOBJ__SCRIPTAUDIOCHANNEL_H
namespace AGS3 {
struct ScriptAudioChannel {
int id = 0;
int reserved = 0;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,74 @@
/* 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/engine/ac/dynobj/script_camera.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/engine/ac/game_state.h"
#include "ags/shared/util/bbop.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
ScriptCamera::ScriptCamera(int id) : _id(id) {
}
const char *ScriptCamera::GetType() {
return "Camera2";
}
int ScriptCamera::Dispose(void *address, bool force) {
// Note that ScriptCamera is a reference to actual Camera object,
// and this deletes the reference, while camera may remain in GameState.
delete this;
return 1;
}
size_t ScriptCamera::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
void ScriptCamera::Serialize(const void *address, Stream *out) {
out->WriteInt32(_id);
}
void ScriptCamera::Unserialize(int index, Stream *in, size_t data_sz) {
_id = in->ReadInt32();
ccRegisterUnserializedObject(index, this, this);
}
ScriptCamera *Camera_Unserialize(int handle, Stream *in, size_t data_sz) {
// The way it works now, we must not create a new script object,
// but acquire one from the GameState, which keeps the first reference.
// This is essential because GameState should be able to invalidate any
// script references when Camera gets removed.
const int id = in->ReadInt32();
if (id >= 0) {
auto scam = _GP(play).RegisterRoomCamera(id, handle);
if (scam)
return scam;
}
return new ScriptCamera(-1); // make invalid reference
}
} // namespace AGS3

View File

@@ -0,0 +1,64 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_SCRIPT_CAMERA_H
#define AGS_ENGINE_AC_DYNOBJ_SCRIPT_CAMERA_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
// ScriptCamera keeps a reference to actual room Camera in script.
struct ScriptCamera final : AGSCCDynamicObject {
public:
ScriptCamera(int id);
// Get camera index; negative means the camera was deleted
int GetID() const {
return _id;
}
void SetID(int id) {
_id = id;
}
// Reset camera index to indicate that this reference is no longer valid
void Invalidate() {
_id = -1;
}
const char *GetType() override;
int Dispose(void *address, bool force) override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
private:
int _id = -1; // index of camera in the game state array
};
// Unserialize camera from the memory stream
ScriptCamera *Camera_Unserialize(int handle, AGS::Shared::Stream *in, size_t data_sz);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,41 @@
/* 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_ENGINE_AC_DYNOBJ_SCRIPTCONTAINERS_H
#define AGS_ENGINE_AC_DYNOBJ_SCRIPTCONTAINERS_H
namespace AGS3 {
class ScriptDictBase;
class ScriptSetBase;
// Create and register new dictionary
ScriptDictBase *Dict_Create(bool sorted, bool case_sensitive);
// Unserialize dictionary from the memory stream
ScriptDictBase *Dict_Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz);
// Create and register new set
ScriptSetBase *Set_Create(bool sorted, bool case_sensitive);
// Unserialize set from the memory stream
ScriptSetBase *Set_Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz);
} // namespace AGS3
#endif

View File

@@ -0,0 +1,71 @@
/* 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/engine/ac/dynobj/script_date_time.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/util/stream.h"
namespace AGS3 {
using namespace AGS::Shared;
int ScriptDateTime::Dispose(void *address, bool force) {
// always dispose a DateTime
delete this;
return 1;
}
const char *ScriptDateTime::GetType() {
return "DateTime";
}
size_t ScriptDateTime::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t) * 7;
}
void ScriptDateTime::Serialize(const void *address, Stream *out) {
out->WriteInt32(year);
out->WriteInt32(month);
out->WriteInt32(day);
out->WriteInt32(hour);
out->WriteInt32(minute);
out->WriteInt32(second);
out->WriteInt32(rawUnixTime);
}
void ScriptDateTime::Unserialize(int index, Stream *in, size_t data_sz) {
year = in->ReadInt32();
month = in->ReadInt32();
day = in->ReadInt32();
hour = in->ReadInt32();
minute = in->ReadInt32();
second = in->ReadInt32();
rawUnixTime = in->ReadInt32();
ccRegisterUnserializedObject(index, this, this);
}
ScriptDateTime::ScriptDateTime() {
year = month = day = 0;
hour = minute = second = 0;
rawUnixTime = 0;
}
} // namespace AGS3

View File

@@ -0,0 +1,49 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AGS_ENGINE_DYNOBJ_SCRIPT_DATE_TIME_H
#define AGS_ENGINE_DYNOBJ_SCRIPT_DATE_TIME_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct ScriptDateTime final : AGSCCDynamicObject {
int year, month, day;
int hour, minute, second;
int rawUnixTime;
int Dispose(void *address, bool force) override;
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
ScriptDateTime();
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,34 @@
/* 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_ENGINE_DYNOBJ__SCRIPTDIALOG_H
#define AGS_ENGINE_DYNOBJ__SCRIPTDIALOG_H
namespace AGS3 {
struct ScriptDialog {
int id;
int reserved;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,69 @@
/* 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/engine/ac/dynobj/script_dialog_options_rendering.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/util/stream.h"
namespace AGS3 {
using namespace AGS::Shared;
// return the type name of the object
const char *ScriptDialogOptionsRendering::GetType() {
return "DialogOptionsRendering";
}
size_t ScriptDialogOptionsRendering::CalcSerializeSize(const void * /*address*/) {
return 0;
}
// serialize the object into BUFFER (which is BUFSIZE bytes)
// return number of bytes used
void ScriptDialogOptionsRendering::Serialize(const void *address, Stream *out) {
}
void ScriptDialogOptionsRendering::Unserialize(int index, Stream *in, size_t data_sz) {
ccRegisterUnserializedObject(index, this, this);
}
void ScriptDialogOptionsRendering::Reset() {
x = 0;
y = 0;
width = 0;
height = 0;
hasAlphaChannel = false;
parserTextboxX = 0;
parserTextboxY = 0;
parserTextboxWidth = 0;
dialogID = 0;
surfaceToRenderTo = nullptr;
surfaceAccessed = false;
activeOptionID = -1;
chosenOptionID = -1;
needRepaint = false;
}
ScriptDialogOptionsRendering::ScriptDialogOptionsRendering() {
Reset();
}
} // namespace AGS3

View File

@@ -0,0 +1,59 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_SCRIPT_DIALOG_OPTIONS_RENDERING_H
#define AGS_ENGINE_AC_DYNOBJ_SCRIPT_DIALOG_OPTIONS_RENDERING_H
#include "ags/engine/ac/dynobj/script_drawing_surface.h"
namespace AGS3 {
struct ScriptDialogOptionsRendering final : AGSCCDynamicObject {
int x, y, width, height;
bool hasAlphaChannel;
int parserTextboxX, parserTextboxY;
int parserTextboxWidth;
int dialogID;
int activeOptionID;
int chosenOptionID;
ScriptDrawingSurface *surfaceToRenderTo;
bool surfaceAccessed;
bool needRepaint;
// return the type name of the object
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
void Reset();
ScriptDialogOptionsRendering();
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View 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/engine/ac/dynobj/script_dict.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
namespace AGS3 {
int ScriptDictBase::Dispose(void *address, bool force) {
Clear();
delete this;
return 1;
}
const char *ScriptDictBase::GetType() {
return "StringDictionary";
}
size_t ScriptDictBase::CalcSerializeSize(const void * /*address*/) {
return CalcContainerSize();
}
void ScriptDictBase::Serialize(const void *address, Stream *out) {
out->WriteInt32(IsSorted());
out->WriteInt32(IsCaseSensitive());
SerializeContainer(out);
}
void ScriptDictBase::Unserialize(int index, Stream *in, size_t data_sz) {
// NOTE: we expect sorted/case flags are read by external reader;
// this is awkward, but I did not find better design solution atm
UnserializeContainer(in);
ccRegisterUnserializedObject(index, this, this);
}
} // namespace AGS3

View File

@@ -0,0 +1,193 @@
/* 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/>.
*
*/
//=============================================================================
//
// Managed script object wrapping std::map<String, String> and
// unordered_map<String, String>.
//
// TODO: support wrapping non-owned Dictionary, passed by the reference, -
// that would let expose internal engine's dicts using same interface.
// TODO: maybe optimize key lookup operations further by not creating a String
// object from const char*. It seems, C++14 standard allows to use convertible
// types as keys; need to research what performance impact that would make.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_DYNOBJ_SCRIPTDICT_H
#define AGS_ENGINE_AC_DYNOBJ_SCRIPTDICT_H
#include "common/std/map.h"
#include "common/std/map.h"
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
#include "ags/shared/util/stream.h"
#include "ags/shared/util/string.h"
#include "ags/shared/util/string_types.h"
namespace AGS3 {
using namespace AGS::Shared;
class ScriptDictBase : public AGSCCDynamicObject {
public:
int Dispose(void *address, bool force) override;
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
virtual bool IsCaseSensitive() const = 0;
virtual bool IsSorted() const = 0;
virtual void Clear() = 0;
virtual bool Contains(const char *key) = 0;
virtual const char *Get(const char *key) = 0;
virtual bool Remove(const char *key) = 0;
virtual bool Set(const char *key, const char *value) = 0;
virtual int GetItemCount() = 0;
virtual void GetKeys(std::vector<const char *> &buf) const = 0;
virtual void GetValues(std::vector<const char *> &buf) const = 0;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
private:
virtual size_t CalcContainerSize() = 0;
virtual void SerializeContainer(AGS::Shared::Stream *out) = 0;
virtual void UnserializeContainer(AGS::Shared::Stream *in) = 0;
};
template <typename TDict, bool is_sorted, bool is_casesensitive>
class ScriptDictImpl final : public ScriptDictBase {
public:
typedef typename TDict::const_iterator ConstIterator;
ScriptDictImpl() {}
bool IsCaseSensitive() const override {
return is_casesensitive;
}
bool IsSorted() const override {
return is_sorted;
}
void Clear() override {
for (auto it = _dic.begin(); it != _dic.end(); ++it)
DeleteItem(it);
_dic.clear();
}
bool Contains(const char *key) override {
#ifdef AGS_PLATFORM_SCUMMVM
return _dic.find(String::Wrapper(key)) != _dic.end();
#else
return _dic.count(String::Wrapper(key)) != 0;
#endif
}
const char *Get(const char *key) override {
auto it = _dic.find(String::Wrapper(key));
if (it == _dic.end()) return nullptr;
return it->_value.GetCStr();
}
bool Remove(const char *key) override {
auto it = _dic.find(String::Wrapper(key));
if (it == _dic.end()) return false;
DeleteItem(it);
_dic.erase(it);
return true;
}
bool Set(const char *key, const char *value) override {
if (!key)
return false;
if (!value) {
// Remove keys with null value
Remove(key);
return true;
}
return TryAddItem(String(key), String(value));
}
int GetItemCount() override {
return _dic.size();
}
void GetKeys(std::vector<const char *> &buf) const override {
for (auto it = _dic.begin(); it != _dic.end(); ++it)
buf.push_back(it->_key.GetCStr());
}
void GetValues(std::vector<const char *> &buf) const override {
for (auto it = _dic.begin(); it != _dic.end(); ++it)
buf.push_back(it->_value.GetCStr());
}
private:
bool TryAddItem(const String &key, const String &value) {
_dic[key] = value;
return true;
}
void DeleteItem(ConstIterator /*it*/) { /* do nothing */ }
size_t CalcContainerSize() override {
// 2 class properties + item count
size_t total_sz = sizeof(int32_t) * 3;
// (int32 + string buffer) per item
for (auto it = _dic.begin(); it != _dic.end(); ++it) {
total_sz += sizeof(int32_t) + it->_key.GetLength();
total_sz += sizeof(int32_t) + it->_value.GetLength();
}
return total_sz;
}
void SerializeContainer(AGS::Shared::Stream *out) override
{
out->WriteInt32((int)_dic.size());
for (auto it = _dic.begin(); it != _dic.end(); ++it)
{
out->WriteInt32((int)it->_key.GetLength());
out->Write(it->_key.GetCStr(), it->_key.GetLength());
out->WriteInt32((int)it->_value.GetLength());
out->Write(it->_value.GetCStr(), it->_value.GetLength());
}
}
void UnserializeContainer(AGS::Shared::Stream *in) override {
size_t item_count = in->ReadInt32();
for (size_t i = 0; i < item_count; ++i) {
size_t key_len = in->ReadInt32();
String key = String::FromStreamCount(in, key_len);
size_t value_len = in->ReadInt32();
if (value_len != (size_t)-1) // do not restore keys with null value (old format)
{
String value = String::FromStreamCount(in, value_len);
TryAddItem(key, value);
}
}
}
TDict _dic;
};
typedef ScriptDictImpl< std::map<String, String>, true, true > ScriptDict;
typedef ScriptDictImpl< std::map<String, String, IgnoreCase_LessThan>, true, false > ScriptDictCI;
typedef ScriptDictImpl< std::unordered_map<String, String>, false, true > ScriptHashDict;
typedef ScriptDictImpl< std::unordered_map<String, String, IgnoreCase_Hash, IgnoreCase_EqualTo>, false, false > ScriptHashDictCI;
} // namespace AGS3
#endif

View File

@@ -0,0 +1,138 @@
/* 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/engine/ac/dynobj/script_drawing_surface.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/ac/sprite_cache.h"
#include "ags/engine/ac/runtime_defines.h"
#include "ags/shared/ac/common.h"
#include "ags/engine/ac/draw.h"
#include "ags/engine/ac/drawing_surface.h"
#include "ags/engine/ac/game_state.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/shared/game/room_struct.h"
#include "ags/shared/gfx/bitmap.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
Bitmap *ScriptDrawingSurface::GetBitmapSurface() {
// TODO: consider creating weak_ptr here, and store one in the DrawingSurface!
if (roomBackgroundNumber >= 0)
return _GP(thisroom).BgFrames[roomBackgroundNumber].Graphic.get();
else if (dynamicSpriteNumber >= 0)
return _GP(spriteset)[dynamicSpriteNumber];
else if (dynamicSurfaceNumber >= 0)
return _G(dynamicallyCreatedSurfaces)[dynamicSurfaceNumber].get();
else if (linkedBitmapOnly != nullptr)
return linkedBitmapOnly;
else if (roomMaskType > kRoomAreaNone)
return _GP(thisroom).GetMask(roomMaskType);
quit("!DrawingSurface: attempted to use surface after Release was called");
return nullptr;
}
Bitmap *ScriptDrawingSurface::StartDrawing() {
return this->GetBitmapSurface();
}
void ScriptDrawingSurface::FinishedDrawingReadOnly() {
}
void ScriptDrawingSurface::FinishedDrawing() {
FinishedDrawingReadOnly();
modified = 1;
}
int ScriptDrawingSurface::Dispose(void *address, bool force) {
// dispose the drawing surface
DrawingSurface_Release(this);
delete this;
return 1;
}
const char *ScriptDrawingSurface::GetType() {
return "DrawingSurface";
}
size_t ScriptDrawingSurface::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t) * 9;
}
void ScriptDrawingSurface::Serialize(const void *address, Stream *out) {
// pack mask type in the last byte of a negative integer
// note: (-1) is reserved for "unused", for backward compatibility
if (roomMaskType > 0)
out->WriteInt32(0xFFFFFF00 | roomMaskType);
else
out->WriteInt32(roomBackgroundNumber);
out->WriteInt32(dynamicSpriteNumber);
out->WriteInt32(dynamicSurfaceNumber);
out->WriteInt32(currentColour);
out->WriteInt32(currentColourScript);
out->WriteInt32(highResCoordinates);
out->WriteInt32(modified);
out->WriteInt32(hasAlphaChannel);
out->WriteInt32(isLinkedBitmapOnly ? 1 : 0);
}
void ScriptDrawingSurface::Unserialize(int index, Stream *in, size_t data_sz) {
int room_ds = in->ReadInt32();
if (room_ds >= 0)
roomBackgroundNumber = room_ds;
// negative value may contain a mask type
else if ((room_ds & 0xFF) != 0xFF)
roomMaskType = (RoomAreaMask)(room_ds & 0xFF);
dynamicSpriteNumber = in->ReadInt32();
dynamicSurfaceNumber = in->ReadInt32();
currentColour = in->ReadInt32();
currentColourScript = in->ReadInt32();
highResCoordinates = in->ReadInt32();
modified = in->ReadInt32();
hasAlphaChannel = in->ReadInt32();
isLinkedBitmapOnly = (in->ReadInt32() != 0);
ccRegisterUnserializedObject(index, this, this);
}
ScriptDrawingSurface::ScriptDrawingSurface() {
roomBackgroundNumber = -1;
roomMaskType = kRoomAreaNone;
dynamicSpriteNumber = -1;
dynamicSurfaceNumber = -1;
isLinkedBitmapOnly = false;
linkedBitmapOnly = nullptr;
currentColour = _GP(play).raw_color;
currentColourScript = 0;
modified = 0;
hasAlphaChannel = 0;
highResCoordinates = 0;
// NOTE: Normally in contemporary games coordinates ratio will always be 1:1.
// But we still support legacy drawing, so have to set this up even for modern games,
// otherwise we'd have to complicate conversion conditions further.
if (_GP(game).IsLegacyHiRes() && _GP(game).IsDataInNativeCoordinates()) {
highResCoordinates = 1;
}
}
} // namespace AGS3

View File

@@ -0,0 +1,71 @@
/* 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_ENGINE_AC_DYNOBJ_SCRIPT_DRAWING_SURFACE_H
#define AGS_ENGINE_AC_DYNOBJ_SCRIPT_DRAWING_SURFACE_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
#include "ags/shared/game/room_struct.h"
#include "ags/shared/gfx/bitmap.h"
#include "ags/shared/util/stream.h"
namespace AGS3 {
struct ScriptDrawingSurface final : AGSCCDynamicObject {
// These numbers and types are used to determine the source of this drawing surface;
// only one of them can be valid for this surface.
int roomBackgroundNumber;
RoomAreaMask roomMaskType;
int dynamicSpriteNumber;
int dynamicSurfaceNumber;
bool isLinkedBitmapOnly;
AGS::Shared::Bitmap *linkedBitmapOnly;
int currentColour;
int currentColourScript;
int highResCoordinates;
int modified;
int hasAlphaChannel;
//Shared::Bitmap* abufBackup;
int Dispose(void *address, bool force) override;
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
AGS::Shared::Bitmap *GetBitmapSurface();
AGS::Shared::Bitmap *StartDrawing();
void PointToGameResolution(int *xcoord, int *ycoord);
void SizeToGameResolution(int *width, int *height);
void SizeToGameResolution(int *adjustValue);
void SizeToDataResolution(int *adjustValue);
void FinishedDrawing();
void FinishedDrawingReadOnly();
ScriptDrawingSurface();
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,67 @@
/* 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/engine/ac/dynobj/script_dynamic_sprite.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/util/stream.h"
#include "ags/engine/ac/dynamic_sprite.h"
namespace AGS3 {
using namespace AGS::Shared;
int ScriptDynamicSprite::Dispose(void *address, bool force) {
// always dispose
if ((slot) && (!force))
free_dynamic_sprite(slot);
delete this;
return 1;
}
const char *ScriptDynamicSprite::GetType() {
return "DynamicSprite";
}
size_t ScriptDynamicSprite::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t);
}
void ScriptDynamicSprite::Serialize(const void *address, Stream *out) {
out->WriteInt32(slot);
}
void ScriptDynamicSprite::Unserialize(int index, Stream *in, size_t data_sz) {
slot = in->ReadInt32();
ccRegisterUnserializedObject(index, this, this);
}
ScriptDynamicSprite::ScriptDynamicSprite(int theSlot) {
slot = theSlot;
ccRegisterManagedObject(this, this);
}
ScriptDynamicSprite::ScriptDynamicSprite() {
slot = 0;
}
} // namespace AGS3

View 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/>.
*
*/
#ifndef AGS_ENGINE_AC_DYNOBJ_SCRIPTDYNAMICSPRITE_H
#define AGS_ENGINE_AC_DYNOBJ_SCRIPTDYNAMICSPRITE_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct ScriptDynamicSprite final : AGSCCDynamicObject {
int slot;
int Dispose(void *address, bool force) override;
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
ScriptDynamicSprite(int slot);
ScriptDynamicSprite();
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View 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/engine/ac/dynobj/script_file.h"
#include "ags/engine/ac/global_file.h"
namespace AGS3 {
// CHECKME: actually NULLs here will be equal to kFile_Open & kFile_Read
const Shared::FileOpenMode sc_File::fopenModes[] =
{ Shared::kFile_Open/*CHECKME, was undefined*/, Shared::kFile_Open, Shared::kFile_CreateAlways, Shared::kFile_Create };
const Shared::FileWorkMode sc_File::fworkModes[] =
{ Shared::kFile_Read/*CHECKME, was undefined*/, Shared::kFile_Read, Shared::kFile_Write, Shared::kFile_Write };
int sc_File::Dispose(void *address, bool force) {
Close();
delete this;
return 1;
}
const char *sc_File::GetType() {
return "File";
}
int sc_File::Serialize(void *address, uint8_t *buffer, int bufsize) {
// we cannot serialize an open file, so it will get closed
return 0;
}
int sc_File::OpenFile(const char *filename, int mode) {
handle = FileOpen(filename, fopenModes[mode], fworkModes[mode]);
if (handle <= 0)
return 0;
return 1;
}
void sc_File::Close() {
if (handle > 0) {
FileClose(handle);
handle = 0;
}
}
sc_File::sc_File() {
handle = 0;
}
} // namespace AGS3

View File

@@ -0,0 +1,56 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef AGS_ENGINE_DYNOBJ__SCRIPTFILE_H
#define AGS_ENGINE_DYNOBJ__SCRIPTFILE_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
#include "ags/shared/util/file.h"
namespace AGS3 {
using namespace AGS; // FIXME later
#define scFileRead 1
#define scFileWrite 2
#define scFileAppend 3
struct sc_File final : CCBasicObject {
int32_t handle;
static const Shared::FileOpenMode fopenModes[];
static const Shared::FileWorkMode fworkModes[];
int Dispose(void *address, bool force) override;
const char *GetType() override;
int Serialize(void *address, uint8_t *buffer, int bufsize) override;
int OpenFile(const char *filename, int mode);
void Close();
sc_File();
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,442 @@
/* 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/engine/debugging/debug_log.h"
#include "ags/engine/ac/dynobj/script_game.h"
#include "ags/engine/ac/game.h"
#include "ags/engine/ac/game_state.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/shared/gui/gui_main.h"
#include "ags/shared/script/cc_common.h" // cc_error
#include "ags/globals.h"
namespace AGS3 {
int32_t CCScriptGame::ReadInt32(void *address, intptr_t offset) {
const int index = offset / sizeof(int32_t);
if (index >= 5 && index < 5 + MAXGLOBALVARS)
return _GP(play).globalvars[index - 5];
switch (index) {
case 0:
return _GP(play).score;
case 1:
return _GP(play).usedmode;
case 2:
return _GP(play).disabled_user_interface;
case 3:
return _GP(play).gscript_timer;
case 4:
return _GP(play).debug_mode;
// 5 -> 54: _GP(play).globalvars
case 55:
return _GP(play).messagetime;
case 56:
return _GP(play).usedinv;
case 57:
return _GP(play).inv_top;
case 58:
return _GP(play).inv_numdisp;
case 59:
return _GP(play).inv_numorder;
case 60:
return _GP(play).inv_numinline;
case 61:
return _GP(play).text_speed;
case 62:
return _GP(play).sierra_inv_color;
case 63:
return _GP(play).talkanim_speed;
case 64:
return _GP(play).inv_item_wid;
case 65:
return _GP(play).inv_item_hit;
case 66:
return _GP(play).speech_text_shadow;
case 67:
return _GP(play).swap_portrait_side;
case 68:
return _GP(play).speech_textwindow_gui;
case 69:
return _GP(play).follow_change_room_timer;
case 70:
return _GP(play).totalscore;
case 71:
return _GP(play).skip_display;
case 72:
return _GP(play).no_multiloop_repeat;
case 73:
return _GP(play).roomscript_finished;
case 74:
return _GP(play).used_inv_on;
case 75:
return _GP(play).no_textbg_when_voice;
case 76:
return _GP(play).max_dialogoption_width;
case 77:
return _GP(play).no_hicolor_fadein;
case 78:
return _GP(play).bgspeech_game_speed;
case 79:
return _GP(play).bgspeech_stay_on_display;
case 80:
return _GP(play).unfactor_speech_from_textlength;
case 81:
return _GP(play).mp3_loop_before_end;
case 82:
return _GP(play).speech_music_drop;
case 83:
return _GP(play).in_cutscene;
case 84:
return _GP(play).fast_forward;
case 85:
return _GP(play).room_width;
case 86:
return _GP(play).room_height;
case 87:
return _GP(play).game_speed_modifier;
case 88:
return _GP(play).score_sound;
case 89:
return _GP(play).takeover_data;
case 90:
return 0; // _GP(play).replay_hotkey
case 91:
return _GP(play).dialog_options_x;
case 92:
return _GP(play).dialog_options_y;
case 93:
return _GP(play).narrator_speech;
case 94:
return _GP(play).ambient_sounds_persist;
case 95:
return _GP(play).lipsync_speed;
case 96:
return _GP(play).close_mouth_speech_time;
case 97:
return _GP(play).disable_antialiasing;
case 98:
return _GP(play).text_speed_modifier;
case 99:
return _GP(play).text_align;
case 100:
return _GP(play).speech_bubble_width;
case 101:
return _GP(play).min_dialogoption_width;
case 102:
return _GP(play).disable_dialog_parser;
case 103:
return _GP(play).anim_background_speed;
case 104:
return _GP(play).top_bar_backcolor;
case 105:
return _GP(play).top_bar_textcolor;
case 106:
return _GP(play).top_bar_bordercolor;
case 107:
return _GP(play).top_bar_borderwidth;
case 108:
return _GP(play).top_bar_ypos;
case 109:
return _GP(play).screenshot_width;
case 110:
return _GP(play).screenshot_height;
case 111:
return _GP(play).top_bar_font;
case 112:
return _GP(play).speech_text_align;
case 113:
return _GP(play).auto_use_walkto_points;
case 114:
return _GP(play).inventory_greys_out;
case 115:
return _GP(play).skip_speech_specific_key;
case 116:
return _GP(play).abort_key;
case 117:
return _GP(play).fade_to_red;
case 118:
return _GP(play).fade_to_green;
case 119:
return _GP(play).fade_to_blue;
case 120:
return _GP(play).show_single_dialog_option;
case 121:
return _GP(play).keep_screen_during_instant_transition;
case 122:
return _GP(play).read_dialog_option_colour;
case 123:
return _GP(play).stop_dialog_at_end;
case 124:
return _GP(play).speech_portrait_placement;
case 125:
return _GP(play).speech_portrait_x;
case 126:
return _GP(play).speech_portrait_y;
case 127:
return _GP(play).speech_display_post_time_ms;
case 128:
return _GP(play).dialog_options_highlight_color;
default:
cc_error("ScriptGame: unsupported variable offset %d", offset);
return 0;
}
}
void CCScriptGame::WriteInt32(void *address, intptr_t offset, int32_t val) {
const int index = offset / sizeof(int32_t);
if (index >= 5 && index < 5 + MAXGLOBALVARS) {
_GP(play).globalvars[index - 5] = val;
return;
}
switch (index) {
case 0:
_GP(play).score = val;
break;
case 1:
_GP(play).usedmode = val;
break;
case 2:
_GP(play).disabled_user_interface = val;
break;
case 3:
_GP(play).gscript_timer = val;
break;
case 4:
set_debug_mode(val != 0);
break; // _GP(play).debug_mode
// 5 -> 54: _GP(play).globalvars
case 55:
_GP(play).messagetime = val;
break;
case 56:
_GP(play).usedinv = val;
break;
case 57:
_GP(play).inv_top = val;
GUI::MarkInventoryForUpdate(_GP(game).playercharacter, true);
break;
case 58: // play.inv_numdisp
case 59: // play.inv_numorder
case 60: // play.inv_numinline
debug_script_warn("ScriptGame: attempt to write in readonly variable at offset %d, value %d", offset, val);
break;
case 61:
_GP(play).text_speed = val;
break;
case 62:
_GP(play).sierra_inv_color = val;
break;
case 63:
_GP(play).talkanim_speed = val;
break;
case 64:
_GP(play).inv_item_wid = val;
break;
case 65:
_GP(play).inv_item_hit = val;
break;
case 66:
_GP(play).speech_text_shadow = val;
break;
case 67:
_GP(play).swap_portrait_side = val;
break;
case 68:
_GP(play).speech_textwindow_gui = val;
break;
case 69:
_GP(play).follow_change_room_timer = val;
break;
case 70:
_GP(play).totalscore = val;
break;
case 71:
_GP(play).skip_display = val;
break;
case 72:
_GP(play).no_multiloop_repeat = val;
break;
case 73:
_GP(play).roomscript_finished = val;
break;
case 74:
_GP(play).used_inv_on = val;
break;
case 75:
_GP(play).no_textbg_when_voice = val;
break;
case 76:
_GP(play).max_dialogoption_width = val;
break;
case 77:
_GP(play).no_hicolor_fadein = val;
break;
case 78:
_GP(play).bgspeech_game_speed = val;
break;
case 79:
_GP(play).bgspeech_stay_on_display = val;
break;
case 80:
_GP(play).unfactor_speech_from_textlength = val;
break;
case 81:
_GP(play).mp3_loop_before_end = val;
break;
case 82:
_GP(play).speech_music_drop = val;
break;
case 83: // _GP(play).in_cutscene
case 84: // _GP(play).fast_forward;
case 85: // _GP(play).room_width;
case 86: // _GP(play).room_height;
debug_script_warn("ScriptGame: attempt to write in readonly variable at offset %d, value %d", offset, val);
break;
case 87:
_GP(play).game_speed_modifier = val;
break;
case 88:
_GP(play).score_sound = val;
break;
case 89:
_GP(play).takeover_data = val;
break;
case 90:
break; // _GP(play).replay_hotkey
case 91:
_GP(play).dialog_options_x = val;
break;
case 92:
_GP(play).dialog_options_y = val;
break;
case 93:
_GP(play).narrator_speech = val;
break;
case 94:
_GP(play).ambient_sounds_persist = val;
break;
case 95:
_GP(play).lipsync_speed = val;
break;
case 96:
_GP(play).close_mouth_speech_time = val;
break;
case 97:
_GP(play).disable_antialiasing = val;
break;
case 98:
_GP(play).text_speed_modifier = val;
break;
case 99:
_GP(play).text_align = ReadScriptAlignment(val);
break;
case 100:
_GP(play).speech_bubble_width = val;
break;
case 101:
_GP(play).min_dialogoption_width = val;
break;
case 102:
_GP(play).disable_dialog_parser = val;
break;
case 103:
_GP(play).anim_background_speed = val;
break;
case 104:
_GP(play).top_bar_backcolor = val;
break;
case 105:
_GP(play).top_bar_textcolor = val;
break;
case 106:
_GP(play).top_bar_bordercolor = val;
break;
case 107:
_GP(play).top_bar_borderwidth = val;
break;
case 108:
_GP(play).top_bar_ypos = val;
break;
case 109:
_GP(play).screenshot_width = val;
break;
case 110:
_GP(play).screenshot_height = val;
break;
case 111:
_GP(play).top_bar_font = val;
break;
case 112:
_GP(play).speech_text_align = ReadScriptAlignment(val);
break;
case 113:
_GP(play).auto_use_walkto_points = val;
break;
case 114:
_GP(play).inventory_greys_out = val;
break;
case 115:
_GP(play).skip_speech_specific_key = val;
break;
case 116:
_GP(play).abort_key = val;
break;
case 117: // _GP(play).fade_to_red;
case 118: // _GP(play).fade_to_green;
case 119: // _GP(play).fade_to_blue;
debug_script_warn("ScriptGame: attempt to write in readonly variable at offset %d, value %d", offset, val);
break;
case 120:
_GP(play).show_single_dialog_option = val;
break;
case 121:
_GP(play).keep_screen_during_instant_transition = val;
break;
case 122:
_GP(play).read_dialog_option_colour = val;
break;
case 123:
_GP(play).stop_dialog_at_end = val;
break;
case 124:
_GP(play).speech_portrait_placement = val;
break;
case 125:
_GP(play).speech_portrait_x = val;
break;
case 126:
_GP(play).speech_portrait_y = val;
break;
case 127:
_GP(play).speech_display_post_time_ms = val;
break;
case 128:
_GP(play).dialog_options_highlight_color = val;
break;
default:
cc_error("ScriptGame: unsupported variable offset %d", offset);
break;
}
}
} // namespace AGS3

View File

@@ -0,0 +1,42 @@
/* 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/>.
*
*/
//=============================================================================
//
// Wrapper around script "GameState" struct, managing access to its variables.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_DYNOBJ_AGS_SCRIPT_GAME_H
#define AGS_ENGINE_AC_DYNOBJ_AGS_SCRIPT_GAME_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct CCScriptGame : public AGSCCStaticObject {
int32_t ReadInt32(void *address, intptr_t offset) override;
void WriteInt32(void *address, intptr_t offset, int32_t val) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,35 @@
/* 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_ENGINE_DYNOBJ__SCRIPTGUI_H
#define AGS_ENGINE_DYNOBJ__SCRIPTGUI_H
namespace AGS3 {
// 64 bit: This struct must be 8 byte long
struct ScriptGUI {
int id;
int __padding;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,34 @@
/* 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_ENGINE_DYNOBJ__SCRIPTHOTSPOT_H
#define AGS_ENGINE_DYNOBJ__SCRIPTHOTSPOT_H
namespace AGS3 {
struct ScriptHotspot {
int id = 0;
int reserved = 0;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,34 @@
/* 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_ENGINE_DYNOBJ__SCRIPTINVITEM_H
#define AGS_ENGINE_DYNOBJ__SCRIPTINVITEM_H
namespace AGS3 {
struct ScriptInvItem {
int id = 0;
int reserved = 0;
};
} // namespace AGS3
#endif

View 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/>.
*
*/
#include "ags/engine/debugging/debug_log.h"
#include "ags/engine/ac/dynobj/script_mouse.h"
#include "ags/shared/script/cc_common.h" // cc_error
namespace AGS3 {
int32_t ScriptMouse::ReadInt32(void *address, intptr_t offset) {
switch (offset) {
case 0:
return x;
case 4:
return y;
default:
cc_error("ScriptMouse: unsupported variable offset %d", offset);
return 0;
}
}
void ScriptMouse::WriteInt32(void *address, intptr_t offset, int32_t val) {
switch (offset) {
case 0:
case 4:
debug_script_warn("ScriptMouse: attempt to write in readonly variable at offset %d, value", offset, val);
break;
default:
cc_error("ScriptMouse: unsupported variable offset %d", offset);
break;
}
}
} // namespace AGS3

View 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/>.
*
*/
//=============================================================================
//
// Wrapper around script "Mouse" struct, managing access to its variables.
//
//=============================================================================
#ifndef AGS_ENGINE_DYNOBJ__SCRIPTMOUSE_H
#define AGS_ENGINE_DYNOBJ__SCRIPTMOUSE_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct ScriptMouse : public AGSCCStaticObject {
int x;
int y;
int32_t ReadInt32(void *address, intptr_t offset) override;
void WriteInt32(void *address, intptr_t offset, int32_t val) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,37 @@
/* 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_ENGINE_DYNOBJ_SCRIPT_OBJECT_H
#define AGS_ENGINE_DYNOBJ_SCRIPT_OBJECT_H
#include "ags/engine/ac/room_object.h"
namespace AGS3 {
// WARNING: struct size must be 8 byte for old scripts to work
struct ScriptObject {
int id = -1;
int __padding = 0;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,90 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ags/engine/ac/dynobj/script_overlay.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/ac/common.h"
#include "ags/shared/util/stream.h"
#include "ags/engine/ac/overlay.h"
#include "ags/engine/ac/runtime_defines.h"
#include "ags/engine/ac/screen_overlay.h"
#include "ags/engine/debugging/debug_log.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
int ScriptOverlay::Dispose(void * /*address*/, bool force) {
// since the managed object is being deleted, remove the
// reference so it doesn't try and dispose something else
// with that handle later
if (overlayId >= 0) {
auto *over = get_overlay(overlayId);
if (over) {
over->associatedOverlayHandle = 0;
}
}
// if this is being removed voluntarily (ie. pointer out of
// scope) then remove the associateed overlay
// Otherwise, it's a Restore Game or something so don't
if ((!force) && (Overlay_GetValid(this))) {
Remove();
}
delete this;
return 1;
}
const char *ScriptOverlay::GetType() {
return "Overlay";
}
size_t ScriptOverlay::CalcSerializeSize(const void * /*address*/) {
return sizeof(int32_t) * 4;
}
void ScriptOverlay::Serialize(const void * /*address*/, Stream *out) {
out->WriteInt32(overlayId);
out->WriteInt32(0); // unused (was text window x padding)
out->WriteInt32(0); // unused (was text window y padding)
out->WriteInt32(0); // unused (was internal ref flag)
}
void ScriptOverlay::Unserialize(int index, Stream *in, size_t data_sz) {
overlayId = in->ReadInt32();
in->ReadInt32(); // unused (was text window x padding)
in->ReadInt32(); // unused (was text window y padding)
in->ReadInt32(); // unused (was internal ref flag)
ccRegisterUnserializedObject(index, this, this);
}
void ScriptOverlay::Remove() {
if (overlayId < 0) {
debug_script_warn("Overlay.Remove: overlay is invalid, could have been removed earlier.");
return;
}
remove_screen_overlay(overlayId);
overlayId = -1;
}
} // namespace AGS3

View 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_ENGINE_AC_DYNOBJ_SCRIPT_OVERLAY_H
#define AGS_ENGINE_AC_DYNOBJ_SCRIPT_OVERLAY_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct ScriptOverlay final : AGSCCDynamicObject {
int overlayId = -1;
int Dispose(void *address, bool force) override;
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
void Remove();
ScriptOverlay() = default;
protected:
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,34 @@
/* 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_ENGINE_DYNOBJ__SCRIPTREGION_H
#define AGS_ENGINE_DYNOBJ__SCRIPTREGION_H
namespace AGS3 {
struct ScriptRegion {
int id = 0;
int reserved = 0;
};
} // namespace AGS3
#endif

View 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/engine/ac/dynobj/script_set.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/shared/util/stream.h"
namespace AGS3 {
int ScriptSetBase::Dispose(void * /*address*/, bool force) {
Clear();
delete this;
return 1;
}
const char *ScriptSetBase::GetType() {
return "StringSet";
}
size_t ScriptSetBase::CalcSerializeSize(const void * /*address*/) {
return CalcContainerSize();
}
void ScriptSetBase::Serialize(const void * /*address*/, Stream *out) {
out->WriteInt32(IsSorted());
out->WriteInt32(IsCaseSensitive());
SerializeContainer(out);
}
void ScriptSetBase::Unserialize(int index, Stream *in, size_t data_sz) {
// NOTE: we expect sorted/case flags are read by external reader;
// this is awkward, but I did not find better design solution atm
UnserializeContainer(in);
ccRegisterUnserializedObject(index, this, this);
}
} // namespace AGS3

View File

@@ -0,0 +1,159 @@
/* 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/>.
*
*/
//=============================================================================
//
// Managed script object wrapping std::set<String> and unordered_set<String>.
//
// TODO: support wrapping non-owned Set, passed by the reference, -
// that would let expose internal engine's sets using same interface.
// TODO: maybe optimize key lookup operations further by not creating a String
// object from const char*. It seems, C++14 standard allows to use convertible
// types as keys; need to research what performance impact that would make.
//
//=============================================================================
#ifndef AGS_ENGINE_AC_DYNOBJ_SCRIPTSET_H
#define AGS_ENGINE_AC_DYNOBJ_SCRIPTSET_H
#include "common/std/set.h"
#include "common/std/unordered_set.h"
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
#include "ags/shared/util/stream.h"
#include "ags/shared/util/string.h"
#include "ags/shared/util/string_types.h"
namespace AGS3 {
using namespace AGS::Shared;
class ScriptSetBase : public AGSCCDynamicObject {
public:
int Dispose(void *address, bool force) override;
const char *GetType() override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
virtual bool IsCaseSensitive() const = 0;
virtual bool IsSorted() const = 0;
virtual bool Add(const char *item) = 0;
virtual void Clear() = 0;
virtual bool Contains(const char *item) const = 0;
virtual bool Remove(const char *item) = 0;
virtual int GetItemCount() const = 0;
virtual void GetItems(std::vector<const char *> &buf) const = 0;
protected:
// Calculate and return required space for serialization, in bytes
virtual size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
private:
virtual size_t CalcContainerSize() = 0;
virtual void SerializeContainer(AGS::Shared::Stream *out) = 0;
virtual void UnserializeContainer(AGS::Shared::Stream *in) = 0;
};
template <typename TSet, bool is_sorted, bool is_casesensitive>
class ScriptSetImpl final : public ScriptSetBase {
public:
typedef typename TSet::const_iterator ConstIterator;
ScriptSetImpl() {}
bool IsCaseSensitive() const override {
return is_casesensitive;
}
bool IsSorted() const override {
return is_sorted;
}
bool Add(const char *item) override {
if (!item) return false;
return TryAddItem(String(item));
}
void Clear() override {
for (auto it = _set.begin(); it != _set.end(); ++it)
DeleteItem(it);
_set.clear();
}
bool Contains(const char *item) const override {
return _set.count(String::Wrapper(item)) != 0;
}
bool Remove(const char *item) override {
auto it = _set.find(String::Wrapper(item));
if (it == _set.end()) return false;
DeleteItem(it);
_set.erase(it);
return true;
}
int GetItemCount() const override {
return _set.size();
}
void GetItems(std::vector<const char *> &buf) const override {
for (auto it = _set.begin(); it != _set.end(); ++it)
buf.push_back(it->GetCStr());
}
private:
bool TryAddItem(const String &s) {
return _set.insert(s)._value;
}
void DeleteItem(ConstIterator /*it*/) { /* do nothing */ }
size_t CalcContainerSize() override {
// 2 class properties + item count
size_t total_sz = sizeof(int32_t) * 3;
// (int32 + string buffer) per item
for (auto it = _set.begin(); it != _set.end(); ++it)
total_sz += sizeof(int32_t) + it->GetLength();
return total_sz;
}
void SerializeContainer(AGS::Shared::Stream *out) override {
out->WriteInt32((int)_set.size());
for (auto it = _set.begin(); it != _set.end(); ++it) {
out->WriteInt32((int)it->GetLength());
out->Write(it->GetCStr(), it->GetLength());
}
}
void UnserializeContainer(AGS::Shared::Stream *in) override {
size_t item_count = in->ReadInt32();
for (size_t i = 0; i < item_count; ++i) {
size_t len = in->ReadInt32();
String item = String::FromStreamCount(in, len);
TryAddItem(item);
}
}
TSet _set;
};
typedef ScriptSetImpl< std::set<String>, true, true > ScriptSet;
typedef ScriptSetImpl< std::set<String, IgnoreCase_LessThan>, true, false > ScriptSetCI;
typedef ScriptSetImpl< std::unordered_set<String>, false, true > ScriptHashSet;
typedef ScriptSetImpl< std::unordered_set<String, IgnoreCase_Hash, IgnoreCase_EqualTo>, false, false > ScriptHashSetCI;
} // namespace AGS3
#endif

View File

@@ -0,0 +1,79 @@
/* 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/engine/ac/dynobj/script_string.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/engine/ac/string.h"
#include "ags/shared/util/stream.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
const char *ScriptString::GetType() {
return "String";
}
int ScriptString::Dispose(void *address, bool /*force*/) {
delete[] (static_cast<uint8_t *>(address) - MemHeaderSz);
return 1;
}
size_t ScriptString::CalcSerializeSize(const void *address) {
const Header &hdr = GetHeader(address);
return hdr.Length + 1 + FileHeaderSz;
}
void ScriptString::Serialize(const void *address, Stream *out) {
const Header &hdr = GetHeader(address);
out->WriteInt32(hdr.Length);
out->Write(address, hdr.Length + 1); // it was writing trailing 0 for some reason
}
void ScriptString::Unserialize(int index, Stream *in, size_t /*data_sz*/) {
size_t len = in->ReadInt32();
uint8_t *buf = new uint8_t[len + 1 + MemHeaderSz];
Header &hdr = reinterpret_cast<Header &>(*buf);
hdr.Length = len;
char *text_ptr = reinterpret_cast<char *>(buf + MemHeaderSz);
in->Read(text_ptr, len + 1); // it was writing trailing 0 for some reason
text_ptr[len] = 0; // for safety
ccRegisterUnserializedObject(index, text_ptr, this);
}
DynObjectRef ScriptString::CreateImpl(const char *text, size_t buf_len) {
size_t len = text ? strlen(text) : buf_len;
uint8_t *buf = new uint8_t[len + 1 + MemHeaderSz];
Header &hdr = reinterpret_cast<Header &>(*buf);
hdr.Length = len;
char *text_ptr = reinterpret_cast<char *>(buf + MemHeaderSz);
if (text)
memcpy(text_ptr, text, len + 1);
int32_t handle = ccRegisterManagedObject(text_ptr, &_GP(myScriptStringImpl));
if (handle == 0) {
delete[] buf;
return DynObjectRef();
}
return DynObjectRef(handle, text_ptr, &_GP(myScriptStringImpl));
}
} // namespace AGS3

View 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_ENGINE_AC_DYNOBJ_SCRIPT_STRING_H
#define AGS_ENGINE_AC_DYNOBJ_SCRIPT_STRING_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct ScriptString final : AGSCCDynamicObject {
public:
struct Header {
uint32_t Length = 0u;
};
ScriptString() = default;
~ScriptString() = default;
inline static const Header &GetHeader(const void *address) {
return reinterpret_cast<const Header &>(*(static_cast<const uint8_t *>(address) - MemHeaderSz));
}
// Create a new script string by copying the given text
static DynObjectRef Create(const char *text) { return CreateImpl(text, 0); }
// Create a new script string with a buffer of at least the given text length
static DynObjectRef Create(size_t buf_len) { return CreateImpl(nullptr, buf_len); }
const char *GetType() override;
int Dispose(void *address, bool force) override;
void Unserialize(int index, AGS::Shared::Stream *in, size_t data_sz) override;
private:
// The size of the array's header in memory, prepended to the element data
static const size_t MemHeaderSz = sizeof(Header);
// The size of the serialized header
static const size_t FileHeaderSz = sizeof(uint32_t);
static DynObjectRef CreateImpl(const char *text, size_t buf_len);
// Savegame serialization
// Calculate and return required space for serialization, in bytes
size_t CalcSerializeSize(const void *address) override;
// Write object data into the provided stream
void Serialize(const void *address, AGS::Shared::Stream *out) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,74 @@
/* 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/engine/debugging/debug_log.h"
#include "ags/engine/ac/dynobj/script_system.h"
#include "ags/shared/script/cc_common.h" // cc_error
namespace AGS3 {
int32_t ScriptSystem::ReadInt32(void *address, intptr_t offset) {
const int index = offset / sizeof(int32_t);
switch (index) {
case 0:
return width;
case 1:
return height;
case 2:
return coldepth;
case 3:
return os;
case 4:
return windowed;
case 5:
return vsync;
case 6:
return viewport_width;
case 7:
return viewport_height;
default:
cc_error("ScriptSystem: unsupported variable offset %d", offset);
return 0;
}
}
void ScriptSystem::WriteInt32(void *address, intptr_t offset, int32_t val) {
const int index = offset / sizeof(int32_t);
switch (index) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 6:
case 7:
debug_script_warn("ScriptSystem: attempt to write in readonly variable at offset %d, value %d", offset, val);
break;
case 5:
vsync = val;
break;
default:
cc_error("ScriptSystem: unsupported variable offset %d", offset);
break;
}
}
} // namespace AGS3

View 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/>.
*
*/
// Wrapper around script "System" struct, managing access to its variables.
// ScriptSystem is a readable/writeable struct which had been exposed to
// script in older versions of API (deprecated).
// WARNING: it *MUST* keep its size exact to avoid breaking address offsets
// when running old scripts. In case of emergency you may use its reserved
// fields, but it's not recommended to do, as this struct is not a part of
// the modern API anymore.
#ifndef AGS_ENGINE_DYNOBJ_SCRIPT_SYSTEM_H
#define AGS_ENGINE_DYNOBJ_SCRIPT_SYSTEM_H
#include "ags/engine/ac/dynobj/cc_ags_dynamic_object.h"
namespace AGS3 {
struct ScriptSystem : AGSCCStaticObject {
int width = 0; // game screen width
int height = 0; // game screen height
int coldepth = 0; // game's color depth, in bits per pixel (8, 16, 32)
int os = 0; // operating system's code (see eScriptSystemOSID)
int windowed = 0; // windowed/fullscreen flag
int vsync = 0; // vertical sync flag
int viewport_width = 0; // game viewport width (normal or letterboxed)
int viewport_height = 0; // game viewport height (normal or letterboxed)
char aci_version[10]{}; // engine version string (informational)
int reserved[5]{}; // reserved fields
int32_t ReadInt32(void *address, intptr_t offset) override;
void WriteInt32(void *address, intptr_t offset, int32_t val) override;
};
} // namespace AGS3
#endif

View File

@@ -0,0 +1,85 @@
/* 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/memory.h"
#include "ags/shared/util/stream.h"
#include "ags/engine/ac/dynobj/script_user_object.h"
#include "ags/engine/ac/dynobj/dynobj_manager.h"
#include "ags/globals.h"
namespace AGS3 {
using namespace AGS::Shared;
const char *ScriptUserObject::TypeName = "UserObject";
// return the type name of the object
const char *ScriptUserObject::GetType() {
return TypeName;
}
/* static */ DynObjectRef ScriptUserObject::Create(size_t size) {
uint8_t *new_data = new uint8_t[size + MemHeaderSz];
memset(new_data, 0, size + MemHeaderSz);
Header &hdr = reinterpret_cast<Header &>(*new_data);
hdr.Size = size;
void *obj_ptr = &new_data[MemHeaderSz];
int32_t handle = ccRegisterManagedObject(obj_ptr, &_G(globalDynamicStruct));
if (handle == 0) {
delete[] new_data;
return DynObjectRef();
}
return DynObjectRef(handle, obj_ptr, &_G(globalDynamicStruct));
}
int ScriptUserObject::Dispose(void *address, bool /*force*/) {
delete[] (static_cast<uint8_t *>(address) - MemHeaderSz);
return 1;
}
size_t ScriptUserObject::CalcSerializeSize(const void *address) {
const Header &hdr = GetHeader(address);
return hdr.Size + FileHeaderSz;
}
void ScriptUserObject::Serialize(const void *address, AGS::Shared::Stream *out) {
const Header &hdr = GetHeader(address);
// NOTE: we only write the data, no header at the moment
out->Write(address, hdr.Size);
}
void ScriptUserObject::Unserialize(int index, Stream *in, size_t data_sz) {
uint8_t *new_data = new uint8_t[(data_sz - FileHeaderSz) + MemHeaderSz];
Header &hdr = reinterpret_cast<Header &>(*new_data);
hdr.Size = data_sz - FileHeaderSz;
in->Read(new_data + MemHeaderSz, data_sz - FileHeaderSz);
ccRegisterUnserializedObject(index, &new_data[MemHeaderSz], this);
}
// Allocates managed struct containing two ints: X and Y
ScriptUserObject *ScriptStructHelpers::CreatePoint(int x, int y) {
DynObjectRef ref = ScriptUserObject::Create(sizeof(int32_t) * 2);
ref.Mgr->WriteInt32(ref.Obj, 0, x);
ref.Mgr->WriteInt32(ref.Obj, sizeof(int32_t), y);
return static_cast<ScriptUserObject *>(ref.Obj);
}
} // namespace AGS3

Some files were not shown because too many files have changed in this diff Show More